From eb803a8c8c675c1bf2603bf02f6be9afbfc1b1ac Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:13:31 +0300 Subject: [PATCH] Update about screen --- src/android/app/build.gradle.kts | 2 + .../info/cemu/cemu/about/AboutCemuScreen.kt | 186 ++++++++++++++---- .../app/src/main/res/values/strings.xml | 1 + src/android/build.gradle.kts | 1 + 4 files changed, 151 insertions(+), 39 deletions(-) diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 349747b2..314d437e 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -11,6 +11,7 @@ plugins { alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.kotlinx.gettext) + alias(libs.plugins.aboutlibraries.android) } fun String.runCommand(workingDir: File = File(".")): String? { @@ -217,6 +218,7 @@ gettext { } dependencies { + implementation(libs.aboutlibraries.compose.m3) implementation(libs.kotlinx.gettext) implementation(libs.kotlinx.serialization.json) implementation(libs.androidx.activity.compose) diff --git a/src/android/app/src/main/java/info/cemu/cemu/about/AboutCemuScreen.kt b/src/android/app/src/main/java/info/cemu/cemu/about/AboutCemuScreen.kt index 3a1fd304..4b917e7f 100644 --- a/src/android/app/src/main/java/info/cemu/cemu/about/AboutCemuScreen.kt +++ b/src/android/app/src/main/java/info/cemu/cemu/about/AboutCemuScreen.kt @@ -1,16 +1,24 @@ package info.cemu.cemu.about +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.LinkAnnotation @@ -18,18 +26,31 @@ import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextLinkStyles import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.withLink import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.mikepenz.aboutlibraries.Libs +import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults +import com.mikepenz.aboutlibraries.ui.compose.android.rememberLibraries +import com.mikepenz.aboutlibraries.ui.compose.m3.LicenseDialog +import com.mikepenz.aboutlibraries.ui.compose.m3.LicenseDialogBody +import com.mikepenz.aboutlibraries.ui.compose.m3.libraryColors +import com.mikepenz.aboutlibraries.ui.compose.util.author import info.cemu.cemu.BuildConfig import info.cemu.cemu.R -import info.cemu.cemu.core.components.ScreenContent +import info.cemu.cemu.core.components.ScreenContentLazy import info.cemu.cemu.core.translation.tr +import kotlinx.collections.immutable.persistentListOf + +typealias AboutLibrary = com.mikepenz.aboutlibraries.entity.Library -// TODO @Composable fun AboutCemuScreen(navigateBack: () -> Unit) { - ScreenContent( + var openLicenseDialog by remember { mutableStateOf(null) } + val libraries by rememberLibraries(R.raw.aboutlibraries) + + ScreenContentLazy( appBarText = tr("About Cemu"), navigateBack = navigateBack, contentModifier = Modifier @@ -37,6 +58,33 @@ fun AboutCemuScreen(navigateBack: () -> Unit) { .padding(16.dp), contentVerticalArrangement = Arrangement.spacedBy(16.dp), ) { + aboutCemuSection() + disclaimerSection() + nativeLibrariesSection() + kotlinLibrariesSection( + libraries = libraries, + onOpenLicense = { lib -> openLicenseDialog = lib }, + ) + } + + openLicenseDialog?.let { library -> + LicenseDialog( + library = library, + body = { library, modifier -> + LicenseDialogBody( + library = library, + colors = LibraryDefaults.libraryColors(), + modifier = Modifier.padding(4.dp) + ) + }, + onDismiss = { openLicenseDialog = null }, + confirmText = tr("OK"), + ) + } +} + +private fun LazyListScope.aboutCemuSection() { + item { AboutSection { Text( text = stringResource(R.string.app_name), @@ -55,34 +103,87 @@ fun AboutCemuScreen(navigateBack: () -> Unit) { ) CemuWebsite() } + } +} + +private fun LazyListScope.disclaimerSection() { + item { AboutSection { Text( text = tr("Cemu is a Wii U emulator.\n\nWii and Wii U are trademarks of Nintendo.\nCemu is not affiliated with Nintendo."), fontSize = 18.sp ) } + } +} + +private fun LazyListScope.nativeLibrariesSection() { + item { AboutSection { Text( text = tr("Used libraries:"), - fontSize = 18.sp, + fontSize = 24.sp, ) UsedLibraries.forEach { Library(it) } - Text(tr("Modified ih264 from Android project")) + } + } +} + +private fun LazyListScope.kotlinLibrariesSection( + libraries: Libs?, + onOpenLicense: (AboutLibrary) -> Unit, +) { + val libs = libraries?.libraries ?: persistentListOf() + item { + Text( + modifier = Modifier.padding(horizontal = 8.dp), + text = tr("Kotlin libraries:"), + fontSize = 24.sp, + ) + } + items(items = libs) { lib -> + Column( + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier + .padding(horizontal = 8.dp) + .clickable { onOpenLicense(lib) }, + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = lib.name, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f) + ) + Text(lib.artifactVersion ?: "") + } + Text(lib.author) + FlowRow(horizontalArrangement = Arrangement.SpaceBetween) { + lib.licenses.forEach { license -> + Card { + Text( + text = license.name, + modifier = Modifier.padding(horizontal = 4.dp) + ) + } + } + } } } } @Composable -fun CemuWebsite() { +private fun CemuWebsite() { Text( buildAnnotatedString { - append(tr("Website:")) - append(" ") withLink( LinkAnnotation.Url( - CEMU_WEBSITE, + stringResource(R.string.cemu_website), TextLinkStyles( style = SpanStyle( color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -91,40 +192,33 @@ fun CemuWebsite() { ) ) ) { - append(CEMU_WEBSITE) + append(stringResource(R.string.cemu_website)) } } ) } @Composable -fun AboutSection(content: @Composable ColumnScope.() -> Unit) { - Card( - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surfaceContainerHigh, - ), - modifier = Modifier.fillMaxWidth(), - ) { - SelectionContainer { - Column( - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.padding(16.dp), - content = content, - ) - } +private fun AboutSection(content: @Composable ColumnScope.() -> Unit) { + SelectionContainer { + Column( + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.padding(8.dp), + content = content, + ) } } @Composable -fun Library(nameLinkPair: Pair) { - val (name, link) = nameLinkPair +private fun Library(library: Library) { + val (name, source) = library Text( buildAnnotatedString { append(name) append(" (") withLink( LinkAnnotation.Url( - link, + source.url, TextLinkStyles( style = SpanStyle( color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -133,21 +227,35 @@ fun Library(nameLinkPair: Pair) { ) ) ) { - append(link) + append(source.name ?: source.url) } append(")") } ) } -private val UsedLibraries: List> = listOf( - "zlib" to "https://www.zlib.net", - "OpenSSL" to "https://www.openssl.org", - "libcurl" to "https://curl.haxx.se/libcurl", - "imgui" to "https://github.com/ocornut/imgui", - "fontawesome" to "https://github.com/FortAwesome/Font-Awesome", - "boost" to "https://www.boost.org", - "libusb" to "https://libusb.info", -) +private data class LibrarySource(val url: String, val name: String? = null) -private const val CEMU_WEBSITE = "https://cemu.info" +private data class Library( + val text: String, + val source: LibrarySource, +) { + constructor(text: String, url: String) : this(text, LibrarySource(url)) +} + +private val UsedLibraries: List = listOf( + Library("zlib", "https://www.zlib.net"), + Library("OpenSSL", "https://www.openssl.org"), + Library("libcurl", "https://curl.haxx.se/libcurl"), + Library("imgui", "https://github.com/ocornut/imgui"), + Library("fontawesome", "https://github.com/FortAwesome/Font-Awesome"), + Library("boost", "https://www.boost.org"), + Library("libusb", "https://libusb.info"), + Library( + "Modified ih264 from Android project", + LibrarySource( + "https://github.com/cemu-project/Cemu/tree/main/dependencies/ih264d", + "Source" + ) + ) +) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 1d130bd6..0008947b 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ Cemu Exzap, Petergov + https://cemu.info \ No newline at end of file diff --git a/src/android/build.gradle.kts b/src/android/build.gradle.kts index d3527356..04957b8d 100644 --- a/src/android/build.gradle.kts +++ b/src/android/build.gradle.kts @@ -5,4 +5,5 @@ plugins { alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.kotlin.serialization) apply false + alias(libs.plugins.aboutlibraries.android) apply false }