From 79e3f72cd288e5851e7c418e990c8daa9bb0dbbe Mon Sep 17 00:00:00 2001 From: McCal-Codes <175259256+McCal-Codes@users.noreply.github.com> Date: Tue, 22 Sep 2026 11:22:06 -0400 Subject: [PATCH] The Market says when AI helped make a package A package that declares aiAssisted gets an AI-assisted tag beside its developer, a Made with AI line (and the author's note) under Information, and a Made with help from AI line on the install sheet before Get. Plain grey, not a warning. English and Simplified Chinese. --- .../com/mccal/folio/MarketInstallSheet.kt | 11 ++++++++++ .../main/java/com/mccal/folio/MarketScreen.kt | 22 +++++++++++++++++++ app/src/main/res/values-b+zh+Hans/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 4 ++++ .../com/mccal/folio/MarketScreenRenderTest.kt | 16 ++++++++++++++ docs/standards/ai-contributions.md | 6 ++--- 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/mccal/folio/MarketInstallSheet.kt b/app/src/main/java/com/mccal/folio/MarketInstallSheet.kt index a9f99de8..c2899336 100644 --- a/app/src/main/java/com/mccal/folio/MarketInstallSheet.kt +++ b/app/src/main/java/com/mccal/folio/MarketInstallSheet.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.AutoAwesome import androidx.compose.material.icons.rounded.Check import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.Shield @@ -78,6 +79,16 @@ internal fun MarketInstallSheet( stringResource(R.string.text_1_s_version_2_s, manifest.author.name.english, manifest.version.toString()), color = Color.White.copy(alpha = .55f), fontSize = 14.sp, modifier = Modifier.padding(bottom = 12.dp), ) + // Said before Get, because it's part of deciding: the author declared AI helped make this. + manifest.aiAssisted?.let { ai -> + Row(Modifier.padding(bottom = 12.dp).testTag("install-ai-assisted"), verticalAlignment = Alignment.Top) { + Icon(Icons.Rounded.AutoAwesome, contentDescription = null, tint = Color.White.copy(alpha = .55f), modifier = Modifier.size(16.dp).padding(top = 2.dp)) + Column(Modifier.padding(start = 8.dp)) { + Text(stringResource(R.string.made_with_help_from_ai_1_s, ai.tools.joinToString()), color = Color.White.copy(alpha = .85f), fontSize = 14.sp) + ai.note?.let { Text(it.english, color = Color.White.copy(alpha = .55f), fontSize = 13.sp) } + } + } + } Row(Modifier.fillMaxWidth().clip(RoundedCornerShape(14.dp)).background(Color(0xFF2C2C2E)).padding(14.dp)) { Icon(Icons.Rounded.Shield, contentDescription = null, tint = Color(0xFF30D158), modifier = Modifier.size(20.dp)) diff --git a/app/src/main/java/com/mccal/folio/MarketScreen.kt b/app/src/main/java/com/mccal/folio/MarketScreen.kt index ca02e0e6..dbd0b9fd 100644 --- a/app/src/main/java/com/mccal/folio/MarketScreen.kt +++ b/app/src/main/java/com/mccal/folio/MarketScreen.kt @@ -24,6 +24,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.border import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -1044,6 +1045,9 @@ private fun MarketPackagePage( Column { Text(name, color = Color.White, fontSize = 26.sp, fontWeight = FontWeight.Bold) entry.manifest?.author?.name?.english?.let { Text(it, color = Color.White.copy(alpha = .55f), fontSize = 14.sp) } + // The author said AI helped make it (the manifest's aiAssisted). A plain tag, not a warning: it's + // how the package was made, the way the author line says who made it. + if (entry.manifest?.aiAssisted != null) AiAssistedTag(Modifier.padding(top = 4.dp)) } } @@ -1179,6 +1183,13 @@ private fun MarketPackagePage( color = Color.White.copy(alpha = .55f), fontSize = 13.sp, ) installed?.let { Text(stringResource(R.string.installed_1_s, it.version), color = Color.White.copy(alpha = .55f), fontSize = 13.sp) } + entry.manifest?.aiAssisted?.let { ai -> + Text( + stringResource(R.string.made_with_ai_1_s, ai.tools.joinToString()), + color = Color.White.copy(alpha = .85f), fontSize = 14.sp, modifier = Modifier.padding(top = 4.dp), + ) + ai.note?.let { Text(it.english, color = Color.White.copy(alpha = .55f), fontSize = 13.sp) } + } if (external) { // Where it comes from, and whether Android has it - the two things the store can honestly say // about an app it doesn't install. @@ -1219,6 +1230,17 @@ private fun MarketPackagePage( } } +/** "AI-assisted", beside the developer on a package page. */ +@Composable +internal fun AiAssistedTag(modifier: Modifier = Modifier) { + Text( + stringResource(R.string.ai_assisted), + color = Color.White.copy(alpha = .7f), fontSize = 11.sp, + modifier = modifier.border(0.5.dp, Color.White.copy(alpha = .3f), RoundedCornerShape(50)) + .padding(horizontal = 7.dp, vertical = 1.dp).testTag("package-ai-assisted"), + ) +} + /** The "… is on · Undo" line, the same shape as Folio's other undo messages. */ @Composable private fun MarketMessage(text: String, undo: (() -> Unit)?, onDismiss: () -> Unit) { diff --git a/app/src/main/res/values-b+zh+Hans/strings.xml b/app/src/main/res/values-b+zh+Hans/strings.xml index 5ece3c94..aecd3829 100644 --- a/app/src/main/res/values-b+zh+Hans/strings.xml +++ b/app/src/main/res/values-b+zh+Hans/strings.xml @@ -834,6 +834,9 @@ 信息 源:%1$s 内置于 Folio + AI 辅助 + 借助 AI 制作:%1$s + 在 AI 帮助下制作:%1$s 在 App 内 Folio 无法连接到这个源 显示的是之前的列表。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 868879b0..e95a3a35 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -838,6 +838,10 @@ Information Source: %1$s Built into Folio + + AI-assisted + Made with AI: %1$s + Made with help from AI: %1$s Inside the app Folio couldn\'t reach this source Showing the list it had before. diff --git a/app/src/test/java/com/mccal/folio/MarketScreenRenderTest.kt b/app/src/test/java/com/mccal/folio/MarketScreenRenderTest.kt index 37b637e6..3060505c 100644 --- a/app/src/test/java/com/mccal/folio/MarketScreenRenderTest.kt +++ b/app/src/test/java/com/mccal/folio/MarketScreenRenderTest.kt @@ -171,6 +171,22 @@ class MarketScreenRenderTest { assertEquals(listOf("com.mccal.folio.cabinet"), session.installed().map { it.id }) } + @Test fun `the install sheet says when AI helped make a package, and says nothing when it didn't`() { + val root = generateSequence(java.io.File("").absoluteFile) { it.parentFile }.first { java.io.File(it, "CHANGELOG.md").exists() } + val cabinet = org.json.JSONObject(java.io.File(root, "docs/sdk/source/packages/cabinet/manifest.json").readText()) + fun manifest(json: org.json.JSONObject) = + (com.mccal.folio.market.PackageManifest.parse(json.toString()) as com.mccal.folio.market.ParseResult.Ok).value + val helped = manifest(org.json.JSONObject(cabinet.toString()).put("aiAssisted", + org.json.JSONObject().put("tools", org.json.JSONArray().put("Claude").put("Example tool")).put("note", "Drafted the page."))) + val shown = androidx.compose.runtime.mutableStateOf(helped) + compose.setContent { MarketInstallSheet(shown.value, InstallOrigin("From a source"), onGet = {}, onCancel = {}) } + compose.onNodeWithText("Made with help from AI: Claude, Example tool").assertExists() + compose.onNodeWithText("Drafted the page.").assertExists() + shown.value = manifest(cabinet) + compose.waitForIdle() + compose.onNodeWithTag("install-ai-assisted", useUnmergedTree = true).assertDoesNotExist() + } + @Test fun `a package from a source shows up in the list, with where it came from`() { val session = session() session.prefs.introductionSeen = true diff --git a/docs/standards/ai-contributions.md b/docs/standards/ai-contributions.md index 69ae911c..6b3153d4 100644 --- a/docs/standards/ai-contributions.md +++ b/docs/standards/ai-contributions.md @@ -34,8 +34,8 @@ The short version: an icon pack, a wallpaper, a layout preset) as **AI-assisted**, naming the tool: - a Market package sets `aiAssisted` in its manifest: `{ "tools": ["Claude"], "note": "Drafted the colours." }` ([format](../sdk/format-v1.md)); - - and, until the Market shows that field, also starts `description` with "AI-assisted (tool name)." so every Folio - version shows it (see Gaps); + - and also starts `description` with "AI-assisted (tool name).", because Folio 0.6.6 doesn't show the field + (later versions show it on the package page and the install sheet; see Gaps); - a theme in `themes/` starts its description the same way; - the credits or README that travels with it says so too. - **AI-7 MUST NOT** remove or reword an AI-assisted label when republishing, forking or updating someone else's @@ -73,6 +73,6 @@ The short version: | # | Work | Size | |---|---|---| -| 1 | Show `aiAssisted` on the Market's package page and at install; then the `description` prefix is no longer needed (the field itself is in schema v1 and the parser) | S | +| 1 | Drop the `description` prefix rule once the release that shows `aiAssisted` (package page and install sheet) has replaced 0.6.6 on most phones | S | | 2 | The same field in the community theme format (`themes/README.md`, `CommunityThemesTest`) | S | | 3 | A "made with AI" filter in the Market | S |