Browse Source

Basic initial port of About screen to Compose

arkon 2 years ago
parent
commit
d6c87ec10e

+ 1 - 0
app/build.gradle.kts

@@ -142,6 +142,7 @@ dependencies {
     implementation(compose.foundation)
     implementation(compose.material3.core)
     implementation(compose.material3.adapter)
+    implementation(compose.material.icons)
     implementation(compose.animation)
     implementation(compose.ui.tooling)
 

+ 39 - 0
app/src/main/java/eu/kanade/presentation/components/LinkIcon.kt

@@ -0,0 +1,39 @@
+package eu.kanade.presentation.components
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.platform.LocalUriHandler
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun LinkIcon(
+    modifier: Modifier = Modifier,
+    label: String,
+    painter: Painter,
+    url: String,
+) {
+    val uriHandler = LocalUriHandler.current
+    LinkIcon(modifier, label, painter) { uriHandler.openUri(url) }
+}
+
+@Composable
+fun LinkIcon(
+    modifier: Modifier = Modifier,
+    label: String,
+    painter: Painter,
+    onClick: () -> Unit,
+) {
+    Icon(
+        modifier = modifier
+            .clickable(onClick = onClick)
+            .padding(16.dp),
+        painter = painter,
+        tint = MaterialTheme.colorScheme.primary,
+        contentDescription = label,
+    )
+}

+ 89 - 0
app/src/main/java/eu/kanade/presentation/components/Preferences.kt

@@ -0,0 +1,89 @@
+package eu.kanade.presentation.components
+
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.contentColorFor
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import eu.kanade.presentation.util.horizontalPadding
+
+@Composable
+fun PreferenceRow(
+    title: String,
+    icon: ImageVector? = null,
+    onClick: () -> Unit = {},
+    onLongClick: () -> Unit = {},
+    subtitle: String? = null,
+    action: @Composable (() -> Unit)? = null,
+) {
+    val height = if (subtitle != null) 72.dp else 56.dp
+
+    // TODO: adjust text styles, especially subtitles
+    val textStyle = MaterialTheme.typography.titleMedium.copy(
+        color = contentColorFor(MaterialTheme.colorScheme.background),
+    )
+
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .requiredHeight(height)
+            .combinedClickable(
+                onLongClick = onLongClick,
+                onClick = onClick
+            ),
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+        if (icon != null) {
+            Icon(
+                imageVector = icon,
+                modifier = Modifier
+                    .padding(horizontal = horizontalPadding)
+                    .size(24.dp),
+                tint = MaterialTheme.colorScheme.primary,
+                contentDescription = null
+            )
+        }
+        Column(
+            Modifier
+                .padding(horizontal = horizontalPadding)
+                .weight(1f)
+        ) {
+            Text(
+                text = title,
+                overflow = TextOverflow.Ellipsis,
+                maxLines = 1,
+                style = textStyle,
+            )
+            if (subtitle != null) {
+                Text(
+                    text = subtitle,
+                    overflow = TextOverflow.Ellipsis,
+                    maxLines = 1,
+                    style = textStyle.copy(
+                        fontWeight = FontWeight.Normal,
+                    ),
+                )
+            }
+        }
+        if (action != null) {
+            Box(Modifier.widthIn(min = 56.dp)) {
+                action()
+            }
+        }
+    }
+}

+ 144 - 0
app/src/main/java/eu/kanade/presentation/more/AboutScreen.kt

@@ -0,0 +1,144 @@
+package eu.kanade.presentation.more
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Public
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalUriHandler
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import eu.kanade.presentation.components.LinkIcon
+import eu.kanade.presentation.components.PreferenceRow
+import eu.kanade.tachiyomi.BuildConfig
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.updater.RELEASE_URL
+import eu.kanade.tachiyomi.util.CrashLogUtil
+import eu.kanade.tachiyomi.util.system.copyToClipboard
+
+@Composable
+fun AboutScreen(
+    nestedScrollInterop: NestedScrollConnection,
+    checkVersion: () -> Unit,
+    getFormattedBuildTime: () -> String,
+    onClickLicenses: () -> Unit,
+) {
+    val context = LocalContext.current
+    val uriHandler = LocalUriHandler.current
+
+    LazyColumn(
+        modifier = Modifier.nestedScroll(nestedScrollInterop),
+    ) {
+        item {
+            LogoHeader()
+        }
+
+        item {
+            PreferenceRow(
+                title = stringResource(R.string.version),
+                subtitle = when {
+                    BuildConfig.DEBUG -> {
+                        "Debug ${BuildConfig.COMMIT_SHA} (${getFormattedBuildTime()})"
+                    }
+                    BuildConfig.PREVIEW -> {
+                        "Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA}, ${getFormattedBuildTime()})"
+                    }
+                    else -> {
+                        "Stable ${BuildConfig.VERSION_NAME} (${getFormattedBuildTime()})"
+                    }
+                },
+                onClick = {
+                    val deviceInfo = CrashLogUtil(context).getDebugInfo()
+                    context.copyToClipboard("Debug information", deviceInfo)
+                },
+            )
+        }
+
+        if (BuildConfig.INCLUDE_UPDATER) {
+            item {
+                PreferenceRow(
+                    title = stringResource(R.string.check_for_updates),
+                    onClick = {
+                        checkVersion()
+                    },
+                )
+            }
+        }
+        if (!BuildConfig.DEBUG) {
+            item {
+                PreferenceRow(
+                    title = stringResource(R.string.whats_new),
+                    onClick = {
+                        uriHandler.openUri(RELEASE_URL)
+                    },
+                )
+            }
+        }
+
+        item {
+            PreferenceRow(
+                title = stringResource(R.string.help_translate),
+                onClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") },
+            )
+        }
+
+        item {
+            PreferenceRow(
+                title = stringResource(R.string.licenses),
+                onClick = onClickLicenses,
+            )
+        }
+
+        item {
+            PreferenceRow(
+                title = stringResource(R.string.privacy_policy),
+                onClick = { uriHandler.openUri("https://tachiyomi.org/privacy") },
+            )
+        }
+
+        item {
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalArrangement = Arrangement.Center,
+            ) {
+                LinkIcon(
+                    label = stringResource(R.string.website),
+                    painter = rememberVectorPainter(Icons.Outlined.Public),
+                    url = "https://tachiyomi.org",
+                )
+                LinkIcon(
+                    label = "Discord",
+                    painter = painterResource(R.drawable.ic_discord_24dp),
+                    url = "https://discord.gg/tachiyomi",
+                )
+                LinkIcon(
+                    label = "Twitter",
+                    painter = painterResource(R.drawable.ic_twitter_24dp),
+                    url = "https://twitter.com/tachiyomiorg",
+                )
+                LinkIcon(
+                    label = "Facebook",
+                    painter = painterResource(R.drawable.ic_facebook_24dp),
+                    url = "https://facebook.com/tachiyomiorg",
+                )
+                LinkIcon(
+                    label = "Reddit",
+                    painter = painterResource(R.drawable.ic_reddit_24dp),
+                    url = "https://www.reddit.com/r/Tachiyomi",
+                )
+                LinkIcon(
+                    label = "GitHub",
+                    painter = painterResource(R.drawable.ic_github_24dp),
+                    url = "https://github.com/tachiyomiorg",
+                )
+            }
+        }
+    }
+}

+ 28 - 0
app/src/main/java/eu/kanade/presentation/more/LicensesScreen.kt

@@ -0,0 +1,28 @@
+package eu.kanade.presentation.more
+
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.contentColorFor
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
+import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
+
+@Composable
+fun LicensesScreen(
+    nestedScrollInterop: NestedScrollConnection,
+) {
+    LibrariesContainer(
+        modifier = Modifier
+            .fillMaxSize()
+            .nestedScroll(nestedScrollInterop),
+        colors = LibraryDefaults.libraryColors(
+            backgroundColor = MaterialTheme.colorScheme.background,
+            contentColor = contentColorFor(MaterialTheme.colorScheme.background),
+            badgeBackgroundColor = MaterialTheme.colorScheme.primary,
+            badgeContentColor = contentColorFor(MaterialTheme.colorScheme.primary),
+        ),
+    )
+}

+ 36 - 0
app/src/main/java/eu/kanade/presentation/more/LogoHeader.kt

@@ -0,0 +1,36 @@
+package eu.kanade.presentation.more
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Divider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import eu.kanade.tachiyomi.R
+
+@Composable
+fun LogoHeader() {
+    Column {
+        Surface(
+            modifier = Modifier.fillMaxWidth()
+        ) {
+            Icon(
+                painter = painterResource(R.drawable.ic_tachi),
+                contentDescription = null,
+                tint = MaterialTheme.colorScheme.onSurface,
+                modifier = Modifier
+                    .padding(32.dp)
+                    .size(56.dp),
+            )
+        }
+
+        // TODO: proper color
+        Divider()
+    }
+}

+ 19 - 81
app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt

@@ -1,106 +1,44 @@
 package eu.kanade.tachiyomi.ui.more
 
-import androidx.preference.PreferenceScreen
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import eu.kanade.presentation.more.AboutScreen
 import eu.kanade.tachiyomi.BuildConfig
 import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
 import eu.kanade.tachiyomi.data.updater.AppUpdateResult
-import eu.kanade.tachiyomi.data.updater.RELEASE_URL
+import eu.kanade.tachiyomi.ui.base.controller.BasicComposeController
 import eu.kanade.tachiyomi.ui.base.controller.NoAppBarElevationController
-import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
-import eu.kanade.tachiyomi.ui.setting.SettingsController
-import eu.kanade.tachiyomi.util.CrashLogUtil
 import eu.kanade.tachiyomi.util.lang.launchNow
 import eu.kanade.tachiyomi.util.lang.toDateTimestampString
-import eu.kanade.tachiyomi.util.preference.add
-import eu.kanade.tachiyomi.util.preference.onClick
-import eu.kanade.tachiyomi.util.preference.preference
-import eu.kanade.tachiyomi.util.preference.titleRes
-import eu.kanade.tachiyomi.util.system.copyToClipboard
 import eu.kanade.tachiyomi.util.system.logcat
 import eu.kanade.tachiyomi.util.system.toast
 import logcat.LogPriority
+import uy.kohesive.injekt.injectLazy
 import java.text.DateFormat
 import java.text.SimpleDateFormat
 import java.util.Locale
 import java.util.TimeZone
 
-class AboutController : SettingsController(), NoAppBarElevationController {
+class AboutController : BasicComposeController(), NoAppBarElevationController {
 
+    private val preferences: PreferencesHelper by injectLazy()
     private val updateChecker by lazy { AppUpdateChecker() }
 
-    private val dateFormat: DateFormat = preferences.dateFormat()
+    override fun getTitle() = resources?.getString(R.string.pref_category_about)
 
-    override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
-        titleRes = R.string.pref_category_about
-
-        add(MoreHeaderPreference(context))
-
-        preference {
-            key = "pref_about_version"
-            titleRes = R.string.version
-            summary = when {
-                BuildConfig.DEBUG -> {
-                    "Debug ${BuildConfig.COMMIT_SHA} (${getFormattedBuildTime()})"
-                }
-                BuildConfig.PREVIEW -> {
-                    "Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA}, ${getFormattedBuildTime()})"
-                }
-                else -> {
-                    "Stable ${BuildConfig.VERSION_NAME} (${getFormattedBuildTime()})"
-                }
-            }
-
-            onClick {
-                activity?.let {
-                    val deviceInfo = CrashLogUtil(it).getDebugInfo()
-                    it.copyToClipboard("Debug information", deviceInfo)
-                }
-            }
-        }
-        if (BuildConfig.INCLUDE_UPDATER) {
-            preference {
-                key = "pref_about_check_for_updates"
-                titleRes = R.string.check_for_updates
-
-                onClick { checkVersion() }
-            }
-        }
-        if (!BuildConfig.DEBUG) {
-            preference {
-                key = "pref_about_whats_new"
-                titleRes = R.string.whats_new
-
-                onClick {
-                    openInBrowser(RELEASE_URL)
-                }
-            }
-        }
-        preference {
-            key = "pref_about_help_translate"
-            titleRes = R.string.help_translate
-
-            onClick {
-                openInBrowser("https://tachiyomi.org/help/contribution/#translation")
-            }
-        }
-        preference {
-            key = "pref_about_licenses"
-            titleRes = R.string.licenses
-            onClick {
+    @Composable
+    override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
+        AboutScreen(
+            nestedScrollInterop = nestedScrollInterop,
+            checkVersion = this::checkVersion,
+            getFormattedBuildTime = this::getFormattedBuildTime,
+            onClickLicenses = {
                 router.pushController(LicensesController().withFadeTransaction())
-            }
-        }
-        preference {
-            key = "pref_about_privacy_policy"
-            titleRes = R.string.privacy_policy
-            onClick {
-                openInBrowser("https://tachiyomi.org/privacy")
-            }
-        }
-
-        add(AboutLinksPreference(context))
+            },
+        )
     }
 
     /**
@@ -142,7 +80,7 @@ class AboutController : SettingsController(), NoAppBarElevationController {
             )
             outputDf.timeZone = TimeZone.getDefault()
 
-            buildTime!!.toDateTimestampString(dateFormat)
+            buildTime!!.toDateTimestampString(preferences.dateFormat())
         } catch (e: Exception) {
             BuildConfig.BUILD_TIME
         }

+ 2 - 18
app/src/main/java/eu/kanade/tachiyomi/ui/more/LicensesController.kt

@@ -1,14 +1,8 @@
 package eu.kanade.tachiyomi.ui.more
 
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.contentColorFor
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
-import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults.libraryColors
+import eu.kanade.presentation.more.LicensesScreen
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.ui.base.controller.BasicComposeController
 
@@ -18,16 +12,6 @@ class LicensesController : BasicComposeController() {
 
     @Composable
     override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
-        LibrariesContainer(
-            modifier = Modifier
-                .fillMaxSize()
-                .nestedScroll(nestedScrollInterop),
-            colors = libraryColors(
-                backgroundColor = MaterialTheme.colorScheme.background,
-                contentColor = contentColorFor(MaterialTheme.colorScheme.background),
-                badgeBackgroundColor = MaterialTheme.colorScheme.primary,
-                badgeContentColor = contentColorFor(MaterialTheme.colorScheme.primary),
-            ),
-        )
+        LicensesScreen(nestedScrollInterop = nestedScrollInterop)
     }
 }

+ 1 - 0
gradle/compose.versions.toml

@@ -5,5 +5,6 @@ compose = "1.2.0-alpha07"
 foundation = { module = "androidx.compose.foundation:foundation", version.ref="compose" }
 material3-core = "androidx.compose.material3:material3:1.0.0-alpha09"
 material3-adapter = "com.google.android.material:compose-theme-adapter-3:1.0.6"
+material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref="compose" }
 animation = { module = "androidx.compose.animation:animation", version.ref="compose" }
 ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref="compose" }