diff --git a/README.md b/README.md index d11c483be..adb4736c4 100755 --- a/README.md +++ b/README.md @@ -98,6 +98,37 @@ multiplatformResources { } ``` +#### Default resource source sets + +By default, resources for each Kotlin source set must be placed in +`src//moko-resources`. No additional `resourcesSourceSets` configuration is required. +For example, common resources belong in `src/commonMain/moko-resources`, Android-only resources in +`src/androidMain/moko-resources`, and common test resources in `src/commonTest/moko-resources`. + +The default common resource directory has the following structure: + +``` +projectDirectory +└── src + └── commonMain + └── moko-resources + ├── base + │ ├── strings.xml + │ └── plurals.xml + ├── + │ ├── strings.xml + │ └── plurals.xml + ├── images + ├── fonts + ├── files + └── assets +``` + +This directory layout was introduced in moko-resources 0.24.0. When upgrading from 0.23.x, move +resources from `src/commonMain/resources/MR` to `src/commonMain/moko-resources`; the directory +structure inside the resource root remains unchanged. See the +[0.24.0 changelog and migration guide](https://github.com/icerockdev/moko-resources/discussions/730). + #### Custom resource sourceSet If you need custom path for source of resources, you need add in plugin configuration resourcesSourceSets option: @@ -121,7 +152,7 @@ On next step, you must create inside of project directory folder with name: `cus -- customResources --- assets --- base ---- image +--- images ``` Example of custom sourceSet in: `resources-gallery` sample, inside `jvm-app` @@ -134,7 +165,7 @@ should [add `export` declarations](https://kotlinlang.org/docs/multiplatform-bui ``` framework { export("dev.icerock.moko:resources:0.26.4") - export("dev.icerock.moko:graphics:0.10.0") // toUIColor here + export("dev.icerock.moko:graphics:0.10.2") // toUIColor here } ``` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f00b8ee30..538188616 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,7 +38,7 @@ commonsCodecVersion = "1.15" batikVersion = "1.17" # moko -mokoGraphicsVersion = "0.10.0" +mokoGraphicsVersion = "0.10.2" mokoTestVersion = "0.6.1" mokoMultiplatformPluginVersion = "0.14.2" @@ -81,4 +81,4 @@ composeJetBrainsPlugin = { module = "org.jetbrains.compose:compose-gradle-plugin nexusPublishing = { module = "io.github.gradle-nexus:publish-plugin", version = "2.0.0" } [plugins] -composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlinVersion" } \ No newline at end of file +composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlinVersion" } diff --git a/gradle/moko.versions.toml b/gradle/moko.versions.toml index 80a171ead..b278a38fc 100644 --- a/gradle/moko.versions.toml +++ b/gradle/moko.versions.toml @@ -1,7 +1,9 @@ [versions] -resourcesVersion = "0.26.4" +graphicsVersion = "0.10.2" +resourcesVersion = "0.27.0" [libraries] +graphics = { module = "dev.icerock.moko:graphics", version.ref = "graphicsVersion" } resources = { module = "dev.icerock.moko:resources", version.ref = "resourcesVersion" } resourcesCompose = { module = "dev.icerock.moko:resources-compose", version.ref = "resourcesVersion" } resourcesTest = { module = "dev.icerock.moko:resources-test", version.ref = "resourcesVersion" } diff --git a/resources-build-logic/src/main/kotlin/multiplatform-library-extended-convention.gradle.kts b/resources-build-logic/src/main/kotlin/multiplatform-library-extended-convention.gradle.kts index 593b56354..553e51dbb 100644 --- a/resources-build-logic/src/main/kotlin/multiplatform-library-extended-convention.gradle.kts +++ b/resources-build-logic/src/main/kotlin/multiplatform-library-extended-convention.gradle.kts @@ -10,6 +10,7 @@ kotlin { watchosX64() watchosArm32() watchosArm64() + watchosDeviceArm64() watchosSimulatorArm64() sourceSets { @@ -27,9 +28,11 @@ kotlin { val watchosArm64Main by getting{ dependsOn(watchosMain) } + val watchosDeviceArm64Main by getting { + dependsOn(watchosMain) + } val watchosSimulatorArm64Main by getting{ dependsOn(watchosMain) } } } - diff --git a/resources-compose/src/commonJsMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt b/resources-compose/src/commonJsMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt index df90ce28b..074a505c2 100644 --- a/resources-compose/src/commonJsMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt +++ b/resources-compose/src/commonJsMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt @@ -4,12 +4,10 @@ package dev.icerock.moko.resources.compose +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.InternalComposeUiApi -import androidx.compose.ui.LocalSystemTheme -import androidx.compose.ui.SystemTheme import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter @@ -25,10 +23,9 @@ import org.jetbrains.skia.Data import org.jetbrains.skia.Image import org.jetbrains.skia.svg.SVGDOM -@OptIn(InternalComposeUiApi::class) @Composable actual fun painterResource(imageResource: ImageResource): Painter { - val fileUrl: String = if (LocalSystemTheme.current == SystemTheme.Dark) { + val fileUrl: String = if (isSystemInDarkTheme()) { imageResource.darkFileUrl ?: imageResource.fileUrl } else { imageResource.fileUrl diff --git a/resources-compose/src/iosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt b/resources-compose/src/iosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt index da8b3ae98..588db0d39 100644 --- a/resources-compose/src/iosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt +++ b/resources-compose/src/iosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt @@ -4,10 +4,9 @@ package dev.icerock.moko.resources.compose +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.InternalComposeUiApi -import androidx.compose.ui.LocalSystemTheme import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.toComposeImageBitmap @@ -18,10 +17,11 @@ import org.jetbrains.skia.Image import platform.CoreGraphics.CGImageRef import platform.UIKit.UIImage -@OptIn(ExperimentalForeignApi::class, InternalComposeUiApi::class) +@OptIn(ExperimentalForeignApi::class) @Composable actual fun painterResource(imageResource: ImageResource): Painter { - return remember(LocalSystemTheme.current, imageResource) { + val isDarkTheme: Boolean = isSystemInDarkTheme() + return remember(isDarkTheme, imageResource) { val uiImage: UIImage = imageResource.toUIImage() ?: throw IllegalArgumentException("can't read UIImage of $imageResource") diff --git a/resources-compose/src/jvmMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt b/resources-compose/src/jvmMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt index c55b420cb..740344d96 100644 --- a/resources-compose/src/jvmMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt +++ b/resources-compose/src/jvmMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt @@ -4,18 +4,15 @@ package dev.icerock.moko.resources.compose +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.InternalComposeUiApi -import androidx.compose.ui.LocalSystemTheme -import androidx.compose.ui.SystemTheme import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import dev.icerock.moko.resources.ImageResource -@OptIn(InternalComposeUiApi::class) @Composable actual fun painterResource(imageResource: ImageResource): Painter { - val filePath: String = if (LocalSystemTheme.current == SystemTheme.Dark) { + val filePath: String = if (isSystemInDarkTheme()) { imageResource.darkFilePath ?: imageResource.filePath } else { imageResource.filePath diff --git a/resources-compose/src/macosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt b/resources-compose/src/macosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt index 7e1d0efd2..bb62cf637 100644 --- a/resources-compose/src/macosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt +++ b/resources-compose/src/macosMain/kotlin/dev/icerock/moko/resources/compose/ImageResource.kt @@ -4,10 +4,9 @@ package dev.icerock.moko.resources.compose +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.InternalComposeUiApi -import androidx.compose.ui.LocalSystemTheme import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.toComposeImageBitmap @@ -19,10 +18,11 @@ import platform.AppKit.NSImage import platform.CoreGraphics.CGImageRef import platform.CoreGraphics.CGImageRelease -@OptIn(ExperimentalForeignApi::class, InternalComposeUiApi::class) +@OptIn(ExperimentalForeignApi::class) @Composable actual fun painterResource(imageResource: ImageResource): Painter { - return remember(LocalSystemTheme.current, imageResource) { + val isDarkTheme: Boolean = isSystemInDarkTheme() + return remember(isDarkTheme, imageResource) { val nsImage: NSImage = imageResource.toNSImage() ?: throw IllegalArgumentException("can't read NSImage of $imageResource") diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/CodeGenerators.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/CodeGenerators.kt index aa178062f..2e20ea85f 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/CodeGenerators.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/CodeGenerators.kt @@ -8,34 +8,20 @@ package dev.icerock.gradle.generator import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.STRING import com.squareup.kotlinpoet.TypeSpec -import dev.icerock.gradle.generator.Constants.Apple import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.platform.js.JsFilePathMode -import dev.icerock.gradle.metadata.resource.HierarchyMetadata -import dev.icerock.gradle.metadata.resource.ResourceMetadata -import org.gradle.api.GradleException - -internal fun TypeSpec.Builder.addAppleResourcesBundleProperty(bundleIdentifier: String) { - val bundleProperty: PropertySpec = PropertySpec.builder( - Apple.resourcesBundlePropertyName, - Apple.nsBundleName, - KModifier.PRIVATE - ).delegate(CodeBlock.of("lazy { NSBundle.loadableBundle(%S) }", bundleIdentifier)) - .build() - - addProperty(bundleProperty) -} internal fun TypeSpec.Builder.addContentHashProperty(hash: String) { val bundleProperty: PropertySpec = - PropertySpec.builder("contentHash", STRING, KModifier.PRIVATE) + PropertySpec.builder("contentHash", STRING, KModifier.PUBLIC, KModifier.CONST) .initializer("%S", hash) .build() @@ -45,58 +31,19 @@ internal fun TypeSpec.Builder.addContentHashProperty(hash: String) { internal fun TypeSpec.Builder.addAppleContainerBundleInitializerProperty( modifier: KModifier? = null, ) { - val codeBlock = "${PlatformDetails.platformDetailsClass}(${Apple.resourcesBundlePropertyName})" - - val resourcePlatformDetailsPropertySpec = PropertySpec - .builder( - PlatformDetails.platformDetailsPropertyName, - Constants.resourcePlatformDetailsName - ) - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .initializer( - CodeBlock.of(codeBlock) - ).build() - - addProperty(resourcePlatformDetailsPropertySpec) -} - -internal fun TypeSpec.Builder.addJvmClassLoaderProperty(resourcesClassName: String) { - val property: PropertySpec = PropertySpec.builder( - Jvm.resourcesClassLoaderPropertyName, - Jvm.classLoaderName, - KModifier.PRIVATE - ).initializer(CodeBlock.of("$resourcesClassName::class.java.classLoader")) - .build() - - addProperty(property) + addContainerPlatformDetailsProperty( + initializer = CodeBlock.of(PlatformDetails.providerReference), + modifier = modifier + ) } internal fun TypeSpec.Builder.addJvmPlatformResourceClassLoaderProperty( modifier: KModifier? = null, ) { - val codeBlock = - "${PlatformDetails.platformDetailsClass}(${Jvm.resourcesClassLoaderPropertyName})" - - val resourcePlatformDetailsPropertySpec = PropertySpec - .builder( - PlatformDetails.platformDetailsPropertyName, - Constants.resourcePlatformDetailsName - ) - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .initializer(CodeBlock.of(codeBlock)) - .build() - - addProperty(resourcePlatformDetailsPropertySpec) + addContainerPlatformDetailsProperty( + initializer = CodeBlock.of(PlatformDetails.providerReference), + modifier = modifier + ) } internal fun TypeSpec.Builder.addJvmPlatformResourceBundleProperty( @@ -113,61 +60,82 @@ internal fun TypeSpec.Builder.addJvmPlatformResourceBundleProperty( addProperty(property) } +internal fun FileSpec.Builder.addJvmPlatformResourceBundleProperty( + bundlePropertyName: String, + bundlePath: String +) { + addProperty( + PropertySpec.builder( + name = bundlePropertyName, + type = STRING, + KModifier.PRIVATE + ).initializer(CodeBlock.of("\"%L/%L\"", Jvm.localizationDir, bundlePath)) + .build() + ) +} + internal fun TypeSpec.Builder.addEmptyPlatformResourceProperty( modifier: KModifier? = null, ) { - val resourcePlatformDetailsPropertySpec = PropertySpec - .builder( - PlatformDetails.platformDetailsPropertyName, - Constants.resourcePlatformDetailsName - ) + addContainerPlatformDetailsProperty( + initializer = CodeBlock.of("${PlatformDetails.platformDetailsClass}()"), + modifier = modifier + ) +} + +internal fun TypeSpec.Builder.addValuesFunctionFromAccessors( + accessorObjectNames: List, + classType: ClassName, + modifier: KModifier? = null, +) { + val valuesFun: FunSpec = FunSpec.builder("values") .also { if (modifier != null) { it.addModifiers(modifier) } } .addModifiers(KModifier.OVERRIDE) - .initializer( - CodeBlock.of("${PlatformDetails.platformDetailsClass}()") - ).build() + .addCode( + CodeBlock.builder() + .apply { + if (accessorObjectNames.isEmpty()) { + addStatement("return emptyList()") + } else if (accessorObjectNames.size == 1) { + addStatement("return %N.values()", accessorObjectNames.single()) + } else { + add("return listOf(\n") + accessorObjectNames.forEach { accessorObjectName -> + add("%N.values(),\n", accessorObjectName) + } + add(").flatten()\n") + } + } + .build() + ) + .returns( + ClassName(packageName = "kotlin.collections", "List") + .parameterizedBy(classType) + ) + .build() - addProperty(resourcePlatformDetailsPropertySpec) + addFunction(valuesFun) } -internal fun TypeSpec.Builder.addValuesFunction( - metadata: List, +internal fun TypeSpec.Builder.addAccessorValuesFunction( + propertyReferences: List, classType: ClassName, - modifier: KModifier? = null, + memberModifier: KModifier? = null, ) { - // Find metadata type - val resourceMetadata: T = metadata.first() - val languageKeysList: String = - if (resourceMetadata is HierarchyMetadata) { - // For Assets and Files need create key considering File path - val hierarchyMetadata: List = metadata - .filterIsInstance() - .takeIf { - it.size == metadata.size - } ?: throw GradleException("Invalid ResourceMetadata type for Assets or Files") - - hierarchyMetadata.joinToString { meta -> - meta.path.joinToString(separator = ".") + - (".".takeIf { meta.path.isNotEmpty() } ?: "") + - meta.key - } - } else { - // Create simple resource key - metadata.joinToString { it.key } - } - val valuesFun: FunSpec = FunSpec.builder("values") .also { - if (modifier != null) { - it.addModifiers(modifier) + if (memberModifier != null) { + it.addModifiers(memberModifier) } } - .addModifiers(KModifier.OVERRIDE) - .addStatement("return listOf($languageKeysList)") + .addStatement( + "return listOf(%L)", + propertyReferences.joinToString() + ) .returns( ClassName(packageName = "kotlin.collections", "List") .parameterizedBy(classType) @@ -182,7 +150,8 @@ internal fun TypeSpec.Builder.addOverridePlatformProperty(): TypeSpec.Builder { PlatformDetails.platformDetailsPropertyName, Constants.resourcePlatformDetailsName, KModifier.OVERRIDE - ).build() + ) + .build() return addProperty(resourcePlatformDetailsPropertySpec) } @@ -219,6 +188,24 @@ internal fun TypeSpec.Builder.addJsFallbackProperty( addProperty(property) } +internal fun FileSpec.Builder.addJsFallbackProperty( + fallbackFilePath: String, + filePathMode: JsFilePathMode +) { + addProperty( + PropertySpec + .builder(Constants.Js.fallbackFilePropertyName, String::class, KModifier.PRIVATE) + .initializer( + CodeBlock.of( + "${filePathMode.format} as %T", + filePathMode.argument(fallbackFilePath), + String::class + ) + ) + .build() + ) +} + internal fun TypeSpec.Builder.addJsSupportedLocalesProperty( bcpLangToPath: List>, filePathMode: JsFilePathMode @@ -249,6 +236,36 @@ internal fun TypeSpec.Builder.addJsSupportedLocalesProperty( addProperty(property) } +internal fun FileSpec.Builder.addJsSupportedLocalesProperty( + bcpLangToPath: List>, + filePathMode: JsFilePathMode +) { + addProperty( + PropertySpec + .builder( + Constants.Js.supportedLocalesPropertyName, + Constants.Js.supportedLocalesName, + KModifier.PRIVATE + ).initializer( + CodeBlock + .builder() + .apply { + add("%T(listOf(\n", Constants.Js.supportedLocalesName) + bcpLangToPath.forEach { (bcpLang, filePath) -> + add( + "%T(%S, ${filePathMode.format} as %T),\n", + Constants.Js.supportedLocaleName, + bcpLang, + filePathMode.argument(filePath), + String::class + ) + } + add("))") + }.build() + ).build() + ) +} + internal fun TypeSpec.Builder.addJsContainerStringsLoaderProperty() { val property = PropertySpec.builder( Constants.Js.stringsLoaderPropertyName, @@ -263,3 +280,40 @@ internal fun TypeSpec.Builder.addJsContainerStringsLoaderProperty() { ).build() addProperty(property) } + +internal fun FileSpec.Builder.addJsAccessorFileStringsLoaderProperty() { + addProperty( + PropertySpec.builder( + Constants.Js.stringsLoaderPropertyName, + Constants.Js.stringLoaderName, + KModifier.PRIVATE + ).initializer( + CodeBlock.of( + "${Constants.Js.remoteStringLoaderClassName}.Impl(supportedLocales = %N, fallbackFileUri = %N)", + Constants.Js.supportedLocalesPropertyName, + Constants.Js.fallbackFilePropertyName + ) + ).build() + ) +} + +private fun TypeSpec.Builder.addContainerPlatformDetailsProperty( + initializer: CodeBlock, + modifier: KModifier? = null, +) { + val resourcePlatformDetailsPropertySpec = PropertySpec + .builder( + PlatformDetails.platformDetailsPropertyName, + Constants.resourcePlatformDetailsName + ) + .also { + if (modifier != null) { + it.addModifiers(modifier) + } + } + .addModifiers(KModifier.OVERRIDE) + .initializer(initializer) + .build() + + addProperty(resourcePlatformDetailsPropertySpec) +} diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/Constants.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/Constants.kt index c6a8ecefb..0bb46a1ff 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/Constants.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/Constants.kt @@ -23,6 +23,9 @@ internal object Constants { object PlatformDetails { const val platformDetailsPropertyName = "__platformDetails" const val platformDetailsClass: String = "ResourcePlatformDetails" + const val providerObjectName = "PlatformDetailsProvider" + const val providerDetailsPropertyName = "details" + const val providerReference = "$providerObjectName.$providerDetailsPropertyName" } object Apple { @@ -34,12 +37,15 @@ internal object Constants { const val resourcesBundlePropertyName = "bundle" private const val containerBundlePropertyName = "nsBundle" val platformContainerBundlePropertyName = "$platformDetailsPropertyName.$containerBundlePropertyName" + val providerBundleReference = "${PlatformDetails.providerReference}.$containerBundlePropertyName" } object Jvm { val classLoaderName = ClassName("java.lang", "ClassLoader") const val resourcesClassLoaderPropertyName = "resourcesClassLoader" const val localizationDir = "localization" + val providerClassLoaderReference = + "${PlatformDetails.providerReference}.$resourcesClassLoaderPropertyName" } object Js { diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/GenerationResult.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/GenerationResult.kt index 39378e9e3..bb7a20dc4 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/GenerationResult.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/GenerationResult.kt @@ -4,10 +4,12 @@ package dev.icerock.gradle.generator +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.metadata.container.ContainerMetadata internal data class GenerationResult( val typeSpec: TypeSpec, - val metadata: ContainerMetadata + val metadata: ContainerMetadata, + val fileSpecs: List = emptyList() ) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformContainerGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformContainerGenerator.kt index a7ee8813c..eb68adcfd 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformContainerGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformContainerGenerator.kt @@ -5,10 +5,12 @@ package dev.icerock.gradle.generator import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.TypeSpec internal interface PlatformContainerGenerator { fun getImports(): List = emptyList() + fun generateAdditionalFiles(packageName: String): List = emptyList() fun generateBeforeTypes(objectName: String, builder: TypeSpec.Builder) = Unit fun generateAfterTypes(builder: TypeSpec.Builder) = Unit } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformResourceGenerator.kt index 199aaa8f0..63ec91c02 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PlatformResourceGenerator.kt @@ -6,25 +6,41 @@ package dev.icerock.gradle.generator import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.metadata.resource.ResourceMetadata internal interface PlatformResourceGenerator { fun imports(): List - fun generateBeforeProperties( - builder: Builder, + fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier? = null, ) = Unit - fun generateAfterProperties( - builder: Builder, + fun generateContainerMembers( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier? = null, ) = Unit + fun generateAccessorFilePreamble( + builder: FileSpec.Builder, + metadata: List, + objectName: String, + ) = Unit + + fun generateAccessorInitializer(metadata: T): CodeBlock = generateInitializer(metadata) + + fun generateAccessorInitializer( + metadata: T, + accessorObjectName: String, + ): CodeBlock = generateAccessorInitializer(metadata) + + fun generateAdditionalAccessorFiles(packageName: String): List = emptyList() + fun generateInitializer(metadata: T): CodeBlock fun generateResourceFiles(data: List) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PropertiesGenerationStrategy.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PropertiesGenerationStrategy.kt index 739f77914..3d9b7a18e 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PropertiesGenerationStrategy.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/PropertiesGenerationStrategy.kt @@ -17,6 +17,13 @@ internal interface PropertiesGenerationStrategy { modifier: KModifier?, generateProperty: (T) -> PropertySpec, ) + + fun generateSkeleton( + builder: TypeSpec.Builder, + resources: List, + modifier: KModifier?, + generateProperty: (T) -> PropertySpec, + ) = Unit } internal class FlatPropertiesGenerationStrategy : @@ -50,6 +57,19 @@ internal class HierarchyPropertiesGenerationStrategy : ) } + override fun generateSkeleton( + builder: TypeSpec.Builder, + resources: List, + modifier: KModifier?, + generateProperty: (T) -> PropertySpec, + ) { + builder.addObjectsSkeleton( + typeResources = resources, + generateProperty = generateProperty, + modifier = modifier + ) + } + private fun TypeSpec.Builder.addObjectsProperties( typeResources: List, generateProperty: (T) -> PropertySpec, @@ -70,6 +90,26 @@ internal class HierarchyPropertiesGenerationStrategy : ) } + private fun TypeSpec.Builder.addObjectsSkeleton( + typeResources: List, + generateProperty: (T) -> PropertySpec, + modifier: KModifier? = null, + ) { + val filesMap = typeResources.groupBy { + it.path + }.mapValues { + it.value.map { resValue -> + generateProperty(resValue) + } + } + + this.generateSkeletonObjects( + map = filesMap, + objectKey = emptyList(), + modifier = modifier + ) + } + private fun TypeSpec.Builder.generateObjects( map: Map, List>, objectKey: List, @@ -99,4 +139,32 @@ internal class HierarchyPropertiesGenerationStrategy : } ) } + + private fun TypeSpec.Builder.generateSkeletonObjects( + map: Map, List>, + objectKey: List, + modifier: KModifier?, + ) { + addTypes( + map.filter { + it.key.size == objectKey.size + 1 + }.filter { + it.key.dropLast(1) == objectKey + }.map { + TypeSpec + .objectBuilder(it.key.last()) + .also { builder -> + builder.generateSkeletonObjects( + map = map, + objectKey = it.key, + modifier = modifier + ) + }.also { builder -> + if (modifier == KModifier.ACTUAL) { + builder.addModifiers(KModifier.ACTUAL) + } + }.build() + } + ) + } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt index 4b50f1a09..d5d3ffa93 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourceTypeGenerator.kt @@ -5,15 +5,21 @@ package dev.icerock.gradle.generator import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec +import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.metadata.container.ContainerMetadata import dev.icerock.gradle.metadata.container.ResourceType +import dev.icerock.gradle.metadata.resource.HierarchyMetadata import dev.icerock.gradle.metadata.resource.ResourceMetadata +import dev.icerock.gradle.utils.capitalize import dev.icerock.gradle.utils.filterClass import org.gradle.api.tasks.util.PatternFilterable +import java.io.File import kotlin.reflect.KClass @Suppress("LongParameterList", "TooManyFunctions", "UnusedPrivateMember") @@ -26,9 +32,15 @@ internal class ResourceTypeGenerator( private val generator: ResourceGenerator, private val platformResourceGenerator: PlatformResourceGenerator, private val filter: PatternFilterable.() -> Unit, + private val resourcesPackageName: String? = null, + private val batchSize: Int = DEFAULT_BATCH_SIZE, ) { fun generateMetadata(files: ResourcesFiles): List { - return generator.generateMetadata(files.matching(filter).ownSourceSet.fileTree.files) + // Sort for deterministic output; FileTree.files iteration is filesystem-dependent. + val sortedFiles: Set = files.matching(filter).ownSourceSet.fileTree.files + .sortedBy { it.absolutePath } + .toCollection(LinkedHashSet()) + return generator.generateMetadata(sortedFiles) } fun getImports(): List = platformResourceGenerator.imports() @@ -36,10 +48,11 @@ internal class ResourceTypeGenerator( fun generateExpectObject( parentObjectName: String, resources: List, + sourceSetName: String, ): GenerationResult? { val typeMetadata: List = resources .filterClass(typeClass = metadataClass) - .sortedBy { it.key } + .sortedResources() // if we not have any resources of our type at all - not generate object if (typeMetadata.isEmpty()) return null @@ -52,39 +65,54 @@ internal class ResourceTypeGenerator( .addSuperinterface(Constants.resourceContainerName.parameterizedBy(resourceClass)) // implement ResourceContainer platform property .addOverridePlatformProperty() - // add all properties of available resources .also { builder -> - propertiesGenerationStrategy.generateProperties( - builder = builder, - resources = typeMetadata, - modifier = null, - generateProperty = { - generator.generateProperty(it).build() - } - ) + if (isHierarchyPropertiesStrategy()) { + propertiesGenerationStrategy.generateSkeleton( + builder = builder, + resources = typeMetadata, + modifier = KModifier.EXPECT, + generateProperty = { + generator.generateProperty(it).build() + } + ) + } } // implement ResourceContainer values function .addOverrideAbstractValuesFunction(resourceClass) + val fileSpecs: List = createExpectExtensionFileSpecs( + parentObjectName = parentObjectName, + objectName = objectName, + sourceSetName = sourceSetName, + resources = typeMetadata + ) + return GenerationResult( typeSpec = objectBuilder.build(), metadata = ContainerMetadata( parentObjectName = parentObjectName, name = objectName, resourceType = resourceType, - resources = typeMetadata - ) + resources = typeMetadata, + sourceSetName = sourceSetName + ), + fileSpecs = fileSpecs ) } + @Suppress("LongMethod") fun generateActualObject( parentObjectName: String, objects: List, + sourceSetName: String, ): GenerationResult? { val typeObject: ContainerMetadata = objects .singleOrNull { it.resourceType == resourceType } ?: return null - val typeResources: List = typeObject.resources.filterClass(metadataClass) + val typeResources: List = typeObject.resources + .filterClass(metadataClass) + .sortedResources() + val objectBuilder: TypeSpec.Builder = TypeSpec .objectBuilder(typeObject.name) .addModifiers(visibilityModifier) @@ -92,47 +120,70 @@ internal class ResourceTypeGenerator( // implement ResourceType<**Resource> for extensions .addSuperinterface(Constants.resourceContainerName.parameterizedBy(resourceClass)) .also { builder -> - platformResourceGenerator.generateBeforeProperties( + platformResourceGenerator.generateContainerProperties( builder = builder, metadata = typeResources, modifier = KModifier.ACTUAL, ) } - // add all properties of object .also { builder -> - propertiesGenerationStrategy.generateProperties( - builder = builder, - resources = typeResources, - modifier = KModifier.ACTUAL, - generateProperty = ::createActualProperty + if (isHierarchyPropertiesStrategy()) { + propertiesGenerationStrategy.generateSkeleton( + builder = builder, + resources = typeResources, + modifier = KModifier.ACTUAL, + generateProperty = { + generator.generateProperty(it).build() + } + ) + } + builder.addValuesFunctionFromAccessors( + accessorObjectNames = getAccessorObjectNames( + sourceSetName = typeObject.sourceSetName ?: sourceSetName, + objectName = typeObject.name, + resources = typeResources + ), + classType = resourceClass, + modifier = KModifier.ACTUAL ) - } - .also { builder -> - platformResourceGenerator.generateAfterProperties( + platformResourceGenerator.generateContainerMembers( builder = builder, metadata = typeResources, modifier = KModifier.ACTUAL, ) } + val fileSpecs: List = createAccessorFileSpecs( + parentObjectName = parentObjectName, + objectName = typeObject.name, + resourceSourceSetName = typeObject.sourceSetName ?: sourceSetName, + targetSourceSetName = sourceSetName, + resources = typeResources, + actualModifier = KModifier.ACTUAL + ) + platformResourceGenerator.generateAdditionalAccessorFiles(requireResourcesPackageName()) + return GenerationResult( typeSpec = objectBuilder.build(), metadata = ContainerMetadata( parentObjectName = parentObjectName, name = typeObject.name, resourceType = resourceType, - resources = typeObject.resources - ) + resources = typeObject.resources, + sourceSetName = typeObject.sourceSetName + ), + fileSpecs = fileSpecs ) } + @Suppress("LongMethod") fun generateObject( parentObjectName: String, resources: List, + sourceSetName: String, ): GenerationResult? { val typeResources: List = resources .filterClass(typeClass = metadataClass) - .sortedBy { it.key } + .sortedResources() // if we not have any resources of our type at all - not generate object if (typeResources.isEmpty()) return null @@ -145,35 +196,55 @@ internal class ResourceTypeGenerator( .addSuperinterface(Constants.resourceContainerName.parameterizedBy(resourceClass)) // implement interfaces for generated expect object .also { builder -> - platformResourceGenerator.generateBeforeProperties( + platformResourceGenerator.generateContainerProperties( builder = builder, metadata = typeResources, ) } - // add all properties of object .also { builder -> - propertiesGenerationStrategy.generateProperties( - builder = builder, - resources = typeResources, - modifier = null, - generateProperty = ::createSimpleProperty + if (isHierarchyPropertiesStrategy()) { + propertiesGenerationStrategy.generateSkeleton( + builder = builder, + resources = typeResources, + modifier = null, + generateProperty = { + generator.generateProperty(it).build() + } + ) + } + builder.addValuesFunctionFromAccessors( + accessorObjectNames = getAccessorObjectNames( + sourceSetName = sourceSetName, + objectName = objectName, + resources = typeResources + ), + classType = resourceClass ) - } - .also { builder -> - platformResourceGenerator.generateAfterProperties( + platformResourceGenerator.generateContainerMembers( builder = builder, metadata = typeResources, ) } + val fileSpecs: List = createAccessorFileSpecs( + parentObjectName = parentObjectName, + objectName = objectName, + resourceSourceSetName = sourceSetName, + targetSourceSetName = sourceSetName, + resources = typeResources, + actualModifier = null + ) + platformResourceGenerator.generateAdditionalAccessorFiles(requireResourcesPackageName()) + return GenerationResult( typeSpec = objectBuilder.build(), metadata = ContainerMetadata( parentObjectName = parentObjectName, name = objectName, resourceType = resourceType, - resources = typeResources - ) + resources = typeResources, + sourceSetName = sourceSetName + ), + fileSpecs = fileSpecs ) } @@ -183,23 +254,298 @@ internal class ResourceTypeGenerator( platformResourceGenerator.generateResourceFiles(typeMetadata) } - private fun createSimpleProperty(resource: T): PropertySpec { - return createProperty(resource) + private fun createExpectExtensionFileSpecs( + parentObjectName: String, + objectName: String, + sourceSetName: String, + resources: List, + ): List { + return resources.chunked(batchSize).mapIndexed { index, batch -> + val accessorObjectName: String = getAccessorObjectName( + sourceSetName = sourceSetName, + objectName = objectName, + index = index + ) + + createExtensionFileSpecBuilder("$accessorObjectName.$sourceSetName") + .also { fileSpec -> + addExpectExtensionAccessors( + fileSpec = fileSpec, + parentObjectName = parentObjectName, + objectName = objectName, + resources = batch + ) + } + .build() + } + } + + @Suppress("LongMethod") + private fun createAccessorFileSpecs( + parentObjectName: String, + objectName: String, + resourceSourceSetName: String, + targetSourceSetName: String, + resources: List, + actualModifier: KModifier?, + ): List { + return resources.chunked(batchSize).mapIndexed { index, batch -> + val accessorObjectName: String = getAccessorObjectName( + sourceSetName = resourceSourceSetName, + objectName = objectName, + index = index + ) + val accessorResources: List> = buildAccessorResources(batch) + val fileSpec = createExtensionFileSpecBuilder( + fileName = "$accessorObjectName.$targetSourceSetName" + ) + + platformResourceGenerator.generateAccessorFilePreamble( + builder = fileSpec, + metadata = batch, + objectName = accessorObjectName + ) + + val groupObject = TypeSpec.objectBuilder(accessorObjectName) + .addModifiers(KModifier.INTERNAL) + .also { builder -> + accessorResources.forEach { resource -> + builder.addProperty( + PropertySpec.builder(resource.internalName, resourceClass) + .addModifiers(KModifier.INTERNAL) + .delegate( + CodeBlock.of( + "lazy { %L() }", + initFunctionName(resource.internalName) + ) + ) + .build() + ) + } + builder.addAccessorValuesFunction( + propertyReferences = accessorResources.map { it.internalName }, + classType = resourceClass, + memberModifier = KModifier.INTERNAL + ) + } + .build() + + fileSpec.addType(groupObject) + + accessorResources.forEach { resource -> + fileSpec.addFunction( + FunSpec.builder(initFunctionName(resource.internalName)) + .addModifiers(KModifier.PRIVATE) + .returns(resourceClass) + .addStatement( + "return %L", + platformResourceGenerator.generateAccessorInitializer( + metadata = resource.metadata, + accessorObjectName = accessorObjectName + ) + ) + .build() + ) + } + + addActualExtensionAccessors( + fileSpec = fileSpec, + parentObjectName = parentObjectName, + objectName = objectName, + groupName = accessorObjectName, + resources = accessorResources, + actualModifier = actualModifier + ) + + fileSpec.build() + } + } + + private fun addExpectExtensionAccessors( + fileSpec: FileSpec.Builder, + parentObjectName: String, + objectName: String, + resources: List, + ) { + resources.forEach { resource -> + fileSpec.addProperty( + PropertySpec + .builder( + name = resource.key, + type = resourceClass + ) + .receiver( + receiverType = getReceiverClassName( + parentObjectName = parentObjectName, + objectName = objectName, + path = resource.pathSegments() + ) + ) + .addModifiers(visibilityModifier, KModifier.EXPECT) + .build() + ) + } + } + + private fun addActualExtensionAccessors( + fileSpec: FileSpec.Builder, + parentObjectName: String, + objectName: String, + groupName: String, + resources: List>, + actualModifier: KModifier?, + ) { + resources.forEach { resource -> + val resourcePath: List = resource.metadata.pathSegments() + fileSpec.addProperty( + PropertySpec + .builder( + name = resource.metadata.key, + type = resourceClass + ) + .receiver( + receiverType = getReceiverClassName( + parentObjectName = parentObjectName, + objectName = objectName, + path = resourcePath + ) + ) + .addModifiers(visibilityModifier) + .also { property -> + if (actualModifier != null) { + property.addModifiers(actualModifier) + } + } + .getter( + FunSpec.getterBuilder() + .addStatement( + "return %L", + "$groupName.${resource.internalName}" + ) + .build() + ) + .build() + ) + } + } + + private fun createExtensionFileSpecBuilder(fileName: String): FileSpec.Builder { + return FileSpec.builder( + packageName = requireResourcesPackageName(), + fileName = fileName + ).also { fileSpec -> + platformResourceGenerator.imports().forEach { import -> + fileSpec.addImport( + packageName = import.packageName, + names = import.simpleNames + ) + } + } + } + + private fun getReceiverClassName( + parentObjectName: String, + objectName: String, + path: List = emptyList(), + ): ClassName { + return ClassName( + packageName = requireResourcesPackageName(), + simpleNames = listOf( + parentObjectName, + objectName + ) + path + ) + } + + private fun buildAccessorResources(resources: List): List> { + if (!isHierarchyPropertiesStrategy()) { + return resources.map { resource -> + AccessorResource( + metadata = resource, + internalName = resource.key + ) + } + } + + val duplicates: Map> = resources + .groupBy { it.key } + .mapValues { (_, groupedResources) -> + groupedResources.sortedBy { resourceLogicalPath(it = it) } + } + + return resources.map { resource -> + val duplicateGroup: List = duplicates.getValue(resource.key) + val internalName = if (duplicateGroup.size == 1) { + resource.key + } else { + "${resource.key}__${duplicateGroup.indexOf(resource)}" + } + + AccessorResource(metadata = resource, internalName = internalName) + } + } + + private fun initFunctionName(internalName: String): String { + return "init_$internalName" + } + + private fun resourceLogicalPath(it: T): String { + return it.pathSegments().joinToString(separator = "/") + "/${it.key}" + } + + private fun getAccessorObjectNames( + sourceSetName: String, + objectName: String, + resources: List, + ): List { + return resources.chunked(batchSize).indices.map { index -> + getAccessorObjectName( + sourceSetName = sourceSetName, + objectName = objectName, + index = index + ) + } + } + + private fun getAccessorObjectName( + sourceSetName: String, + objectName: String, + index: Int, + ): String { + return "${sourceSetName.capitalize()}${objectName.capitalize()}$index" + } + + private fun requireResourcesPackageName(): String { + return requireNotNull(resourcesPackageName) { + "resourcesPackageName should be provided to generate extension properties" + } } - private fun createActualProperty(resource: T): PropertySpec { - return createProperty(resource, KModifier.ACTUAL) + private fun isHierarchyPropertiesStrategy(): Boolean { + return propertiesGenerationStrategy is HierarchyPropertiesGenerationStrategy<*> } - private fun createProperty( - resource: T, - modifier: KModifier? = null, - ): PropertySpec { - return generator.generateProperty(resource) - .apply { - if (modifier != null) addModifiers(modifier) + private fun T.pathSegments(): List { + return (this as? HierarchyMetadata)?.path.orEmpty() + } + + private fun List.sortedResources(): List { + return if (firstOrNull() is HierarchyMetadata) { + sortedBy { + val hierarchy = it as HierarchyMetadata + hierarchy.path.joinToString(separator = "/") + "/" + it.key } - .initializer(platformResourceGenerator.generateInitializer(resource)) - .build() + } else { + sortedBy { it.key } + } } + + private companion object { + const val DEFAULT_BATCH_SIZE = 50 + } + + private data class AccessorResource( + val metadata: T, + val internalName: String, + ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourcesGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourcesGenerator.kt index bc34416f8..ed1be332d 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourcesGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ResourcesGenerator.kt @@ -5,7 +5,6 @@ package dev.icerock.gradle.generator import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.FileSpec.Builder import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.metadata.container.ContainerMetadata @@ -43,6 +42,8 @@ internal class ResourcesGenerator( ) val outputMetadata: MutableList = mutableListOf() + val additionalFileSpecs: MutableList = mutableListOf() + additionalFileSpecs.addAll(containerGenerator.generateAdditionalFiles(resourcesPackageName)) if (inputMetadata.isEmpty()) { // we not have expect - we should generate simple object @@ -51,7 +52,8 @@ internal class ResourcesGenerator( outputMetadata = outputMetadata, parentObjectName = resourcesClassName, fileSpec = fileSpec, - inputMetadata = inputMetadata + inputMetadata = inputMetadata, + additionalFileSpecs = additionalFileSpecs ) } else { val inputMetadataObjectsMap: Map> = @@ -67,10 +69,12 @@ internal class ResourcesGenerator( val objects: List = typesGenerators.mapNotNull { typeGenerator -> typeGenerator.generateActualObject( parentObjectName = expectObjectName, - objects = inputMetadataList + objects = inputMetadataList, + sourceSetName = sourceSetName ) } objects.forEach { outputMetadata.add(it.metadata) } + objects.flatMapTo(additionalFileSpecs) { it.fileSpecs } val objectSpec: TypeSpec.Builder = TypeSpec.objectBuilder(expectObjectName) // default: object MR @@ -97,13 +101,17 @@ internal class ResourcesGenerator( outputMetadata = outputMetadata, parentObjectName = targetObjectResourceName, fileSpec = fileSpec, - inputMetadata = inputMetadata + inputMetadata = inputMetadata, + additionalFileSpecs = additionalFileSpecs ) } } // write file fileSpec.build().writeTo(sourcesGenerationDir) + additionalFileSpecs + .distinctBy { it.packageName + "." + it.name } + .forEach { it.writeTo(sourcesGenerationDir) } return outputMetadata } @@ -112,16 +120,19 @@ internal class ResourcesGenerator( ownMetadata: List, parentObjectName: String, outputMetadata: MutableList, - fileSpec: Builder, + fileSpec: FileSpec.Builder, inputMetadata: List, + additionalFileSpecs: MutableList, ) { val objects: List = typesGenerators.mapNotNull { typeGenerator -> typeGenerator.generateObject( parentObjectName = parentObjectName, - resources = ownMetadata + resources = ownMetadata, + sourceSetName = sourceSetName ) } objects.forEach { outputMetadata.add(it.metadata) } + objects.flatMapTo(additionalFileSpecs) { it.fileSpecs } val objectSpec: TypeSpec.Builder = TypeSpec.objectBuilder(parentObjectName) // default: object MR @@ -155,6 +166,8 @@ internal class ResourcesGenerator( ) val outputMetadata: MutableList = mutableListOf() + val additionalFileSpecs: MutableList = mutableListOf() + additionalFileSpecs.addAll(containerGenerator.generateAdditionalFiles(resourcesPackageName)) // if previous levels doesn't have resources should use "MR" // but if resources is found, need generate "MRsourceSet" object @@ -170,6 +183,7 @@ internal class ResourcesGenerator( typeGenerator.generateExpectObject( parentObjectName = expectObjectName, resources = ownMetadata, + sourceSetName = sourceSetName ) } @@ -182,12 +196,16 @@ internal class ResourcesGenerator( objects.forEach { result -> objectSpec.addType(result.typeSpec) outputMetadata.add(result.metadata) + additionalFileSpecs.addAll(result.fileSpecs) } fileSpec.addType(objectSpec.build()) // write file fileSpec.build().writeTo(sourcesGenerationDir) + additionalFileSpecs + .distinctBy { it.packageName + "." + it.name } + .forEach { it.writeTo(sourcesGenerationDir) } return outputMetadata } @@ -199,7 +217,7 @@ internal class ResourcesGenerator( private fun finalizeObjectSpec( objectName: String, - fileSpec: Builder, + fileSpec: FileSpec.Builder, objectSpec: TypeSpec.Builder, generatedObjects: List, inputMetadata: List, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/AppleContainerGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/AppleContainerGenerator.kt index cf11256df..cb065648e 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/AppleContainerGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/AppleContainerGenerator.kt @@ -5,10 +5,13 @@ package dev.icerock.gradle.generator.container import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformContainerGenerator -import dev.icerock.gradle.generator.addAppleResourcesBundleProperty internal class AppleContainerGenerator( private val bundleIdentifier: String, @@ -20,7 +23,43 @@ internal class AppleContainerGenerator( ) } - override fun generateBeforeTypes(objectName: String, builder: TypeSpec.Builder) { - builder.addAppleResourcesBundleProperty(bundleIdentifier) + override fun generateAdditionalFiles(packageName: String): List { + val provider = TypeSpec.objectBuilder(Constants.PlatformDetails.providerObjectName) + .addModifiers(KModifier.INTERNAL) + .addProperty( + PropertySpec.builder( + Constants.Apple.resourcesBundlePropertyName, + Constants.Apple.nsBundleName, + KModifier.PRIVATE + ).delegate(CodeBlock.of("lazy { NSBundle.loadableBundle(%S) }", bundleIdentifier)) + .build() + ) + .addProperty( + PropertySpec.builder( + Constants.PlatformDetails.providerDetailsPropertyName, + Constants.resourcePlatformDetailsName + ).delegate( + CodeBlock.of( + "lazy { %T(%N) }", + Constants.resourcePlatformDetailsName, + Constants.Apple.resourcesBundlePropertyName + ) + ).build() + ) + .build() + + return listOf( + FileSpec.builder(packageName, Constants.PlatformDetails.providerObjectName) + .addImport( + Constants.Apple.nsBundleName.packageName, + Constants.Apple.nsBundleName.simpleNames + ) + .addImport( + Constants.Apple.loadableBundleName.packageName, + Constants.Apple.loadableBundleName.simpleNames + ) + .addType(provider) + .build() + ) } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/JvmContainerGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/JvmContainerGenerator.kt index e58fec59b..68818c0b3 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/JvmContainerGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/container/JvmContainerGenerator.kt @@ -5,17 +5,56 @@ package dev.icerock.gradle.generator.container import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformContainerGenerator -import dev.icerock.gradle.generator.addJvmClassLoaderProperty internal class JvmContainerGenerator : PlatformContainerGenerator { override fun getImports(): List { - return listOf(Constants.Jvm.classLoaderName) + return listOf( + Constants.Jvm.classLoaderName, + ClassName("kotlin.jvm", "java") + ) } - override fun generateBeforeTypes(objectName: String, builder: TypeSpec.Builder) { - builder.addJvmClassLoaderProperty(objectName) + override fun generateAdditionalFiles(packageName: String): List { + val provider = TypeSpec.objectBuilder(Constants.PlatformDetails.providerObjectName) + .addModifiers(KModifier.INTERNAL) + .addProperty( + PropertySpec.builder( + Constants.Jvm.resourcesClassLoaderPropertyName, + Constants.Jvm.classLoaderName, + KModifier.PRIVATE + ).initializer( + CodeBlock.of( + "%L::class.java.classLoader", + Constants.PlatformDetails.providerObjectName + ) + ).build() + ) + .addProperty( + PropertySpec.builder( + Constants.PlatformDetails.providerDetailsPropertyName, + Constants.resourcePlatformDetailsName + ).delegate( + CodeBlock.of( + "lazy { %T(%N) }", + Constants.resourcePlatformDetailsName, + Constants.Jvm.resourcesClassLoaderPropertyName + ) + ).build() + ) + .build() + + return listOf( + FileSpec.builder(packageName, Constants.PlatformDetails.providerObjectName) + .addImport("kotlin.jvm", "java") + .addType(provider) + .build() + ) } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/AssetGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/AssetGeneratorFactory.kt index 447421a77..4937fdb5b 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/AssetGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/AssetGeneratorFactory.kt @@ -28,6 +28,7 @@ import java.io.File @Suppress("LongParameterList") internal class AssetGeneratorFactory( + private val resourcesPackageName: String, private val resourcesVisibility: MRVisibility, private val outputResourcesDir: File, private val outputAssetsDir: File, @@ -51,6 +52,7 @@ internal class AssetGeneratorFactory( .toSet() ), platformResourceGenerator = createPlatformAssetGenerator(), + resourcesPackageName = resourcesPackageName, filter = { include("assets/**") } ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ColorGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ColorGeneratorFactory.kt index 8ebbd9109..db7d362a7 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ColorGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ColorGeneratorFactory.kt @@ -25,6 +25,7 @@ import java.io.File @Suppress("LongParameterList") internal class ColorGeneratorFactory( + private val resourcesPackageName: String, private val resourcesVisibility: MRVisibility, private val outputResourcesDir: File, private val outputAssetsDir: File, @@ -41,7 +42,8 @@ internal class ColorGeneratorFactory( visibilityModifier = resourcesVisibility.toModifier(), generator = ColorResourceGenerator(), platformResourceGenerator = createPlatformColorGenerator(), - filter = { include("**/colors*.xml") } + filter = { include("**/colors*.xml") }, + resourcesPackageName = resourcesPackageName ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FileGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FileGeneratorFactory.kt index de9616338..d34dde21a 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FileGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FileGeneratorFactory.kt @@ -28,6 +28,7 @@ import java.io.File @Suppress("LongParameterList") internal class FileGeneratorFactory( + private val resourcesPackageName: String, private val resourcesVisibility: MRVisibility, private val outputResourcesDir: File, private val kotlinPlatformType: KotlinPlatformType, @@ -50,6 +51,7 @@ internal class FileGeneratorFactory( .toSet() ), platformResourceGenerator = createPlatformFileGenerator(), + resourcesPackageName = resourcesPackageName, filter = { include("files/**") } ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FontGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FontGeneratorFactory.kt index 723f4f329..9ceae4c00 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FontGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/FontGeneratorFactory.kt @@ -42,7 +42,8 @@ internal class FontGeneratorFactory( visibilityModifier = resourcesVisibility.toModifier(), generator = FontResourceGenerator(), platformResourceGenerator = createPlatformFontGenerator(), - filter = { include("fonts/**.ttf", "fonts/**.otf") } + filter = { include("fonts/**.ttf", "fonts/**.otf") }, + resourcesPackageName = resourcesPackageName ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ImageGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ImageGeneratorFactory.kt index 0dda5d84c..88237f7df 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ImageGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/ImageGeneratorFactory.kt @@ -27,6 +27,7 @@ import java.io.File @Suppress("LongParameterList") internal class ImageGeneratorFactory( + private val resourcesPackageName: String, private val resourcesVisibility: MRVisibility, private val outputResourcesDir: File, private val outputAssetsDir: File, @@ -44,6 +45,7 @@ internal class ImageGeneratorFactory( visibilityModifier = resourcesVisibility.toModifier(), generator = ImageResourceGenerator(), platformResourceGenerator = createPlatformImageGenerator(), + resourcesPackageName = resourcesPackageName, filter = { include("images/**/*.png", "images/**/*.jpg", "images/**/*.svg") } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/PluralGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/PluralGeneratorFactory.kt index d97efeca2..b0c363f2b 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/PluralGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/PluralGeneratorFactory.kt @@ -47,7 +47,8 @@ internal class PluralGeneratorFactory( strictLineBreaks = strictLineBreaks ), platformResourceGenerator = createPlatformPluralGenerator(), - filter = { include("**/plurals*.xml") } + filter = { include("**/plurals*.xml") }, + resourcesPackageName = resourcesPackageName ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/StringGeneratorFactory.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/StringGeneratorFactory.kt index 65744168b..e7e9bd4d0 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/StringGeneratorFactory.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/factory/StringGeneratorFactory.kt @@ -47,7 +47,8 @@ internal class StringGeneratorFactory( strictLineBreaks = strictLineBreaks ), platformResourceGenerator = createPlatformStringGenerator(), - filter = { include("**/strings*.xml") } + filter = { include("**/strings*.xml") }, + resourcesPackageName = resourcesPackageName ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/platform/android/AddAndroidGeneratedSources.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/platform/android/AddAndroidGeneratedSources.kt index f6639b9f3..ffa3d9202 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/platform/android/AddAndroidGeneratedSources.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/platform/android/AddAndroidGeneratedSources.kt @@ -9,11 +9,11 @@ import dev.icerock.gradle.tasks.GenerateMultiplatformResourcesTask import org.gradle.api.tasks.TaskProvider /** - * Registers generated Kotlin sources and assets for Android variants when using the + * Registers generated Kotlin sources, resources and assets for Android variants when using the * classic AGP plugin (`com.android.library`). * - * The generated resource directory (`res`) is not attached here; it is added later during - * source set configuration, as required by the legacy AGP source set wiring model. + * Resources are also registered through the legacy source set API for IDE indexing. Registering + * them here exposes the task-backed generated directory to variant consumers such as Paparazzi. * * Use this function only with the traditional Android plugin. */ @@ -25,13 +25,10 @@ internal fun Sources.addLegacyAndroidGeneratedSources( wiredWith = GenerateMultiplatformResourcesTask::outputSourcesDir ) - // Resources doesn't add in android variants for IDE indexing - // Resource directory set here: - // dev.icerock.gradle.MultiplatformResourcesPlugin.setupSourceSets - // res?.addGeneratedSourceDirectory( - // taskProvider = provider, - // wiredWith = GenerateMultiplatformResourcesTask::outputResourcesDir - // ) + res?.addGeneratedSourceDirectory( + taskProvider = provider, + wiredWith = GenerateMultiplatformResourcesTask::outputResourcesDir + ) // Assets add here, for correct compilation assets?.addGeneratedSourceDirectory( diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/NOPResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/NOPResourceGenerator.kt index 77f23bcb1..edd0f0504 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/NOPResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/NOPResourceGenerator.kt @@ -11,14 +11,14 @@ import dev.icerock.gradle.metadata.resource.ResourceMetadata internal class NOPResourceGenerator : PlatformResourceGenerator { override fun imports(): List { - TODO("Not yet implemented") + return emptyList() } override fun generateResourceFiles(data: List) { - TODO("Not yet implemented") + Unit } override fun generateInitializer(metadata: T): CodeBlock { - TODO("Not yet implemented") + return CodeBlock.of("error(%S)", "NOP resource generator should not create initializers") } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AndroidAssetResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AndroidAssetResourceGenerator.kt index 5d2e44de1..5fcb8c8f5 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AndroidAssetResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AndroidAssetResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.asset import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.AssetMetadata import java.io.File @@ -30,26 +28,14 @@ internal class AndroidAssetResourceGenerator( ) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier? ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier? - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.assetResourceName - ) - } - override fun generateResourceFiles(data: List) { data.forEach { metadata -> metadata.filePath.copyTo(File(assetsGenerationDir, metadata.pathRelativeToBase.path)) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AppleAssetResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AppleAssetResourceGenerator.kt index abb658795..c082654d9 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AppleAssetResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/AppleAssetResourceGenerator.kt @@ -6,19 +6,22 @@ package dev.icerock.gradle.generator.resources.asset import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.AssetMetadata import java.io.File internal class AppleAssetResourceGenerator( private val resourcesGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: AssetMetadata): CodeBlock { return CodeBlock.of( @@ -30,6 +33,16 @@ internal class AppleAssetResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: AssetMetadata): CodeBlock { + return CodeBlock.of( + "AssetResource(originalPath = %S, fileName = %S, extension = %S, bundle = %L)", + metadata.pathRelativeToBase.invariantSeparatorsPath, + processedFilePath(metadata).substringBeforeLast('.'), + metadata.filePath.extension, + Constants.Apple.providerBundleReference + ) + } + override fun generateResourceFiles(data: List) { data.forEach { metadata -> val newName: String = processedFilePath(metadata) @@ -42,25 +55,19 @@ internal class AppleAssetResourceGenerator( .replace('/', PATH_DELIMITER) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.assetResourceName - ) - } + objectName: String, + ) = Unit private companion object { const val PATH_DELIMITER = '+' diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JsAssetResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JsAssetResourceGenerator.kt index bd7b471b5..002bd1ce2 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JsAssetResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JsAssetResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.asset import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.platform.js.JsFilePathMode import dev.icerock.gradle.metadata.resource.AssetMetadata import java.io.File @@ -35,8 +33,8 @@ internal class JsAssetResourceGenerator( ) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { @@ -52,18 +50,6 @@ internal class JsAssetResourceGenerator( } } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.assetResourceName - ) - } - private companion object { const val ASSETS_DIR = "assets" } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JvmAssetResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JvmAssetResourceGenerator.kt index b0e7cd3f4..276913b0a 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JvmAssetResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/asset/JvmAssetResourceGenerator.kt @@ -6,14 +6,13 @@ package dev.icerock.gradle.generator.resources.asset import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.AssetMetadata import java.io.File @@ -31,31 +30,34 @@ internal class JvmAssetResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: AssetMetadata): CodeBlock { + return CodeBlock.of( + "AssetResource(resourcesClassLoader = %L, originalPath = %S, path = %S)", + Jvm.providerClassLoaderReference, + metadata.pathRelativeToBase.invariantSeparatorsPath, + buildAssetPath(metadata) + ) + } + override fun generateResourceFiles(data: List) { data.forEach { metadata -> metadata.filePath.copyTo(File(resourcesGenerationDir, buildAssetPath(metadata))) } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addJvmPlatformResourceClassLoaderProperty(modifier = modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.assetResourceName - ) - } + objectName: String, + ) = Unit private fun buildAssetPath(metadata: AssetMetadata): String { return File(ASSETS_DIR, metadata.pathRelativeToBase.path).path diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AndroidColorResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AndroidColorResourceGenerator.kt index 1d529f2b2..96d16c7d8 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AndroidColorResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AndroidColorResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.color import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.ColorMetadata import java.io.File @@ -27,26 +25,14 @@ internal class AndroidColorResourceGenerator( return CodeBlock.of("ColorResource(R.color.%L)", metadata.key) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.colorResourceName - ) - } - override fun generateResourceFiles(data: List) { val valuesDir = File(resourcesGenerationDir, "values") val defaultStringsFile = File(valuesDir, COLORS_XML_FILE_NAME) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AppleColorResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AppleColorResourceGenerator.kt index 1e379f45d..539c79a53 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AppleColorResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/AppleColorResourceGenerator.kt @@ -6,12 +6,12 @@ package dev.icerock.gradle.generator.resources.color import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.ColorMetadata import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject @@ -23,7 +23,10 @@ import java.io.File internal class AppleColorResourceGenerator( private val assetsGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: ColorMetadata): CodeBlock { return CodeBlock.of( @@ -33,6 +36,14 @@ internal class AppleColorResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: ColorMetadata): CodeBlock { + return CodeBlock.of( + "ColorResource(name = %S, bundle = %L)", + metadata.key, + Constants.Apple.providerBundleReference + ) + } + override fun generateResourceFiles(data: List) { val assetsDirectory = File(assetsGenerationDir, Constants.Apple.assetsDirectoryName) @@ -87,25 +98,19 @@ internal class AppleColorResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.colorResourceName - ) - } + objectName: String, + ) = Unit private fun buildAppearancesIdiomJson( valueTag: String, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JsColorResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JsColorResourceGenerator.kt index 2998ef5a0..f6b86df69 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JsColorResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JsColorResourceGenerator.kt @@ -6,10 +6,8 @@ package dev.icerock.gradle.generator.resources.color import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty @@ -24,35 +22,11 @@ internal class JsColorResourceGenerator : PlatformResourceGenerator) = Unit - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - val languageKeysList: String = metadata.joinToString { it.key } - - val valuesFun: FunSpec = FunSpec.builder("values") - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .addStatement("return listOf($languageKeysList)") - .returns( - ClassName("kotlin.collections", "List") - .parameterizedBy(Constants.colorResourceName) - ) - .build() - - builder.addFunction(valuesFun) - } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JvmColorResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JvmColorResourceGenerator.kt index e855902b5..760b062c5 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JvmColorResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/color/JvmColorResourceGenerator.kt @@ -7,11 +7,10 @@ package dev.icerock.gradle.generator.resources.color import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.ColorMetadata internal class JvmColorResourceGenerator : PlatformResourceGenerator { @@ -23,23 +22,11 @@ internal class JvmColorResourceGenerator : PlatformResourceGenerator) = Unit - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addJvmPlatformResourceClassLoaderProperty(modifier = modifier) } - - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.colorResourceName - ) - } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AndroidFileResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AndroidFileResourceGenerator.kt index 2d6272bf1..ce4926bc4 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AndroidFileResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AndroidFileResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.file import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.FileMetadata import java.io.File import java.util.Locale @@ -28,26 +26,14 @@ internal class AndroidFileResourceGenerator( return CodeBlock.of("FileResource(R.raw.%L)", keyToResourceId(metadata.key)) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fileResourceName - ) - } - override fun generateResourceFiles(data: List) { val targetDir = File(resourcesGenerationDir, "raw") targetDir.mkdirs() diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AppleFileResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AppleFileResourceGenerator.kt index f662956dd..5a4326091 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AppleFileResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/AppleFileResourceGenerator.kt @@ -6,19 +6,22 @@ package dev.icerock.gradle.generator.resources.file import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.FileMetadata import java.io.File internal class AppleFileResourceGenerator( private val resourcesGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: FileMetadata): CodeBlock { return CodeBlock.of( @@ -29,6 +32,15 @@ internal class AppleFileResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: FileMetadata): CodeBlock { + return CodeBlock.of( + "FileResource(fileName = %S, extension = %S, bundle = %L)", + metadata.filePath.nameWithoutExtension, + metadata.filePath.extension, + Constants.Apple.providerBundleReference + ) + } + override fun generateResourceFiles(data: List) { val targetDir = File(resourcesGenerationDir, "files") targetDir.mkdirs() @@ -38,23 +50,17 @@ internal class AppleFileResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fileResourceName - ) - } + objectName: String, + ) = Unit } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JsFileResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JsFileResourceGenerator.kt index a98b202ae..58ec44f19 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JsFileResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JsFileResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.file import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.platform.js.JsFilePathMode import dev.icerock.gradle.metadata.resource.FileMetadata import java.io.File @@ -40,26 +38,14 @@ internal class JsFileResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier? - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fileResourceName - ) - } - private companion object { const val FILES_DIR = "files" } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JvmFileResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JvmFileResourceGenerator.kt index b8e98b114..ea5cfafad 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JvmFileResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/file/JvmFileResourceGenerator.kt @@ -6,14 +6,13 @@ package dev.icerock.gradle.generator.resources.file import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.FileMetadata import java.io.File @@ -30,6 +29,14 @@ internal class JvmFileResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: FileMetadata): CodeBlock { + return CodeBlock.of( + "FileResource(resourcesClassLoader = %L, filePath = %S)", + Jvm.providerClassLoaderReference, + "$FILES_DIR/${metadata.filePath.name}" + ) + } + override fun generateResourceFiles(data: List) { val fontsDir = File(resourcesGenerationDir, FILES_DIR) fontsDir.mkdirs() @@ -39,25 +46,19 @@ internal class JvmFileResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addJvmPlatformResourceClassLoaderProperty(modifier = modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fileResourceName - ) - } + objectName: String, + ) = Unit private companion object { const val FILES_DIR = "files" diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AndroidFontResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AndroidFontResourceGenerator.kt index 9ccc77b3e..13014304e 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AndroidFontResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AndroidFontResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.font import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.FontMetadata import java.io.File @@ -27,8 +25,8 @@ internal class AndroidFontResourceGenerator( return CodeBlock.of("FontResource(R.font.%L)", metadata.key) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { @@ -44,16 +42,4 @@ internal class AndroidFontResourceGenerator( metadata.filePath.copyTo(File(fontResDir, fileName)) } } - - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fontResourceName - ) - } } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AppleFontResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AppleFontResourceGenerator.kt index 98acc57db..3e147755c 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AppleFontResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/AppleFontResourceGenerator.kt @@ -6,19 +6,22 @@ package dev.icerock.gradle.generator.resources.font import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.FontMetadata import java.io.File internal class AppleFontResourceGenerator( private val resourcesGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: FontMetadata): CodeBlock { return CodeBlock.of( @@ -28,29 +31,31 @@ internal class AppleFontResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: FontMetadata): CodeBlock { + return CodeBlock.of( + "FontResource(fontName = %S, bundle = %L)", + metadata.filePath.name, + Constants.Apple.providerBundleReference + ) + } + override fun generateResourceFiles(data: List) { data.map { it.filePath }.forEach { file -> file.copyTo(File(resourcesGenerationDir, file.name)) } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fontResourceName - ) - } + objectName: String, + ) = Unit } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JsFontResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JsFontResourceGenerator.kt index e377bffa3..0e1e01df2 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JsFontResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JsFontResourceGenerator.kt @@ -8,9 +8,7 @@ import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty import dev.icerock.gradle.generator.platform.js.JsFilePathMode @@ -63,37 +61,19 @@ internal class JsFontResourceGenerator( cssDeclarationsFile.writeText(declarations) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateContainerMembers( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier? ) { - val languageKeysList: String = metadata.joinToString { it.key } - - val valuesFun: FunSpec = FunSpec.builder("values") - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .addStatement("return listOf($languageKeysList)") - .returns( - ClassName("kotlin.collections", "List") - .parameterizedBy(Constants.fontResourceName) - ) - .build() - - builder.addFunction(valuesFun) - val addFontsFun: FunSpec = FunSpec.builder("addFontsToPage") .addCode( filePathMode.format, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JvmFontResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JvmFontResourceGenerator.kt index 79aaf3e45..33ec4772f 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JvmFontResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/font/JvmFontResourceGenerator.kt @@ -6,14 +6,13 @@ package dev.icerock.gradle.generator.resources.font import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.FontMetadata import java.io.File @@ -30,6 +29,14 @@ internal class JvmFontResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: FontMetadata): CodeBlock { + return CodeBlock.of( + "FontResource(resourcesClassLoader = %L, filePath = %S)", + Jvm.providerClassLoaderReference, + "$FONTS_DIR/${metadata.filePath.name}" + ) + } + override fun generateResourceFiles(data: List) { val fontsDir = File(resourcesGenerationDir, FONTS_DIR) fontsDir.mkdirs() @@ -39,25 +46,19 @@ internal class JvmFontResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addJvmPlatformResourceClassLoaderProperty(modifier = modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.fontResourceName - ) - } + objectName: String, + ) = Unit private companion object { const val FONTS_DIR = "fonts" diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AndroidImageResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AndroidImageResourceGenerator.kt index b5418a9fd..06a8d750e 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AndroidImageResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AndroidImageResourceGenerator.kt @@ -8,11 +8,9 @@ import com.android.ide.common.vectordrawable.Svg2Vector import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.ImageMetadata import org.slf4j.Logger import java.io.File @@ -35,26 +33,14 @@ internal class AndroidImageResourceGenerator( return CodeBlock.of("ImageResource(R.drawable.%L)", processKey(metadata.key)) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - metadata = metadata, - classType = Constants.imageResourceName, - modifier = modifier - ) - } - override fun generateResourceFiles(data: List) { data.flatMap { imageMetadata -> imageMetadata.values.map { imageMetadata.key to it } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AppleImageResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AppleImageResourceGenerator.kt index e9156488b..a77bf8dc7 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AppleImageResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/AppleImageResourceGenerator.kt @@ -6,12 +6,12 @@ package dev.icerock.gradle.generator.resources.image import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.ImageMetadata import dev.icerock.gradle.metadata.resource.ImageMetadata.ImageItem import kotlinx.serialization.json.JsonArray @@ -24,7 +24,10 @@ import java.io.File internal class AppleImageResourceGenerator( private val assetsGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: ImageMetadata): CodeBlock { return CodeBlock.of( @@ -34,6 +37,14 @@ internal class AppleImageResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: ImageMetadata): CodeBlock { + return CodeBlock.of( + "ImageResource(assetImageName = %S, bundle = %L)", + metadata.key, + Constants.Apple.providerBundleReference + ) + } + @Suppress("LongMethod") override fun generateResourceFiles(data: List) { val assetsDirectory = File(assetsGenerationDir, Constants.Apple.assetsDirectoryName) @@ -50,7 +61,16 @@ internal class AppleImageResourceGenerator( resourceIsValidOrError(validItems, imageMetadata) - validItems.forEach { it.filePath.copyTo(File(assetDir, it.filePath.name)) } + validItems.forEach { item -> + val targetFile = File(assetDir, item.filePath.name) + if (item.filePath.extension.equals("svg", ignoreCase = true)) { + val content = item.filePath.readText() + val processedContent = SvgColorTransformer.transform(content) + targetFile.writeText(processedContent) + } else { + item.filePath.copyTo(targetFile) + } + } val imagesContent: JsonArray = getImagesContent(validItems, imageMetadata) val content: String = prepareContentInfo(imagesContent, validItems) @@ -59,25 +79,19 @@ internal class AppleImageResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - metadata = metadata, - classType = Constants.imageResourceName, - modifier = modifier - ) - } + objectName: String, + ) = Unit private fun getImagesContent( validItems: List, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JsImageResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JsImageResourceGenerator.kt index f07ef5234..f3c776cb2 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JsImageResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JsImageResourceGenerator.kt @@ -6,11 +6,8 @@ package dev.icerock.gradle.generator.resources.image import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty import dev.icerock.gradle.generator.platform.js.JsFilePathMode @@ -59,8 +56,8 @@ internal class JsImageResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { @@ -75,30 +72,6 @@ internal class JsImageResourceGenerator( ) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - val languageKeysList: String = metadata.joinToString { it.key } - - val valuesFun: FunSpec = FunSpec.builder("values") - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .addStatement("return listOf($languageKeysList)") - .returns( - ClassName("kotlin.collections", "List") - .parameterizedBy(Constants.imageResourceName) - ) - .build() - - builder.addFunction(valuesFun) - } - private companion object { const val IMAGES_DIR = "images" } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JvmImageResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JvmImageResourceGenerator.kt index 967dddd2b..a2178ef73 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JvmImageResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/JvmImageResourceGenerator.kt @@ -6,14 +6,13 @@ package dev.icerock.gradle.generator.resources.image import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.metadata.resource.ImageMetadata import dev.icerock.gradle.metadata.resource.ImageMetadata.Appearance import java.io.File @@ -50,6 +49,33 @@ internal class JvmImageResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: ImageMetadata): CodeBlock { + var fileName: String = "" + var darkFileName: String? = null + + metadata.values.groupBy { it.appearance }.forEach { (theme, resources) -> + val item: ImageMetadata.ImageItem = resources.getHighestQualityItem(theme) + + if (theme == Appearance.DARK) { + darkFileName = "${metadata.key}${theme.themeSuffix}.${item.filePath.extension}" + } else { + fileName = "${metadata.key}.${item.filePath.extension}" + } + } + + val darkFilePath: String = if (darkFileName != null) { + "\"$IMAGES_DIR/$darkFileName\"" + } else { + "null" + } + + return CodeBlock.of( + "ImageResource(resourcesClassLoader = %L, filePath = %S, darkFilePath = $darkFilePath)", + Jvm.providerClassLoaderReference, + "$IMAGES_DIR/$fileName" + ) + } + override fun generateResourceFiles(data: List) { generateHighestQualityImageResources( resourcesGenerationDir = resourcesGenerationDir, @@ -58,25 +84,19 @@ internal class JvmImageResourceGenerator( ) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addJvmPlatformResourceClassLoaderProperty(modifier = modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.imageResourceName - ) - } + objectName: String, + ) = Unit private companion object { const val IMAGES_DIR = "images" diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/SvgColorTransformer.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/SvgColorTransformer.kt new file mode 100644 index 000000000..485f39ef4 --- /dev/null +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/image/SvgColorTransformer.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator.resources.image + +import java.util.Locale + +@Suppress("MagicNumber") +internal object SvgColorTransformer { + private const val LONG_HEX_WITH_ALPHA_LENGTH = 8 + private const val SHORT_HEX_WITH_ALPHA_LENGTH = 4 + private const val MAX_ALPHA_CHANNEL_VALUE = 255.0 + + fun transform(content: String): String { + val attrNamesPattern = ColorAttribute.allNames.joinToString("|") + val attrRegex = Regex("""($attrNamesPattern)\s*=\s*(['"])#([0-9a-fA-F]+)\2""") + + var result = attrRegex.replace(content) { matchResult -> + val attrName = matchResult.groupValues[1] + val quote = matchResult.groupValues[2] + val hex = matchResult.groupValues[3] + + val color = parseColorWithAlpha(hex) ?: return@replace matchResult.value + formatXmlAttribute(attrName = attrName, quote = quote, color = color) + } + + val styleAttrRegex = Regex("""style\s*=\s*(['"])([^"']*)\1""") + result = styleAttrRegex.replace(result) { matchResult -> + val quote = matchResult.groupValues[1] + val styleContent = matchResult.groupValues[2] + + val colorRegex = Regex("""($attrNamesPattern)\s*:\s*#([0-9a-fA-F]+)""") + val transformedStyle = colorRegex.replace(styleContent) { colorMatch -> + val attrName = colorMatch.groupValues[1] + val hex = colorMatch.groupValues[2] + + val color = parseColorWithAlpha(hex) ?: return@replace colorMatch.value + formatStyleProperty(attrName = attrName, color = color) + } + """style=$quote$transformedStyle$quote""" + } + + return result + } + + private fun formatXmlAttribute( + attrName: String, + quote: String, + color: SvgColorWithAlpha, + ): String { + val opacityAttrName = ColorAttribute.findByName(attrName).opacityAttrName + + return """$attrName=$quote#${color.rgb}$quote $opacityAttrName=$quote${color.alpha}$quote""" + } + + private fun formatStyleProperty( + attrName: String, + color: SvgColorWithAlpha, + ): String { + val opacityAttrName = ColorAttribute.findByName(attrName).opacityAttrName + + return "$attrName:#${color.rgb};$opacityAttrName:${color.alpha}" + } + + private fun parseColorWithAlpha(hex: String): SvgColorWithAlpha? { + return when (hex.length) { + LONG_HEX_WITH_ALPHA_LENGTH -> { + SvgColorWithAlpha( + rgb = hex.substring(0, 6), + alpha = formatAlpha(hex.substring(6, 8)) + ) + } + + SHORT_HEX_WITH_ALPHA_LENGTH -> { + val rgb = hex.take(3).map { "$it$it" }.joinToString(separator = "") + val alpha = hex.last().let { "$it$it" } + + SvgColorWithAlpha( + rgb = rgb, + alpha = formatAlpha(alpha) + ) + } + + else -> null + } + } + + private fun formatAlpha(hex: String): String { + val alphaFloat = hex.toInt(16) / MAX_ALPHA_CHANNEL_VALUE + return "%.2f".format(Locale.US, alphaFloat) + } + + private data class SvgColorWithAlpha( + val rgb: String, + val alpha: String, + ) +} + +private enum class ColorAttribute(val attrName: String, val opacityAttrName: String) { + FILL(attrName = "fill", opacityAttrName = "fill-opacity"), + STROKE(attrName = "stroke", opacityAttrName = "stroke-opacity"), + STOP_COLOR(attrName = "stop-color", opacityAttrName = "stop-opacity"), + FLOOD_COLOR(attrName = "flood-color", opacityAttrName = "flood-opacity"); + + companion object { + val allNames: List = entries.map { it.attrName } + fun findByName(name: String): ColorAttribute = entries.first { it.attrName == name } + } +} diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/AndroidPluralResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/AndroidPluralResourceGenerator.kt index 1bc5994dc..a703e4fa8 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/AndroidPluralResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/AndroidPluralResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.plural import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.localization.LanguageType import dev.icerock.gradle.metadata.resource.PluralMetadata import dev.icerock.gradle.utils.convertXmlStringToAndroidLocalization @@ -29,8 +27,8 @@ internal class AndroidPluralResourceGenerator( return CodeBlock.of("PluralsResource(R.plurals.%L)", metadata.key) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { @@ -46,18 +44,6 @@ internal class AndroidPluralResourceGenerator( } } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.pluralsResourceName - ) - } - private fun generateLanguageFile( language: LanguageType, strings: Map>, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/ApplePluralResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/ApplePluralResourceGenerator.kt index 96dd8e0c6..0351a9166 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/ApplePluralResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/ApplePluralResourceGenerator.kt @@ -6,12 +6,12 @@ package dev.icerock.gradle.generator.resources.plural import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.localization.LanguageType import dev.icerock.gradle.metadata.resource.PluralMetadata import dev.icerock.gradle.utils.convertXmlStringToApplePluralLocalization @@ -21,7 +21,10 @@ internal class ApplePluralResourceGenerator( private val baseLocalizationRegion: String, private val resourcesGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: PluralMetadata): CodeBlock { return CodeBlock.of( @@ -31,6 +34,14 @@ internal class ApplePluralResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: PluralMetadata): CodeBlock { + return CodeBlock.of( + "PluralsResource(resourceId = %S, bundle = %L)", + metadata.key, + Constants.Apple.providerBundleReference + ) + } + override fun generateResourceFiles(data: List) { data.processLanguages().forEach { (lang, strings) -> generateLanguageFile( @@ -40,25 +51,19 @@ internal class ApplePluralResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.pluralsResourceName - ) - } + objectName: String, + ) = Unit private fun generateLanguageFile( language: LanguageType, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JsPluralResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JsPluralResourceGenerator.kt index c5d99cc78..48c33a5c2 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JsPluralResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JsPluralResourceGenerator.kt @@ -6,13 +6,13 @@ package dev.icerock.gradle.generator.resources.plural import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty +import dev.icerock.gradle.generator.addJsAccessorFileStringsLoaderProperty import dev.icerock.gradle.generator.addJsContainerStringsLoaderProperty import dev.icerock.gradle.generator.addJsFallbackProperty import dev.icerock.gradle.generator.addJsSupportedLocalesProperty @@ -51,8 +51,8 @@ internal class JsPluralResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier? ) { @@ -79,28 +79,28 @@ internal class JsPluralResourceGenerator( builder.addJsContainerStringsLoaderProperty() } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier? + objectName: String, ) { - val languageKeysList: String = metadata.joinToString { it.key } - - val valuesFun: FunSpec = FunSpec.builder("values") - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .addStatement("return listOf($languageKeysList)") - .returns( - ClassName("kotlin.collections", "List") - .parameterizedBy(Constants.pluralsResourceName) - ) - .build() - - builder.addFunction(valuesFun) + builder.addJsFallbackProperty( + fallbackFilePath = "./" + LOCALIZATION_DIR + "/" + getFileNameForLanguage(LanguageType.Base), + filePathMode = filePathMode + ) + builder.addJsSupportedLocalesProperty( + bcpLangToPath = metadata.asSequence() + .flatMap { resource -> + resource.values.map { it.locale } + }.distinct().map { locale -> + LanguageType.fromLanguage(locale) + }.filterIsInstance().map { language -> + val fileName: String = getFileNameForLanguage(language) + language.toBcpString() to "./$LOCALIZATION_DIR/$fileName" + }.toList(), + filePathMode = filePathMode + ) + builder.addJsAccessorFileStringsLoaderProperty() } private fun generateLanguageFile( diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JvmPluralResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JvmPluralResourceGenerator.kt index 2e056c7c6..0c68c9229 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JvmPluralResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/plural/JvmPluralResourceGenerator.kt @@ -6,15 +6,15 @@ package dev.icerock.gradle.generator.resources.plural import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceBundleProperty import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.localization.LanguageType import dev.icerock.gradle.metadata.resource.PluralMetadata import dev.icerock.gradle.utils.convertXmlStringToLocalization @@ -35,6 +35,15 @@ internal class JvmPluralResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: PluralMetadata): CodeBlock { + return CodeBlock.of( + "PluralsResource(resourcesClassLoader = %L, bundleName = %L, key = %S)", + Jvm.providerClassLoaderReference, + pluralsBundlePropertyName, + metadata.key + ) + } + override fun generateResourceFiles(data: List) { data.processLanguages().forEach { (lang, strings) -> generateLanguageFile( @@ -44,8 +53,8 @@ internal class JvmPluralResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { @@ -57,15 +66,14 @@ internal class JvmPluralResourceGenerator( ) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, + objectName: String, ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.pluralsResourceName + builder.addJvmPlatformResourceBundleProperty( + bundlePropertyName = pluralsBundlePropertyName, + bundlePath = getBundlePath() ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AndroidStringResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AndroidStringResourceGenerator.kt index ee9a1652f..8bfe51296 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AndroidStringResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AndroidStringResourceGenerator.kt @@ -7,11 +7,9 @@ package dev.icerock.gradle.generator.resources.string import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.localization.LanguageType import dev.icerock.gradle.metadata.resource.StringMetadata import dev.icerock.gradle.utils.convertXmlStringToAndroidLocalization @@ -29,26 +27,14 @@ internal class AndroidStringResourceGenerator( return CodeBlock.of("StringResource(R.string.%L)", metadata.key) } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addEmptyPlatformResourceProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, - metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.stringResourceName - ) - } - override fun generateResourceFiles(data: List) { data.processLanguages().forEach { (lang, strings) -> generateLanguageFile( diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AppleStringResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AppleStringResourceGenerator.kt index 735bdca30..5b5301e57 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AppleStringResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/AppleStringResourceGenerator.kt @@ -6,12 +6,12 @@ package dev.icerock.gradle.generator.resources.string import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addAppleContainerBundleInitializerProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.localization.LanguageType import dev.icerock.gradle.metadata.resource.StringMetadata import dev.icerock.gradle.utils.convertXmlStringToLocalization @@ -21,7 +21,10 @@ internal class AppleStringResourceGenerator( private val baseLocalizationRegion: String, private val resourcesGenerationDir: File, ) : PlatformResourceGenerator { - override fun imports(): List = emptyList() + override fun imports(): List = listOf( + Constants.Apple.nsBundleName, + Constants.Apple.loadableBundleName + ) override fun generateInitializer(metadata: StringMetadata): CodeBlock { return CodeBlock.of( @@ -31,6 +34,14 @@ internal class AppleStringResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: StringMetadata): CodeBlock { + return CodeBlock.of( + "StringResource(resourceId = %S, bundle = %L)", + metadata.key, + Constants.Apple.providerBundleReference + ) + } + override fun generateResourceFiles(data: List) { data.processLanguages().forEach { (lang, strings) -> generateLanguageFile( @@ -40,25 +51,19 @@ internal class AppleStringResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { builder.addAppleContainerBundleInitializerProperty(modifier) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, - ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.stringResourceName - ) - } + objectName: String, + ) = Unit private fun generateLanguageFile(language: LanguageType, strings: Map) { val resDir = File(resourcesGenerationDir, language.appleResourcesDir) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JsStringResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JsStringResourceGenerator.kt index 52fa3d3ff..fddb61092 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JsStringResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JsStringResourceGenerator.kt @@ -6,13 +6,13 @@ package dev.icerock.gradle.generator.resources.string import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeSpec.Builder +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addEmptyPlatformResourceProperty +import dev.icerock.gradle.generator.addJsAccessorFileStringsLoaderProperty import dev.icerock.gradle.generator.addJsContainerStringsLoaderProperty import dev.icerock.gradle.generator.addJsFallbackProperty import dev.icerock.gradle.generator.addJsSupportedLocalesProperty @@ -51,8 +51,8 @@ internal class JsStringResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier? ) { @@ -79,28 +79,28 @@ internal class JsStringResourceGenerator( builder.addJsContainerStringsLoaderProperty() } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier? + objectName: String, ) { - val languageKeysList: String = metadata.joinToString { it.key } - - val valuesFun: FunSpec = FunSpec.builder("values") - .also { - if (modifier != null) { - it.addModifiers(modifier) - } - } - .addModifiers(KModifier.OVERRIDE) - .addStatement("return listOf($languageKeysList)") - .returns( - ClassName("kotlin.collections", "List") - .parameterizedBy(Constants.stringResourceName) - ) - .build() - - builder.addFunction(valuesFun) + builder.addJsFallbackProperty( + fallbackFilePath = "./" + LOCALIZATION_DIR + "/" + getFileNameForLanguage(LanguageType.Base), + filePathMode = filePathMode + ) + builder.addJsSupportedLocalesProperty( + bcpLangToPath = metadata.asSequence() + .flatMap { resource -> + resource.values.map { it.locale } + }.distinct().map { locale -> + LanguageType.fromLanguage(locale) + }.filterIsInstance().map { language -> + val fileName: String = getFileNameForLanguage(language) + language.toBcpString() to "./$LOCALIZATION_DIR/$fileName" + }.toList(), + filePathMode = filePathMode + ) + builder.addJsAccessorFileStringsLoaderProperty() } private fun generateLanguageFile(language: LanguageType, strings: Map) { diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JvmStringResourceGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JvmStringResourceGenerator.kt index e4514ce39..6df397cb1 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JvmStringResourceGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/resources/string/JvmStringResourceGenerator.kt @@ -6,15 +6,14 @@ package dev.icerock.gradle.generator.resources.string import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeSpec.Builder -import dev.icerock.gradle.generator.Constants +import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.generator.Constants.Jvm import dev.icerock.gradle.generator.Constants.PlatformDetails import dev.icerock.gradle.generator.PlatformResourceGenerator import dev.icerock.gradle.generator.addJvmPlatformResourceBundleProperty import dev.icerock.gradle.generator.addJvmPlatformResourceClassLoaderProperty -import dev.icerock.gradle.generator.addValuesFunction import dev.icerock.gradle.generator.localization.LanguageType import dev.icerock.gradle.metadata.resource.StringMetadata import dev.icerock.gradle.utils.convertXmlStringToLocalization @@ -35,6 +34,15 @@ internal class JvmStringResourceGenerator( ) } + override fun generateAccessorInitializer(metadata: StringMetadata): CodeBlock { + return CodeBlock.of( + "StringResource(resourcesClassLoader = %L, bundleName = %L, key = %S)", + Jvm.providerClassLoaderReference, + stringsBundlePropertyName, + metadata.key + ) + } + override fun generateResourceFiles(data: List) { data.processLanguages().forEach { (lang, strings) -> generateLanguageFile( @@ -44,8 +52,8 @@ internal class JvmStringResourceGenerator( } } - override fun generateBeforeProperties( - builder: Builder, + override fun generateContainerProperties( + builder: TypeSpec.Builder, metadata: List, modifier: KModifier?, ) { @@ -57,15 +65,14 @@ internal class JvmStringResourceGenerator( ) } - override fun generateAfterProperties( - builder: Builder, + override fun generateAccessorFilePreamble( + builder: FileSpec.Builder, metadata: List, - modifier: KModifier?, + objectName: String, ) { - builder.addValuesFunction( - modifier = modifier, - metadata = metadata, - classType = Constants.stringResourceName + builder.addJvmPlatformResourceBundleProperty( + bundlePropertyName = stringsBundlePropertyName, + bundlePath = getBundlePath() ) } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/MetadataException.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/MetadataException.kt index 5b8203937..ef4ed46a1 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/MetadataException.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/MetadataException.kt @@ -9,7 +9,7 @@ class InvalidResourceKeyException(val key: String) : Exception( " underscores or digits: $key" ) -class InvalidImageResourceConfiguration(val imageName: String) : Exception( +class InvalidImageResourceConfiguration(imageName: String) : Exception( "For image {$imageName} found only dark image resources." + " Please, add correct resources, or remove '-dark' flag from name." ) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/container/ContainerMetadata.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/container/ContainerMetadata.kt index 21ac71b86..ab6968940 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/container/ContainerMetadata.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/container/ContainerMetadata.kt @@ -16,6 +16,7 @@ internal data class ContainerMetadata( val parentObjectName: String, val resourceType: ResourceType, val resources: List, + val sourceSetName: String? = null, ) { fun contentHash(): String = resources.mapNotNull { it.contentHash() }.calculateHash() } diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt index 06bf63e16..a270b4076 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/resource/ResourceMetadata.kt @@ -61,7 +61,7 @@ internal data class StringMetadata( ) @Suppress("MagicNumber") - override fun contentHash(): String = values.hashCode().toString(16) + override fun contentHash(): String = values.toString().hashCode().toString(16) } @Serializable @@ -94,7 +94,7 @@ internal data class PluralMetadata( } @Suppress("MagicNumber") - override fun contentHash(): String = values.hashCode().toString(16) + override fun contentHash(): String = values.toString().hashCode().toString(16) } @Serializable @@ -256,7 +256,11 @@ internal data class FileMetadata( override val path: List = getFilePath(filePath, relativePath) - override fun contentHash(): String = filePath.calculateResourcesHash() + override fun contentHash(): String = listOf( + key, + path.joinToString(separator = "/"), + filePath.calculateResourcesHash() + ).calculateHash() } @Serializable @@ -278,7 +282,11 @@ internal data class AssetMetadata( override val path: List = getFilePath(filePath, relativePath) - override fun contentHash(): String = filePath.calculateResourcesHash() + override fun contentHash(): String = listOf( + key, + path.joinToString(separator = "/"), + filePath.calculateResourcesHash() + ).calculateHash() } interface HierarchyMetadata : ResourceMetadata { diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt index edbdc11f5..950d25644 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/tasks/GenerateMultiplatformResourcesTask.kt @@ -36,6 +36,7 @@ import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.OutputFile @@ -61,7 +62,7 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { @get:PathSensitive(PathSensitivity.RELATIVE) abstract val ownResources: ConfigurableFileCollection - @get:Input + @get:Internal abstract val upperSourceSets: MapProperty @get:Optional @@ -155,9 +156,12 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { ) val serializer: KSerializer> = ListSerializer(ContainerMetadata.serializer()) - val inputMetadata: List = inputMetadataFiles.files.flatMap { file -> - json.decodeFromString(serializer, file.readText()) - } + // Sort for deterministic output. + val inputMetadata: List = inputMetadataFiles.files + .sortedBy { it.absolutePath } + .flatMap { file -> + json.decodeFromString(serializer, file.readText()) + } val outputMetadata: List = if (kotlinPlatformType.isCommon) { generator.generateCommonKotlin(files, inputMetadata) @@ -227,6 +231,7 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { iosBaseLocalizationRegion = iosBaseLocalizationRegion::get, ).create(), ImageGeneratorFactory( + resourcesPackageName = resourcesPackageName.get(), resourcesVisibility = resourcesVisibility.get(), outputResourcesDir = outputResourcesDir.get().asFile, outputAssetsDir = outputAssetsDir.get().asFile, @@ -236,6 +241,7 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { logger = logger ).create(), ColorGeneratorFactory( + resourcesPackageName = resourcesPackageName.get(), resourcesVisibility = resourcesVisibility.get(), outputResourcesDir = outputResourcesDir.get().asFile, outputAssetsDir = outputAssetsDir.get().asFile, @@ -252,6 +258,7 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { androidRClassPackage = androidRClassPackage::get, ).create(), FileGeneratorFactory( + resourcesPackageName = resourcesPackageName.get(), resourcesVisibility = resourcesVisibility.get(), outputResourcesDir = outputResourcesDir.get().asFile, kotlinPlatformType = kotlinPlatformType, @@ -260,6 +267,7 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { ownResources = ownResources ).create(), AssetGeneratorFactory( + resourcesPackageName = resourcesPackageName.get(), resourcesVisibility = resourcesVisibility.get(), outputResourcesDir = outputResourcesDir.get().asFile, outputAssetsDir = outputAssetsDir.get().asFile, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt index 5df62d2a9..b0d2351dc 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/utils/calcHash.kt @@ -12,8 +12,11 @@ import java.io.InputStream import java.io.SequenceInputStream internal fun File.calculateResourcesHash(): String { + val root: File = this + // Sort for deterministic output; walkTopDown() order is filesystem-dependent. val inputStreams: List = walkTopDown() .filterNot { it.isDirectory } + .sortedBy { it.relativeTo(root).path } .map { it.inputStream() }.toList() val singleInputStream: InputStream = SequenceInputStream(inputStreams.toEnumeration()) diff --git a/resources-generator/src/test/kotlin/dev/icerock/gradle/generator/DeterministicOutputTest.kt b/resources-generator/src/test/kotlin/dev/icerock/gradle/generator/DeterministicOutputTest.kt new file mode 100644 index 000000000..592acc114 --- /dev/null +++ b/resources-generator/src/test/kotlin/dev/icerock/gradle/generator/DeterministicOutputTest.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator + +import dev.icerock.gradle.metadata.resource.PluralMetadata +import dev.icerock.gradle.metadata.resource.PluralMetadata.PluralItem +import dev.icerock.gradle.metadata.resource.PluralMetadata.PluralItem.Quantity +import dev.icerock.gradle.metadata.resource.StringMetadata +import dev.icerock.gradle.utils.calculateResourcesHash +import java.io.File +import java.nio.file.Files +import kotlin.test.Test +import kotlin.test.assertEquals + +class DeterministicOutputTest { + + private val plural = PluralMetadata( + key = "apples", + values = listOf( + PluralMetadata.LocaleItem( + locale = "base", + values = listOf( + PluralItem(Quantity.ONE, "one apple"), + PluralItem(Quantity.OTHER, "%d apples"), + ), + ), + PluralMetadata.LocaleItem( + locale = "ru", + values = listOf( + PluralItem(Quantity.ONE, "яблоко"), + PluralItem(Quantity.FEW, "яблока"), + PluralItem(Quantity.MANY, "яблок"), + ), + ), + ), + ) + + private val string = StringMetadata( + key = "hello", + values = listOf( + StringMetadata.LocaleItem(locale = "base", value = "Hello, world"), + StringMetadata.LocaleItem(locale = "ru", value = "Привет, мир"), + ), + ) + + @Test + fun pluralContentHashIsStable() { + assertEquals(expected = "-9167ca0", actual = plural.contentHash()) + } + + @Test + fun stringContentHashIsStable() { + assertEquals(expected = "367b4e74", actual = string.contentHash()) + } + + @Test + fun equivalentMetadataProduceEqualContentHash() { + assertEquals(expected = plural.contentHash(), actual = plural.copy().contentHash()) + } + + @Test + fun directoryHashIgnoresFilesystemOrder() { + val forward = createTree(listOf("a.txt" to "A", "b.txt" to "B", "c.txt" to "C")) + val reverse = createTree(listOf("c.txt" to "C", "b.txt" to "B", "a.txt" to "A")) + try { + assertEquals(expected = forward.calculateResourcesHash(), actual = reverse.calculateResourcesHash()) + } finally { + forward.deleteRecursively() + reverse.deleteRecursively() + } + } + + private fun createTree(entries: List>): File { + val dir = Files.createTempDirectory("moko-hash-test").toFile() + entries.forEach { (name, content) -> File(dir, name).writeText(content) } + return dir + } +} diff --git a/resources-generator/src/test/kotlin/dev/icerock/gradle/generator/resources/image/SvgColorTransformerTest.kt b/resources-generator/src/test/kotlin/dev/icerock/gradle/generator/resources/image/SvgColorTransformerTest.kt new file mode 100644 index 000000000..5b2630f5d --- /dev/null +++ b/resources-generator/src/test/kotlin/dev/icerock/gradle/generator/resources/image/SvgColorTransformerTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2024 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator.resources.image + +import org.junit.Test +import kotlin.test.assertEquals + +class SvgColorTransformerTest { + + @Test + fun `test transform fill attribute 8-digit`() { + val input = """""" + val expected = """""" + assertEquals(expected, SvgColorTransformer.transform(input)) + } + + @Test + fun `test transform fill attribute 4-digit`() { + val input = """""" + val expected = """""" + assertEquals(expected, SvgColorTransformer.transform(input)) + } + + @Test + fun `test keep color attribute 8-digit unchanged`() { + // color attribute doesn't have a corresponding color-opacity attribute in SVG + val input = """""" + val expected = input + assertEquals(expected, SvgColorTransformer.transform(input)) + } + + @Test + fun `test transform style attribute 8-digit`() { + val input = """""" + val expected = """""" + assertEquals(expected, SvgColorTransformer.transform(input)) + } + + @Test + fun `test transform style attribute 4-digit`() { + val input = """""" + val expected = """""" + assertEquals(expected, SvgColorTransformer.transform(input)) + } + + @Test + fun `test user provided sample`() { + val input = """ + + + + """.trimIndent() + val expected = """ + + + + """.trimIndent() + assertEquals(expected, SvgColorTransformer.transform(input)) + } +} diff --git a/samples/android-mpp-app/app/src/androidMain/kotlin/com/icerockdev/mpp/MainActivity.kt b/samples/android-mpp-app/app/src/androidMain/kotlin/com/icerockdev/mpp/MainActivity.kt index 5ce14f92c..abd9e25c1 100755 --- a/samples/android-mpp-app/app/src/androidMain/kotlin/com/icerockdev/mpp/MainActivity.kt +++ b/samples/android-mpp-app/app/src/androidMain/kotlin/com/icerockdev/mpp/MainActivity.kt @@ -6,13 +6,17 @@ package com.icerockdev.mpp import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import com.icerockdev.library.TestRes +import com.icerockdev.library.MR +import com.icerockdev.library.MR.strings +import com.icerockdev.library.MRandroidMain +import com.icerockdev.library.android_name +import com.icerockdev.library.common_name class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - TestRes.test() + println(MR.strings.common_name) + println(MRandroidMain.strings.android_name) } } diff --git a/samples/android-mpp-app/app/src/androidMain/moko-resources/base/strings.xml b/samples/android-mpp-app/app/src/androidMain/moko-resources/base/strings.xml new file mode 100644 index 000000000..23223c55e --- /dev/null +++ b/samples/android-mpp-app/app/src/androidMain/moko-resources/base/strings.xml @@ -0,0 +1,4 @@ + + + Test Project + \ No newline at end of file diff --git a/samples/android-mpp-app/app/src/commonMain/kotlin/com/icerockdev/library/TestRes.kt b/samples/android-mpp-app/app/src/commonMain/kotlin/com/icerockdev/library/TestRes.kt index 07b1de217..ef95ca4b0 100644 --- a/samples/android-mpp-app/app/src/commonMain/kotlin/com/icerockdev/library/TestRes.kt +++ b/samples/android-mpp-app/app/src/commonMain/kotlin/com/icerockdev/library/TestRes.kt @@ -7,5 +7,9 @@ package com.icerockdev.library object TestRes { fun test() { println(MR.strings.common_name) + println(MR.strings.common_name1) + println(MR.strings.common_name10) + println(MR.strings.common_name20) + println(MR.strings.common_name22) } } diff --git a/samples/android-mpp-app/app/src/commonMain/moko-resources/base/strings.xml b/samples/android-mpp-app/app/src/commonMain/moko-resources/base/strings.xml index c4c177224..9387846a3 100644 --- a/samples/android-mpp-app/app/src/commonMain/moko-resources/base/strings.xml +++ b/samples/android-mpp-app/app/src/commonMain/moko-resources/base/strings.xml @@ -1,4 +1,26 @@ Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project + Test Project \ No newline at end of file diff --git a/samples/cm-resources-sample/composeApp/src/commonMain/kotlin/com/icerock/cm/sample/app/App.kt b/samples/cm-resources-sample/composeApp/src/commonMain/kotlin/com/icerock/cm/sample/app/App.kt index e6f652938..1f83a7ed8 100644 --- a/samples/cm-resources-sample/composeApp/src/commonMain/kotlin/com/icerock/cm/sample/app/App.kt +++ b/samples/cm-resources-sample/composeApp/src/commonMain/kotlin/com/icerock/cm/sample/app/App.kt @@ -52,6 +52,9 @@ import org.jetbrains.compose.resources.Font import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.vectorResource import com.icerock.cm.sample.library.MokoRes +import com.icerock.cm.sample.library.hello_world +import com.icerock.cm.sample.library.moko_logo +import dev.icerock.moko.resources.compose.stringResource as mokoStringResource @Composable internal fun App() = AppTheme { @@ -127,7 +130,7 @@ internal fun App() = AppTheme { } Text("Moko resources:") Text( - text = dev.icerock.moko.resources.compose.stringResource(MokoRes.strings.hello_world) + text = mokoStringResource(MokoRes.strings.hello_world) ) Image( modifier = Modifier diff --git a/samples/compose-jvm-app/common/src/commonMain/kotlin/me/amikhailov/common/App.kt b/samples/compose-jvm-app/common/src/commonMain/kotlin/me/amikhailov/common/App.kt index bb170ee08..1d0ee0aea 100644 --- a/samples/compose-jvm-app/common/src/commonMain/kotlin/me/amikhailov/common/App.kt +++ b/samples/compose-jvm-app/common/src/commonMain/kotlin/me/amikhailov/common/App.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import com.icerockdev.app.MR +import com.icerockdev.app.hello_world @Composable fun App() { diff --git a/samples/compose-jvm-app/common/src/desktopMain/kotlin/me/amikhailov/common/Main.kt b/samples/compose-jvm-app/common/src/desktopMain/kotlin/me/amikhailov/common/Main.kt index ed978ade1..ebc76eb04 100644 --- a/samples/compose-jvm-app/common/src/desktopMain/kotlin/me/amikhailov/common/Main.kt +++ b/samples/compose-jvm-app/common/src/desktopMain/kotlin/me/amikhailov/common/Main.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.singleWindowApplication import com.icerockdev.app.MRdesktopMain +import com.icerockdev.app.title fun main() { singleWindowApplication( diff --git a/samples/compose-resources-gallery/build.gradle.kts b/samples/compose-resources-gallery/build.gradle.kts index 8a93d4641..f90798c8e 100644 --- a/samples/compose-resources-gallery/build.gradle.kts +++ b/samples/compose-resources-gallery/build.gradle.kts @@ -6,6 +6,7 @@ plugins { kotlin("android") apply false id("com.android.application") apply false id("com.android.library") apply false + id("app.cash.paparazzi") version "1.3.5" apply false id("org.jetbrains.compose") apply false } diff --git a/samples/compose-resources-gallery/gradle.properties b/samples/compose-resources-gallery/gradle.properties index 792e28e1c..3553881c4 100644 --- a/samples/compose-resources-gallery/gradle.properties +++ b/samples/compose-resources-gallery/gradle.properties @@ -19,6 +19,8 @@ org.jetbrains.compose.experimental.uikit.enabled=true kotlin.mpp.androidSourceSetLayoutVersion=2 kotlin.mpp.androidGradlePluginCompatibility.nowarn=true +moko.resources.disableStaticFrameworkWarning=true + # update to future versions after fix of https://youtrack.jetbrains.com/issue/CMP-7207 kotlin.version=2.1.0 agp.version=8.4.0 diff --git a/samples/compose-resources-gallery/iosApp/iosApp/Info.plist b/samples/compose-resources-gallery/iosApp/iosApp/Info.plist index 9a269f5ea..709e3eca6 100644 --- a/samples/compose-resources-gallery/iosApp/iosApp/Info.plist +++ b/samples/compose-resources-gallery/iosApp/iosApp/Info.plist @@ -44,5 +44,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + CADisableMinimumFrameDurationOnPhone + diff --git a/samples/compose-resources-gallery/local-check.sh b/samples/compose-resources-gallery/local-check.sh index 7c3a3412f..033b40ec4 100755 --- a/samples/compose-resources-gallery/local-check.sh +++ b/samples/compose-resources-gallery/local-check.sh @@ -8,7 +8,7 @@ log() { echo "\033[0;32m> $1\033[0m" } -./gradlew clean assembleDebug +./gradlew clean assembleDebug verifyPaparazziDebug log "compose-resources-gallery android success" ./gradlew clean jvmJar @@ -39,4 +39,3 @@ else ) log "compose-resources-gallery ios xcode success" fi - diff --git a/samples/compose-resources-gallery/macosApp/src/commonMain/kotlin/Main.macos.kt b/samples/compose-resources-gallery/macosApp/src/commonMain/kotlin/Main.macos.kt index 2a1c746aa..68236dc95 100644 --- a/samples/compose-resources-gallery/macosApp/src/commonMain/kotlin/Main.macos.kt +++ b/samples/compose-resources-gallery/macosApp/src/commonMain/kotlin/Main.macos.kt @@ -1,5 +1,6 @@ import androidx.compose.ui.window.Window import com.icerockdev.library.MR +import com.icerockdev.library.hello_world import dev.icerock.moko.resources.desc.desc import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.staticCFunction diff --git a/samples/compose-resources-gallery/shared/build.gradle.kts b/samples/compose-resources-gallery/shared/build.gradle.kts index 80275c6bd..0bea65ac7 100644 --- a/samples/compose-resources-gallery/shared/build.gradle.kts +++ b/samples/compose-resources-gallery/shared/build.gradle.kts @@ -7,6 +7,7 @@ plugins { kotlin("multiplatform") kotlin("native.cocoapods") id("com.android.library") + id("app.cash.paparazzi") id("org.jetbrains.compose") id("org.jetbrains.kotlin.plugin.compose") id("dev.icerock.mobile.multiplatform-resources") diff --git a/samples/compose-resources-gallery/shared/src/androidUnitTest/kotlin/com/myapplication/common/MokoResourcesPaparazziTest.kt b/samples/compose-resources-gallery/shared/src/androidUnitTest/kotlin/com/myapplication/common/MokoResourcesPaparazziTest.kt new file mode 100644 index 000000000..3a293fdb0 --- /dev/null +++ b/samples/compose-resources-gallery/shared/src/androidUnitTest/kotlin/com/myapplication/common/MokoResourcesPaparazziTest.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package com.myapplication.common + +import androidx.compose.material.Text +import app.cash.paparazzi.Paparazzi +import com.icerockdev.library.MR +import com.icerockdev.library.hello_world +import dev.icerock.moko.resources.compose.stringResource +import org.junit.Rule +import org.junit.Test + +class MokoResourcesPaparazziTest { + @get:Rule + val paparazzi = Paparazzi() + + @Test + fun rendersGeneratedStringResource() { + paparazzi.snapshot { + Text(text = stringResource(MR.strings.hello_world)) + } + } +} diff --git a/samples/compose-resources-gallery/shared/src/commonMain/kotlin/App.kt b/samples/compose-resources-gallery/shared/src/commonMain/kotlin/App.kt index beeeac34d..5e78644be 100644 --- a/samples/compose-resources-gallery/shared/src/commonMain/kotlin/App.kt +++ b/samples/compose-resources-gallery/shared/src/commonMain/kotlin/App.kt @@ -1,6 +1,7 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -21,8 +22,24 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.icerockdev.library.MR +import com.icerockdev.library.car_black +import com.icerockdev.library.chars_count +import com.icerockdev.library.cormorant_italic +import com.icerockdev.library.cr +import com.icerockdev.library.font_style_text +import com.icerockdev.library.hello_world +import com.icerockdev.library.innerFile_txt +import com.icerockdev.library.innerText_txt +import com.icerockdev.library.moko_logo +import com.icerockdev.library.new_line_test +import com.icerockdev.library.opacity_test_image +import com.icerockdev.library.second_inner_text_file_txt +import com.icerockdev.library.some_asset_txt +import com.icerockdev.library.symbols_text +import com.icerockdev.library.textColor import dev.icerock.moko.resources.compose.colorResource import dev.icerock.moko.resources.compose.fontFamilyResource import dev.icerock.moko.resources.compose.painterResource @@ -85,6 +102,15 @@ internal fun App() { Text(text = stringResource(MR.strings.hello_world)) } + Box( + modifier = Modifier.background(Color.Red) + ){ + Image( + painter = painterResource(MR.images.opacity_test_image), + contentDescription = null + ) + } + Text( modifier = Modifier.padding(vertical = 8.dp), text = stringResource(MR.strings.new_line_test), @@ -103,7 +129,7 @@ internal fun App() { color = MaterialTheme.colors.onBackground, ) - val fileContent: String? by MR.files.some_file_txt.readTextAsState() + val fileContent: String? by MR.files.innerDirWithSingleFile.innerFile_txt.readTextAsState() Text( modifier = Modifier.padding(top = 16.dp), text = fileContent.orEmpty(), diff --git a/samples/compose-resources-gallery/shared/src/commonMain/moko-resources/images/opacity_test_image.svg b/samples/compose-resources-gallery/shared/src/commonMain/moko-resources/images/opacity_test_image.svg new file mode 100644 index 000000000..4526861c2 --- /dev/null +++ b/samples/compose-resources-gallery/shared/src/commonMain/moko-resources/images/opacity_test_image.svg @@ -0,0 +1,20 @@ + + + + + + + diff --git a/samples/compose-resources-gallery/shared/src/test/snapshots/images/com.myapplication.common_MokoResourcesPaparazziTest_rendersGeneratedStringResource.png b/samples/compose-resources-gallery/shared/src/test/snapshots/images/com.myapplication.common_MokoResourcesPaparazziTest_rendersGeneratedStringResource.png new file mode 100644 index 000000000..c1c3b600a Binary files /dev/null and b/samples/compose-resources-gallery/shared/src/test/snapshots/images/com.myapplication.common_MokoResourcesPaparazziTest_rendersGeneratedStringResource.png differ diff --git a/samples/gradle-agp-9-sample/shared/src/commonMain/kotlin/com/gradle9sample/Greeting.kt b/samples/gradle-agp-9-sample/shared/src/commonMain/kotlin/com/gradle9sample/Greeting.kt index 7a51c2844..072bc3af5 100644 --- a/samples/gradle-agp-9-sample/shared/src/commonMain/kotlin/com/gradle9sample/Greeting.kt +++ b/samples/gradle-agp-9-sample/shared/src/commonMain/kotlin/com/gradle9sample/Greeting.kt @@ -1,6 +1,7 @@ package com.gradle9sample import app.gradle9sample.library.MR +import app.gradle9sample.library.hello_world import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.desc diff --git a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt index 371c2b701..d6cf32387 100644 --- a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt +++ b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt @@ -5,6 +5,8 @@ package com.icerock.library import app.gradle9sample.library.MR +import app.gradle9sample.library.test_plural +import app.gradle9sample.library.test_plural_fallback import dev.icerock.moko.resources.desc.desc import kotlin.test.Ignore import kotlin.test.Test diff --git a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt index 861a51ff0..9aff5543a 100644 --- a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt +++ b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt @@ -5,6 +5,8 @@ package com.icerock.library import app.gradle9sample.library.MR +import app.gradle9sample.library.test_plural +import app.gradle9sample.library.test_plural_fallback import dev.icerock.moko.resources.desc.desc import kotlin.test.Ignore import kotlin.test.Test diff --git a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt index 9c430d651..3362acf12 100644 --- a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt +++ b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt @@ -5,6 +5,7 @@ package com.icerock.library import app.gradle9sample.library.MR +import app.gradle9sample.library.test import dev.icerock.moko.resources.desc.desc import kotlin.test.Test diff --git a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt index 960113674..2b0a862e1 100644 --- a/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt +++ b/samples/gradle-agp-9-sample/shared/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt @@ -5,6 +5,7 @@ package com.icerock.library import app.gradle9sample.library.MR +import app.gradle9sample.library.test import dev.icerock.moko.resources.desc.desc import kotlin.test.Test diff --git a/samples/ios-cocoapods-static-framework/shared/build.gradle.kts b/samples/ios-cocoapods-static-framework/shared/build.gradle.kts index c21165d45..a78b2a223 100644 --- a/samples/ios-cocoapods-static-framework/shared/build.gradle.kts +++ b/samples/ios-cocoapods-static-framework/shared/build.gradle.kts @@ -23,7 +23,7 @@ kotlin { isStatic = true export(moko.resources) - export("dev.icerock.moko:graphics:0.10.0") + export(moko.graphics) } } @@ -39,6 +39,7 @@ kotlin { implementation(compose.material) @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) implementation(compose.components.resources) + api(moko.graphics) api(moko.resources) api(moko.resourcesCompose) } diff --git a/samples/ios-cocoapods-static-framework/shared/src/commonMain/kotlin/App.kt b/samples/ios-cocoapods-static-framework/shared/src/commonMain/kotlin/App.kt index c32803090..1dafa2177 100644 --- a/samples/ios-cocoapods-static-framework/shared/src/commonMain/kotlin/App.kt +++ b/samples/ios-cocoapods-static-framework/shared/src/commonMain/kotlin/App.kt @@ -13,6 +13,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.share.resources.module.MR +import com.share.resources.module.action_back_white +import com.share.resources.module.hello_world import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource diff --git a/samples/kotlin-2-dynamic-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt b/samples/kotlin-2-dynamic-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt index e2428e433..0b79e8f93 100644 --- a/samples/kotlin-2-dynamic-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt +++ b/samples/kotlin-2-dynamic-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt @@ -1,6 +1,7 @@ package app.kotlin2sample import app.kotlin2sample.library.MR +import app.kotlin2sample.library.hello_world import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.desc diff --git a/samples/kotlin-2-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt b/samples/kotlin-2-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt index e2428e433..0b79e8f93 100644 --- a/samples/kotlin-2-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt +++ b/samples/kotlin-2-sample/shared/src/commonMain/kotlin/app/kotlin2sample/Greeting.kt @@ -1,6 +1,7 @@ package app.kotlin2sample import app.kotlin2sample.library.MR +import app.kotlin2sample.library.hello_world import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.desc diff --git a/samples/kotlin-2-tests/shared/src/commonTest/kotlin/testutils/GeneratedResourcesTest.kt b/samples/kotlin-2-tests/shared/src/commonTest/kotlin/testutils/GeneratedResourcesTest.kt index 3c4389dd8..fd7a8116c 100644 --- a/samples/kotlin-2-tests/shared/src/commonTest/kotlin/testutils/GeneratedResourcesTest.kt +++ b/samples/kotlin-2-tests/shared/src/commonTest/kotlin/testutils/GeneratedResourcesTest.kt @@ -7,6 +7,7 @@ package testutils import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest import template.composemultiplatform.shared.SharedRes +import template.composemultiplatform.shared.appName import kotlin.test.Test class GeneratedResourcesTest : MultiPlatformTest() { diff --git a/samples/kotlin-ios-app/mpp-library/build.gradle.kts b/samples/kotlin-ios-app/mpp-library/build.gradle.kts index 8e3bb9642..1d59efe83 100644 --- a/samples/kotlin-ios-app/mpp-library/build.gradle.kts +++ b/samples/kotlin-ios-app/mpp-library/build.gradle.kts @@ -16,9 +16,10 @@ kotlin { val watchosX64 = watchosX64() val watchosArm64 = watchosArm64() + val watchosDeviceArm64 = watchosDeviceArm64() val watchosSimulatorArm64 = watchosSimulatorArm64() - configure(listOf(watchosX64, watchosArm64, watchosSimulatorArm64)) { + configure(listOf(watchosX64, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64)) { binaries { framework { baseName = "MppLibrary" diff --git a/samples/kotlin-ios-app/mpp-library/src/appleMain/kotlin/com/icerockdev/library/Testing.kt b/samples/kotlin-ios-app/mpp-library/src/appleMain/kotlin/com/icerockdev/library/Testing.kt index 571cecc22..40c567f7f 100644 --- a/samples/kotlin-ios-app/mpp-library/src/appleMain/kotlin/com/icerockdev/library/Testing.kt +++ b/samples/kotlin-ios-app/mpp-library/src/appleMain/kotlin/com/icerockdev/library/Testing.kt @@ -4,23 +4,10 @@ package com.icerockdev.library -import dev.icerock.moko.resources.AssetResource -import dev.icerock.moko.resources.ColorResource -import dev.icerock.moko.resources.FileResource -import dev.icerock.moko.resources.FontResource -import dev.icerock.moko.resources.ImageResource -import dev.icerock.moko.resources.desc.Plural -import dev.icerock.moko.resources.desc.PluralFormatted -import dev.icerock.moko.resources.desc.Raw -import dev.icerock.moko.resources.desc.Resource -import dev.icerock.moko.resources.desc.ResourceFormatted import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.desc -import dev.icerock.moko.resources.desc.joinToStringDesc -import dev.icerock.moko.resources.desc.plus -import dev.icerock.moko.resources.format -import dev.icerock.moko.resources.getAssetByFilePath -import dev.icerock.moko.resources.getImageByFileName +import com.icerockdev.library.MR +import com.icerockdev.library.hello_world object Testing { diff --git a/samples/resources-gallery/jvm-app/src/jvmMain/kotlin/com/icerockdev/desktop/Main.kt b/samples/resources-gallery/jvm-app/src/jvmMain/kotlin/com/icerockdev/desktop/Main.kt index 808164746..ed6bca83b 100644 --- a/samples/resources-gallery/jvm-app/src/jvmMain/kotlin/com/icerockdev/desktop/Main.kt +++ b/samples/resources-gallery/jvm-app/src/jvmMain/kotlin/com/icerockdev/desktop/Main.kt @@ -21,8 +21,11 @@ import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.singleWindowApplication +import com.icerockdev.app.AppMR +import com.icerockdev.app.customHelloWorld import com.icerockdev.library.MR import com.icerockdev.library.Testing +import com.icerockdev.library.textColor fun main() { val testing = Testing @@ -43,7 +46,7 @@ fun main() { modifier = Modifier.size(56.dp) ) - Text(text = com.icerockdev.app.AppMR.strings.customHelloWorld.localized()) + Text(text = AppMR.strings.customHelloWorld.localized()) val image by produceState (null){ try { diff --git a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/AssetsTests.kt b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/AssetsTests.kt index 28fb1178f..f368a9620 100644 --- a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/AssetsTests.kt +++ b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/AssetsTests.kt @@ -6,6 +6,7 @@ package com.icerock.library import BaseUnitTest import com.icerockdev.library.MR +import com.icerockdev.library.test2_txt import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import readTextContent diff --git a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt index 934d5436b..971b63eef 100644 --- a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt +++ b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceEnTests.kt @@ -6,6 +6,8 @@ package com.icerock.library import com.icerockdev.library.MR import com.icerockdev.library.Testing +import com.icerockdev.library.test_plural +import com.icerockdev.library.test_plural_fallback import dev.icerock.moko.resources.desc.desc import kotlin.test.Ignore import kotlin.test.Test diff --git a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt index 27c8d15b1..836813075 100644 --- a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt +++ b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/PluralResourceRuTests.kt @@ -6,6 +6,8 @@ package com.icerock.library import com.icerockdev.library.MR import com.icerockdev.library.Testing +import com.icerockdev.library.test_plural +import com.icerockdev.library.test_plural_fallback import dev.icerock.moko.resources.desc.desc import kotlin.test.Ignore import kotlin.test.Test diff --git a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt index b6149821e..4d3280e98 100644 --- a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt +++ b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceEnTests.kt @@ -5,6 +5,9 @@ package com.icerock.library import com.icerockdev.library.MR +import com.icerockdev.library.format +import com.icerockdev.library.common_name +import com.icerockdev.library.hello_formatted_string import dev.icerock.moko.resources.desc.desc import dev.icerock.moko.resources.format import kotlin.test.Test diff --git a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt index fbda1d678..f7eb668a2 100644 --- a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt +++ b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceRuTests.kt @@ -5,6 +5,9 @@ package com.icerock.library import com.icerockdev.library.MR +import com.icerockdev.library.format +import com.icerockdev.library.common_name +import com.icerockdev.library.hello_formatted_string import dev.icerock.moko.resources.desc.desc import dev.icerock.moko.resources.format import kotlin.test.Test diff --git a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceTests.kt b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceTests.kt index e7bc8055a..b47fe875d 100644 --- a/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceTests.kt +++ b/samples/resources-gallery/mpp-library/src/commonTest/kotlin/com/icerock/library/StringResourceTests.kt @@ -7,6 +7,9 @@ package com.icerock.library import BaseUnitTest import com.icerockdev.library.MR import com.icerockdev.library.Testing +import com.icerockdev.library.format +import com.icerockdev.library.test_dialect +import com.icerockdev.library.test_simple import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.desc import dev.icerock.moko.resources.format diff --git a/samples/resources-gallery/web-app/src/jsMain/kotlin/com/icerockdev/web/Main.kt b/samples/resources-gallery/web-app/src/jsMain/kotlin/com/icerockdev/web/Main.kt index dae268c33..591521cfc 100644 --- a/samples/resources-gallery/web-app/src/jsMain/kotlin/com/icerockdev/web/Main.kt +++ b/samples/resources-gallery/web-app/src/jsMain/kotlin/com/icerockdev/web/Main.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import com.icerockdev.library.MR import com.icerockdev.library.Testing +import com.icerockdev.library.some_json import kotlinx.browser.window import org.jetbrains.compose.web.css.DisplayStyle import org.jetbrains.compose.web.css.FlexDirection