diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/BaseGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/BaseGenerator.kt index a0531c24..8cf4e746 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/BaseGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/BaseGenerator.kt @@ -11,7 +11,7 @@ import com.squareup.kotlinpoet.PropertySpec.Builder import com.squareup.kotlinpoet.TypeSpec import dev.icerock.gradle.metadata.GeneratedObject import dev.icerock.gradle.metadata.GeneratedObjectModifier -import dev.icerock.gradle.metadata.GeneratedProperties +import dev.icerock.gradle.metadata.GeneratedProperty import dev.icerock.gradle.metadata.addActual import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject @@ -39,7 +39,7 @@ abstract class BaseGenerator : MRGenerator.Generator { // If target object is actual object: skip read files again // // Structure: language - key - value - val languageMap: Map> = if (targetObject.isActualObject) { + val languageMap: Map> = if (targetObject.isActualObject || targetObject.isTargetObject) { emptyMap() } else { loadLanguageMap() @@ -55,7 +55,6 @@ abstract class BaseGenerator : MRGenerator.Generator { beforeGenerateResources(objectBuilder, languagesAllMaps) val stringsClass = createTypeSpec( - project, inputMetadata = inputMetadata, generatedObjects = generatedObjects, targetObject = targetObject, @@ -76,7 +75,6 @@ abstract class BaseGenerator : MRGenerator.Generator { } private fun createTypeSpec( - project: Project, inputMetadata: MutableList, generatedObjects: MutableList, targetObject: GeneratedObject, @@ -85,20 +83,20 @@ abstract class BaseGenerator : MRGenerator.Generator { objectBuilder: TypeSpec.Builder, ): TypeSpec? { if (targetObject.isActual) { - objectBuilder.addModifiers(*getClassModifiers()) + objectBuilder.addModifiers(KModifier.ACTUAL) } if (targetObject.isActualObject || targetObject.isTargetObject) { extendObjectBodyAtStart(objectBuilder) } - val generatedProperties = mutableListOf() + val generatedProperties = mutableListOf() keys.forEach { key -> val name = key.replace(".", "_") //Create metadata property - var generatedProperty = GeneratedProperties( + var generatedProperty = GeneratedProperty( modifier = GeneratedObjectModifier.None, name = name, data = JsonObject( @@ -111,7 +109,7 @@ abstract class BaseGenerator : MRGenerator.Generator { val property: Builder = PropertySpec.builder(name, resourceClassName) - if (targetObject.isObject) { + if (targetObject.isActualObject || targetObject.isTargetObject) { // Add modifier for property and setup metadata generatedProperty = generatedProperty.copy( modifier = addActualOverrideModifier( diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ColorsGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ColorsGenerator.kt index eeabbaed..cb6f13a6 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ColorsGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ColorsGenerator.kt @@ -16,7 +16,7 @@ import dev.icerock.gradle.generator.js.JsColorsGenerator import dev.icerock.gradle.generator.jvm.JvmColorsGenerator import dev.icerock.gradle.metadata.GeneratedObject import dev.icerock.gradle.metadata.GeneratedObjectModifier -import dev.icerock.gradle.metadata.GeneratedProperties +import dev.icerock.gradle.metadata.GeneratedProperty import dev.icerock.gradle.metadata.GeneratorType import dev.icerock.gradle.metadata.addActual import dev.icerock.gradle.metadata.objectsWithProperties @@ -44,7 +44,7 @@ abstract class ColorsGenerator( override val type: GeneratorType = GeneratorType.Colors - open fun beforeGenerate(objectBuilder: TypeSpec.Builder, keys: List) {} + open fun beforeGenerate(objectBuilder: TypeSpec.Builder, keys: List) = Unit @Suppress("SpreadOperator") override fun generate( @@ -74,7 +74,7 @@ abstract class ColorsGenerator( // Read target colors val targetColors: List = parseColors() val allColors: List = (previousColors + targetColors).distinct() - val generatedProperties: MutableList = mutableListOf() + val generatedProperties: MutableList = mutableListOf() beforeGenerate(objectBuilder, allColors.map { it.name }) @@ -84,13 +84,13 @@ abstract class ColorsGenerator( val property = PropertySpec.builder(colorNode.name, resourceClassName) // Create metadata property - var generatedProperty = GeneratedProperties( + var generatedProperty = GeneratedProperty( modifier = GeneratedObjectModifier.None, name = colorNode.name, data = json.encodeToJsonElement(colorNode) ) - if (targetObject.isObject) { + if (targetObject.isActualObject || targetObject.isTargetObject) { // Setup property modifier and correction metadata info generatedProperty = generatedProperty.copy( modifier = addActualOverrideModifier( diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ImagesGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ImagesGenerator.kt index 2419f826..dfef4437 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ImagesGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/ImagesGenerator.kt @@ -15,15 +15,24 @@ import dev.icerock.gradle.generator.common.CommonImagesGenerator import dev.icerock.gradle.generator.js.JsImagesGenerator import dev.icerock.gradle.generator.jvm.JvmImagesGenerator import dev.icerock.gradle.metadata.GeneratedObject +import dev.icerock.gradle.metadata.GeneratedObjectModifier +import dev.icerock.gradle.metadata.GeneratedProperty import dev.icerock.gradle.metadata.GeneratorType +import dev.icerock.gradle.metadata.addActual +import dev.icerock.gradle.metadata.objectsWithProperties import dev.icerock.gradle.utils.withoutScale +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.decodeFromJsonElement import org.gradle.api.Project import org.gradle.api.file.FileTree import org.gradle.api.logging.Logger import java.io.File abstract class ImagesGenerator( - private val resourcesFileTree: FileTree + private val resourcesFileTree: FileTree, ) : MRGenerator.Generator { override val inputFiles: Iterable @@ -45,22 +54,36 @@ abstract class ImagesGenerator( resourcesGenerationDir: File, objectBuilder: TypeSpec.Builder, ): TypeSpec? { - val fileMap: Map> = inputFiles.groupBy { file -> - // SVGs do not have scale suffixes, so we need to remove the extension first - val key = file - .nameWithoutExtension - .withoutScale + val previousFilesMap: Map> = getPreviousImageFilesMap( + inputMetadata = inputMetadata, + targetObject = targetObject + ) - "$key.${file.extension}" + val imageFileMap: Map> = if ( + targetObject.isActualObject || targetObject.isTargetObject + ) { + emptyMap() + } else { + inputFiles.getImageMap() } - beforeGenerateResources(objectBuilder, fileMap.keys.sorted()) - val typeSpec = createTypeSpec(fileMap.keys.sorted(), objectBuilder) + val allImagesMap: Map> = getAllImagesMap(previousFilesMap, imageFileMap) + + beforeGenerateResources(objectBuilder, allImagesMap.keys.sorted()) + + val typeSpec: TypeSpec? = createTypeSpec( + inputMetadata = inputMetadata, + generatedObjects = generatedObjects, + targetObject = targetObject, + fileNames = allImagesMap.keys.sorted(), + allImagesMap = allImagesMap, + objectBuilder = objectBuilder + ) generateResources( resourcesGenerationDir = resourcesGenerationDir, - keyFileMap = fileMap.mapKeys { (key, _) -> + keyFileMap = allImagesMap.mapKeys { (key, _) -> key.substringBeforeLast(".") // Remove file extension from keys } ) @@ -68,39 +91,154 @@ abstract class ImagesGenerator( return typeSpec } - @Suppress("SpreadOperator") - private fun createTypeSpec(fileNames: List, objectBuilder: TypeSpec.Builder): TypeSpec { - objectBuilder.addModifiers(*getClassModifiers()) + private fun createTypeSpec( + inputMetadata: MutableList, + generatedObjects: MutableList, + targetObject: GeneratedObject, + fileNames: List, + allImagesMap: Map>, + objectBuilder: TypeSpec.Builder, + ): TypeSpec? { + if (targetObject.isActual) { + objectBuilder.addModifiers(KModifier.ACTUAL) + } + + if (targetObject.isActualObject || targetObject.isTargetObject) { + extendObjectBodyAtStart(objectBuilder) + } - extendObjectBodyAtStart(objectBuilder) + val generatedProperties = mutableListOf() - fileNames.forEach { fileName -> + fileNames.forEach { fileName: String -> val updatedFileName = fileName.substringBeforeLast(".") .replace(".", "_") + ".${fileName.substringAfterLast(".")}" val propertyName = updatedFileName.substringBeforeLast(".") val property = PropertySpec.builder(propertyName, resourceClassName) - property.addModifiers(*getPropertyModifiers()) - getPropertyInitializer(updatedFileName)?.let { property.initializer(it) } + var generatedProperty = GeneratedProperty( + modifier = GeneratedObjectModifier.None, + name = propertyName, + data = JsonObject( + content = getPropertyMetadata( + fileName = fileName, + allImagesMap = allImagesMap + ) + ) + ) + + if (targetObject.isActualObject || targetObject.isTargetObject) { + // Add modifier for property and setup metadata + generatedProperty = generatedProperty.copy( + modifier = addActualOverrideModifier( + propertyName = propertyName, + property = property, + inputMetadata = inputMetadata, + targetObject = targetObject + ) + ) + + getPropertyInitializer(updatedFileName)?.let { + property.initializer(it) + } + } + objectBuilder.addProperty(property.build()) + generatedProperties.add(generatedProperty) } extendObjectBodyAtEnd(objectBuilder) - return objectBuilder.build() + return if (generatedProperties.isNotEmpty()) { + // Add object in metadata with remove expect realisation + generatedObjects.addActual( + targetObject.copy(properties = generatedProperties) + ) + + objectBuilder.build() + } else { + null + } + } + + private fun getPropertyMetadata( + fileName: String, + allImagesMap: Map>, + ): Map { + //Structure: FileName, Path + val resultMap = mutableMapOf() + + allImagesMap[fileName]?.forEach { + resultMap[it.name] = JsonPrimitive(it.path) + } + + return resultMap + } + + private fun getPreviousImageFilesMap( + inputMetadata: List, + targetObject: GeneratedObject, + ): Map> { + if (!targetObject.isObject || !targetObject.isActual) return emptyMap() + + val json = Json + val objectsWithProperties: List = inputMetadata.objectsWithProperties( + targetObject = targetObject + ) + + val fileImage = mutableListOf() + + objectsWithProperties.forEach { generatedObject -> + generatedObject.properties.forEach { property -> + val data = json.decodeFromJsonElement>(property.data) + + data.forEach { + fileImage.add(File(it.value.content)) + } + } + } + + return fileImage.getImageMap() + } + + private fun Iterable.getImageMap(): Map> { + return this.groupBy { file -> + // SVGs do not have scale suffixes, so we need to remove the extension first + val key = file + .nameWithoutExtension + .withoutScale + + "$key.${file.extension}" + } + } + + private fun getAllImagesMap( + previousFilesMap: Map>, + imageFileMap: Map>, + ): Map> { + val resultMap = mutableMapOf>() + + previousFilesMap.forEach { map -> + resultMap[map.key] = map.value + } + + imageFileMap.forEach { map -> + resultMap[map.key] = map.value + } + + return resultMap } override fun getImports(): List = emptyList() protected open fun beforeGenerateResources( objectBuilder: TypeSpec.Builder, - keys: List + keys: List, ) { } protected open fun generateResources( resourcesGenerationDir: File, - keyFileMap: Map> + keyFileMap: Map>, ) { } @@ -112,7 +250,7 @@ abstract class ImagesGenerator( class Feature( private val settings: MRGenerator.Settings, - private val logger: Logger + private val logger: Logger, ) : ResourceGeneratorFeature { override fun createCommonGenerator(): ImagesGenerator = CommonImagesGenerator( ownInputFileTree = settings.ownResourcesFileTree, diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/StringsGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/StringsGenerator.kt index 4f3e5deb..874697d4 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/StringsGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/StringsGenerator.kt @@ -63,6 +63,7 @@ abstract class StringsGenerator( targetObject: GeneratedObject, ): Map> { if (!targetObject.isObject || !targetObject.isActual) return emptyMap() + val json = Json val objectsWithProperties: List = inputMetadata.objectsWithProperties(targetObject) diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/common/CommonMRGenerator.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/common/CommonMRGenerator.kt index cbeff8c1..9f8f772a 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/common/CommonMRGenerator.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/generator/common/CommonMRGenerator.kt @@ -191,7 +191,7 @@ class CommonMRGenerator( processMRClass(mrClassSpec) //Create file only if generated expect objects has expect MR object - if (generatedExpectObjects.isNotEmpty()){ + if (generatedExpectObjects.isNotEmpty()) { val mrClass: TypeSpec = mrClassSpec.build() fileSpec.addType(mrClass) @@ -220,16 +220,19 @@ class CommonMRGenerator( val generatorType: GeneratorType = if (it.path.matches(StringsGenerator.STRINGS_REGEX)) { GeneratorType.Strings - } else if (it.path.matches(PluralsGenerator.PLURALS_REGEX)) { + } + else if (it.path.matches(PluralsGenerator.PLURALS_REGEX)) { GeneratorType.Plurals - } else if (it.path.matches(ColorsGenerator.COLORS_REGEX)) { - GeneratorType.Colors - } else return@forEach + } + else if (it.path.matches(ColorsGenerator.COLORS_REGEX)) { + GeneratorType.Colors + } + else if (it.parentFile.name == "images") { + GeneratorType.Images + } else return@forEach //TODO: Implement with generator -// else if (it.parentFile.name == "images") { -// GeneratorType.Images -// } else if (it.parentFile.name == "files") { +// else if (it.parentFile.name == "files") { // GeneratorType.Files // } else if (it.parentFile.name == "assets") { // GeneratorType.Assets diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedObject.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedObject.kt index 68733a6f..f36adb48 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedObject.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedObject.kt @@ -9,7 +9,7 @@ data class GeneratedObject( val type: GeneratedObjectType, val name: String, val interfaces: List = emptyList(), - val properties: List = emptyList(), + val properties: List = emptyList(), val objects: List = emptyList() ) { val isExpect: Boolean diff --git a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedProperties.kt b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedProperty.kt similarity index 90% rename from resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedProperties.kt rename to resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedProperty.kt index a2d2ad3b..2968f6f5 100644 --- a/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedProperties.kt +++ b/resources-generator/src/main/kotlin/dev/icerock/gradle/metadata/GeneratedProperty.kt @@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonElement @Serializable -data class GeneratedProperties( +data class GeneratedProperty( val modifier: GeneratedObjectModifier, val name: String, val data: JsonElement // Can contain data with dependencies from generator type 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 4aa20652..251e1d18 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 @@ -7,6 +7,7 @@ package dev.icerock.gradle.tasks import dev.icerock.gradle.MRVisibility import dev.icerock.gradle.configuration.getAndroidRClassPackage import dev.icerock.gradle.generator.ColorsGenerator +import dev.icerock.gradle.generator.ImagesGenerator import dev.icerock.gradle.generator.MRGenerator import dev.icerock.gradle.generator.PluralsGenerator import dev.icerock.gradle.generator.ResourceGeneratorFeature @@ -161,7 +162,7 @@ abstract class GenerateMultiplatformResourcesTask : DefaultTask() { StringsGenerator.Feature(settings), PluralsGenerator.Feature(settings), ColorsGenerator.Feature(settings), -// ImagesGenerator.Feature(settings, logger), + ImagesGenerator.Feature(settings, logger), // FontsGenerator.Feature(settings), // FilesGenerator.Feature(settings), // AssetsGenerator.Feature(settings)