feat: update aboutlibraries, refine oss screen

This commit is contained in:
infi 2026-05-10 18:52:44 +02:00
parent 02050172f2
commit 779275ce62
8 changed files with 92 additions and 99 deletions

View File

@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.aboutlibraries)
alias(libs.plugins.aboutlibraries.android)
alias(libs.plugins.ksp)
alias(libs.plugins.sentry.android)
alias(libs.plugins.sqldelight)
@ -130,6 +131,7 @@ android {
viewBinding = true
compose = true
buildConfig = true
resValues = true
}
packaging {
resources {
@ -279,10 +281,9 @@ dependencies {
}
aboutLibraries {
additionalLicenses += listOf("ofl")
includePlatform = true
license {
strictMode = StrictMode.FAIL
allowedLicenses += listOf(
allowedLicenses.addAll(
"Apache-2.0",
"ASDKL",
"BSD-2-Clause",
@ -295,7 +296,13 @@ aboutLibraries {
"OFL",
"Public Domain"
)
configPath = "compliance"
additionalLicenses.addAll("ofl")
}
collect {
includePlatform = true
configPath = file("../compliance")
}
}
sqldelight {

View File

@ -1,16 +1,24 @@
package chat.stoat.composables.screens.settings
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.clickable
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.core.net.toUri
import chat.stoat.R
import chat.stoat.screens.about.Library
@Composable
fun AttributionItem(library: Library, onClick: () -> Unit) {
val context = LocalContext.current
ListItem(
headlineContent = {
Text(
@ -22,6 +30,21 @@ fun AttributionItem(library: Library, onClick: () -> Unit) {
text = stringResource(id = R.string.oss_attribution_tap_to_view_license)
)
},
trailingContent = {
library.website?.let { website ->
IconButton(onClick = {
val customTab = CustomTabsIntent
.Builder()
.build()
customTab.launchUrl(context, website.toUri())
}) {
Icon(
painter = painterResource(id = R.drawable.ic_open_in_new_24dp),
contentDescription = stringResource(id = R.string.oss_attribution_open_library_website)
)
}
}
},
modifier = Modifier
.clickable(onClick = onClick)
)

View File

@ -1,5 +1,6 @@
package chat.stoat.screens.about
import android.content.ClipData
import android.os.Build
import android.widget.Toast
import androidx.compose.foundation.Image
@ -30,17 +31,18 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.platform.toClipEntry
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@ -134,22 +136,9 @@ fun DebugInfo(viewModel: AboutViewModel) {
@Composable
fun AboutScreen(navController: NavController, viewModel: AboutViewModel = viewModel()) {
val context = LocalContext.current
val clipboardManager: ClipboardManager =
LocalClipboardManager.current
fun copyDebugInformation() {
clipboardManager.setText(
AnnotatedString(StoatJson.encodeToString(viewModel.getDebugInformation()))
)
if (Platform.needsShowClipboardNotification()) {
Toast.makeText(
context,
context.getString(R.string.copied),
Toast.LENGTH_SHORT
).show()
}
}
val resources = LocalResources.current
val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
Scaffold(
topBar = {
@ -248,7 +237,24 @@ fun AboutScreen(navController: NavController, viewModel: AboutViewModel = viewMo
1 -> {
DebugInfo(viewModel)
TextButton(onClick = ::copyDebugInformation) {
TextButton(onClick = {
scope.launch {
clipboard.setClipEntry(
ClipData.newPlainText(
"Stoat Debug Information",
StoatJson.encodeToString(viewModel.getDebugInformation())
).toClipEntry()
)
if (Platform.needsShowClipboardNotification()) {
Toast.makeText(
context,
resources.getString(R.string.copied),
Toast.LENGTH_SHORT
).show()
}
}
}) {
Text(text = stringResource(id = R.string.copy))
}
}

View File

@ -1,11 +1,8 @@
package chat.stoat.screens.about
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@ -16,7 +13,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
@ -30,12 +26,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
@ -47,16 +41,10 @@ import kotlinx.serialization.json.JsonArray
@Serializable
data class AboutLibraries(
val metadata: Metadata,
val libraries: List<Library>,
val licenses: Map<String, License>
)
@Serializable
data class Metadata(
val generated: String
)
@Serializable
data class License(
val content: String? = null,
@ -105,13 +93,13 @@ data class Scm(
fun AttributionScreen(navController: NavController) {
var libraries by remember { mutableStateOf<AboutLibraries?>(null) }
val context = LocalContext.current
val resources = LocalResources.current
var licenceSheetOpen by remember { mutableStateOf(false) }
var licenseSheetTarget by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
context.resources.openRawResource(R.raw.aboutlibraries).use { stream ->
resources.openRawResource(R.raw.aboutlibraries).use { stream ->
val text = stream.bufferedReader().use { it.readText() }
libraries = Json.decodeFromString(AboutLibraries.serializer(), text)
}
@ -181,37 +169,6 @@ fun AttributionScreen(navController: NavController) {
Box(Modifier.padding(pv)) {
libraries?.let {
LazyColumn {
item {
Column(
modifier = Modifier
.padding(16.dp)
.clip(MaterialTheme.shapes.medium)
.background(MaterialTheme.colorScheme.surfaceContainer)
.fillMaxWidth()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = stringResource(R.string.oss_attribution_body)
)
Text(
text = stringResource(R.string.oss_attribution_body_2)
)
Text(
text = stringResource(R.string.oss_attribution_warning),
color = MaterialTheme.colorScheme.error
)
Text(
text = stringResource(
R.string.oss_attribution_generation_date,
libraries?.metadata?.generated ?: ""
),
color = LocalContentColor.current.copy(alpha = 0.6f)
)
}
}
items(
items = it.libraries.sortedBy { library -> library.name }
) { library ->
@ -220,16 +177,6 @@ fun AttributionScreen(navController: NavController) {
licenseSheetTarget = library.licenses.firstOrNull() ?: ""
}
}
item(key = "cat") {
Text(
text = "🐈",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
textAlign = TextAlign.Center
)
}
}
}
}

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L480,120L480,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L760,760Q760,760 760,760Q760,760 760,760L760,480L840,480L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM388,628L332,572L704,200L560,200L560,120L840,120L840,400L760,400L760,256L388,628Z"/>
</vector>

View File

@ -90,12 +90,9 @@
<string name="about_tab_version">Version</string>
<string name="about_tab_details">Details</string>
<string name="oss_attribution">OSS Attribution</string>
<string name="oss_attribution_body">Stoat is built with the help of these awesome open-source projects.</string>
<string name="oss_attribution_body_2">We\'re grateful to the developers of these projects for making their work available to the world.</string>
<string name="oss_attribution_warning">The list below is automatically generated. It may be incomplete or inaccurate.</string>
<string name="oss_attribution_generation_date">Last updated: %1$s</string>
<string name="oss_attribution">OSS Licenses</string>
<string name="oss_attribution_tap_to_view_license">Tap to view license</string>
<string name="oss_attribution_open_library_website">Open library website</string>
<string name="comingsoon_toast">Sorry, this feature is not ready yet.</string>

View File

@ -6,6 +6,7 @@ plugins {
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.aboutlibraries) apply false
alias(libs.plugins.aboutlibraries.android) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.google.services) apply false
}

View File

@ -16,7 +16,7 @@ lifecycle = "2.10.0"
accompanist = "0.37.3"
ktor = "3.4.1"
glide = "5.0.5"
aboutlibraries = "11.3.0-rc02"
aboutlibraries = "15.0.0-a02"
media3 = "1.9.2"
telephoto = "1.0.0-alpha02"
haze = "1.7.2"
@ -110,6 +110,7 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
aboutlibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }
aboutlibraries-android = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutlibraries" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
sentry-android = { id = "io.sentry.android.gradle", version = "6.5.0" }