Browse Source

[gradle] Add DSL to configure compose resources (#4482)

Example:
```kotlin
compose.resources {
    publicResClass = true
    packageOfResClass = "me.sample.library.resources"
    generateResClass = auto
}
```
pull/4526/head
Konstantin 9 months ago committed by GitHub
parent
commit
0d0e133e86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt
  2. 6
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/GenerateResClassTask.kt
  3. 33
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesExtension.kt
  4. 113
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesGenerator.kt
  5. 10
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesSpec.kt
  6. 16
      gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt
  7. 84
      gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/Drawable0.kt
  8. 28
      gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/Font0.kt
  9. 31
      gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/Res.kt
  10. 130
      gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/String0.kt
  11. 9
      gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/commonTest/kotlin/ComposeAppTest.kt
  12. 5
      gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/build.gradle.kts
  13. 2
      gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/src/commonMain/kotlin/me/sample/library/Lib.kt

4
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt

@ -28,6 +28,7 @@ import org.jetbrains.compose.internal.mppExtOrNull
import org.jetbrains.compose.internal.service.ConfigurationProblemReporterService
import org.jetbrains.compose.internal.service.GradlePropertySnapshotService
import org.jetbrains.compose.internal.utils.currentTarget
import org.jetbrains.compose.resources.ResourcesExtension
import org.jetbrains.compose.resources.configureComposeResources
import org.jetbrains.compose.resources.ios.configureSyncTask
import org.jetbrains.compose.web.WebExtension
@ -52,6 +53,7 @@ abstract class ComposePlugin : Plugin<Project> {
val desktopExtension = composeExtension.extensions.create("desktop", DesktopExtension::class.java)
val androidExtension = composeExtension.extensions.create("android", AndroidExtension::class.java)
val experimentalExtension = composeExtension.extensions.create("experimental", ExperimentalExtension::class.java)
val resourcesExtension = composeExtension.extensions.create("resources", ResourcesExtension::class.java)
project.dependencies.extensions.add("compose", Dependencies(project))
@ -65,7 +67,7 @@ abstract class ComposePlugin : Plugin<Project> {
project.plugins.apply(ComposeCompilerKotlinSupportPlugin::class.java)
project.configureNativeCompilerCaching()
project.configureComposeResources()
project.configureComposeResources(resourcesExtension)
project.afterEvaluate {
configureDesktop(project, desktopExtension)

6
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/GenerateResClassTask.kt

@ -23,6 +23,9 @@ internal abstract class GenerateResClassTask : DefaultTask() {
@get:Input
abstract val shouldGenerateResClass: Property<Boolean>
@get:Input
abstract val makeResClassPublic: Property<Boolean>
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val resDir: Property<File>
@ -63,7 +66,8 @@ internal abstract class GenerateResClassTask : DefaultTask() {
getResFileSpecs(
resources,
packageName.get(),
moduleDir.getOrNull()?.let { it.invariantSeparatorsPath + "/" } ?: ""
moduleDir.getOrNull()?.let { it.invariantSeparatorsPath + "/" } ?: "",
makeResClassPublic.get()
).forEach { it.writeTo(kotlinDir) }
} else {
logger.info("Generation Res class is disabled")

33
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesExtension.kt

@ -0,0 +1,33 @@
package org.jetbrains.compose.resources
abstract class ResourcesExtension {
/**
* Whether the generated resources accessors class should be public or not.
*
* Default is false.
*/
var publicResClass: Boolean = false
/**
* The unique identifier of the resources in the current project.
* Uses as package for the generated Res class and for isolation resources in a final artefact.
*
* If it is empty then `{group name}.{module name}.generated.resources` will be used.
*
*/
var packageOfResClass: String = ""
enum class ResourceClassGeneration { Auto, Always }
//to support groovy DSL
val auto = ResourceClassGeneration.Auto
val always = ResourceClassGeneration.Always
/**
* The mode of resource class generation.
*
* - `auto`: The Res class will be generated if the current project has an explicit "implementation" or "api" dependency on the resource's library.
* - `always`: Unconditionally generate the Res class. This may be useful when the resources library is available transitively.
*/
var generateResClass: ResourceClassGeneration = auto
}

113
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesGenerator.kt

@ -38,14 +38,20 @@ private val androidPluginIds = listOf(
"com.android.library"
)
internal fun Project.configureComposeResources() {
val projectId = provider {
val groupName = project.group.toString().lowercase().asUnderscoredIdentifier()
val moduleName = project.name.lowercase().asUnderscoredIdentifier()
if (groupName.isNotEmpty()) "$groupName.$moduleName"
else moduleName
internal fun Project.configureComposeResources(config: ResourcesExtension) {
val resourcePackage = provider {
config.packageOfResClass.takeIf { it.isNotEmpty() } ?: run {
val groupName = project.group.toString().lowercase().asUnderscoredIdentifier()
val moduleName = project.name.lowercase().asUnderscoredIdentifier()
val id = if (groupName.isNotEmpty()) "$groupName.$moduleName" else moduleName
"$id.generated.resources"
}
}
val publicResClass = provider { config.publicResClass }
val generateResClassMode = provider { config.generateResClass }
plugins.withId(KOTLIN_MPP_PLUGIN_ID) {
val kotlinExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
@ -53,7 +59,13 @@ internal fun Project.configureComposeResources() {
val currentGradleVersion = GradleVersion.current()
val minGradleVersion = GradleVersion.version(MIN_GRADLE_VERSION_FOR_KMP_RESOURCES)
if (hasKmpResources && currentGradleVersion >= minGradleVersion) {
configureKmpResources(kotlinExtension, extraProperties.get(KMP_RES_EXT)!!, projectId)
configureKmpResources(
kotlinExtension,
extraProperties.get(KMP_RES_EXT)!!,
resourcePackage,
publicResClass,
generateResClassMode
)
} else {
if (!hasKmpResources) {
logger.info(
@ -73,7 +85,13 @@ internal fun Project.configureComposeResources() {
}
//current KGP doesn't have KPM resources
configureComposeResources(kotlinExtension, KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME, projectId)
configureComposeResources(
kotlinExtension,
KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME,
resourcePackage,
publicResClass,
generateResClassMode
)
//when applied AGP then configure android resources
androidPluginIds.forEach { pluginId ->
@ -86,14 +104,22 @@ internal fun Project.configureComposeResources() {
}
plugins.withId(KOTLIN_JVM_PLUGIN_ID) {
val kotlinExtension = project.extensions.getByType(KotlinProjectExtension::class.java)
configureComposeResources(kotlinExtension, SourceSet.MAIN_SOURCE_SET_NAME, projectId)
configureComposeResources(
kotlinExtension,
SourceSet.MAIN_SOURCE_SET_NAME,
resourcePackage,
publicResClass,
generateResClassMode
)
}
}
private fun Project.configureComposeResources(
kotlinExtension: KotlinProjectExtension,
commonSourceSetName: String,
projectId: Provider<String>
resourcePackage: Provider<String>,
publicResClass: Provider<Boolean>,
generateResClassMode: Provider<ResourcesExtension.ResourceClassGeneration>
) {
logger.info("Configure compose resources")
kotlinExtension.sourceSets.all { sourceSet ->
@ -105,7 +131,14 @@ private fun Project.configureComposeResources(
sourceSet.resources.srcDirs(composeResourcesPath)
if (sourceSetName == commonSourceSetName) {
configureResourceGenerator(composeResourcesPath, sourceSet, projectId, false)
configureResourceGenerator(
composeResourcesPath,
sourceSet,
resourcePackage,
publicResClass,
generateResClassMode,
false
)
}
}
}
@ -114,7 +147,9 @@ private fun Project.configureComposeResources(
private fun Project.configureKmpResources(
kotlinExtension: KotlinProjectExtension,
kmpResources: Any,
projectId: Provider<String>
resourcePackage: Provider<String>,
publicResClass: Provider<Boolean>,
generateResClassMode: Provider<ResourcesExtension.ResourceClassGeneration>
) {
kotlinExtension as KotlinMultiplatformExtension
kmpResources as KotlinTargetResourcesPublication
@ -136,7 +171,7 @@ private fun Project.configureKmpResources(
if (target is KotlinAndroidTarget) listOf("**/font*/*") else emptyList()
)
},
projectId.asModuleDir()
resourcePackage.asModuleDir()
)
if (target is KotlinAndroidTarget) {
@ -151,7 +186,7 @@ private fun Project.configureKmpResources(
emptyList()
)
},
projectId.asModuleDir()
resourcePackage.asModuleDir()
)
}
}
@ -161,7 +196,14 @@ private fun Project.configureKmpResources(
val sourceSetName = sourceSet.name
if (sourceSetName == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) {
val composeResourcesPath = project.projectDir.resolve("src/$sourceSetName/$COMPOSE_RESOURCES_DIR")
configureResourceGenerator(composeResourcesPath, sourceSet, projectId, true)
configureResourceGenerator(
composeResourcesPath,
sourceSet,
resourcePackage,
publicResClass,
generateResClassMode,
true
)
}
}
@ -251,27 +293,35 @@ private fun Project.configureAndroidComposeResources(
private fun Project.configureResourceGenerator(
commonComposeResourcesDir: File,
commonSourceSet: KotlinSourceSet,
projectId: Provider<String>,
resourcePackage: Provider<String>,
publicResClass: Provider<Boolean>,
generateResClassMode: Provider<ResourcesExtension.ResourceClassGeneration>,
generateModulePath: Boolean
) {
val packageName = projectId.map { "$it.generated.resources" }
logger.info("Configure accessors for '${commonSourceSet.name}'")
fun buildDir(path: String) = layout.dir(layout.buildDirectory.map { File(it.asFile, path) })
//lazy check a dependency on the Resources library
val shouldGenerateResClass: Provider<Boolean> = provider {
if (ComposeProperties.alwaysGenerateResourceAccessors(project).get()) {
true
} else {
configurations.run {
//because the implementation configuration doesn't extend the api in the KGP ¯\_(ツ)_/¯
getByName(commonSourceSet.implementationConfigurationName).allDependencies +
getByName(commonSourceSet.apiConfigurationName).allDependencies
}.any { dep ->
val depStringNotation = dep.let { "${it.group}:${it.name}:${it.version}" }
depStringNotation == ComposePlugin.CommonComponentsDependencies.resources
val shouldGenerateResClass = generateResClassMode.map { mode ->
when (mode) {
ResourcesExtension.ResourceClassGeneration.Auto -> {
//todo remove the gradle property when the gradle plugin will be published
if (ComposeProperties.alwaysGenerateResourceAccessors(project).get()) {
true
} else {
configurations.run {
//because the implementation configuration doesn't extend the api in the KGP ¯\_(ツ)_/¯
getByName(commonSourceSet.implementationConfigurationName).allDependencies +
getByName(commonSourceSet.apiConfigurationName).allDependencies
}.any { dep ->
val depStringNotation = dep.let { "${it.group}:${it.name}:${it.version}" }
depStringNotation == ComposePlugin.CommonComponentsDependencies.resources
}
}
}
ResourcesExtension.ResourceClassGeneration.Always -> {
true
}
}
}
@ -280,13 +330,14 @@ private fun Project.configureResourceGenerator(
"generateComposeResClass",
GenerateResClassTask::class.java
) { task ->
task.packageName.set(packageName)
task.packageName.set(resourcePackage)
task.shouldGenerateResClass.set(shouldGenerateResClass)
task.makeResClassPublic.set(publicResClass)
task.resDir.set(commonComposeResourcesDir)
task.codeDir.set(buildDir("$RES_GEN_DIR/kotlin"))
if (generateModulePath) {
task.moduleDir.set(projectId.asModuleDir())
task.moduleDir.set(resourcePackage.asModuleDir())
}
}

10
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesSpec.kt

@ -117,8 +117,10 @@ internal fun getResFileSpecs(
//type -> id -> items
resources: Map<ResourceType, Map<String, List<ResourceItem>>>,
packageName: String,
moduleDir: String
moduleDir: String,
isPublic: Boolean
): List<FileSpec> {
val resModifier = if (isPublic) KModifier.PUBLIC else KModifier.INTERNAL
val files = mutableListOf<FileSpec>()
val resClass = FileSpec.builder(packageName, "Res").also { file ->
file.addAnnotation(
@ -128,7 +130,7 @@ internal fun getResFileSpecs(
.build()
)
file.addType(TypeSpec.objectBuilder("Res").also { resObject ->
resObject.addModifiers(KModifier.INTERNAL)
resObject.addModifiers(resModifier)
resObject.addAnnotation(experimentalAnnotation)
//readFileBytes
@ -169,6 +171,7 @@ internal fun getResFileSpecs(
index,
packageName,
moduleDir,
resModifier,
idToResources.subMap(ids.first(), true, ids.last(), true)
)
)
@ -183,6 +186,7 @@ private fun getChunkFileSpec(
index: Int,
packageName: String,
moduleDir: String,
resModifier: KModifier,
idToResources: Map<String, List<ResourceItem>>
): FileSpec {
val chunkClassName = type.typeName.uppercaseFirstChar() + index
@ -206,7 +210,7 @@ private fun getChunkFileSpec(
chunkFile.addType(objectSpec)
idToResources.forEach { (resName, items) ->
val accessor = PropertySpec.builder(resName, type.getClassName(), KModifier.INTERNAL)
val accessor = PropertySpec.builder(resName, type.getClassName(), resModifier)
.receiver(ClassName(packageName, "Res", type.typeName))
.addAnnotation(experimentalAnnotation)
.getter(FunSpec.getterBuilder().addStatement("return $chunkClassName.$resName").build())

16
gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt

@ -126,10 +126,20 @@ class ResourcesTest : GradlePluginTestBase() {
file("src/commonMain/composeResources/drawable/vector_3.xml").renameTo(
file("src/commonMain/composeResources/drawable/vector_2.xml")
)
file("build.gradle.kts").modify { txt ->
txt + """
compose.resources {
publicResClass = true
packageOfResClass = "my.lib.res"
}
""".trimIndent()
}
gradle("generateComposeResClass").checks {
assertDirectoriesContentEquals(
file("build/generated/compose/resourceGenerator/kotlin/app/group/resources_test/generated/resources"),
file("expected")
file("build/generated/compose/resourceGenerator/kotlin/my/lib/res"),
file("expected-open-res")
)
}
}
@ -155,7 +165,7 @@ class ResourcesTest : GradlePluginTestBase() {
val resourcesFiles = resDir.walkTopDown()
.filter { !it.isDirectory && !it.isHidden }
.map { it.relativeTo(resDir).invariantSeparatorsPath }
val subdir = "me.sample.library.cmplib"
val subdir = "me.sample.library.resources"
fun libpath(target: String, ext: String) =
"my-mvn/me/sample/library/cmplib-$target/1.0/cmplib-$target-1.0$ext"

84
gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/Drawable0.kt

@ -0,0 +1,84 @@
@file:OptIn(org.jetbrains.compose.resources.InternalResourceApi::class)
package my.lib.res
import kotlin.OptIn
import org.jetbrains.compose.resources.DrawableResource
import org.jetbrains.compose.resources.ExperimentalResourceApi
@ExperimentalResourceApi
private object Drawable0 {
public val _3_strange_name: DrawableResource by
lazy { init__3_strange_name() }
public val camelCaseName: DrawableResource by
lazy { init_camelCaseName() }
public val vector: DrawableResource by
lazy { init_vector() }
public val vector_2: DrawableResource by
lazy { init_vector_2() }
}
@ExperimentalResourceApi
public val Res.drawable._3_strange_name: DrawableResource
get() = Drawable0._3_strange_name
@ExperimentalResourceApi
private fun init__3_strange_name(): DrawableResource =
org.jetbrains.compose.resources.DrawableResource(
"drawable:_3_strange_name",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "drawable/3-strange-name.xml"),
)
)
@ExperimentalResourceApi
public val Res.drawable.camelCaseName: DrawableResource
get() = Drawable0.camelCaseName
@ExperimentalResourceApi
private fun init_camelCaseName(): DrawableResource =
org.jetbrains.compose.resources.DrawableResource(
"drawable:camelCaseName",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "drawable/camelCaseName.xml"),
)
)
@ExperimentalResourceApi
public val Res.drawable.vector: DrawableResource
get() = Drawable0.vector
@ExperimentalResourceApi
private fun init_vector(): DrawableResource = org.jetbrains.compose.resources.DrawableResource(
"drawable:vector",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(org.jetbrains.compose.resources.LanguageQualifier("ast"),
), "drawable-ast/vector.xml"),
org.jetbrains.compose.resources.ResourceItem(setOf(org.jetbrains.compose.resources.LanguageQualifier("au"),
org.jetbrains.compose.resources.RegionQualifier("US"), ), "drawable-au-rUS/vector.xml"),
org.jetbrains.compose.resources.ResourceItem(setOf(org.jetbrains.compose.resources.ThemeQualifier.DARK,
org.jetbrains.compose.resources.LanguageQualifier("ge"), ), "drawable-dark-ge/vector.xml"),
org.jetbrains.compose.resources.ResourceItem(setOf(org.jetbrains.compose.resources.LanguageQualifier("en"),
), "drawable-en/vector.xml"),
org.jetbrains.compose.resources.ResourceItem(setOf(), "drawable/vector.xml"),
)
)
@ExperimentalResourceApi
public val Res.drawable.vector_2: DrawableResource
get() = Drawable0.vector_2
@ExperimentalResourceApi
private fun init_vector_2(): DrawableResource = org.jetbrains.compose.resources.DrawableResource(
"drawable:vector_2",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "drawable/vector_2.xml"),
)
)

28
gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/Font0.kt

@ -0,0 +1,28 @@
@file:OptIn(org.jetbrains.compose.resources.InternalResourceApi::class)
package my.lib.res
import kotlin.OptIn
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.FontResource
@ExperimentalResourceApi
private object Font0 {
public val emptyFont: FontResource by
lazy { init_emptyFont() }
}
@ExperimentalResourceApi
public val Res.font.emptyFont: FontResource
get() = Font0.emptyFont
@ExperimentalResourceApi
private fun init_emptyFont(): FontResource = org.jetbrains.compose.resources.FontResource(
"font:emptyFont",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(org.jetbrains.compose.resources.LanguageQualifier("en"),
), "font-en/emptyFont.otf"),
org.jetbrains.compose.resources.ResourceItem(setOf(), "font/emptyFont.otf"),
)
)

31
gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/Res.kt

@ -0,0 +1,31 @@
@file:OptIn(
org.jetbrains.compose.resources.InternalResourceApi::class,
org.jetbrains.compose.resources.ExperimentalResourceApi::class,
)
package my.lib.res
import kotlin.ByteArray
import kotlin.OptIn
import kotlin.String
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.readResourceBytes
@ExperimentalResourceApi
public object Res {
/**
* Reads the content of the resource file at the specified path and returns it as a byte array.
*
* Example: `val bytes = Res.readBytes("files/key.bin")`
*
* @param path The path of the file to read in the compose resource's directory.
* @return The content of the file as a byte array.
*/
public suspend fun readBytes(path: String): ByteArray = readResourceBytes("" + path)
public object drawable
public object string
public object font
}

130
gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected-open-res/String0.kt

@ -0,0 +1,130 @@
@file:OptIn(org.jetbrains.compose.resources.InternalResourceApi::class)
package my.lib.res
import kotlin.OptIn
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.StringResource
@ExperimentalResourceApi
private object String0 {
public val PascalCase: StringResource by
lazy { init_PascalCase() }
public val _1_kebab_case: StringResource by
lazy { init__1_kebab_case() }
public val app_name: StringResource by
lazy { init_app_name() }
public val camelCase: StringResource by
lazy { init_camelCase() }
public val hello: StringResource by
lazy { init_hello() }
public val multi_line: StringResource by
lazy { init_multi_line() }
public val str_arr: StringResource by
lazy { init_str_arr() }
public val str_template: StringResource by
lazy { init_str_template() }
}
@ExperimentalResourceApi
public val Res.string.PascalCase: StringResource
get() = String0.PascalCase
@ExperimentalResourceApi
private fun init_PascalCase(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:PascalCase", "PascalCase",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string._1_kebab_case: StringResource
get() = String0._1_kebab_case
@ExperimentalResourceApi
private fun init__1_kebab_case(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:_1_kebab_case", "_1_kebab_case",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string.app_name: StringResource
get() = String0.app_name
@ExperimentalResourceApi
private fun init_app_name(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:app_name", "app_name",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string.camelCase: StringResource
get() = String0.camelCase
@ExperimentalResourceApi
private fun init_camelCase(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:camelCase", "camelCase",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string.hello: StringResource
get() = String0.hello
@ExperimentalResourceApi
private fun init_hello(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:hello", "hello",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string.multi_line: StringResource
get() = String0.multi_line
@ExperimentalResourceApi
private fun init_multi_line(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:multi_line", "multi_line",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string.str_arr: StringResource
get() = String0.str_arr
@ExperimentalResourceApi
private fun init_str_arr(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:str_arr", "str_arr",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)
@ExperimentalResourceApi
public val Res.string.str_template: StringResource
get() = String0.str_template
@ExperimentalResourceApi
private fun init_str_template(): StringResource = org.jetbrains.compose.resources.StringResource(
"string:str_template", "str_template",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"),
)
)

9
gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/commonTest/kotlin/ComposeAppTest.kt

@ -11,6 +11,8 @@ import me.sample.app.MyFeatureText
import me.sample.library.MyLibraryText
import org.jetbrains.compose.resources.stringResource
import kmpresourcepublication.appmodule.generated.resources.*
import me.sample.library.resources.Res as LibRes
import me.sample.library.resources.*
import kotlin.test.Test
@OptIn(ExperimentalTestApi::class)
@ -28,11 +30,18 @@ class ComposeAppTest {
)
MyFeatureText(Modifier.testTag("feature-text"), txt)
MyLibraryText(Modifier.testTag("library-text"), txt)
//direct read a resource from library
Text(
modifier = Modifier.testTag("library-resource-text"),
text = stringResource(LibRes.string.str_1)
)
}
}
onNodeWithTag("app-text").assertTextEquals("test text: App text str_1")
onNodeWithTag("feature-text").assertTextEquals("test text: Feature text str_1")
onNodeWithTag("library-text").assertTextEquals("test text: Library text str_1")
onNodeWithTag("library-resource-text").assertTextEquals("Library text str_1")
}
}

5
gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/build.gradle.kts

@ -53,4 +53,9 @@ android {
compose {
kotlinCompilerPlugin.set(dependencies.compiler.forKotlin("COMPOSE_COMPILER_PLUGIN_PLACEHOLDER"))
kotlinCompilerPluginArgs.add("suppressKotlinVersionCompatibilityCheck=KOTLIN_VERSION_PLACEHOLDER")
}
compose.resources {
publicResClass = true
packageOfResClass = "me.sample.library.resources"
}

2
gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/src/commonMain/kotlin/me/sample/library/Lib.kt

@ -6,7 +6,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontFamily
import me.sample.library.cmplib.generated.resources.*
import me.sample.library.resources.*
import org.jetbrains.compose.resources.Font
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource

Loading…
Cancel
Save