diff --git a/playground/theme-builder/build.gradle.kts b/playground/theme-builder/build.gradle.kts index ee122f5044..9c14c37524 100644 --- a/playground/theme-builder/build.gradle.kts +++ b/playground/theme-builder/build.gradle.kts @@ -15,9 +15,16 @@ android { } themeBuilder { - themeSource { - url("file://${projectDir.path}/json/test_theme.zip") - name("sdds_serv") + themeSources(baseAlias = "SddsServ") { + defaultSourceFromUrl( + name = "sdds_serv", + url = "file://${projectDir.path}/json/latest.zip", + ) + sourceFromUrl( + name = "sdds_serv", + url = "file://${projectDir.path}/json/latest_gold.zip", + tenant = "Gold", + ) } componentSource { url("file://${projectDir.path}/json/test_components.zip") diff --git a/playground/theme-builder/json/latest.zip b/playground/theme-builder/json/latest.zip new file mode 100644 index 0000000000..eb9305837c Binary files /dev/null and b/playground/theme-builder/json/latest.zip differ diff --git a/playground/theme-builder/json/latest_gold.zip b/playground/theme-builder/json/latest_gold.zip new file mode 100644 index 0000000000..890d6014d7 Binary files /dev/null and b/playground/theme-builder/json/latest_gold.zip differ diff --git a/playground/theme-builder/json/test_theme.zip b/playground/theme-builder/json/test_theme.zip deleted file mode 100644 index 429d741865..0000000000 Binary files a/playground/theme-builder/json/test_theme.zip and /dev/null differ diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/GenerateThemeTask.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/GenerateThemeTask.kt index b836a8ca92..430919aa87 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/GenerateThemeTask.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/GenerateThemeTask.kt @@ -3,6 +3,7 @@ package com.sdds.plugin.themebuilder import com.sdds.plugin.themebuilder.internal.PackageResolver import com.sdds.plugin.themebuilder.internal.ThemeBuilderTarget import com.sdds.plugin.themebuilder.internal.dimens.DimensAggregator +import com.sdds.plugin.themebuilder.internal.exceptions.ThemeBuilderException import com.sdds.plugin.themebuilder.internal.factory.FontDownloaderFactory import com.sdds.plugin.themebuilder.internal.factory.GeneratorFactory import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory @@ -11,6 +12,7 @@ import com.sdds.plugin.themebuilder.internal.factory.XmlFontFamilyDocumentBuilde import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.fonts.FontsAggregator import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ColorToken import com.sdds.plugin.themebuilder.internal.token.FontToken import com.sdds.plugin.themebuilder.internal.token.FontTokenValue @@ -29,14 +31,17 @@ import com.sdds.plugin.themebuilder.internal.utils.ResourceReferenceProvider import com.sdds.plugin.themebuilder.internal.utils.decode import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction +import java.io.File /** * Gradle-задача для генерации темы @@ -57,52 +62,58 @@ abstract class GenerateThemeTask : DefaultTask() { abstract val paletteFile: RegularFileProperty /** - * Путь до json-файла с темой + * Список тенантов + */ + @get:Input + abstract val themeTenants: ListProperty + + /** + * Список мета-файлов темы */ @get:InputFile abstract val metaFile: RegularFileProperty /** - * Путь до json-файла с цветами + * Список файлов с токенами цветов */ - @get:InputFile - abstract val colorFile: RegularFileProperty + @get:InputFiles + abstract val colorFiles: ConfigurableFileCollection /** - * Путь до json-файла с типографикой + * Список файлов с токенами типографики */ - @get:InputFile - abstract val typographyFile: RegularFileProperty + @get:InputFiles + abstract val typographyFiles: ConfigurableFileCollection /** - * Путь до json-файла со шрифтами + * Список файлов с токенами шрифтов */ - @get:InputFile - abstract val fontFile: RegularFileProperty + @get:InputFiles + abstract val fontFiles: ConfigurableFileCollection /** - * Путь до json-файла с тенями + * Список файлов с токенами теней */ - @get:InputFile - abstract val shadowFile: RegularFileProperty + @get:InputFiles + abstract val shadowFiles: ConfigurableFileCollection /** - * Путь до json-файла с отступами + * Список файлов с токенами отступов */ - @get:InputFile - abstract val spacingFile: RegularFileProperty + @get:InputFiles + abstract val spacingFiles: ConfigurableFileCollection /** - * Путь до json-файла с градиентами + * Список файлов с токенами градиентов */ - @get:InputFile - abstract val gradientFile: RegularFileProperty + @get:InputFiles + abstract val gradientFiles: ConfigurableFileCollection /** - * Путь до json-файла с формами + * Список файлов с токенами форм */ - @get:InputFile - abstract val shapeFile: RegularFileProperty + @get:InputFiles + abstract val shapeFiles: ConfigurableFileCollection /** * Название пакета для файлов kotlin @@ -218,48 +229,111 @@ abstract class GenerateThemeTask : DefaultTask() { } private val themeGenerator by unsafeLazy { generatorFactory.createThemeGenerator() } - private val colorGenerator by unsafeLazy { - generatorFactory.createColorGenerator(colors, palette) - } - private val gradientGenerator by unsafeLazy { - generatorFactory.createGradientGenerator( - gradients, - palette, - ) - } - private val fontGenerator by unsafeLazy { generatorFactory.createFontGenerator(fonts) } - private val typographyGenerator by unsafeLazy { - generatorFactory.createTypographyGenerator(typography) - } private val dimensGenerator by unsafeLazy { generatorFactory.createDimensGenerator() } - private val shapesGenerator by unsafeLazy { generatorFactory.createShapesGenerator(shapes) } - private val shadowGenerator by unsafeLazy { generatorFactory.createShadowGenerator(shadows, palette) } - private val spacingGenerator by unsafeLazy { generatorFactory.createSpacingGenerator(spacing) } /** * Генерирует файлы с токенами */ @TaskAction + @Suppress("CyclomaticComplexMethod") fun generate() { - collectTokens() - generateAll() - } + checkCollectionSize() + val tenants = themeTenants.get() + val tenantDataMap = tenants.mapIndexed { index, tenant -> + TenantData( + colorFile = colorFiles.files.elementAt(index), + gradientFile = gradientFiles.files.elementAt(index), + fontFile = fontFiles.files.elementAt(index), + typographyFile = typographyFiles.files.elementAt(index), + shapeFile = shapeFiles.files.elementAt(index), + shadowFile = shadowFiles.files.elementAt(index), + spacingFile = spacingFiles.files.elementAt(index), + tenant = tenant, + ) + }.associateBy { Tenant(it.tenant) } + + val metaFileTokens = decodeMeta().tokens + + val defaultTenant = tenantDataMap[Tenant.Default] + ?: throw ThemeBuilderException("Theme must have default tenant") + + val defaultTenantColors = colors(defaultTenant.colorFile) + val defaultTenantGradients = gradients(defaultTenant.gradientFile) + val defaultTenantFonts = fonts(defaultTenant.fontFile) + val defaultTenantTypography = typography(defaultTenant.typographyFile) + val defaultTenantShapes = shapes(defaultTenant.shapeFile) + val defaultTenantShadows = shadows(defaultTenant.shadowFile) + val defaultTenantSpacings = spacing(defaultTenant.spacingFile) + + val allColors = mutableMapOf>() + .apply { this[Tenant.Default] = defaultTenantColors } + val allGradients = mutableMapOf>>() + .apply { this[Tenant.Default] = defaultTenantGradients } + val allFonts = mutableMapOf>() + .apply { this[Tenant.Default] = defaultTenantFonts } + val allTypography = mutableMapOf>() + .apply { this[Tenant.Default] = defaultTenantTypography } + val allShapes = mutableMapOf>() + .apply { this[Tenant.Default] = defaultTenantShapes } + val allShadows = mutableMapOf>>() + .apply { this[Tenant.Default] = defaultTenantShadows } + val allSpacings = mutableMapOf>() + .apply { this[Tenant.Default] = defaultTenantSpacings } + + tenantDataMap + .filter { it.key != Tenant.Default } + .forEach { tenantEntry -> + val tenant = tenantEntry.key + + val tenantColors = colors(tenantEntry.value.colorFile) + val tenantDiffColors = tenantToDefaultDiff(defaultTenantColors, tenantColors) + allColors[tenant] = tenantDiffColors + + val tenantGradients = gradients(tenantEntry.value.gradientFile) + val tenantDiffGradients = tenantToDefaultDiff(defaultTenantGradients, tenantGradients) + allGradients[tenant] = tenantDiffGradients + + val tenantFonts = fonts(tenantEntry.value.fontFile) + val tenantDiffFonts = tenantToDefaultDiff(defaultTenantFonts, tenantFonts) + allFonts[tenant] = tenantDiffFonts + + val tenantTypography = typography(tenantEntry.value.typographyFile) + val tenantDiffTypography = tenantToDefaultDiff(defaultTenantTypography, tenantTypography) + allTypography[tenant] = tenantDiffTypography + + val tenantShapes = shapes(tenantEntry.value.shapeFile) + val tenantDiffShapes = tenantToDefaultDiff(defaultTenantShapes, tenantShapes) + allShapes[tenant] = tenantDiffShapes + + val tenantShadows = shadows(tenantEntry.value.shadowFile) + val tenantDiffShadows = tenantToDefaultDiff(defaultTenantShadows, tenantShadows) + allShadows[tenant] = tenantDiffShadows + + val tenantSpacings = spacing(tenantEntry.value.spacingFile) + val tenantDiffSpacings = tenantToDefaultDiff(defaultTenantSpacings, tenantSpacings) + allSpacings[tenant] = tenantDiffSpacings + } - private fun collectTokens() { - decodeBase().tokens.onEach { - when (it) { - is ColorToken -> colorGenerator.addToken(it) - is GradientToken -> gradientGenerator.addToken(it) - is ShadowToken -> shadowGenerator.addToken(it) - is ShapeToken -> shapesGenerator.addToken(it) - is TypographyToken -> typographyGenerator.addToken(it) - is FontToken -> fontGenerator.addToken(it) - is SpacingToken -> spacingGenerator.addToken(it) + val colorGenerator = generatorFactory.createColorGenerator(allColors, palette) + val gradientGenerator = generatorFactory.createGradientGenerator(allGradients, palette) + val fontGenerator = generatorFactory.createFontGenerator(allFonts) + val typographyGenerator = generatorFactory.createTypographyGenerator(allTypography) + val shapesGenerator = generatorFactory.createShapesGenerator(allShapes) + val shadowGenerator = generatorFactory.createShadowGenerator(allShadows, palette) + val spacingGenerator = generatorFactory.createSpacingGenerator(allSpacings) + + metaFileTokens.onEach { token -> + when (token) { + is ColorToken -> colorGenerator.addToken(token) + is GradientToken -> gradientGenerator.addToken(token) + is ShadowToken -> shadowGenerator.addToken(token) + is ShapeToken -> shapesGenerator.addToken(token) + is TypographyToken -> typographyGenerator.addToken(token) + is FontToken -> fontGenerator.addToken(token) + is SpacingToken -> spacingGenerator.addToken(token) } } - } - private fun generateAll() { colorGenerator.generate().also(themeGenerator::setColorTokenData) gradientGenerator.generate().also(themeGenerator::setGradientTokenData) typographyGenerator.generate().also(themeGenerator::setTypographyTokenData) @@ -272,7 +346,67 @@ abstract class GenerateThemeTask : DefaultTask() { themeGenerator.generate() } - private fun decodeBase(): Theme = + private fun tenantToDefaultDiff( + defaultTokens: Map, + tenantTokens: Map, + ): Map { + return tenantTokens.filter { + defaultTokens[it.key] != it.value + } + } + + @Suppress("ThrowsCount") + private fun checkCollectionSize() { + val tenantSize = themeTenants.get().size + if (colorFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "colorFiles count and themeTenants count must be the same", + ) + } + if (gradientFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "gradientFiles count and themeTenants count must be the same", + ) + } + if (fontFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "fontFiles count and themeTenants count must be the same", + ) + } + if (typographyFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "typographyFiles count and themeTenants count must be the same", + ) + } + if (shapeFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "shapeFiles count and themeTenants count must be the same", + ) + } + if (shadowFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "shadowFiles count and themeTenants count must be the same", + ) + } + if (spacingFiles.files.size != tenantSize) { + throw ThemeBuilderException( + "spacingFiles count and themeTenants count must be the same", + ) + } + } + + private data class TenantData( + val tenant: String, + val colorFile: File, + val gradientFile: File, + val fontFile: File, + val typographyFile: File, + val shapeFile: File, + val shadowFile: File, + val spacingFile: File, + ) + + private fun decodeMeta(): Theme = metaFile.get().asFile.decode(Serializer.meta) .let { theme -> if (ignoreDisabledTokens.get()) { @@ -283,38 +417,38 @@ abstract class GenerateThemeTask : DefaultTask() { } .also { logger.debug("decoded base $it") } - private val colors: Map by unsafeLazy { - colorFile.get().asFile.decode>() + private fun colors(file: File): Map { + return file.decode>() .also { logger.debug("decoded colors $it") } } - private val shapes: Map by unsafeLazy { - shapeFile.get().asFile.decode>() + private fun shapes(file: File): Map { + return file.decode>() .also { logger.debug("decoded shapes $it") } } - private val gradients: Map> by unsafeLazy { - gradientFile.get().asFile.decode>>() + private fun gradients(file: File): Map> { + return file.decode>>() .also { logger.debug("decoded gradients $it") } } - private val shadows: Map> by unsafeLazy { - shadowFile.get().asFile.decode>>() + private fun shadows(file: File): Map> { + return file.decode>>() .also { logger.debug("decoded shadows $it") } } - private val spacing: Map by unsafeLazy { - spacingFile.get().asFile.decode>() + private fun spacing(file: File): Map { + return file.decode>() .also { logger.debug("decoded spacing $it") } } - private val typography: Map by unsafeLazy { - typographyFile.get().asFile.decode>() + private fun typography(file: File): Map { + return file.decode>() .also { logger.debug("decoded typography $it") } } - private val fonts: Map by unsafeLazy { - fontFile.get().asFile.decode>() + private fun fonts(file: File): Map { + return file.decode>() .also { logger.debug("decoded fonts $it") } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderExtension.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderExtension.kt index d80c3221e7..c3b235dc96 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderExtension.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderExtension.kt @@ -16,7 +16,8 @@ open class ThemeBuilderExtension { internal var resourcesPrefix: String? = null internal var viewThemeParents: Set = emptySet() internal var viewShapeAppearanceConfig: Set = emptySet() - internal var themeSource: ThemeBuilderSource? = null + private var themeSource: ThemeBuilderSource? = null + private var themeSources: ThemeBuilderSources? = null internal var componentSource: ThemeBuilderSource? = null internal var componentsSource: String? = null internal var paletteUrl: String = DEFAULT_PALETTE_URL @@ -107,6 +108,30 @@ open class ThemeBuilderExtension { } } + /** + * Конфигурирует источники темы + */ + fun themeSources(baseAlias: String = "", sourceBuilder: ThemeSourcesBuilder.() -> Unit) { + val builder = ThemeSourcesBuilder(baseAlias).apply(sourceBuilder) + if (!builder.defaultSourceWasDefined) { + throw ThemeBuilderException("Default source must be defined when use multitenant mode") + } + this.themeSources = ThemeBuilderSources( + baseAlias = baseAlias, + sources = builder.sources, + ) + } + + internal fun getThemeSources(): ThemeBuilderSources { + val themeSrc = themeSource + val themeSrcs = themeSources + return when { + themeSrc != null -> ThemeBuilderSources(baseAlias = themeSrc.themeName, sources = listOf(themeSrc)) + themeSrcs != null && themeSrcs.sources.isNotEmpty() -> themeSrcs + else -> throw ThemeBuilderException("themeSource(s) must be set") + } + } + /** * Устанавливает View фреймворк для генерации темы и токенов * @@ -219,6 +244,58 @@ open class ThemeBuilderExtension { } } +/** + * Класс, описывающий источники теы + */ +class ThemeSourcesBuilder(private val baseAlias: String) { + internal val sources = mutableListOf() + internal var defaultSourceWasDefined = false + + /** + * Устанавливает базовый источник темы с помощью [name] и [version] темы + */ + fun defaultSource( + name: String, + version: String = ThemeSourceBuilder.VERSION_LATEST, + ) { + source(name, version, "") + defaultSourceWasDefined = true + } + + /** + * Устанавливает базовый источник темы с помощью ссылки [url] + */ + fun defaultSourceFromUrl( + name: String, + url: String, + ) { + sourceFromUrl(name, url, "") + defaultSourceWasDefined = true + } + + /** + * Устанавливает источник тенанта [tenant] темы с помощью [name] и [version]. + */ + fun source( + name: String, + version: String = ThemeSourceBuilder.VERSION_LATEST, + tenant: String, + ) { + sources.add(ThemeBuilderSource.withNameAndVersion(name, version, baseAlias, tenant)) + } + + /** + * Устанавливает источник тенанта [tenant] темы с помощью ссылки [url]. + */ + fun sourceFromUrl( + name: String, + url: String, + tenant: String = "", + ) { + sources.add(ThemeBuilderSource.withUrl(url, name, tenant)) + } +} + /** * Конфигуратор источника темы */ diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderPlugin.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderPlugin.kt index eb99f83947..0d0f2acbd5 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderPlugin.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderPlugin.kt @@ -18,6 +18,7 @@ import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.findByType import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.register +import java.io.File /** * Плагин для генерации тем и токенов ДС @@ -25,7 +26,6 @@ import org.gradle.kotlin.dsl.register */ class ThemeBuilderPlugin : Plugin { override fun apply(project: Project) { - val themeZip = project.layout.buildDirectory.file("$THEME_PATH/theme.zip") val componentsZip = project.layout.buildDirectory.file("$COMPONENTS_PATH/components.zip") val paletteJson = project.layout.buildDirectory.file("$THEME_PATH/$PALETTE_JSON_NAME") val extension = project.themeBuilderExt() @@ -33,11 +33,34 @@ class ThemeBuilderPlugin : Plugin { project.afterEvaluate { project.registerClean(extension) - val unzipThemeTask = registerFetchAndUnzipTheme(extension, themeZip, paletteJson) + val themeSources = extension.getThemeSources() + + val fetchPaletteTask = registerPaletteFetcher( + taskName = "fetchPalette", + paletteUrl = extension.paletteUrl, + paletteOutput = paletteJson, + ) + + val unzipTasks = mutableListOf>() + themeSources.sources.forEach { source -> + val tenantId = source.tenant + val tenantIdForPath = if (tenantId.isEmpty()) "default" else tenantId.lowercase() + val themeZip = project.layout.buildDirectory.file("$THEME_PATH/$tenantIdForPath/theme.zip") + + val unzipThemeTask = registerFetchAndUnzipTheme( + source = source, + themeOutputZip = themeZip, + themeId = tenantId, + fetchPaletteTask = fetchPaletteTask, + ) + unzipTasks.add(unzipThemeTask) + } + registerThemeBuilder( extension = extension, - unzipThemeTask = unzipThemeTask, + unzipThemeTasks = unzipTasks, dependOnPreBuild = extension.autoGenerate, + themeSources = themeSources, ) val fetchComponentsTask = registerFetchAndUnzipComponents(extension, componentsZip) @@ -78,27 +101,23 @@ class ThemeBuilderPlugin : Plugin { } private fun Project.registerFetchAndUnzipTheme( - extension: ThemeBuilderExtension, themeOutputZip: Provider, - paletteOutputJson: Provider, + source: ThemeBuilderSource, + themeId: String, + fetchPaletteTask: TaskProvider, ): TaskProvider { - val source = getThemeSource(extension) + val themeIdPathToken = if (themeId.isEmpty()) "default" else themeId.lowercase() - val fetchPaletteTask = registerPaletteFetcher( - taskName = "fetchPalette", - paletteUrl = extension.paletteUrl, - paletteOutput = paletteOutputJson, - ) val fetchThemeTask = registerFileFetcher( - taskName = "fetchTheme", + taskName = "fetchTheme$themeId", url = getThemeUrl(source), output = themeOutputZip, dependsOnTask = fetchPaletteTask, ) val unzipTask = registerUnzip( - taskName = "unpackThemeFiles", + taskName = "unpackThemeFiles$themeId", zipFile = themeOutputZip, - outputPath = THEME_PATH, + outputPath = "$THEME_PATH$themeIdPathToken", dependsOnTask = fetchThemeTask, ) return unzipTask @@ -129,22 +148,48 @@ class ThemeBuilderPlugin : Plugin { private fun Project.registerThemeBuilder( extension: ThemeBuilderExtension, - unzipThemeTask: Any, + unzipThemeTasks: List, dependOnPreBuild: Boolean, + themeSources: ThemeBuilderSources, ) { + val tenants = mutableListOf() + val colorFiles = mutableListOf() + val gradientFiles = mutableListOf() + val typographyFiles = mutableListOf() + val fontFiles = mutableListOf() + val shapeFiles = mutableListOf() + val shadowFiles = mutableListOf() + val spacingFiles = mutableListOf() + + themeSources.sources.forEach { + val themeId = it.tenant.also(tenants::add) + val themeIdPathToken = if (themeId.isEmpty()) "default" else themeId.lowercase() + colorFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.COLORS))) + gradientFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.GRADIENTS))) + typographyFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.TYPOGRAPHY))) + fontFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.FONTS))) + shapeFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.SHAPES))) + shadowFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.SHADOWS))) + spacingFiles.add(file(getValueFile(themeIdPathToken, TokenValueFile.SPACING))) + } + + logger.warn("themeSources=$themeSources") + val generateThemeTask = registerThemeGenerator( extension = extension, paletteFileProvider = getPaletteFile(), - baseFileProvider = getMetaFile(), - colorFileProvider = getValueFile(TokenValueFile.COLORS), - typographyFileProvider = getValueFile(TokenValueFile.TYPOGRAPHY), - fontFileProvider = getValueFile(TokenValueFile.FONTS), - shadowFileProvider = getValueFile(TokenValueFile.SHADOWS), - spacingFileProvider = getValueFile(TokenValueFile.SPACING), - gradientFileProvider = getValueFile(TokenValueFile.GRADIENTS), - shapeFileProvider = getValueFile(TokenValueFile.SHAPES), - unzipTask = unzipThemeTask, + metaFileProvider = getMetaFile(), + tenants = tenants, + colorFiles = colorFiles, + typographyFiles = typographyFiles, + fontFiles = fontFiles, + shadowFiles = shadowFiles, + spacingFiles = spacingFiles, + gradientFiles = gradientFiles, + shapeFiles = shapeFiles, + unzipTasks = unzipThemeTasks, + themeName = themeSources.baseAlias, ) if (dependOnPreBuild) { tasks.named("preBuild").dependsOn(generateThemeTask) @@ -163,9 +208,6 @@ class ThemeBuilderPlugin : Plugin { } } - private fun getThemeSource(extension: ThemeBuilderExtension): ThemeBuilderSource = - extension.themeSource ?: throw GradleException("themeSource must be set") - private fun getThemeUrl(source: ThemeBuilderSource): String { return getSourceUrl(source, BASE_THEME_URL) } @@ -200,11 +242,11 @@ class ThemeBuilderPlugin : Plugin { } private fun Project.getMetaFile(): Provider { - return layout.buildDirectory.file("$THEME_PATH/$META_JSON_NAME") + return layout.buildDirectory.file("${THEME_PATH}default/$META_JSON_NAME") } - private fun Project.getValueFile(fileType: TokenValueFile): Provider { - return layout.buildDirectory.file("$THEME_PATH/android/${fileType.fileName}") + private fun Project.getValueFile(themeIdPathToken: String, fileType: TokenValueFile): String { + return "build/$THEME_PATH$themeIdPathToken/android/${fileType.fileName}" } private fun Project.getComponentConfigFile(fileName: String): Provider { @@ -257,31 +299,35 @@ class ThemeBuilderPlugin : Plugin { } } + @Suppress("SpreadOperator") private fun Project.registerThemeGenerator( extension: ThemeBuilderExtension, paletteFileProvider: Provider, - baseFileProvider: Provider, - colorFileProvider: Provider, - typographyFileProvider: Provider, - fontFileProvider: Provider, - shadowFileProvider: Provider, - spacingFileProvider: Provider, - gradientFileProvider: Provider, - shapeFileProvider: Provider, - unzipTask: Any, + metaFileProvider: Provider, + unzipTasks: List, + tenants: List, + colorFiles: List, + typographyFiles: List, + fontFiles: List, + shadowFiles: List, + spacingFiles: List, + gradientFiles: List, + shapeFiles: List, + themeName: String, ): TaskProvider { return project.tasks.register("generateTheme") { group = TASK_GROUP paletteFile.set(paletteFileProvider) - themeName.set(getThemeSource(extension).themeName) - metaFile.set(baseFileProvider) - colorFile.set(colorFileProvider) - typographyFile.set(typographyFileProvider) - fontFile.set(fontFileProvider) - shadowFile.set(shadowFileProvider) - spacingFile.set(spacingFileProvider) - gradientFile.set(gradientFileProvider) - shapeFile.set(shapeFileProvider) + metaFile.set(metaFileProvider) + this.themeTenants.set(tenants) + this.themeName.set(themeName) + this.colorFiles.setFrom(colorFiles) + this.typographyFiles.setFrom(typographyFiles) + this.fontFiles.setFrom(fontFiles) + this.shadowFiles.setFrom(shadowFiles) + this.spacingFiles.setFrom(spacingFiles) + this.gradientFiles.setFrom(gradientFiles) + this.shapeFiles.setFrom(shapeFiles) packageName.set(extension.ktPackage ?: DEFAULT_KT_PACKAGE) target.set(extension.target) @@ -298,7 +344,7 @@ class ThemeBuilderPlugin : Plugin { dimensionsConfig.set(extension.dimensionsConfig) defaultThemeTypography.set(extension.defaultThemeTypography) ignoreDisabledTokens.set(extension.ignoreDisabledTokens) - dependsOn(unzipTask) + dependsOn(*unzipTasks.toTypedArray()) } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderSource.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderSource.kt index 638c09261b..bc749d64ab 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderSource.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/ThemeBuilderSource.kt @@ -1,9 +1,14 @@ package com.sdds.plugin.themebuilder +internal data class ThemeBuilderSources( + val baseAlias: String = "", + val sources: List, +) + /** * Способ получения темы. */ -internal sealed class ThemeBuilderSource(val themeName: String) { +internal sealed class ThemeBuilderSource(val themeName: String, val tenant: String) { /** * Предпочтительный способ получения темы с помощью названия [remoteName] и версии [version] темы. @@ -12,12 +17,17 @@ internal sealed class ThemeBuilderSource(val themeName: String) { val remoteName: String, val version: String, val alias: String = remoteName, - ) : ThemeBuilderSource(alias) + val suffix: String, + ) : ThemeBuilderSource(alias, suffix) /** * Способ получения темы с помощью ссылки [url]. */ - data class Url(val url: String, val name: String) : ThemeBuilderSource(name) + data class Url( + val url: String, + val name: String, + val suffix: String, + ) : ThemeBuilderSource(name, suffix) companion object { @@ -26,12 +36,21 @@ internal sealed class ThemeBuilderSource(val themeName: String) { /** * Позволяет указать источник получения темы с помощью [name] и [version] */ - fun withNameAndVersion(name: String, version: String, alias: String = name): ThemeBuilderSource = - NameAndVersion(name, version, alias) + fun withNameAndVersion( + name: String, + version: String, + alias: String = name, + suffix: String = "", + ): ThemeBuilderSource = + NameAndVersion(name, version, alias, suffix) /** * Позволяет указать источник получения темы с помощью [url] */ - fun withUrl(url: String, name: String = DEFAULT_THEME_NAME): ThemeBuilderSource = Url(url, name) + fun withUrl( + url: String, + name: String = DEFAULT_THEME_NAME, + suffix: String = "", + ): ThemeBuilderSource = Url(url, name, suffix) } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/builder/KtFileBuilder.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/builder/KtFileBuilder.kt index 80c5ea676c..818646bb3d 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/builder/KtFileBuilder.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/builder/KtFileBuilder.kt @@ -132,6 +132,38 @@ internal class KtFileBuilder( } .also(rootTypeBuilders::add) + /** + * Создает val свойство в корне файла. + * + * @param name имя свойства + * @param typeName тип свойства + * @param initializer инициализатор свойства + * @param lazy инициализация через lazy делегат + */ + fun appendRootVal( + name: String, + typeName: TypeName, + initializer: String? = null, + modifiers: List? = null, + isMutable: Boolean = false, + setter: Setter? = null, + getter: Getter? = null, + receiver: TypeName? = null, + lazy: Boolean = false, + ) { + appendPropertyInternal( + name = name, + typeName = typeName, + initializer = initializer, + isMutable = isMutable, + modifiers = modifiers?.toKModifiers(), + setter = setter, + getter = getter, + receiver = receiver, + lazy = lazy, + ).also(rootPropBuilders::add) + } + /** * Создает val свойство в корне файла. * diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/factory/GeneratorFactory.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/factory/GeneratorFactory.kt index a83cd4aa05..7f57fde7dc 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/factory/GeneratorFactory.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/factory/GeneratorFactory.kt @@ -20,6 +20,7 @@ import com.sdds.plugin.themebuilder.internal.generator.ShapeTokenGenerator import com.sdds.plugin.themebuilder.internal.generator.SpacingTokenGenerator import com.sdds.plugin.themebuilder.internal.generator.TypographyTokenGenerator import com.sdds.plugin.themebuilder.internal.generator.theme.ThemeGenerator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.FontTokenValue import com.sdds.plugin.themebuilder.internal.token.GradientTokenValue import com.sdds.plugin.themebuilder.internal.token.ShadowTokenValue @@ -273,7 +274,7 @@ internal class GeneratorFactory( * @return [ColorTokenGenerator] генератор токенов цвета */ fun createColorGenerator( - colors: Map, + colors: Map>, palette: Map>, ): ColorTokenGenerator { return ColorTokenGenerator( @@ -292,7 +293,7 @@ internal class GeneratorFactory( * Создает генератор градиентов [GradientTokenGenerator] */ fun createGradientGenerator( - gradients: Map>, + gradients: Map>>, palette: Map>, ): GradientTokenGenerator { return GradientTokenGenerator( @@ -310,7 +311,7 @@ internal class GeneratorFactory( /** * Создает генератор шрифтов [FontTokenGenerator] */ - fun createFontGenerator(fonts: Map): FontTokenGenerator { + fun createFontGenerator(fonts: Map>): FontTokenGenerator { return FontTokenGenerator( OutputLocation.Directory(outputDir), outputResDir, @@ -330,7 +331,7 @@ internal class GeneratorFactory( * Создает генератор типографии [TypographyTokenGenerator] */ fun createTypographyGenerator( - typography: Map, + typography: Map>, ): TypographyTokenGenerator { return TypographyTokenGenerator( outputLocation = OutputLocation.Directory(outputDir), @@ -362,7 +363,7 @@ internal class GeneratorFactory( /** * Создает генератор форм [ShapeTokenGenerator] */ - fun createShapesGenerator(shapes: Map): ShapeTokenGenerator { + fun createShapesGenerator(shapes: Map>): ShapeTokenGenerator { return ShapeTokenGenerator( outputLocation = OutputLocation.Directory(outputDir), outputResDir = outputResDir, @@ -382,7 +383,7 @@ internal class GeneratorFactory( * Создает генератор теней [ShadowTokenGenerator] */ fun createShadowGenerator( - shadows: Map>, + shadows: Map>>, palette: Map>, ): ShadowTokenGenerator { return ShadowTokenGenerator( @@ -403,7 +404,7 @@ internal class GeneratorFactory( /** * Создает генератор форм [SpacingTokenGenerator] */ - fun createSpacingGenerator(spacings: Map): SpacingTokenGenerator { + fun createSpacingGenerator(spacings: Map>): SpacingTokenGenerator { return SpacingTokenGenerator( outputLocation = OutputLocation.Directory(outputDir), outputResDir = outputResDir, diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGenerator.kt index 10062320be..d51ccb07e6 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGenerator.kt @@ -8,6 +8,7 @@ import com.sdds.plugin.themebuilder.internal.exceptions.ThemeBuilderException import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.ColorTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ColorToken import com.sdds.plugin.themebuilder.internal.token.colorAttrName import com.sdds.plugin.themebuilder.internal.token.isDark @@ -37,31 +38,47 @@ internal class ColorTokenGenerator( target: ThemeBuilderTarget, private val xmlBuilderFactory: XmlResourcesDocumentBuilderFactory, private val ktFileBuilderFactory: KtFileBuilderFactory, - private val colorTokenValues: Map, + private val colorTokenValues: Map>, private val resourceReferenceProvider: ResourceReferenceProvider, private val palette: Map>, ) : TokenGenerator(target) { private val xmlDocumentBuilder by unsafeLazy { xmlBuilderFactory.create(DEFAULT_ROOT_ATTRIBUTES) } private val ktFileBuilder by unsafeLazy { ktFileBuilderFactory.create("ColorTokens") } - private val lightBuilder by unsafeLazy { - ktFileBuilder.rootObject(LIGHT_COLOR_TOKENS_NAME, LIGHT_COLOR_TOKENS_DESC) + private val lightBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to ktFileBuilder.rootObject( + LIGHT_COLOR_TOKENS_NAME, + LIGHT_COLOR_TOKENS_DESC, + ), + ) } - private val darkBuilder by unsafeLazy { - ktFileBuilder.rootObject(DARK_COLOR_TOKENS_NAME, DARK_COLOR_TOKENS_DESC) + private val darkBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to ktFileBuilder.rootObject( + DARK_COLOR_TOKENS_NAME, + DARK_COLOR_TOKENS_DESC, + ), + ) } - private val composeLightTokenDataCollector = mutableMapOf() - private val composeDarkTokenDataCollector = mutableMapOf() - private val viewLightTokenDataCollector = mutableMapOf() - private val viewDarkTokenDataCollector = mutableMapOf() + private val composeLightTokenDataCollectors = + mutableMapOf>() + private val composeDarkTokenDataCollectors = + mutableMapOf>() + private val viewLightTokenDataCollector = + mutableMapOf() + private val viewDarkTokenDataCollector = + mutableMapOf() override fun collectResult() = ColorTokenResult( tokens = tokens, - composeTokens = ColorTokenResult.TokenData( - light = composeLightTokenDataCollector, - dark = composeDarkTokenDataCollector, - ), + composeTokens = colorTokenValues.mapValues { + ColorTokenResult.TokenData( + light = composeLightTokenDataCollectors[it.key] ?: emptyMap(), + dark = composeDarkTokenDataCollectors[it.key] ?: emptyMap(), + ) + }, viewTokens = ColorTokenResult.TokenData( light = viewLightTokenDataCollector, dark = viewDarkTokenDataCollector, @@ -87,7 +104,7 @@ internal class ColorTokenGenerator( */ @Suppress("ReturnCount") override fun addViewSystemToken(token: ColorToken): Boolean { - val tokenValue = colorTokenValues[token.name] + val tokenValue = colorTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for color token ${token.name}. " + "It should be in android_color.json.", @@ -112,30 +129,61 @@ internal class ColorTokenGenerator( * @see TokenGenerator.addComposeToken */ @Suppress("ReturnCount") - override fun addComposeToken(token: ColorToken): Boolean = with(ktFileBuilder) { - val tokenValue = colorTokenValues[token.name] + override fun addComposeToken(token: ColorToken): Boolean { + colorTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for color token ${token.name}. " + "It should be in android_color.json.", ) - val root = if (token.isDark) { - darkBuilder - } else { - lightBuilder + colorTokenValues.forEach { (tenant, values) -> + val tokenValue = values[token.name] + if (tokenValue != null) { + val root = if (token.isDark) { + darkBuilders.getOrPut(tenant) { + ktFileBuilder.rootObject( + "${DARK_COLOR_TOKENS_NAME}${tenant.name}", + DARK_COLOR_TOKENS_DESC, + ) + } + } else { + lightBuilders.getOrPut(tenant) { + ktFileBuilder.rootObject( + "${LIGHT_COLOR_TOKENS_NAME}${tenant.name}", + LIGHT_COLOR_TOKENS_DESC, + ) + } + } + val resolvedColor = resolveColor( + tokenValue = tokenValue, + tokenName = token.name, + palette = palette, + hexFormat = HexFormat.INT_HEX, + ) + val value = "Color($resolvedColor)" + with(ktFileBuilder) { + root.appendProperty( + token.ktName, + KtFileBuilder.TypeColor, + value, + token.description, + ) + } + token.addComposeTokenData( + token.ktName.decapitalize(Locale.getDefault()), + token.ktName, + token.description, + tenant, + ) + } } - val resolvedColor = resolveColor( - tokenValue = tokenValue, - tokenName = token.name, - palette = palette, - hexFormat = HexFormat.INT_HEX, - ) - val value = "Color($resolvedColor)" - root.appendProperty(token.ktName, KtFileBuilder.TypeColor, value, token.description) - token.addComposeTokenData(token.ktName.decapitalize(Locale.getDefault()), token.ktName, token.description) return true } - private fun ColorToken.addViewTokenData(attrName: String, tokenRef: String, description: String) { + private fun ColorToken.addViewTokenData( + attrName: String, + tokenRef: String, + description: String, + ) { val info = ColorTokenResult.TokenData.ColorInfo(tokenRef, description) if (this.isLight) { viewLightTokenDataCollector[attrName] = info @@ -147,15 +195,26 @@ internal class ColorTokenGenerator( } } - private fun ColorToken.addComposeTokenData(attrName: String, tokenRef: String, description: String) { + private fun ColorToken.addComposeTokenData( + attrName: String, + tokenRef: String, + description: String, + tenant: Tenant, + ) { val info = ColorTokenResult.TokenData.ColorInfo(tokenRef, description) + val lightCollector = composeLightTokenDataCollectors.getOrPut(tenant) { + mutableMapOf() + } + val darkCollector = composeDarkTokenDataCollectors.getOrPut(tenant) { + mutableMapOf() + } if (this.isLight) { - composeLightTokenDataCollector[attrName] = info + lightCollector[attrName] = info } else if (this.isDark) { - composeDarkTokenDataCollector[attrName] = info + darkCollector[attrName] = info } else { - composeLightTokenDataCollector[attrName] = info - composeDarkTokenDataCollector[attrName] = info + lightCollector[attrName] = info + darkCollector[attrName] = info } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGenerator.kt index 7c4004ad5d..ead04221f9 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGenerator.kt @@ -10,6 +10,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlFontFamilyDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.fonts.FontData import com.sdds.plugin.themebuilder.internal.fonts.FontsAggregator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.FontToken import com.sdds.plugin.themebuilder.internal.token.FontTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider.fontDir @@ -44,7 +45,7 @@ internal class FontTokenGenerator( private val ktFileBuilderFactory: KtFileBuilderFactory, namespace: String, private val resPrefix: String, - private val fontTokenValues: Map, + private val fontTokenValues: Map>, private val fontsAggregator: FontsAggregator, private val dimensionsConfig: DimensionsConfig, ) : TokenGenerator(target) { @@ -59,9 +60,8 @@ internal class FontTokenGenerator( } } } - private val ktFileRootObjectBuilder by unsafeLazy { - ktFileBuilder.rootObject(FONT_TOKENS_NAME, FONT_TOKENS_DESC) - } + private val rootObjectBuilders = + mutableMapOf(Tenant.Default to ktFileBuilder.rootObject(FONT_TOKENS_NAME, FONT_TOKENS_DESC)) private val fontDownloader by unsafeLazy { fontDownloaderFactory.create() } override fun collectResult() = "" @@ -74,7 +74,7 @@ internal class FontTokenGenerator( } override fun addViewSystemToken(token: FontToken): Boolean { - val tokenValue = fontTokenValues[token.name] + val tokenValue = fontTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for font token ${token.name}. " + "It should be in android_fontFamily.json.", @@ -97,17 +97,27 @@ internal class FontTokenGenerator( } override fun addComposeToken(token: FontToken): Boolean { - val tokenValue = fontTokenValues[token.name] + fontTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for font token ${token.name}. " + "It should be in android_fontFamily.json.", ) - FontTokenValidator.validate(tokenValue, token.name) - ktFileRootObjectBuilder.addFontFamilyToken( - name = token.ktName, - description = token.description, - tokenValue = tokenValue, - ) + fontTokenValues.forEach { (tenant, values) -> + val tokenValue = values[token.name] + if (tokenValue != null) { + FontTokenValidator.validate(tokenValue, token.name) + val objectName = "${FONT_TOKENS_NAME}${tenant.name}" + val objectBuilder = rootObjectBuilders.getOrPut(tenant) { + ktFileBuilder.rootObject(objectName, FONT_TOKENS_DESC) + } + objectBuilder.addFontFamilyToken( + name = token.ktName, + description = token.description, + tokenValue = tokenValue, + ) + } + } + return true } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGenerator.kt index bf3aa42406..bfe2489a39 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGenerator.kt @@ -11,6 +11,7 @@ import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilder import com.sdds.plugin.themebuilder.internal.generator.data.GradientTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.GradientTokenResult.ComposeTokenData import com.sdds.plugin.themebuilder.internal.generator.data.GradientTokenResult.ViewTokenData +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.BackgroundGradientTokenValue import com.sdds.plugin.themebuilder.internal.token.GradientPoint import com.sdds.plugin.themebuilder.internal.token.GradientToken @@ -49,26 +50,37 @@ internal class GradientTokenGenerator( target: ThemeBuilderTarget, private val xmlBuilderFactory: XmlResourcesDocumentBuilderFactory, private val ktFileBuilderFactory: KtFileBuilderFactory, - private val gradientTokenValues: Map>, + private val gradientTokenValues: Map>>, private val palette: Map>, private val resourceReferenceProvider: ResourceReferenceProvider, ) : TokenGenerator(target) { private val composeKtFileBuilder by unsafeLazy { ktFileBuilderFactory.create("GradientTokens") } - private val composeLightBuilder by unsafeLazy { - composeKtFileBuilder.rootObject(LIGHT_GRADIENT_TOKENS_NAME, LIGHT_GRADIENT_TOKENS_DESC) + private val composeLightBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to composeKtFileBuilder.rootObject( + LIGHT_GRADIENT_TOKENS_NAME, + LIGHT_GRADIENT_TOKENS_DESC, + ), + ) } - private val composeDarkBuilder by unsafeLazy { - composeKtFileBuilder.rootObject(DARK_GRADIENT_TOKENS_NAME, DARK_GRADIENT_TOKENS_DESC) + private val composeDarkBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to composeKtFileBuilder.rootObject( + DARK_GRADIENT_TOKENS_NAME, + DARK_GRADIENT_TOKENS_DESC, + ), + ) } + private val xmlParametersDocumentBuilder by unsafeLazy { xmlBuilderFactory.create(DEFAULT_ROOT_ATTRIBUTES) } - private val composeKtLightTokenDataCollector = - mutableMapOf>() - private val composeKtDarkTokenDataCollector = - mutableMapOf>() + private val composeKtLightTokenDataCollectors = + mutableMapOf>>() + private val composeKtDarkTokenDataCollectors = + mutableMapOf>>() private val viewXmlDrawableLightTokenDataCollector = mutableMapOf() private val viewXmlDrawableDarkTokenDataCollector = @@ -76,10 +88,12 @@ internal class GradientTokenGenerator( override fun collectResult() = GradientTokenResult( tokens = tokens, - composeTokens = ComposeTokenData( - light = composeKtLightTokenDataCollector, - dark = composeKtDarkTokenDataCollector, - ), + composeTokens = gradientTokenValues.mapValues { + ComposeTokenData( + light = composeKtLightTokenDataCollectors[it.key] ?: emptyMap(), + dark = composeKtDarkTokenDataCollectors[it.key] ?: emptyMap(), + ) + }, viewXmlTokens = ViewTokenData( light = viewXmlDrawableLightTokenDataCollector, dark = viewXmlDrawableDarkTokenDataCollector, @@ -106,7 +120,7 @@ internal class GradientTokenGenerator( * @see TokenGenerator.addViewSystemToken */ override fun addViewSystemToken(token: GradientToken): Boolean { - val tokenValue = gradientTokenValues[token.name] + val tokenValue = gradientTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for gradient token ${token.name}. " + "It should be in android_gradient.json.", @@ -118,12 +132,18 @@ internal class GradientTokenGenerator( * @see TokenGenerator.addComposeToken */ override fun addComposeToken(token: GradientToken): Boolean { - val tokenValues = gradientTokenValues[token.name] + gradientTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for gradient token ${token.name}. " + "It should be in android_gradient.json.", ) - return addKtToken(token, tokenValues) + gradientTokenValues.forEach { (tenant, values) -> + val tokenValues = values[token.name] + if (tokenValues != null) { + addKtToken(token, tokenValues, tenant) + } + } + return true } private fun addXmlViewToken( @@ -219,28 +239,29 @@ internal class GradientTokenGenerator( private fun addKtToken( token: GradientToken, tokenValues: List, - ): Boolean { - val darkLightObjectBuilder = darkLightObjectBuilder(token) + tenant: Tenant, + ) { + val objectBuilder = objectBuilder(token, tenant) val baseTokenName = token.ktName - with(darkLightObjectBuilder) { + with(objectBuilder) { appendObject(baseTokenName, token.description) { if (tokenValues.size > 1) { - appendGradientLayers(tokenValues, token) + appendGradientLayers(tokenValues, token, tenant) } else { - appendGradientLayer(tokenValues.first(), token, null) + appendGradientLayer(tokenValues.first(), token, null, tenant) } } } - return true } private fun TypeSpec.Builder.appendGradientLayers( tokenValues: List, token: GradientToken, + tenant: Tenant, ) { tokenValues.mapIndexed { index, gradient -> appendObject("Layer$index", "Cлой $index") { - appendGradientLayer(gradient, token, index) + appendGradientLayer(gradient, token, index, tenant) } } } @@ -249,36 +270,47 @@ internal class GradientTokenGenerator( tokenValue: GradientTokenValue, token: GradientToken, layerIndex: Int?, + tenant: Tenant, ) { val layerRef = layerIndex?.let { "Layer$it." }.orEmpty() + val objectName = if (token.isDark) { + "${DARK_GRADIENT_TOKENS_NAME}${tenant.name}" + } else { + "${LIGHT_GRADIENT_TOKENS_NAME}${tenant.name}" + } val tokenData = when (tokenValue) { is LinearGradientTokenValue -> appendLinearGradient( token = token, tokenValue = tokenValue, layerRef = layerRef, + objectName = objectName, ) is RadialGradientTokenValue -> appendRadialGradient( token = token, tokenValue = tokenValue, layerRef = layerRef, + objectName = objectName, ) is SweepGradientTokenValue -> appendSweepGradient( token = token, tokenValue = tokenValue, layerRef = layerRef, + objectName = objectName, ) is BackgroundGradientTokenValue -> appendSingleColorBackground( token = token, tokenValue = tokenValue, layerRef = layerRef, + objectName = objectName, ) } token.addKtTokenData( token.attrName(), tokenData, + tenant, ) } @@ -483,11 +515,18 @@ internal class GradientTokenGenerator( } } - private fun darkLightObjectBuilder(token: GradientToken): TypeSpec.Builder { + private fun objectBuilder(token: GradientToken, tenant: Tenant): TypeSpec.Builder { return if (token.isDark) { - composeDarkBuilder + composeDarkBuilders.getOrPut(tenant) { + composeKtFileBuilder.rootObject("${DARK_GRADIENT_TOKENS_NAME}${tenant.name}", DARK_GRADIENT_TOKENS_DESC) + } } else { - composeLightBuilder + composeLightBuilders.getOrPut(tenant) { + composeKtFileBuilder.rootObject( + "${LIGHT_GRADIENT_TOKENS_NAME}${tenant.name}", + LIGHT_GRADIENT_TOKENS_DESC, + ) + } } } @@ -495,6 +534,7 @@ internal class GradientTokenGenerator( token: GradientToken, tokenValue: LinearGradientTokenValue, layerRef: String, + objectName: String, ): ComposeTokenData.Gradient { val baseTokenName = token.ktName LinearGradientTokenValidator.validate(tokenValue, baseTokenName) @@ -527,6 +567,7 @@ internal class GradientTokenGenerator( tokenRefs = tokenRefs, gradientType = ComposeTokenData.GradientType.LINEAR, description = token.description, + tokenObjectName = objectName, ) } @@ -534,6 +575,7 @@ internal class GradientTokenGenerator( token: GradientToken, tokenValue: SweepGradientTokenValue, layerRef: String, + objectName: String, ): ComposeTokenData.Gradient { val baseTokenName = token.ktName SweepGradientTokenValidator.validate(tokenValue, baseTokenName) @@ -563,6 +605,7 @@ internal class GradientTokenGenerator( ), gradientType = ComposeTokenData.GradientType.SWEEP, description = token.description, + tokenObjectName = objectName, ) } @@ -570,6 +613,7 @@ internal class GradientTokenGenerator( token: GradientToken, tokenValue: RadialGradientTokenValue, layerRef: String, + objectName: String, ): ComposeTokenData.Gradient { val baseTokenName = token.ktName RadialGradientTokenValidator.validate(tokenValue, baseTokenName) @@ -609,6 +653,8 @@ internal class GradientTokenGenerator( ), gradientType = ComposeTokenData.GradientType.RADIAL, description = token.description, + tokenObjectName = objectName, + ) } @@ -616,6 +662,7 @@ internal class GradientTokenGenerator( token: GradientToken, tokenValue: BackgroundGradientTokenValue, layerRef: String, + objectName: String, ): ComposeTokenData.Gradient { val baseTokenName = token.ktName val resolvedColor = @@ -634,6 +681,7 @@ internal class GradientTokenGenerator( ), gradientType = ComposeTokenData.GradientType.BACKGROUND, description = token.description, + tokenObjectName = objectName, ) } @@ -689,16 +737,21 @@ internal class GradientTokenGenerator( private fun GradientToken.addKtTokenData( attrName: String, params: ComposeTokenData.Gradient, + tenant: Tenant, ) { - val lightDataCollector = composeKtLightTokenDataCollector - val darkDataCollector = composeKtDarkTokenDataCollector + val lightCollector = composeKtLightTokenDataCollectors.getOrPut(tenant) { + mutableMapOf() + } + val darkCollector = composeKtDarkTokenDataCollectors.getOrPut(tenant) { + mutableMapOf() + } if (this.isLight) { - lightDataCollector.getOrPut(attrName) { mutableListOf() }.add(params) + lightCollector.getOrPut(attrName) { mutableListOf() }.add(params) } else if (this.isDark) { - darkDataCollector.getOrPut(attrName) { mutableListOf() }.add(params) + darkCollector.getOrPut(attrName) { mutableListOf() }.add(params) } else { - lightDataCollector.getOrPut(attrName) { mutableListOf() }.add(params) - darkDataCollector.getOrPut(attrName) { mutableListOf() }.add(params) + lightCollector.getOrPut(attrName) { mutableListOf() }.add(params) + darkCollector.getOrPut(attrName) { mutableListOf() }.add(params) } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGenerator.kt index 5908a98319..02bb87cc35 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGenerator.kt @@ -13,6 +13,7 @@ import com.sdds.plugin.themebuilder.internal.exceptions.ThemeBuilderException import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.ShadowTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ShadowToken import com.sdds.plugin.themebuilder.internal.token.ShadowTokenValue import com.sdds.plugin.themebuilder.internal.utils.ColorResolver.HexFormat @@ -43,7 +44,7 @@ internal class ShadowTokenGenerator( target: ThemeBuilderTarget, private val xmlBuilderFactory: XmlResourcesDocumentBuilderFactory, private val ktFileBuilderFactory: KtFileBuilderFactory, - private val shadowTokenValues: Map>, + private val shadowTokenValues: Map>>, private val resourceReferenceProvider: ResourceReferenceProvider, private val dimensionsConfig: DimensionsConfig, private val dimensAggregator: DimensAggregator, @@ -53,17 +54,18 @@ internal class ShadowTokenGenerator( private val xmlDocumentBuilder by unsafeLazy { xmlBuilderFactory.create(DEFAULT_ROOT_ATTRIBUTES) } private val ktFileBuilder by unsafeLazy { ktFileBuilderFactory.create(SHADOW_TOKENS_NAME) } - private val rootShadows by unsafeLazy { ktFileBuilder.rootObject(SHADOW_TOKENS_NAME, SHADOW_TOKENS_DESC) } + private val rootShadows = + mutableMapOf(Tenant.Default to ktFileBuilder.rootObject(SHADOW_TOKENS_NAME, SHADOW_TOKENS_DESC)) private val rFileImport = ClassName(namespace, "R") - private val composeTokenDataCollector = mutableListOf() + private val composeTokenDataCollectors = mutableMapOf>() private val viewTokenDataCollector = mutableListOf() /** * @see TokenGenerator.collectResult */ override fun collectResult() = ShadowTokenResult( - composeTokenDataCollector, + composeTokenDataCollectors, viewTokenDataCollector, ) @@ -93,7 +95,7 @@ internal class ShadowTokenGenerator( * @see TokenGenerator.addViewSystemToken */ override fun addViewSystemToken(token: ShadowToken): Boolean = with(xmlDocumentBuilder) { - val tokenValues = shadowTokenValues[token.name] + val tokenValues = shadowTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for shadow token ${token.name}. " + "It should be in android_shadow.json.", @@ -166,36 +168,48 @@ internal class ShadowTokenGenerator( /** * @see TokenGenerator.addComposeToken */ - override fun addComposeToken(token: ShadowToken): Boolean = with(ktFileBuilder) { - val tokenValues = shadowTokenValues[token.name] + override fun addComposeToken(token: ShadowToken): Boolean { + shadowTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for shadow token ${token.name}. " + "It should be in android_shadow.json.", ) - val useLayerSuffix = tokenValues.size > 1 - val layers = mutableListOf() - tokenValues.forEachIndexed { index, tokenValue -> - ShadowTokenValidator.validate(tokenValue, token.name) - val tokenName = "${token.ktName}Layer${index + 1}".takeIf { useLayerSuffix } ?: token.ktName - rootShadows.appendObject(tokenName, token.description) { - val layerRef = appendShadowProperties(tokenName, tokenValue, token.description) - layers.add(layerRef) + shadowTokenValues.forEach { (tenant, values) -> + val tokenValues = values[token.name] + if (tokenValues != null) { + val useLayerSuffix = tokenValues.size > 1 + val layers = mutableListOf() + tokenValues.forEachIndexed { index, tokenValue -> + ShadowTokenValidator.validate(tokenValue, token.name) + val tokenName = "${token.ktName}Layer${index + 1}".takeIf { useLayerSuffix } ?: token.ktName + val rootShadowsObject = rootShadows.getOrPut(tenant) { + ktFileBuilder.rootObject("${SHADOW_TOKENS_NAME}${tenant.name}", SHADOW_TOKENS_DESC) + } + rootShadowsObject.appendObject(tokenName, token.description) { + val layerRef = appendShadowProperties(tokenName, tokenValue, token.description, tenant) + layers.add(layerRef) + } + } + val composeTokenDataCollector = composeTokenDataCollectors.getOrPut(tenant) { + mutableListOf() + } + composeTokenDataCollector.add( + ShadowTokenResult.TokenData( + tokenTechName = token.name, + layers = layers, + tokenDescription = token.description, + ), + ) } } - composeTokenDataCollector.add( - ShadowTokenResult.TokenData( - tokenTechName = token.name, - layers = layers, - tokenDescription = token.description, - ), - ) - return@with true + return true } private fun TypeSpec.Builder.appendShadowProperties( tokenName: String, tokenValue: ShadowTokenValue, description: String, + tenant: Tenant, ): ShadowTokenResult.ShadowLayer = with(ktFileBuilder) { val offsetXRef = appendShadowProperty( @@ -203,27 +217,31 @@ internal class ShadowTokenGenerator( "offsetX", tokenValue.offsetX, description, + tenant, ) val offsetYRef = appendShadowProperty( tokenName, "offsetY", tokenValue.offsetY, description, + tenant, ) val spreadRadiusRef = appendShadowProperty( tokenName, "spreadRadius", tokenValue.spreadRadius, description, + tenant, ) val blurRadiusRef = appendShadowProperty( tokenName, "blurRadius", tokenValue.blurRadius, description, + tenant, ) val elevationRef = tokenValue.fallbackElevation?.let { - appendShadowProperty(tokenName, "fallbackElevation", it, description) + appendShadowProperty(tokenName, "fallbackElevation", it, description, tenant) } val resolvedColor = resolveColor( tokenValue = tokenValue.color, @@ -239,7 +257,7 @@ internal class ShadowTokenGenerator( ) ShadowTokenResult.ShadowLayer( - colorRef = "$SHADOW_TOKENS_NAME.$tokenName.color", + colorRef = "$SHADOW_TOKENS_NAME${tenant.name}.$tokenName.color", offsetXRef = offsetXRef, offsetYRef = offsetYRef, spreadRef = spreadRadiusRef, @@ -253,13 +271,14 @@ internal class ShadowTokenGenerator( propertyName: String, value: Float, description: String, + tenant: Tenant, ): String = with(ktFileBuilder) { if (dimensionsConfig.fromResources) { shadowPropertyWithResources(tokenName, propertyName, value, description) } else { shadowProperty(propertyName, value, description) } - return "$SHADOW_TOKENS_NAME.$tokenName.$propertyName" + return "$SHADOW_TOKENS_NAME${tenant.name}.$tokenName.$propertyName" } private fun TypeSpec.Builder.shadowProperty( diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGenerator.kt index 51de8350af..c703f1deb5 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGenerator.kt @@ -14,18 +14,19 @@ import com.sdds.plugin.themebuilder.internal.exceptions.ThemeBuilderException import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.ShapeTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.RoundedShapeTokenValue import com.sdds.plugin.themebuilder.internal.token.ShapeToken import com.sdds.plugin.themebuilder.internal.token.ShapeTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider.shapesXmlFile import com.sdds.plugin.themebuilder.internal.utils.ResourceReferenceProvider +import com.sdds.plugin.themebuilder.internal.utils.decapitalized import com.sdds.plugin.themebuilder.internal.utils.techToSnakeCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy import com.sdds.plugin.themebuilder.internal.validator.ShapeTokenValidator import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.TypeSpec import java.io.File -import java.util.Locale /** * Генератор токенов форм @@ -48,27 +49,25 @@ internal class ShapeTokenGenerator( private val ktFileBuilderFactory: KtFileBuilderFactory, private val dimensAggregator: DimensAggregator, private val resourceReferenceProvider: ResourceReferenceProvider, - private val shapeTokenValues: Map, + private val shapeTokenValues: Map>, private val dimensionsConfig: DimensionsConfig, namespace: String, ) : TokenGenerator(target) { private val xmlDocumentBuilder by unsafeLazy { xmlBuilderFactory.create(DEFAULT_ROOT_ATTRIBUTES) } private val ktFileBuilder by unsafeLazy { ktFileBuilderFactory.create(ROUND_SHAPE_TOKENS_NAME) } - private val rootRoundShapes by unsafeLazy { - ktFileBuilder.rootObject(ROUND_SHAPE_TOKENS_NAME, ROUND_SHAPE_TOKENS_DESC) - } + private val rootRoundShapes = + mutableMapOf(Tenant.Default to ktFileBuilder.rootObject(ROUND_SHAPE_TOKENS_NAME, ROUND_SHAPE_TOKENS_DESC)) private val shouldGenerateShapeStyles: Boolean = viewShapeAppearanceConfig.isNotEmpty() private val rFileImport = ClassName(namespace, "R") private var needCreateStyle: Boolean = true - private val composeTokenDataCollector = - mutableListOf() + private val composeTokenDataCollectors = mutableMapOf>() private val viewTokenDataCollector = mutableListOf() override fun collectResult() = ShapeTokenResult( - composeTokens = composeTokenDataCollector, + composeTokens = composeTokenDataCollectors, viewTokens = viewTokenDataCollector, ) @@ -99,7 +98,7 @@ internal class ShapeTokenGenerator( * @see TokenGenerator.addViewSystemToken */ override fun addViewSystemToken(token: ShapeToken): Boolean = with(xmlDocumentBuilder) { - val roundedShapeTokenValue = shapeTokenValues[token.name] as? RoundedShapeTokenValue + val roundedShapeTokenValue = shapeTokenValues[Tenant.Default]?.get(token.name) as? RoundedShapeTokenValue ?: throw ThemeBuilderException( "Can't find value for shape token ${token.name}. " + "It should be in android_shape.json.", @@ -160,27 +159,39 @@ internal class ShapeTokenGenerator( /** * @see TokenGenerator.addComposeToken */ - override fun addComposeToken(token: ShapeToken): Boolean = with(ktFileBuilder) { - val roundedShapeTokenValue = shapeTokenValues[token.name] as? RoundedShapeTokenValue + override fun addComposeToken(token: ShapeToken): Boolean { + shapeTokenValues[Tenant.Default]?.get(token.name) as? RoundedShapeTokenValue ?: throw ThemeBuilderException( "Can't find value for shape token ${token.name}. " + "It should be in android_shape.json.", ) - ShapeTokenValidator.validate(roundedShapeTokenValue, token.name) + shapeTokenValues.forEach { (tenant, values) -> + val tokenValue = values[token.name] + if (tokenValue != null && tokenValue is RoundedShapeTokenValue) { + ShapeTokenValidator.validate(tokenValue, token.name) - if (dimensionsConfig.fromResources) { - rootRoundShapes.addShapeTokenWithResources(token, roundedShapeTokenValue) - } else { - rootRoundShapes.addShapeToken(token, roundedShapeTokenValue) + val rootObject = rootRoundShapes.getOrPut(tenant) { + ktFileBuilder.rootObject("${ROUND_SHAPE_TOKENS_NAME}${tenant.name}", ROUND_SHAPE_TOKENS_DESC) + } + if (dimensionsConfig.fromResources) { + rootObject.addShapeTokenWithResources(token, tokenValue, tenant) + } else { + rootObject.addShapeToken(token, tokenValue) + } + val composeTokenDataCollector = composeTokenDataCollectors.getOrPut(tenant) { + mutableListOf() + } + composeTokenDataCollector.add( + ShapeTokenResult.TokenData( + attrName = token.ktName.decapitalized(), + tokenRefName = token.ktName, + description = token.description, + tokenObjectName = "${ROUND_SHAPE_TOKENS_NAME}${tenant.name}", + ), + ) + } } - composeTokenDataCollector.add( - ShapeTokenResult.TokenData( - attrName = token.ktName.decapitalize(Locale.getDefault()), - tokenRefName = token.ktName, - description = token.description, - ), - ) - return@with true + return true } private fun TypeSpec.Builder.addShapeToken( @@ -200,9 +211,15 @@ internal class ShapeTokenGenerator( private fun TypeSpec.Builder.addShapeTokenWithResources( token: ShapeToken, value: RoundedShapeTokenValue, + tenant: Tenant, ) = with(ktFileBuilder) { + val tenantSuffix = if (tenant == Tenant.Default) { + "" + } else { + "_${tenant.name}" + } val cornerSize = DimenData( - name = "${token.name.techToSnakeCase()}_corner_size", + name = "${token.name.techToSnakeCase()}_corner_size$tenantSuffix", value = value.cornerRadius, type = DimenData.Type.DP, ) diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGenerator.kt index bf5ac956cc..7a4a56c605 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGenerator.kt @@ -9,6 +9,7 @@ import com.sdds.plugin.themebuilder.internal.dimens.DimensAggregator import com.sdds.plugin.themebuilder.internal.exceptions.ThemeBuilderException import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.SpacingTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.SpacingToken import com.sdds.plugin.themebuilder.internal.token.SpacingTokenValue import com.sdds.plugin.themebuilder.internal.utils.ResourceReferenceProvider @@ -22,7 +23,6 @@ import java.io.File /** * Генератор токенов отступов * @param outputLocation локация для сохранения kt-файла с токенами - * @param outputResDir директория для сохранения xml-файла с токенами * @param target целевой фреймворк * @param ktFileBuilderFactory фабрика делегата построения kt файлов * @param dimensAggregator агрегатор размеров @@ -37,22 +37,29 @@ internal class SpacingTokenGenerator( private val ktFileBuilderFactory: KtFileBuilderFactory, private val dimensAggregator: DimensAggregator, private val resourceReferenceProvider: ResourceReferenceProvider, - private val spacingTokenValues: Map, + private val spacingTokenValues: Map>, private val dimensionsConfig: DimensionsConfig, namespace: String, ) : TokenGenerator(target) { private val ktFileBuilder by unsafeLazy { ktFileBuilderFactory.create(SPACING_TOKENS_NAME) } - private val rootSpacings by unsafeLazy { ktFileBuilder.rootObject(SPACING_TOKENS_NAME, SPACING_TOKENS_DESC) } + private val rootSpacings = + mutableMapOf( + Tenant.Default to ktFileBuilder.rootObject( + SPACING_TOKENS_NAME, + SPACING_TOKENS_DESC, + ), + ) private val rFileImport = ClassName(namespace, "R") - private val composeTokenDataCollector = - mutableListOf() + private val composeTokenDataCollectors = + mutableMapOf(Tenant.Default to mutableListOf()) + private val viewTokenDataCollector = mutableListOf() override fun collectResult() = SpacingTokenResult( - composeTokens = composeTokenDataCollector, + composeTokens = composeTokenDataCollectors, viewTokens = viewTokenDataCollector, ) @@ -73,7 +80,7 @@ internal class SpacingTokenGenerator( * @see TokenGenerator.addViewSystemToken */ override fun addViewSystemToken(token: SpacingToken): Boolean { - val tokenValue = spacingTokenValues[token.name] + val tokenValue = spacingTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for spacing token ${token.name}. " + "It should be in android_spacing.json.", @@ -98,28 +105,43 @@ internal class SpacingTokenGenerator( /** * @see TokenGenerator.addComposeToken */ - override fun addComposeToken(token: SpacingToken): Boolean = with(ktFileBuilder) { - val tokenValue = spacingTokenValues[token.name] + override fun addComposeToken(token: SpacingToken): Boolean { + spacingTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for spacing token ${token.name}. " + "It should be in android_spacing.json.", ) - SpacingTokenValidator.validate(tokenValue, token.name) - - if (dimensionsConfig.fromResources) { - rootSpacings.addSpacingTokenWithResources(token, tokenValue) - } else { - rootSpacings.addSpacingToken(token, tokenValue) + spacingTokenValues.forEach { (tenant, values) -> + val tokenValue = values[token.name] + if (tokenValue != null) { + SpacingTokenValidator.validate(tokenValue, token.name) + val rootSpacingObject = rootSpacings.getOrPut(tenant) { + ktFileBuilder.rootObject( + "${SPACING_TOKENS_NAME}${tenant.name}", + SPACING_TOKENS_DESC, + ) + } + if (dimensionsConfig.fromResources) { + rootSpacingObject.addSpacingTokenWithResources(token, tokenValue, tenant) + } else { + rootSpacingObject.addSpacingToken(token, tokenValue) + } + val decapitalizedName = token.ktName.decapitalized() + val composeTokenDataCollector = composeTokenDataCollectors.getOrPut(tenant) { + mutableListOf() + } + composeTokenDataCollector.add( + SpacingTokenResult.TokenData( + attrName = decapitalizedName, + tokenRefName = decapitalizedName, + description = token.description, + tokenObjectName = "${SPACING_TOKENS_NAME}${tenant.name}", + ), + ) + } } - val decapitalizedName = token.ktName.decapitalized() - composeTokenDataCollector.add( - SpacingTokenResult.TokenData( - attrName = decapitalizedName, - tokenRefName = decapitalizedName, - description = token.description, - ), - ) - return@with true + + return true } private fun TypeSpec.Builder.addSpacingToken( @@ -139,9 +161,15 @@ internal class SpacingTokenGenerator( private fun TypeSpec.Builder.addSpacingTokenWithResources( token: SpacingToken, value: SpacingTokenValue, + tenant: Tenant, ) = with(ktFileBuilder) { + val tenantSuffix = if (tenant == Tenant.Default) { + "" + } else { + "_${tenant.name.lowercase()}" + } val dimenValue = DimenData( - name = token.xmlName, + name = "${token.xmlName}$tenantSuffix", value = value.value, type = DimenData.Type.DP, ) diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGenerator.kt index 9431bb1dc2..4d9a12594f 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGenerator.kt @@ -17,19 +17,22 @@ import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilder import com.sdds.plugin.themebuilder.internal.fonts.FontsAggregator import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult.TypographyInfo +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.TypographyToken import com.sdds.plugin.themebuilder.internal.token.TypographyToken.ScreenClass import com.sdds.plugin.themebuilder.internal.token.TypographyTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider.textAppearancesXmlFile import com.sdds.plugin.themebuilder.internal.utils.FileProvider.typographyXmlFile import com.sdds.plugin.themebuilder.internal.utils.ResourceReferenceProvider +import com.sdds.plugin.themebuilder.internal.utils.decapitalized import com.sdds.plugin.themebuilder.internal.utils.techToSnakeCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy import com.sdds.plugin.themebuilder.internal.validator.TypographyTokenValidator import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.TypeSpec import java.io.File -import java.util.Locale +import kotlin.collections.component1 +import kotlin.collections.component2 /** * Генерирует токены типографики. @@ -59,7 +62,7 @@ internal class TypographyTokenGenerator( private val xmlBuilderFactory: XmlResourcesDocumentBuilderFactory, private val ktFileBuilderFactory: KtFileBuilderFactory, private val resourceReferenceProvider: ResourceReferenceProvider, - private val typographyTokenValues: Map, + private val typographyTokenValues: Map>, private val fontsAggregator: FontsAggregator, private val dimensionsConfig: DimensionsConfig, namespace: String, @@ -74,23 +77,38 @@ internal class TypographyTokenGenerator( ktFileBuilderFactory.create("TypographyTokens") .apply { this.addSuppressAnnotation("DEPRECATION") } } - private val largeBuilder by unsafeLazy { - ktFileBuilder.rootObject(TYPOGRAPHY_LARGE_TOKENS_NAME, TYPOGRAPHY_LARGE_TOKENS_DESC) + private val largeBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to ktFileBuilder.rootObject( + TYPOGRAPHY_LARGE_TOKENS_NAME, + TYPOGRAPHY_LARGE_TOKENS_DESC, + ), + ) } - private val mediumBuilder by unsafeLazy { - ktFileBuilder.rootObject(TYPOGRAPHY_MEDIUM_TOKENS_NAME, TYPOGRAPHY_MEDIUM_TOKENS_DESC) + private val mediumBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to ktFileBuilder.rootObject( + TYPOGRAPHY_MEDIUM_TOKENS_NAME, + TYPOGRAPHY_MEDIUM_TOKENS_DESC, + ), + ) } - private val smallBuilder by unsafeLazy { - ktFileBuilder.rootObject(TYPOGRAPHY_SMALL_TOKENS_NAME, TYPOGRAPHY_SMALL_TOKENS_DESC) + private val smallBuilders by unsafeLazy { + mutableMapOf( + Tenant.Default to ktFileBuilder.rootObject( + TYPOGRAPHY_SMALL_TOKENS_NAME, + TYPOGRAPHY_SMALL_TOKENS_DESC, + ), + ) } private val defaultValuesBuilder by unsafeLazy { ktFileBuilder.rootObject(DEFAULTS_NAME, modifiers = PrivateModifier) } private var needDeclareStyle: Boolean = true - private val composeSmallTokenDataCollector = mutableMapOf() - private val composeMediumTokenDataCollector = mutableMapOf() - private val composeLargeTokenDataCollector = mutableMapOf() + private val composeSmallTokenDataCollectors = mutableMapOf>() + private val composeMediumTokenDataCollectors = mutableMapOf>() + private val composeLargeTokenDataCollectors = mutableMapOf>() private val viewTokenDataCollector = mutableMapOf() @@ -100,11 +118,13 @@ internal class TypographyTokenGenerator( private val rFileImport = ClassName(namespace, "R") override fun collectResult() = TypographyTokenResult( - composeTokens = TypographyTokenResult.ComposeTokenData( - small = composeSmallTokenDataCollector, - medium = composeMediumTokenDataCollector, - large = composeLargeTokenDataCollector, - ), + composeTokens = typographyTokenValues.mapValues { + TypographyTokenResult.ComposeTokenData( + composeSmallTokenDataCollectors[it.key] ?: emptyMap(), + composeMediumTokenDataCollectors[it.key] ?: emptyMap(), + composeLargeTokenDataCollectors[it.key] ?: emptyMap(), + ) + }, viewTokens = TypographyTokenResult.ViewTokenData( attrs = viewTokenDataCollector, ), @@ -165,51 +185,83 @@ internal class TypographyTokenGenerator( * @see TokenGenerator.addComposeToken */ override fun addComposeToken(token: TypographyToken): Boolean { - val tokenValue = typographyTokenValues[token.name] + typographyTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for typography token ${token.name}. " + "It should be in android_typography.json.", ) - TypographyTokenValidator.validate(tokenValue, token.name) - val attrName = token.ktName.decapitalize(Locale.getDefault()) - when (token.screenClass) { - ScreenClass.SMALL -> { - smallBuilder.addTypographyToken( - token, - token.description, - tokenValue, - ) - val tokenRef = "$TYPOGRAPHY_SMALL_TOKENS_NAME.${token.ktName}" - composeSmallTokenDataCollector[attrName] = TypographyInfo(tokenRef, token.description) - } + typographyTokenValues.forEach { (tenant, values) -> + val tokenValue = values[token.name] + if (tokenValue != null) { + TypographyTokenValidator.validate(tokenValue, token.name) + val attrName = token.ktName.decapitalized() + val composeSmallTokenDataCollector = composeSmallTokenDataCollectors.getOrPut(tenant) { mutableMapOf() } + val composeMediumTokenDataCollector = composeMediumTokenDataCollectors.getOrPut( + tenant, + ) { mutableMapOf() } + val composeLargeTokenDataCollector = composeLargeTokenDataCollectors.getOrPut(tenant) { mutableMapOf() } + when (token.screenClass) { + ScreenClass.SMALL -> { + val smallBuilder = smallBuilders.getOrPut(tenant) { + ktFileBuilder.rootObject( + "${TYPOGRAPHY_SMALL_TOKENS_NAME}${tenant.name}", + TYPOGRAPHY_SMALL_TOKENS_DESC, + ) + } + smallBuilder.addTypographyToken( + token, + token.description, + tokenValue, + tenant, + ) + val tokenRef = "$TYPOGRAPHY_SMALL_TOKENS_NAME${tenant.name}.${token.ktName}" + composeSmallTokenDataCollector[attrName] = TypographyInfo(tokenRef, token.description) + } - ScreenClass.LARGE -> { - largeBuilder.addTypographyToken( - token, - token.description, - tokenValue, - ) - val tokenRef = "$TYPOGRAPHY_LARGE_TOKENS_NAME.${token.ktName}" - composeLargeTokenDataCollector[attrName] = TypographyInfo(tokenRef, token.description) - } + ScreenClass.LARGE -> { + val largeBuilder = largeBuilders.getOrPut(tenant) { + ktFileBuilder.rootObject( + "${TYPOGRAPHY_LARGE_TOKENS_NAME}${tenant.name}", + TYPOGRAPHY_LARGE_TOKENS_DESC, + ) + } + largeBuilder.addTypographyToken( + token, + token.description, + tokenValue, + tenant, + ) + val tokenRef = "$TYPOGRAPHY_LARGE_TOKENS_NAME${tenant.name}.${token.ktName}" + composeLargeTokenDataCollector[attrName] = TypographyInfo(tokenRef, token.description) + } - else -> { - mediumBuilder.addTypographyToken( - token, - token.description, - tokenValue, - ) - val tokenRef = "$TYPOGRAPHY_MEDIUM_TOKENS_NAME.${token.ktName}" - composeMediumTokenDataCollector[attrName] = TypographyInfo(tokenRef, token.description) + else -> { + val mediumBuilder = mediumBuilders.getOrPut(tenant) { + ktFileBuilder.rootObject( + "${TYPOGRAPHY_MEDIUM_TOKENS_NAME}${tenant.name}", + TYPOGRAPHY_MEDIUM_TOKENS_DESC, + ) + } + mediumBuilder.addTypographyToken( + token, + token.description, + tokenValue, + tenant, + ) + val tokenRef = "$TYPOGRAPHY_MEDIUM_TOKENS_NAME${tenant.name}.${token.ktName}" + composeMediumTokenDataCollector[attrName] = TypographyInfo(tokenRef, token.description) + } + } } } + return true } private fun generateViewTypographyTokens(tokenName: String, screenClass: ScreenClass) { val token = findTypographyTokenByScreenClass(tokenName, screenClass) ?: throw ThemeBuilderException("Token $tokenName not found") - val tokenValue = typographyTokenValues[token.name] + val tokenValue = typographyTokenValues[Tenant.Default]?.get(token.name) ?: throw ThemeBuilderException( "Can't find value for typography token ${token.name}. " + "It should be in android_typography.json.", @@ -366,6 +418,7 @@ internal class TypographyTokenGenerator( token: TypographyToken, description: String, tokenValue: TypographyTokenValue, + tenant: Tenant, ) = with(ktFileBuilder) { val letterSpacing = if (tokenValue.letterSpacing < 0) { "(${tokenValue.letterSpacing}).sp" @@ -376,13 +429,18 @@ internal class TypographyTokenGenerator( val fontSizeInitializer: String val lineHeightInitializer: String if (fromResources) { + val tenantSuffix = if (tenant == Tenant.Default) { + "" + } else { + "_${tenant.name.lowercase()}" + } val textSizeDimen = DimenData( - "${token.name.techToSnakeCase()}_text_size", + "${token.name.techToSnakeCase()}_text_size$tenantSuffix", tokenValue.textSize, DimenData.Type.SP, ) val lineHeightDimen = DimenData( - "${token.name.techToSnakeCase()}_line_height", + "${token.name.techToSnakeCase()}_line_height$tenantSuffix", tokenValue.lineHeight, DimenData.Type.SP, ) @@ -400,7 +458,7 @@ internal class TypographyTokenGenerator( "fontSize = $fontSizeInitializer", "lineHeight = $lineHeightInitializer", "letterSpacing = $letterSpacing", - "fontFamily = FontTokens.${tokenValue.fontFamilyRef.split('.').last()}", + "fontFamily = FontTokens${tenant.name}.${tokenValue.fontFamilyRef.split('.').last()}", "lineHeightStyle = $DEFAULTS_NAME.$DEFAULTS_LINE_STYLE_NAME", "platformStyle = $DEFAULTS_NAME.$DEFAULTS_PLATFORM_STYLE_NAME", ).trimIndent() diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ColorTokenResult.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ColorTokenResult.kt index 34ace209bb..9408d33bf1 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ColorTokenResult.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ColorTokenResult.kt @@ -1,5 +1,6 @@ package com.sdds.plugin.themebuilder.internal.generator.data +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ColorToken /** @@ -11,7 +12,7 @@ import com.sdds.plugin.themebuilder.internal.token.ColorToken */ internal data class ColorTokenResult( val tokens: List, - val composeTokens: TokenData, + val composeTokens: Map, val viewTokens: TokenData, ) { diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/GradientTokenResult.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/GradientTokenResult.kt index 7446530220..d49a9a0bd3 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/GradientTokenResult.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/GradientTokenResult.kt @@ -1,5 +1,6 @@ package com.sdds.plugin.themebuilder.internal.generator.data +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.GradientToken /** @@ -11,7 +12,7 @@ import com.sdds.plugin.themebuilder.internal.token.GradientToken */ internal data class GradientTokenResult( val tokens: List, - val composeTokens: ComposeTokenData, + val composeTokens: Map, val viewXmlTokens: ViewTokenData, ) { @@ -79,6 +80,7 @@ internal data class GradientTokenResult( val tokenRefs: List, val gradientType: GradientType, val description: String = "", + val tokenObjectName: String? = null, ) /** diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShadowTokenResult.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShadowTokenResult.kt index fadc08cf88..dd328057c4 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShadowTokenResult.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShadowTokenResult.kt @@ -1,5 +1,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data +import com.sdds.plugin.themebuilder.internal.tenant.Tenant + /** * Данные о токенах тени. * @@ -7,7 +9,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data * @property viewTokens данные о токенах для View */ internal data class ShadowTokenResult( - val composeTokens: List, + val composeTokens: Map>, val viewTokens: List, ) { diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShapeTokenResult.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShapeTokenResult.kt index 8fef5edf67..2d5d613e91 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShapeTokenResult.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/ShapeTokenResult.kt @@ -1,5 +1,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data +import com.sdds.plugin.themebuilder.internal.tenant.Tenant + /** * Данные о токенах формы. * @@ -7,7 +9,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data * @property viewTokens данные о токенах для View */ internal data class ShapeTokenResult( - val composeTokens: List, + val composeTokens: Map>, val viewTokens: List, ) { @@ -22,5 +24,6 @@ internal data class ShapeTokenResult( val attrName: String, val tokenRefName: String, val description: String = "", + val tokenObjectName: String? = null, ) } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/SpacingTokenResult.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/SpacingTokenResult.kt index c27b9b58a2..9fc54c5d94 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/SpacingTokenResult.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/SpacingTokenResult.kt @@ -1,5 +1,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data +import com.sdds.plugin.themebuilder.internal.tenant.Tenant + /** * Данные о токенах отступов. * @@ -7,7 +9,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data * @property viewTokens данные о токенах для View */ internal data class SpacingTokenResult( - val composeTokens: List, + val composeTokens: Map>, val viewTokens: List, ) { @@ -22,5 +24,6 @@ internal data class SpacingTokenResult( val attrName: String, val tokenRefName: String, val description: String? = null, + val tokenObjectName: String? = null, ) } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/TypographyTokenResult.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/TypographyTokenResult.kt index 7555384066..1ee812cbe1 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/TypographyTokenResult.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/data/TypographyTokenResult.kt @@ -1,5 +1,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data +import com.sdds.plugin.themebuilder.internal.tenant.Tenant + /** * Данные о токенах типографики. * @@ -7,7 +9,7 @@ package com.sdds.plugin.themebuilder.internal.generator.data * @property viewTokens данные о токенах для View */ internal data class TypographyTokenResult( - val composeTokens: ComposeTokenData, + val composeTokens: Map, val viewTokens: ViewTokenData, ) { diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeColorAttributeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeColorAttributeGenerator.kt index 3e63448b8d..1d1e0251fd 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeColorAttributeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeColorAttributeGenerator.kt @@ -3,6 +3,7 @@ package com.sdds.plugin.themebuilder.internal.generator.theme.compose import com.sdds.plugin.themebuilder.internal.PackageResolver import com.sdds.plugin.themebuilder.internal.TargetPackage import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder +import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Companion.TypeString import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Constructor import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Modifier.INFIX import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Modifier.INTERNAL @@ -14,8 +15,12 @@ import com.sdds.plugin.themebuilder.internal.generator.ColorTokenGenerator.Compa import com.sdds.plugin.themebuilder.internal.generator.SimpleBaseGenerator import com.sdds.plugin.themebuilder.internal.generator.data.ColorTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.mergedLightAndDark +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.asClassName import com.squareup.kotlinpoet.asTypeName /** @@ -33,7 +38,7 @@ internal class ComposeColorAttributeGenerator( private val packageResolver: PackageResolver, ) : SimpleBaseGenerator { - private var tokenData: ColorTokenResult.TokenData? = null + private var tokenData: Map = emptyMap() private val colorAttributes = mutableSetOf() private val colorKtFileBuilder by unsafeLazy { @@ -47,8 +52,6 @@ internal class ComposeColorAttributeGenerator( } override fun generate() { - tokenData ?: return - addImports() addColorsClass() addUpdateColorsFromFun() @@ -56,16 +59,20 @@ internal class ComposeColorAttributeGenerator( addMutableMapExtension() addLightColorsFun() addDarkColorsFun() + addLightTenants() + addDarkTenants() addColorOverrideScopeClass() + addColorAttrOverrideScopeClass() addObtainStateFun() colorKtFileBuilder.build(outputLocation) } - fun setColorTokenData(data: ColorTokenResult.TokenData) { + fun setColorTokenData(data: Map) { tokenData = data + val defaultTenantData = data[Tenant.Default] ?: return colorAttributes.clear() - colorAttributes.addAll(data.mergedLightAndDark()) + colorAttributes.addAll(defaultTenantData.mergedLightAndDark()) } private fun addColorsClass() { @@ -92,7 +99,7 @@ internal class ComposeColorAttributeGenerator( typeName = KtFileBuilder.TypeColor, isMutable = true, delegate = "colors.obtain(\"$color\")", - description = tokenData?.description(color), + description = tokenData[Tenant.Default]?.description(color), ) } @@ -117,6 +124,29 @@ internal class ComposeColorAttributeGenerator( description = "Возвращает копию [$colorClassName]. " + "Предоставляет возможность переопределять цвета.", ) + + rootColorsClass.appendFun( + name = "copyAttrs", + returnType = getInternalClassType(colorClassName), + params = listOf( + KtFileBuilder.FunParameter( + name = "overrideColors", + type = KtFileBuilder.getLambdaType( + receiver = colorKtFileBuilder.getInternalClassType("ColorAttrOverrideScope"), + ), + defValue = "{}", + ), + ), + body = listOf( + "val colorOverrideScope = ColorAttrOverrideScope()\n", + "overrideColors.invoke(colorOverrideScope)\n", + "val overrideMap = colorOverrideScope.overrideMap\n", + "return $colorClassName(colors.mapValues { colors[overrideMap[it.key]] ?: it.value })", + ), + modifiers = listOf(INTERNAL), + description = "Возвращает копию [$colorClassName]. " + + "Предоставляет возможность переопределять цвета.", + ) } } @@ -159,7 +189,73 @@ internal class ComposeColorAttributeGenerator( ) } + private fun addLightTenants() { + tokenData + .filter { it.key != Tenant.Default } + .forEach { (tenant, data) -> + if (data.light.isNotEmpty()) { + colorKtFileBuilder.appendRootFun( + name = "light${camelThemeName}Colors${tenant.name}", + params = listOf( + KtFileBuilder.FunParameter( + name = "overrideColors", + type = KtFileBuilder.getLambdaType( + receiver = colorKtFileBuilder.getInternalClassType("ColorOverrideScope"), + ), + defValue = "{}", + ), + ), + returnType = colorClassType, + body = listOf( + "return light${camelThemeName}Colors {\n", + data.light.entries.joinToString(separator = "\n") { + "${it.key} overrideBy LightColorTokens${tenant.name}.${it.value.colorRef}" + }, + "\noverrideColors()", + "\n}", + ), + description = "Цвета [$colorClassName] для светлой темы в тенанте ${tenant.name}", + suppressAnnotations = listOf("LongMethod"), + ) + } + } + } + + private fun addDarkTenants() { + tokenData + .filter { it.key != Tenant.Default } + .forEach { (tenant, data) -> + if (data.dark.isNotEmpty()) { + colorKtFileBuilder.appendRootFun( + name = "dark${camelThemeName}Colors${tenant.name}", + params = listOf( + KtFileBuilder.FunParameter( + name = "overrideColors", + type = KtFileBuilder.getLambdaType( + receiver = colorKtFileBuilder.getInternalClassType("ColorOverrideScope"), + ), + defValue = "{}", + ), + ), + returnType = colorClassType, + body = listOf( + "return dark${camelThemeName}Colors {\n", + data.light.entries.joinToString(separator = "\n") { + "${it.key} overrideBy DarkColorTokens${tenant.name}.${it.value.colorRef}" + }, + "\noverrideColors()", + "\n}", + ), + description = "Цвета [$colorClassName] для темной темы в тенанте ${tenant.name}", + suppressAnnotations = listOf("LongMethod"), + ) + } + } + } + private fun addLightColorsFun() { + val defaultTokenData = tokenData[Tenant.Default] + ?: throw ThemeBuilderException("color token data must be presented for default tenant") colorKtFileBuilder.appendRootFun( name = "light${camelThemeName}Colors", params = listOf( @@ -178,11 +274,11 @@ internal class ComposeColorAttributeGenerator( "val overwrite = colorOverrideScope.overrideMap\n", "val initial = mutableMapOf()\n", colorAttributes.joinToString(separator = "\n") { - val defaultValue = if (tokenData?.light?.get(it)?.colorRef != null) { - "LightColorTokens.${tokenData?.light?.get(it)?.colorRef}" + val defaultValue = if (defaultTokenData.light[it]?.colorRef != null) { + "LightColorTokens.${defaultTokenData.light[it]?.colorRef}" } else { "DarkColorTokens.${ - tokenData?.dark?.get(it)?.colorRef ?: throw ThemeBuilderException( + defaultTokenData.dark[it]?.colorRef ?: throw ThemeBuilderException( "Can't find token value for color $it", ) }" @@ -197,6 +293,8 @@ internal class ComposeColorAttributeGenerator( } private fun addDarkColorsFun() { + val defaultTokenData = tokenData[Tenant.Default] + ?: throw ThemeBuilderException("color token data must be presented for default tenant") colorKtFileBuilder.appendRootFun( name = "dark${camelThemeName}Colors", params = listOf( @@ -215,11 +313,11 @@ internal class ComposeColorAttributeGenerator( "val overwrite = colorOverrideScope.overrideMap\n", "val initial = mutableMapOf()\n", colorAttributes.joinToString(separator = "\n") { - val defaultValue = if (tokenData?.dark?.get(it)?.colorRef != null) { - "DarkColorTokens.${tokenData?.dark?.get(it)?.colorRef}" + val defaultValue = if (defaultTokenData.dark[it]?.colorRef != null) { + "DarkColorTokens.${defaultTokenData.dark[it]?.colorRef}" } else { "LightColorTokens.${ - tokenData?.light?.get(it)?.colorRef ?: throw ThemeBuilderException( + defaultTokenData.light[it]?.colorRef ?: throw ThemeBuilderException( "Can't find token value for color $it", ) }" @@ -255,14 +353,14 @@ internal class ComposeColorAttributeGenerator( body = "return _overrideMap.toMap()", ), ) - + val defaultTokenData = tokenData[Tenant.Default] colorAttributes.forEach { color -> rootColorsClass.appendProperty( name = color, typeName = KtFileBuilder.TypeString, isMutable = false, initializer = "\"$color\"", - description = tokenData?.description(color), + description = defaultTokenData?.description(color), ) } @@ -279,6 +377,58 @@ internal class ComposeColorAttributeGenerator( } } + private fun addColorAttrOverrideScopeClass() { + with(colorKtFileBuilder) { + val rootColorsClass = rootClass( + name = "ColorAttrOverrideScope", + description = "Скоуп переопределения цветов по арибутам", + modifiers = listOf(INTERNAL), + ) + val mutableMapType = ClassName( + "kotlin.collections", + "MutableMap", + ).parameterizedBy(TypeString, TypeString) + val mapType = Map::class.asClassName().parameterizedBy(TypeString, TypeString) + + rootColorsClass.appendProperty( + name = "_overrideMap", + typeName = mutableMapType, + initializer = "mutableMapOf()", + modifiers = listOf(PRIVATE), + ) + + rootColorsClass.appendProperty( + name = "overrideMap", + typeName = mapType, + modifiers = listOf(INTERNAL), + propGetter = KtFileBuilder.Getter.Annotated( + body = "return _overrideMap.toMap()", + ), + ) + val defaultTokenData = tokenData[Tenant.Default] + colorAttributes.forEach { color -> + rootColorsClass.appendProperty( + name = color, + typeName = KtFileBuilder.TypeString, + isMutable = false, + initializer = "\"$color\"", + description = defaultTokenData?.description(color), + ) + } + + rootColorsClass.appendFun( + name = "overrideBy", + params = listOf( + KtFileBuilder.FunParameter("color", type = KtFileBuilder.TypeString), + ), + modifiers = listOf(INFIX), + receiver = KtFileBuilder.TypeString, + body = listOf("_overrideMap[this] = color"), + description = "Переопределяет аттрибут цвета.", + ) + } + } + private fun addLocalColorsVal() { colorKtFileBuilder.appendRootVal( name = "Local$colorClassName", @@ -310,22 +460,23 @@ internal class ComposeColorAttributeGenerator( packageName = "androidx.compose.ui.graphics", names = listOf("Color"), ) - val tokenData = tokenData ?: return - if (tokenData.dark.isNotEmpty()) { - addImport( - getInternalClassType( - className = DARK_COLOR_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) - } - if (tokenData.light.isNotEmpty()) { - addImport( - getInternalClassType( - className = LIGHT_COLOR_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) + tokenData.forEach { (tenant, data) -> + if (data.dark.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${DARK_COLOR_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } + if (data.light.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${LIGHT_COLOR_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } } } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeGradientAttributeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeGradientAttributeGenerator.kt index 4d0ac5d31a..bb4831b80e 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeGradientAttributeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeGradientAttributeGenerator.kt @@ -3,11 +3,13 @@ package com.sdds.plugin.themebuilder.internal.generator.theme.compose import com.sdds.plugin.themebuilder.internal.PackageResolver import com.sdds.plugin.themebuilder.internal.TargetPackage import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder +import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Companion.TypeString import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Companion.nullable import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Constructor import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.FunParameter import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Getter import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Modifier +import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Modifier.INFIX import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder.Modifier.INTERNAL import com.sdds.plugin.themebuilder.internal.exceptions.ThemeBuilderException import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory @@ -16,8 +18,12 @@ import com.sdds.plugin.themebuilder.internal.generator.GradientTokenGenerator.Co import com.sdds.plugin.themebuilder.internal.generator.SimpleBaseGenerator import com.sdds.plugin.themebuilder.internal.generator.data.GradientTokenResult.ComposeTokenData import com.sdds.plugin.themebuilder.internal.generator.data.mergedLightAndDark +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.asClassName /** * Генератор Compose-атрибутов градиента. @@ -34,7 +40,7 @@ internal class ComposeGradientAttributeGenerator( private val packageResolver: PackageResolver, ) : SimpleBaseGenerator { - private var tokenData: ComposeTokenData? = null + private var tokenData: Map = emptyMap() private val gradientAttributes = mutableSetOf() private val gradientKtFileBuilder: KtFileBuilder by unsafeLazy { @@ -47,17 +53,16 @@ internal class ComposeGradientAttributeGenerator( gradientKtFileBuilder.getInternalClassType(gradientClassName) } - fun setGradientTokenData(data: ComposeTokenData) { + fun setGradientTokenData(data: Map) { tokenData = data + val defaultTenantData = data[Tenant.Default] ?: return gradientAttributes.clear() - gradientAttributes.addAll(data.mergedLightAndDark()) + gradientAttributes.addAll(defaultTenantData.mergedLightAndDark()) } override fun generate() { - tokenData ?: return - + if (tokenData.isEmpty()) return createGradientsFile() - gradientKtFileBuilder.build(outputLocation) } @@ -66,8 +71,11 @@ internal class ComposeGradientAttributeGenerator( addGradientsClass() addMutableMapExtension() addLightGradientsFun() + addLightTenants() addDarkGradientsFun() + addDarkTenants() addGradientOverrideScopeClass() + addGradientAttrOverrideScopeClass() addLinearGradientFun() addRadialGradientFun() addSweepGradientFun() @@ -102,22 +110,23 @@ internal class ComposeGradientAttributeGenerator( names = listOf("Gradients"), ) addImport(KtFileBuilder.TypeOffset) - val tokenData = tokenData ?: return - if (tokenData.dark.isNotEmpty()) { - addImport( - getInternalClassType( - className = DARK_GRADIENT_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) - } - if (tokenData.light.isNotEmpty()) { - addImport( - getInternalClassType( - className = LIGHT_GRADIENT_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) + tokenData.forEach { (tenant, data) -> + if (data.dark.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${DARK_GRADIENT_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } + if (data.light.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${LIGHT_GRADIENT_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } } } } @@ -145,7 +154,7 @@ internal class ComposeGradientAttributeGenerator( name = gradient, typeName = KtFileBuilder.TypeListOfShaderBrush, delegate = "gradients", - description = tokenData?.description(gradient).orEmpty(), + description = tokenData[Tenant.Default]?.description(gradient).orEmpty(), ) } @@ -170,6 +179,29 @@ internal class ComposeGradientAttributeGenerator( description = "Возвращает копию [$gradientClassName]. " + "Предоставляет возможность переопределять градиенты.", ) + + rootGradientClass.appendFun( + name = "copyAttrs", + returnType = getInternalClassType(gradientClassName), + params = listOf( + KtFileBuilder.FunParameter( + name = "overrideGradients", + type = KtFileBuilder.getLambdaType( + receiver = gradientKtFileBuilder.getInternalClassType("GradientAttrOverrideScope"), + ), + defValue = "{}", + ), + ), + body = listOf( + "val gradientOverrideScope = GradientAttrOverrideScope()\n", + "overrideGradients.invoke(gradientOverrideScope)\n", + "val overrideMap = gradientOverrideScope.overrideMap\n", + "return $gradientClassName(gradients.mapValues { gradients[overrideMap[it.key]] ?: it.value })", + ), + modifiers = listOf(INTERNAL), + description = "Возвращает копию [$gradientClassName]. " + + "Предоставляет возможность переопределять цвета.", + ) } } @@ -210,6 +242,70 @@ internal class ComposeGradientAttributeGenerator( ) } + private fun addLightTenants() { + tokenData + .filter { it.key != Tenant.Default } + .forEach { (tenant, data) -> + if (data.light.isNotEmpty()) { + gradientKtFileBuilder.appendRootFun( + name = "light${camelThemeName}Gradients${tenant.name}", + params = listOf( + KtFileBuilder.FunParameter( + name = "overrideGradients", + type = KtFileBuilder.getLambdaType( + receiver = gradientKtFileBuilder.getInternalClassType("GradientOverrideScope"), + ), + defValue = "{}", + ), + ), + returnType = gradientClassType, + body = listOf( + "return light${camelThemeName}Gradients {\n", + data.light.entries.joinToString(separator = "\n") { + "${it.key} overrideBy ${lightGradientValue(it.key, tenant)}" + }, + "\noverrideGradients()", + "\n}", + ), + description = "Градиенты [$gradientClassName] для светлой темы в тенанте ${tenant.name}", + suppressAnnotations = listOf("LongMethod"), + ) + } + } + } + + private fun addDarkTenants() { + tokenData + .filter { it.key != Tenant.Default } + .forEach { (tenant, data) -> + if (data.dark.isNotEmpty()) { + gradientKtFileBuilder.appendRootFun( + name = "dark${camelThemeName}Gradients${tenant.name}", + params = listOf( + KtFileBuilder.FunParameter( + name = "overrideGradients", + type = KtFileBuilder.getLambdaType( + receiver = gradientKtFileBuilder.getInternalClassType("GradientOverrideScope"), + ), + defValue = "{}", + ), + ), + returnType = gradientClassType, + body = listOf( + "return dark${camelThemeName}Gradients {\n", + data.light.entries.joinToString(separator = "\n") { + "${it.key} overrideBy ${darkGradientValue(it.key, tenant)}" + }, + "\noverrideGradients()", + "\n}", + ), + description = "Градиенты [$gradientClassName] для темной темы в тенанте ${tenant.name}", + suppressAnnotations = listOf("LongMethod"), + ) + } + } + } + private fun addLightGradientsFun() { gradientKtFileBuilder.appendRootFun( name = "light${camelThemeName}Gradients", @@ -229,7 +325,7 @@ internal class ComposeGradientAttributeGenerator( "val overwrite = gradientOverrideScope.overrideMap\n", "val initial = mutableMapOf>()\n", gradientAttributes.joinToString(separator = "\n") { - val defaultValue = defaultLightGradientValue(it) + val defaultValue = lightGradientValue(it, Tenant.Default) "initial.add(\"$it\", $defaultValue, overwrite)" }, "\nreturn $gradientClassName(initial)", @@ -239,51 +335,36 @@ internal class ComposeGradientAttributeGenerator( ) } - private fun defaultLightGradientValue(attrName: String): String { - val lightLayers = tokenData?.light?.get(attrName) - val darkLayers = tokenData?.dark?.get(attrName) + private fun lightGradientValue(attrName: String, tenant: Tenant): String { + val data = tokenData[tenant] + val lightLayers = data?.light?.get(attrName) + val darkLayers = data?.dark?.get(attrName) - val parameters: List - val objectName: String - - if (lightLayers != null) { - parameters = lightLayers - objectName = "LightGradientTokens" - } else { - parameters = darkLayers - ?: throw ThemeBuilderException("Can't find token value for gradient $attrName") - objectName = "DarkGradientTokens" - } + val parameters: List = lightLayers + ?: darkLayers + ?: throw ThemeBuilderException("Can't find token value for gradient $attrName") return KtFileBuilder.createFunCall( "listOf", - parameters.map { createGradientFabricCall(objectName, it) }, + parameters.map { createGradientFabricCall(it) }, ) } - private fun defaultDarkGradientValue(attrName: String): String { - val lightLayers = tokenData?.light?.get(attrName) - val darkLayers = tokenData?.dark?.get(attrName) - - val parameters: List - val objectName: String + private fun darkGradientValue(attrName: String, tenant: Tenant): String { + val data = tokenData[tenant] + val lightLayers = data?.light?.get(attrName) + val darkLayers = data?.dark?.get(attrName) - if (darkLayers != null) { - parameters = darkLayers - objectName = "DarkGradientTokens" - } else { - parameters = lightLayers - ?: throw ThemeBuilderException("Can't find token value for gradient $attrName") - objectName = "LightGradientTokens" - } + val parameters: List = darkLayers + ?: lightLayers + ?: throw ThemeBuilderException("Can't find token value for gradient $attrName") return KtFileBuilder.createFunCall( "listOf", - parameters.map { createGradientFabricCall(objectName, it) }, + parameters.map { createGradientFabricCall(it) }, ) } private fun createGradientFabricCall( - objectName: String, gradient: ComposeTokenData.Gradient, ): String { val funName = when (gradient.gradientType) { @@ -294,7 +375,7 @@ internal class ComposeGradientAttributeGenerator( } return KtFileBuilder.createFunCall( funName = funName, - parameters = gradient.tokenRefs.map { "$objectName.$it" }, + parameters = gradient.tokenRefs.map { "${gradient.tokenObjectName}.$it" }, ) } @@ -317,7 +398,7 @@ internal class ComposeGradientAttributeGenerator( "val overwrite = gradientOverrideScope.overrideMap\n", "val initial = mutableMapOf>()\n", gradientAttributes.joinToString(separator = "\n") { - val defaultValue = defaultDarkGradientValue(it) + val defaultValue = darkGradientValue(it, Tenant.Default) "initial.add(\"$it\", $defaultValue, overwrite)" }, "\nreturn $gradientClassName(initial)", @@ -354,7 +435,7 @@ internal class ComposeGradientAttributeGenerator( typeName = KtFileBuilder.TypeString, isMutable = false, initializer = "\"$gradient\"", - description = tokenData?.description(gradient), + description = tokenData[Tenant.Default]?.description(gradient), ) } @@ -371,6 +452,55 @@ internal class ComposeGradientAttributeGenerator( } } + private fun addGradientAttrOverrideScopeClass() { + with(gradientKtFileBuilder) { + val rootColorsClass = rootClass( + name = "GradientAttrOverrideScope", + description = "Скоуп переопределения градиентов", + ) + val mutableMapType = ClassName( + "kotlin.collections", + "MutableMap", + ).parameterizedBy(TypeString, TypeString) + val mapType = Map::class.asClassName().parameterizedBy(TypeString, TypeString) + + rootColorsClass.appendProperty( + name = "_overrideMap", + typeName = mutableMapType, + initializer = "mutableMapOf()", + modifiers = listOf(Modifier.PRIVATE), + ) + + rootColorsClass.appendProperty( + name = "overrideMap", + typeName = mapType, + modifiers = listOf(INTERNAL), + propGetter = Getter.Annotated(body = "return _overrideMap.toMap()"), + ) + + gradientAttributes.forEach { gradient -> + rootColorsClass.appendProperty( + name = gradient, + typeName = KtFileBuilder.TypeString, + isMutable = false, + initializer = "\"$gradient\"", + description = tokenData[Tenant.Default]?.description(gradient), + ) + } + + rootColorsClass.appendFun( + name = "overrideBy", + params = listOf( + FunParameter("gradient", type = KtFileBuilder.TypeString), + ), + modifiers = listOf(INFIX), + receiver = KtFileBuilder.TypeString, + body = listOf("_overrideMap[this] = gradient"), + description = "Переопределяет аттрибут градиента.", + ) + } + } + private fun addLinearGradientFun() { gradientKtFileBuilder.appendRootFun( name = "linearGradient", diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShadowAttributeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShadowAttributeGenerator.kt index eb8dd1bcc5..292c2f3cfd 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShadowAttributeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShadowAttributeGenerator.kt @@ -11,6 +11,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.ShadowTokenGenerator.Companion.SHADOW_TOKENS_NAME import com.sdds.plugin.themebuilder.internal.generator.SimpleBaseGenerator import com.sdds.plugin.themebuilder.internal.generator.data.ShadowTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.decapitalized import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.techToCamelCase @@ -31,7 +32,7 @@ internal class ComposeShadowAttributeGenerator( private val dimensionsConfig: DimensionsConfig, private val packageResolver: PackageResolver, ) : SimpleBaseGenerator { - private val shadows = mutableListOf() + private val shadows: MutableMap> = mutableMapOf() private val shadowKtFileBuilder by unsafeLazy { ktFileBuilderFactory.create(shadowClassName, TargetPackage.THEME) @@ -43,17 +44,18 @@ internal class ComposeShadowAttributeGenerator( shadowKtFileBuilder.getInternalClassType(shadowClassName) } - fun setShadowTokenData(shadows: List) { + fun setShadowTokenData(shadows: Map>) { this.shadows.clear() - this.shadows.addAll(shadows) + this.shadows.putAll(shadows) } override fun generate() { if (shadows.isEmpty()) return + val defaultShadows = shadows[Tenant.Default] ?: return addImports() addShadowClassFactoryFun() - addShadowClass(shadows) + addShadowClass(defaultShadows) addLocalShadowsVal() shadowKtFileBuilder.build(outputLocation) @@ -107,36 +109,46 @@ internal class ComposeShadowAttributeGenerator( addImport(KtFileBuilder.TypeShadowAppearance) addImport(KtFileBuilder.TypeShadowLayer) addImport(KtFileBuilder.TypeDpOffset) - addImport( - getInternalClassType( - className = SHADOW_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) + shadows.keys.forEach { tenant -> + addImport( + getInternalClassType( + className = "${SHADOW_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } } } - private fun addShadowClassFactoryFun() = with(shadowKtFileBuilder) { - appendRootFun( - name = "default$shadowClassName", - returnType = shadowClassType, - body = listOf( - KtFileBuilder.createConstructorCall( - constructorName = shadowClassName, - initializers = shadows.map { - """ + private fun addShadowClassFactoryFun() { + val defaultShadows = shadows[Tenant.Default] ?: return + shadows + .forEach { (tenant, data) -> + val shadowList = (defaultShadows + data) + .associateBy { it.tokenTechName } + .values + .toList() + shadowKtFileBuilder.appendRootFun( + name = "default$shadowClassName${tenant.name}", + returnType = shadowClassType, + body = listOf( + KtFileBuilder.createConstructorCall( + constructorName = shadowClassName, + initializers = shadowList.map { + """ ${it.tokenTechName.attributeName()} = ${createShadowAppearanceCall(it.layers)} - """.trimIndent() - }.toTypedArray(), - ).let { "return $it" }, - ), - description = "Возвращает [$shadowClassName]", - annotations = listOf( - KtFileBuilder.TypeAnnotationComposable, - KtFileBuilder.TypeAnnotationReadOnlyComposable, - ).takeIf { dimensionsConfig.fromResources }, - suppressAnnotations = listOf("LongMethod"), - ) + """.trimIndent() + }.toTypedArray(), + ).let { "return $it" }, + ), + description = "Возвращает [$shadowClassName]", + annotations = listOf( + KtFileBuilder.TypeAnnotationComposable, + KtFileBuilder.TypeAnnotationReadOnlyComposable, + ).takeIf { dimensionsConfig.fromResources }, + suppressAnnotations = listOf("LongMethod"), + ) + } } private companion object { diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShapeAttributeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShapeAttributeGenerator.kt index c59fb489e0..8716516d19 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShapeAttributeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeShapeAttributeGenerator.kt @@ -11,6 +11,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.ShapeTokenGenerator.Companion.ROUND_SHAPE_TOKENS_NAME import com.sdds.plugin.themebuilder.internal.generator.SimpleBaseGenerator import com.sdds.plugin.themebuilder.internal.generator.data.ShapeTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy @@ -29,7 +30,7 @@ internal class ComposeShapeAttributeGenerator( private val dimensionsConfig: DimensionsConfig, private val packageResolver: PackageResolver, ) : SimpleBaseGenerator { - private val shapes = mutableListOf() + private val shapes = mutableMapOf>() private val shapeKtFileBuilder by unsafeLazy { ktFileBuilderFactory.create(shapeClassName, TargetPackage.THEME) @@ -41,17 +42,18 @@ internal class ComposeShapeAttributeGenerator( shapeKtFileBuilder.getInternalClassType(shapeClassName) } - fun setShapeTokenData(shapes: List) { + fun setShapeTokenData(shapes: Map>) { this.shapes.clear() - this.shapes.addAll(shapes) + this.shapes.putAll(shapes) } override fun generate() { if (shapes.isEmpty()) return + val defaultShapes = shapes[Tenant.Default] ?: return addImports() addShapeClassFactoryFun() - addShapesClass(shapes) + addShapesClass(defaultShapes) addLocalShapesVal() shapeKtFileBuilder.build(outputLocation) @@ -103,32 +105,41 @@ internal class ComposeShapeAttributeGenerator( ), ) addImport(KtFileBuilder.TypeRoundRectShape) - addImport( - getInternalClassType( - className = ROUND_SHAPE_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) + shapes.keys.forEach { tenant -> + addImport( + getInternalClassType( + className = "${ROUND_SHAPE_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } } } private fun addShapeClassFactoryFun() = with(shapeKtFileBuilder) { - appendRootFun( - name = "default$shapeClassName", - returnType = shapeClassType, - body = listOf( - KtFileBuilder.createConstructorCall( - constructorName = shapeClassName, - initializers = shapes.map { - "${it.attrName} = RoundShapeTokens.${it.tokenRefName}" - }.toTypedArray(), - ).let { "return $it" }, - ), - description = "Возвращает [$shapeClassName]", - annotations = listOf( - KtFileBuilder.TypeAnnotationComposable, - KtFileBuilder.TypeAnnotationReadOnlyComposable, - ).takeIf { dimensionsConfig.fromResources }, - ) + val defaultShapes = shapes[Tenant.Default] ?: return + shapes.forEach { (tenant, data) -> + val shapeList = (defaultShapes + data) + .associateBy { it.attrName } + .values + .toList() + appendRootFun( + name = "default$shapeClassName${tenant.name}", + returnType = shapeClassType, + body = listOf( + KtFileBuilder.createConstructorCall( + constructorName = shapeClassName, + initializers = shapeList.map { + "${it.attrName} = ${it.tokenObjectName}.${it.tokenRefName}" + }.toTypedArray(), + ).let { "return $it" }, + ), + description = "Возвращает [$shapeClassName]", + annotations = listOf( + KtFileBuilder.TypeAnnotationComposable, + KtFileBuilder.TypeAnnotationReadOnlyComposable, + ).takeIf { dimensionsConfig.fromResources }, + ) + } } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSpacingAttributeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSpacingAttributeGenerator.kt index 1af7689ad4..f1c1268b9e 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSpacingAttributeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSpacingAttributeGenerator.kt @@ -11,6 +11,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.SimpleBaseGenerator import com.sdds.plugin.themebuilder.internal.generator.SpacingTokenGenerator.Companion.SPACING_TOKENS_NAME import com.sdds.plugin.themebuilder.internal.generator.data.SpacingTokenResult +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy @@ -29,7 +30,7 @@ internal class ComposeSpacingAttributeGenerator( private val dimensionsConfig: DimensionsConfig, private val packageResolver: PackageResolver, ) : SimpleBaseGenerator { - private val spacing = mutableListOf() + private val spacing = mutableMapOf>() private val spacingKtFileBuilder by unsafeLazy { ktFileBuilderFactory.create(spacingClassName, TargetPackage.THEME) @@ -41,17 +42,18 @@ internal class ComposeSpacingAttributeGenerator( spacingKtFileBuilder.getInternalClassType(spacingClassName) } - fun setSpacingTokenData(spacing: List) { + fun setSpacingTokenData(spacing: Map>) { this.spacing.clear() - this.spacing.addAll(spacing) + this.spacing.putAll(spacing) } override fun generate() { if (spacing.isEmpty()) return + val defaultSpacing = spacing[Tenant.Default] ?: return addImports() addSpacingClassFactoryFun() - addSpacingClass(spacing) + addSpacingClass(defaultSpacing) addLocalSpacingVal() spacingKtFileBuilder.build(outputLocation) @@ -104,32 +106,41 @@ internal class ComposeSpacingAttributeGenerator( ) addImport(KtFileBuilder.TypeDp) addImport(KtFileBuilder.TypeDpExtension) - addImport( - getInternalClassType( - className = SPACING_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) + spacing.keys.forEach { tenant -> + addImport( + getInternalClassType( + className = "${SPACING_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } } } private fun addSpacingClassFactoryFun() = with(spacingKtFileBuilder) { - appendRootFun( - name = "default$spacingClassName", - returnType = spacingClassType, - body = listOf( - KtFileBuilder.createConstructorCall( - constructorName = spacingClassName, - initializers = spacing.map { - "${it.attrName} = $SPACING_TOKENS_NAME.${it.tokenRefName}" - }.toTypedArray(), - ).let { "return $it" }, - ), - description = "Возвращает [$spacingClassName]", - annotations = listOf( - KtFileBuilder.TypeAnnotationComposable, - KtFileBuilder.TypeAnnotationReadOnlyComposable, - ).takeIf { dimensionsConfig.fromResources }, - ) + val defaultSpacing = spacing[Tenant.Default] ?: return + spacing.forEach { (tenant, data) -> + val spacingList = (defaultSpacing + data) + .associateBy { it.attrName } + .values + .toList() + appendRootFun( + name = "default$spacingClassName${tenant.name}", + returnType = spacingClassType, + body = listOf( + KtFileBuilder.createConstructorCall( + constructorName = spacingClassName, + initializers = spacingList.map { + "${it.attrName} = ${it.tokenObjectName}.${it.tokenRefName}" + }.toTypedArray(), + ).let { "return $it" }, + ), + description = "Возвращает [$spacingClassName]", + annotations = listOf( + KtFileBuilder.TypeAnnotationComposable, + KtFileBuilder.TypeAnnotationReadOnlyComposable, + ).takeIf { dimensionsConfig.fromResources }, + ) + } } } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSubThemeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSubThemeGenerator.kt index e2bcab46e8..5ba2afbfc5 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSubThemeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeSubThemeGenerator.kt @@ -10,9 +10,9 @@ import com.sdds.plugin.themebuilder.internal.generator.data.GradientTokenResult. import com.sdds.plugin.themebuilder.internal.generator.theme.OverrideToken import com.sdds.plugin.themebuilder.internal.generator.theme.SubTheme import com.sdds.plugin.themebuilder.internal.generator.theme.overriddenBySubTheme +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ColorToken import com.sdds.plugin.themebuilder.internal.token.GradientToken -import com.sdds.plugin.themebuilder.internal.token.isDark import com.sdds.plugin.themebuilder.internal.utils.decapitalized import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase @@ -28,16 +28,16 @@ internal class ComposeSubThemeGenerator( private val colorSubThemes: MutableMap> = mutableMapOf() private val gradientsSubThemes: MutableMap> = mutableMapOf() - private var colorTokenData: ColorTokenResult.TokenData? = null - private var gradientTokenData: ComposeTokenData? = null + private var colorTokenData: Map = emptyMap() + private var gradientTokenData: Map = emptyMap() private val themePackage = packageResolver.getPackage(TargetPackage.THEME) - fun setColorTokens(tokens: List, data: ColorTokenResult.TokenData) { + fun setColorTokens(tokens: List, data: Map) { colorTokenData = data colorSubThemes.putAll(tokens.overriddenBySubTheme()) } - fun setGradientTokens(tokens: List, data: ComposeTokenData) { + fun setGradientTokens(tokens: List, data: Map) { gradientTokenData = data gradientsSubThemes.putAll(tokens.overriddenBySubTheme()) } @@ -52,14 +52,12 @@ internal class ComposeSubThemeGenerator( addImports() val colorAttrs = colorSubThemes[subTheme] ?: emptyList() if (colorAttrs.isNotEmpty()) { - addSubThemeColorsVal(subTheme, true, colorAttrs) - addSubThemeColorsVal(subTheme, false, colorAttrs) + addSubThemeColorsVal(subTheme, colorAttrs) } val gradientAttrs = gradientsSubThemes[subTheme] ?: emptyList() if (gradientAttrs.isNotEmpty()) { - addSubThemeGradientsVal(subTheme, true, gradientAttrs) - addSubThemeGradientsVal(subTheme, false, gradientAttrs) + addSubThemeGradientsVal(subTheme, gradientAttrs) } addSubTheme(subTheme, colorAttrs.isNotEmpty(), gradientAttrs.isNotEmpty()) @@ -70,20 +68,8 @@ internal class ComposeSubThemeGenerator( private fun KtFileBuilder.addImports() { addImport("androidx.compose.foundation", listOf("isSystemInDarkTheme")) - val tokensPackage = packageResolver.getPackage(TargetPackage.TOKENS) - addImport(getInternalClassType("DarkColorTokens", tokensPackage)) - addImport(getInternalClassType("DarkGradientTokens", tokensPackage)) - addImport(getInternalClassType("LightColorTokens", tokensPackage)) - addImport(getInternalClassType("LightGradientTokens", tokensPackage)) - - addImport(getInternalClassType("dark${camelCaseThemeName}Colors", themePackage)) - addImport(getInternalClassType("light${camelCaseThemeName}Colors", themePackage)) - addImport(getInternalClassType("dark${camelCaseThemeName}Gradients", themePackage)) - addImport(getInternalClassType("light${camelCaseThemeName}Gradients", themePackage)) - addImport(getInternalClassType("linearGradient", themePackage)) - addImport(getInternalClassType("radialGradient", themePackage)) - addImport(getInternalClassType("sweepGradient", themePackage)) - addImport(getInternalClassType("singleColor", themePackage)) + addImport(getInternalClassType("Local${camelCaseThemeName}Colors", themePackage)) + addImport(getInternalClassType("Local${camelCaseThemeName}Gradients", themePackage)) } private fun KtFileBuilder.addSubTheme( @@ -113,38 +99,29 @@ internal class ComposeSubThemeGenerator( ) } - private fun getSubThemeColorsValName(isDark: Boolean, subTheme: SubTheme): String { - val prefix = if (isDark) "dark" else "light" - return "$prefix${subTheme.suffix}Colors" + private fun getSubThemeColorsValName(subTheme: SubTheme): String { + return "${subTheme.suffix}ColorsOverride" } - private fun getSubThemeGradientValName(isDark: Boolean, subTheme: SubTheme): String { - val prefix = if (isDark) "dark" else "light" - return "$prefix${subTheme.suffix}Gradients" + private fun getSubThemeGradientsValName(subTheme: SubTheme): String { + return "${subTheme.suffix}GradientsOverride" } private fun KtFileBuilder.addSubThemeGradientsVal( subTheme: SubTheme, - isDark: Boolean, attrs: List, ) { - val tokensClassName = if (isDark) "DarkGradientTokens" else "LightGradientTokens" - val builderPrefix = if (isDark) "dark" else "light" appendRootVal( - name = getSubThemeGradientValName(isDark, subTheme), - typeName = getInternalClassType( - "${camelCaseThemeName}Gradients", - packageResolver.getPackage(TargetPackage.THEME), + name = getSubThemeGradientsValName(subTheme), + typeName = KtFileBuilder.getLambdaType( + receiver = getInternalClassType(className = "GradientAttrOverrideScope", themePackage), ), modifiers = listOf(KtFileBuilder.Modifier.PRIVATE), lazy = true, initializer = buildString { - appendLine("$builderPrefix${camelCaseThemeName}Gradients {") + appendLine("{") attrs.forEach { - if (it.new.isDark == isDark) { - val valueReference = getGradientValueReference(tokensClassName, it.new.ktName, isDark) - appendLine("${it.old.ktName.decapitalized()}.overrideBy($valueReference)") - } + appendLine("${it.old.ktName.decapitalized()}.overrideBy(${it.new.ktName.decapitalized()})") } appendLine("}") }, @@ -153,109 +130,62 @@ internal class ComposeSubThemeGenerator( private fun KtFileBuilder.addSubThemeColorsVal( subTheme: SubTheme, - isDark: Boolean, attrs: List, ) { - val tokensClassName = if (isDark) "DarkColorTokens" else "LightColorTokens" - val builderPrefix = if (isDark) "dark" else "light" appendRootVal( - name = getSubThemeColorsValName(isDark, subTheme), - typeName = getInternalClassType( - "${camelCaseThemeName}Colors", - packageResolver.getPackage(TargetPackage.THEME), + name = getSubThemeColorsValName(subTheme), + typeName = KtFileBuilder.getLambdaType( + receiver = getInternalClassType(className = "ColorAttrOverrideScope", themePackage), ), modifiers = listOf(KtFileBuilder.Modifier.PRIVATE), lazy = true, initializer = buildString { - appendLine("$builderPrefix${camelCaseThemeName}Colors {") + appendLine("{") attrs.forEach { - if (it.new.isDark == isDark) { - val valueReference = getValueReference(it.new.ktName, isDark) - appendLine("${it.old.ktName.decapitalized()}.overrideBy($tokensClassName.$valueReference)") - } + appendLine("${it.old.ktName.decapitalized()}.overrideBy(${it.new.ktName.decapitalized()})") } appendLine("}") }, ) } - private fun getValueReference(attributeName: String, isDark: Boolean): String? { - return if (isDark) { - colorTokenData?.dark?.get(attributeName.decapitalized())?.colorRef - } else { - colorTokenData?.light?.get(attributeName.decapitalized())?.colorRef - } - } - - private fun getGradientValueReference(objectName: String, attributeName: String, isDark: Boolean): String? { - val params = if (isDark) { - gradientTokenData?.dark?.get(attributeName.decapitalized()) - } else { - gradientTokenData?.light?.get(attributeName.decapitalized()) - } - params ?: return null - - return KtFileBuilder.createFunCall( - "listOf", - params.map { createGradientFabricCall(objectName, it) }, - ) - } - - private fun createGradientFabricCall( - objectName: String, - gradient: ComposeTokenData.Gradient, - ): String { - val funName = when (gradient.gradientType) { - ComposeTokenData.GradientType.LINEAR -> "linearGradient" - ComposeTokenData.GradientType.RADIAL -> "radialGradient" - ComposeTokenData.GradientType.SWEEP -> "sweepGradient" - ComposeTokenData.GradientType.BACKGROUND -> "singleColor" - } - return KtFileBuilder.createFunCall( - funName = funName, - parameters = gradient.tokenRefs.map { "$objectName.$it" }, - ) - } - private fun buildDefaultSubThemeFunBody(): String = buildString { - appendLine("val colors = if (isDark) {") - appendLine("dark${camelCaseThemeName}Colors()") - appendLine("} else {") - appendLine("light${camelCaseThemeName}Colors()") - appendLine("}") - appendLine("val gradients = if (isDark) {") - appendLine("dark${camelCaseThemeName}Gradients()") - appendLine("} else {") - appendLine("light${camelCaseThemeName}Gradients()") - appendLine("}") - appendLine("$themeKtClassName(colors = colors, gradients = gradients, content = content)") + appendLine("val currentColors = Local${camelCaseThemeName}Colors.current") + appendLine("val currentGradients = Local${camelCaseThemeName}Gradients.current") + appendLine("$themeKtClassName(colors = currentColors, gradients = currentGradients, content = content)") } private fun buildSubThemeFunBody( subTheme: SubTheme, overrideColors: Boolean, - overrideGradient: Boolean, + overrideGradients: Boolean, ): String { return when (subTheme) { SubTheme.DEFAULT -> buildDefaultSubThemeFunBody() else -> buildString { if (overrideColors) { - appendLine("val colors = if (isDark) {") - appendLine(getSubThemeColorsValName(true, subTheme)) - appendLine("} else {") - appendLine(getSubThemeColorsValName(false, subTheme)) - appendLine("}") + appendLine("val currentColors = Local${camelCaseThemeName}Colors.current") + appendLine( + "val overrideColors = currentColors.copyAttrs(${ + getSubThemeColorsValName( + subTheme, + ) + })", + ) } - if (overrideGradient) { - appendLine("val gradients = if (isDark) {") - appendLine(getSubThemeGradientValName(true, subTheme)) - appendLine("} else {") - appendLine(getSubThemeGradientValName(false, subTheme)) - appendLine("}") + if (overrideGradients) { + appendLine("val currentGradients = Local${camelCaseThemeName}Gradients.current") + appendLine( + "val overrideGradients = currentGradients.copyAttrs(${ + getSubThemeGradientsValName( + subTheme, + ) + })", + ) } appendLine("$themeKtClassName(") - if (overrideColors) appendLine("colors = colors,") - if (overrideGradient) appendLine("gradients = gradients,") + if (overrideColors) appendLine("colors = overrideColors,") + if (overrideGradients) appendLine("gradients = overrideGradients,") appendLine("content = content,") appendLine(")") } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeThemeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeThemeGenerator.kt index 8f6e9a5d5f..f696755c2f 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeThemeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeThemeGenerator.kt @@ -10,6 +10,7 @@ import com.sdds.plugin.themebuilder.internal.generator.data.ColorTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.mergedLightAndDark import com.sdds.plugin.themebuilder.internal.generator.data.mergedScreenClasses +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy import com.squareup.kotlinpoet.ClassName @@ -230,14 +231,16 @@ internal class ComposeThemeGenerator( ) } - fun setColorTokenData(colors: ColorTokenResult.TokenData) { - val attrSet = colors.mergedLightAndDark() + fun setColorTokenData(colors: Map) { + val defaultTenantColors = colors[Tenant.Default] ?: return + val attrSet = defaultTenantColors.mergedLightAndDark() findDefaultSelectionColors(attrSet) findDefaultTextStyleColor(attrSet) } - fun setTypographyTokenData(typography: TypographyTokenResult.ComposeTokenData) { - val attrSet = typography.mergedScreenClasses() + fun setTypographyTokenData(typography: Map) { + val defaultTypography = typography[Tenant.Default] ?: return + val attrSet = defaultTypography.mergedScreenClasses() findDefaultTextStyle(attrSet) } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeTypographyAttributeGenerator.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeTypographyAttributeGenerator.kt index 8f2e61cc84..059abd6f53 100644 --- a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeTypographyAttributeGenerator.kt +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/compose/ComposeTypographyAttributeGenerator.kt @@ -14,6 +14,7 @@ import com.sdds.plugin.themebuilder.internal.generator.TypographyTokenGenerator. import com.sdds.plugin.themebuilder.internal.generator.TypographyTokenGenerator.Companion.TYPOGRAPHY_SMALL_TOKENS_NAME import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.mergedScreenClasses +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.TypographyToken.ScreenClass import com.sdds.plugin.themebuilder.internal.utils.snakeToCamelCase import com.sdds.plugin.themebuilder.internal.utils.unsafeLazy @@ -38,7 +39,7 @@ internal class ComposeTypographyAttributeGenerator( private val packageResolver: PackageResolver, ) : SimpleBaseGenerator { - private var tokenData: TypographyTokenResult.ComposeTokenData? = null + private var tokenData: Map = emptyMap() private val typographyAttributes = mutableSetOf() private val typographyKtFileBuilder by unsafeLazy { ktFileBuilderFactory.create(typographyClassName, TargetPackage.THEME) @@ -54,7 +55,7 @@ internal class ComposeTypographyAttributeGenerator( } override fun generate() { - tokenData ?: return + if (tokenData.isEmpty()) return createWindowSizeFile() addImports() @@ -69,10 +70,11 @@ internal class ComposeTypographyAttributeGenerator( typographyKtFileBuilder.build(outputLocation) } - fun setTypographyTokenData(data: TypographyTokenResult.ComposeTokenData) { + fun setTypographyTokenData(data: Map) { tokenData = data + val defaultTenantData = data[Tenant.Default] ?: return typographyAttributes.clear() - typographyAttributes.addAll(data.mergedScreenClasses()) + typographyAttributes.addAll(defaultTenantData.mergedScreenClasses()) } private fun createWindowSizeFile() { @@ -95,30 +97,31 @@ internal class ComposeTypographyAttributeGenerator( ), ) addImport(KtFileBuilder.TypeDpExtension) - val tokenData = tokenData ?: return - if (tokenData.small.isNotEmpty()) { - addImport( - getInternalClassType( - className = TYPOGRAPHY_SMALL_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) - } - if (tokenData.medium.isNotEmpty()) { - addImport( - getInternalClassType( - className = TYPOGRAPHY_MEDIUM_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) - } - if (tokenData.large.isNotEmpty()) { - addImport( - getInternalClassType( - className = TYPOGRAPHY_LARGE_TOKENS_NAME, - classPackage = packageResolver.getPackage(TargetPackage.TOKENS), - ), - ) + tokenData.forEach { (tenant, data) -> + if (data.small.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${TYPOGRAPHY_SMALL_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } + if (data.medium.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${TYPOGRAPHY_MEDIUM_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } + if (data.large.isNotEmpty()) { + addImport( + getInternalClassType( + className = "${TYPOGRAPHY_LARGE_TOKENS_NAME}${tenant.name}", + classPackage = packageResolver.getPackage(TargetPackage.TOKENS), + ), + ) + } } } } @@ -138,23 +141,28 @@ internal class ComposeTypographyAttributeGenerator( } private fun addDynamicTypographyFun() { - typographyKtFileBuilder.appendRootFun( - name = "dynamic$typographyClassName", - annotations = listOf(KtFileBuilder.TypeAnnotationComposable), - returnType = typographyClassType, - body = listOf( - """ + tokenData.forEach { (tenant, data) -> + val largeFunCall = "large$typographyClassName${tenant.name}()" + val mediumFunCall = "medium$typographyClassName${tenant.name}()" + val smallFunCall = "small$typographyClassName${tenant.name}()" + typographyKtFileBuilder.appendRootFun( + name = "dynamic$typographyClassName${tenant.name}", + annotations = listOf(KtFileBuilder.TypeAnnotationComposable), + returnType = typographyClassType, + body = listOf( + """ |val widthClass = collectWindowSizeInfoAsState().value.widthClass |return when (widthClass) { - | ${KtFileBuilder.DEFAULT_FILE_INDENT}WindowSizeClass.Expanded -> large$typographyClassName() - | ${KtFileBuilder.DEFAULT_FILE_INDENT}WindowSizeClass.Medium -> medium$typographyClassName() - | ${KtFileBuilder.DEFAULT_FILE_INDENT}WindowSizeClass.Compact -> small$typographyClassName() + | ${KtFileBuilder.DEFAULT_FILE_INDENT}WindowSizeClass.Expanded -> $largeFunCall + | ${KtFileBuilder.DEFAULT_FILE_INDENT}WindowSizeClass.Medium -> $mediumFunCall + | ${KtFileBuilder.DEFAULT_FILE_INDENT}WindowSizeClass.Compact -> $smallFunCall |} - """.trimMargin(), - ), - description = "Возвращает разные [$typographyClassName] в зависимости от ширины окна. " + - "Значение динамически изменяется при изменении ширины окна.", - ) + """.trimMargin(), + ), + description = "Возвращает разные [$typographyClassName] в зависимости от ширины окна. " + + "Значение динамически изменяется при изменении ширины окна.", + ) + } } private fun addBreakPointFun() { @@ -176,6 +184,7 @@ internal class ComposeTypographyAttributeGenerator( private fun addTypographyClass() { with(typographyKtFileBuilder) { + val defaultTokenData = tokenData[Tenant.Default] rootClass( name = typographyClassName, primaryConstructor = Constructor.Primary( @@ -186,7 +195,7 @@ internal class ComposeTypographyAttributeGenerator( type = KtFileBuilder.TypeTextStyle, defValue = "TextStyle.Default", asProperty = true, - description = tokenData?.description(it), + description = defaultTokenData?.description(it), ) }, modifiers = listOf(Modifier.INTERNAL), @@ -199,33 +208,43 @@ internal class ComposeTypographyAttributeGenerator( } private fun addSmallTypographyFun() { - addScreenSpecificTypographyFun( - funName = "small$typographyClassName", - screenClass = ScreenClass.SMALL, - description = "Возвращает [$typographyClassName] для WindowSizeClass.Compact", - ) + tokenData.forEach { entry -> + addScreenSpecificTypographyFun( + funName = "small$typographyClassName${entry.key.name}", + screenClass = ScreenClass.SMALL, + description = "Возвращает [$typographyClassName] для WindowSizeClass.Compact", + tenant = entry.key, + ) + } } private fun addMediumTypographyFun() { - addScreenSpecificTypographyFun( - funName = "medium$typographyClassName", - screenClass = ScreenClass.MEDIUM, - description = "Возвращает [$typographyClassName] для WindowSizeClass.Medium", - ) + tokenData.forEach { entry -> + addScreenSpecificTypographyFun( + funName = "medium$typographyClassName${entry.key.name}", + screenClass = ScreenClass.MEDIUM, + description = "Возвращает [$typographyClassName] для WindowSizeClass.Medium", + tenant = entry.key, + ) + } } private fun addLargeTypographyFun() { - addScreenSpecificTypographyFun( - funName = "large$typographyClassName", - screenClass = ScreenClass.LARGE, - description = "Возвращает [$typographyClassName] для WindowSizeClass.Expanded", - ) + tokenData.forEach { entry -> + addScreenSpecificTypographyFun( + funName = "large$typographyClassName${entry.key.name}", + screenClass = ScreenClass.LARGE, + description = "Возвращает [$typographyClassName] для WindowSizeClass.Expanded", + tenant = entry.key, + ) + } } private fun addScreenSpecificTypographyFun( funName: String, screenClass: ScreenClass, description: String, + tenant: Tenant, ) { with(typographyKtFileBuilder) { appendRootFun( @@ -235,7 +254,7 @@ internal class ComposeTypographyAttributeGenerator( KtFileBuilder.createConstructorCall( constructorName = typographyClassName, initializers = typographyAttributes.map { - "$it = ${findTypographyTokenRef(it, screenClass)}" + "$it = ${findTypographyTokenRef(it, screenClass, tenant)}" }.toTypedArray(), ).let { "return $it" }, ), @@ -248,20 +267,35 @@ internal class ComposeTypographyAttributeGenerator( } } - private fun findTypographyTokenRef(attributeName: String, screenClass: ScreenClass): String? { - val safeTokenData = tokenData ?: return null + @Suppress("CyclomaticComplexMethod") + private fun findTypographyTokenRef( + attributeName: String, + screenClass: ScreenClass, + tenant: Tenant, + ): String? { + val defaultTokenData = tokenData[Tenant.Default] ?: return null + val safeTokenData = tokenData[tenant] ?: defaultTokenData val info = when (screenClass) { ScreenClass.SMALL -> safeTokenData.small[attributeName] ?: safeTokenData.medium[attributeName] ?: safeTokenData.large[attributeName] + ?: defaultTokenData.small[attributeName] + ?: defaultTokenData.medium[attributeName] + ?: defaultTokenData.large[attributeName] ScreenClass.LARGE -> safeTokenData.large[attributeName] ?: safeTokenData.medium[attributeName] ?: safeTokenData.small[attributeName] + ?: defaultTokenData.large[attributeName] + ?: defaultTokenData.medium[attributeName] + ?: defaultTokenData.small[attributeName] else -> safeTokenData.medium[attributeName] ?: safeTokenData.small[attributeName] ?: safeTokenData.large[attributeName] + ?: defaultTokenData.medium[attributeName] + ?: defaultTokenData.small[attributeName] + ?: defaultTokenData.large[attributeName] } return info?.tokenRef } diff --git a/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/tenant/Tenant.kt b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/tenant/Tenant.kt new file mode 100644 index 0000000000..945e8aede9 --- /dev/null +++ b/sdds-core/plugin_theme_builder/src/main/kotlin/com/sdds/plugin/themebuilder/internal/tenant/Tenant.kt @@ -0,0 +1,8 @@ +package com.sdds.plugin.themebuilder.internal.tenant + +internal data class Tenant(val name: String) { + + internal companion object { + val Default: Tenant = Tenant("") + } +} diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeColorAttributeGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeColorAttributeGeneratorTest.kt index f9885b5cbe..aed506e4db 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeColorAttributeGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeColorAttributeGeneratorTest.kt @@ -6,6 +6,7 @@ import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.ColorTokenResult import com.sdds.plugin.themebuilder.internal.generator.theme.compose.ComposeColorAttributeGenerator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.FileProvider import com.sdds.plugin.themebuilder.internal.utils.getResourceAsText import com.squareup.kotlinpoet.PropertySpec @@ -83,14 +84,16 @@ class ComposeColorAttributeGeneratorTest { } private companion object { - val inputData = ColorTokenResult.TokenData( - light = mapOf( - "textPrimary" to ColorTokenResult.TokenData.ColorInfo("TextPrimary"), - "textTertiary" to ColorTokenResult.TokenData.ColorInfo("TextTertiary"), - ), - dark = mapOf( - "textPrimary" to ColorTokenResult.TokenData.ColorInfo("TextPrimary"), - "textTertiary" to ColorTokenResult.TokenData.ColorInfo("TextTertiary"), + val inputData = mapOf( + Tenant.Default to ColorTokenResult.TokenData( + light = mapOf( + "textPrimary" to ColorTokenResult.TokenData.ColorInfo("TextPrimary"), + "textTertiary" to ColorTokenResult.TokenData.ColorInfo("TextTertiary"), + ), + dark = mapOf( + "textPrimary" to ColorTokenResult.TokenData.ColorInfo("TextPrimary"), + "textTertiary" to ColorTokenResult.TokenData.ColorInfo("TextTertiary"), + ), ), ) } diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeGradientAttributeGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeGradientAttributeGeneratorTest.kt index 4f798a742a..4090c5c0dc 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeGradientAttributeGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeGradientAttributeGeneratorTest.kt @@ -7,6 +7,7 @@ import com.sdds.plugin.themebuilder.internal.builder.KtFileFromResourcesBuilder import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.GradientTokenResult.ComposeTokenData import com.sdds.plugin.themebuilder.internal.generator.theme.compose.ComposeGradientAttributeGenerator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.FileProvider import com.sdds.plugin.themebuilder.internal.utils.getResourceAsText import com.squareup.kotlinpoet.PropertySpec @@ -87,41 +88,46 @@ class ComposeGradientAttributeGeneratorTest { } private companion object { - val inputData = ComposeTokenData( - light = mapOf( - "textDefaultAccentGradient" to listOf( - ComposeTokenData.Gradient( - tokenRefs = listOf( - "TextDefaultAccentGradient.colors", - "TextDefaultAccentGradient.positions", - "TextDefaultAccentGradient.angle", + val inputData = mapOf( + Tenant.Default to ComposeTokenData( + light = mapOf( + "textDefaultAccentGradient" to listOf( + ComposeTokenData.Gradient( + tokenRefs = listOf( + "TextDefaultAccentGradient.colors", + "TextDefaultAccentGradient.positions", + "TextDefaultAccentGradient.angle", + ), + gradientType = ComposeTokenData.GradientType.LINEAR, + tokenObjectName = "LightGradientTokens", ), - gradientType = ComposeTokenData.GradientType.LINEAR, ), - ), - "textDefaultGradientJoyActive" to listOf( - ComposeTokenData.Gradient( - tokenRefs = listOf( - "TextDefaultGradientJoyActive.colors", - "TextDefaultGradientJoyActive.positions", - "TextDefaultGradientJoyActive.centerX", - "TextDefaultGradientJoyActive.centerY", + "textDefaultGradientJoyActive" to listOf( + ComposeTokenData.Gradient( + tokenRefs = listOf( + "TextDefaultGradientJoyActive.colors", + "TextDefaultGradientJoyActive.positions", + "TextDefaultGradientJoyActive.centerX", + "TextDefaultGradientJoyActive.centerY", + ), + gradientType = ComposeTokenData.GradientType.SWEEP, + tokenObjectName = "LightGradientTokens", ), - gradientType = ComposeTokenData.GradientType.SWEEP, ), ), - ), - dark = mapOf( - "textDefaultAccentGradient" to listOf( - ComposeTokenData.Gradient( - tokenRefs = listOf( - "TextDefaultAccentGradient.colors", - "TextDefaultAccentGradient.positions", - "TextDefaultAccentGradient.radius", - "TextDefaultAccentGradient.centerX", - "TextDefaultAccentGradient.centerY", + dark = mapOf( + "textDefaultAccentGradient" to listOf( + ComposeTokenData.Gradient( + tokenRefs = listOf( + "TextDefaultAccentGradient.colors", + "TextDefaultAccentGradient.positions", + "TextDefaultAccentGradient.radius", + "TextDefaultAccentGradient.centerX", + "TextDefaultAccentGradient.centerY", + ), + gradientType = ComposeTokenData.GradientType.RADIAL, + tokenObjectName = "DarkGradientTokens", ), - gradientType = ComposeTokenData.GradientType.RADIAL, ), ), ), diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeShapeAttributeGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeShapeAttributeGeneratorTest.kt index af73c70891..770f61b574 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeShapeAttributeGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeShapeAttributeGeneratorTest.kt @@ -7,6 +7,7 @@ import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.data.ShapeTokenResult import com.sdds.plugin.themebuilder.internal.generator.theme.compose.ComposeShapeAttributeGenerator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.FileProvider import com.sdds.plugin.themebuilder.internal.utils.getResourceAsText import com.squareup.kotlinpoet.PropertySpec @@ -104,9 +105,19 @@ class ComposeShapeAttributeGeneratorTest { } private companion object { - val inputAttrs = listOf( - ShapeTokenResult.TokenData("roundXs", "RoundXs"), - ShapeTokenResult.TokenData("roundXxs", "RoundXxs"), + val inputAttrs = mapOf( + Tenant.Default to listOf( + ShapeTokenResult.TokenData( + attrName = "roundXs", + tokenRefName = "RoundXs", + tokenObjectName = "RoundShapeTokens", + ), + ShapeTokenResult.TokenData( + attrName = "roundXxs", + tokenRefName = "RoundXxs", + tokenObjectName = "RoundShapeTokens", + ), + ), ) } } diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeTypographyAttributeGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeTypographyAttributeGeneratorTest.kt index 3c5e88269a..f61452cdf4 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeTypographyAttributeGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/attributes/generator/ComposeTypographyAttributeGeneratorTest.kt @@ -11,6 +11,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileFromResourcesBuilderF import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult.ComposeTokenData import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult.TypographyInfo import com.sdds.plugin.themebuilder.internal.generator.theme.compose.ComposeTypographyAttributeGenerator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.FileProvider import com.sdds.plugin.themebuilder.internal.utils.getResourceAsText import com.squareup.kotlinpoet.PropertySpec @@ -181,37 +182,43 @@ class ComposeTypographyAttributeGeneratorTest { } private companion object { - val input1 = ComposeTokenData( - small = mapOf( - "displayLNormal" to TypographyInfo("TypographySmallTokens.DisplayLNormal"), - "displayLBold" to TypographyInfo("TypographySmallTokens.DisplayLBold"), - ), - medium = mapOf( - "displayLNormal" to TypographyInfo("TypographyMediumTokens.DisplayLNormal"), - "displayLBold" to TypographyInfo("TypographyMediumTokens.DisplayLBold"), - ), - large = mapOf( - "displayLNormal" to TypographyInfo("TypographyLargeTokens.DisplayLNormal"), - "displayLBold" to TypographyInfo("TypographyLargeTokens.DisplayLBold"), + val input1 = mapOf( + Tenant.Default to ComposeTokenData( + small = mapOf( + "displayLNormal" to TypographyInfo("TypographySmallTokens.DisplayLNormal"), + "displayLBold" to TypographyInfo("TypographySmallTokens.DisplayLBold"), + ), + medium = mapOf( + "displayLNormal" to TypographyInfo("TypographyMediumTokens.DisplayLNormal"), + "displayLBold" to TypographyInfo("TypographyMediumTokens.DisplayLBold"), + ), + large = mapOf( + "displayLNormal" to TypographyInfo("TypographyLargeTokens.DisplayLNormal"), + "displayLBold" to TypographyInfo("TypographyLargeTokens.DisplayLBold"), + ), ), ) - val input2 = ComposeTokenData( - small = mapOf( - "displayLNormal" to TypographyInfo("TypographySmallTokens.DisplayLNormal"), - ), - medium = mapOf( - "displayLBold" to TypographyInfo("TypographyMediumTokens.DisplayLBold"), - ), - large = mapOf( - "displayLNormal" to TypographyInfo("TypographyLargeTokens.DisplayLNormal"), + val input2 = mapOf( + Tenant.Default to ComposeTokenData( + small = mapOf( + "displayLNormal" to TypographyInfo("TypographySmallTokens.DisplayLNormal"), + ), + medium = mapOf( + "displayLBold" to TypographyInfo("TypographyMediumTokens.DisplayLBold"), + ), + large = mapOf( + "displayLNormal" to TypographyInfo("TypographyLargeTokens.DisplayLNormal"), + ), ), ) - val input3 = ComposeTokenData( - small = emptyMap(), - medium = emptyMap(), - large = mapOf( - "displayLNormal" to TypographyInfo("TypographyLargeTokens.DisplayLNormal"), - "displayLBold" to TypographyInfo("TypographyLargeTokens.DisplayLBold"), + val input3 = mapOf( + Tenant.Default to ComposeTokenData( + small = emptyMap(), + medium = emptyMap(), + large = mapOf( + "displayLNormal" to TypographyInfo("TypographyLargeTokens.DisplayLNormal"), + "displayLBold" to TypographyInfo("TypographyLargeTokens.DisplayLBold"), + ), ), ) } diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGeneratorTest.kt index 20946574e8..7749796471 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ColorTokenGeneratorTest.kt @@ -7,6 +7,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.generator.theme.ThemeGenerator import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ColorToken import com.sdds.plugin.themebuilder.internal.utils.FileProvider import com.sdds.plugin.themebuilder.internal.utils.FileProvider.colorsXmlFile @@ -89,8 +90,10 @@ class ColorTokenGeneratorTest { private companion object { val colorTokenValues = mapOf( - "dark.on-light.surface.transparent-accent" to "#FFFFFF1F", - "dark.surface.transparent-accent" to "[general.green.1000]", + Tenant.Default to mapOf( + "dark.on-light.surface.transparent-accent" to "#FFFFFF1F", + "dark.surface.transparent-accent" to "[general.green.1000]", + ), ) val palette = mapOf( "green" to mapOf("1000" to "#EEEEEE1F"), diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGeneratorTest.kt index a4648255e8..37922c89b5 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/FontTokenGeneratorTest.kt @@ -12,6 +12,7 @@ import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlFontFamilyDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.fonts.FontsAggregator import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.FontToken import com.sdds.plugin.themebuilder.internal.token.FontTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider @@ -129,43 +130,45 @@ class FontTokenGeneratorTest { private companion object { val fontTokenValues = mapOf( - "font-family.display" to FontTokenValue( - name = "SB Sans Display", - fonts = listOf( - FontToken.FontVariant( - link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + - "fonts/SBSansDisplay.0.2.0/SBSansDisplay-Regular.otf", - fontWeight = 300, - fontStyle = "normal", - ), - FontToken.FontVariant( - link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + - "fonts/SBSansDisplay.0.2.0/SBSansDisplay-Bold.otf", - fontWeight = 600, - fontStyle = "normal", + Tenant.Default to mapOf( + "font-family.display" to FontTokenValue( + name = "SB Sans Display", + fonts = listOf( + FontToken.FontVariant( + link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + + "fonts/SBSansDisplay.0.2.0/SBSansDisplay-Regular.otf", + fontWeight = 300, + fontStyle = "normal", + ), + FontToken.FontVariant( + link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + + "fonts/SBSansDisplay.0.2.0/SBSansDisplay-Bold.otf", + fontWeight = 600, + fontStyle = "normal", + ), ), ), - ), - "font-family.text" to FontTokenValue( - name = "SB Sans Text", - fonts = listOf( - FontToken.FontVariant( - link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + - "fonts/SBSansText.0.2.0/SBSansText-Regular.otf", - fontWeight = 300, - fontStyle = "normal", - ), - FontToken.FontVariant( - link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + - "fonts/SBSansText.0.2.0/SBSansText-Italic.otf", - fontWeight = 300, - fontStyle = "italic", - ), - FontToken.FontVariant( - link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + - "fonts/SBSansText.0.2.0/SBSansText-Bold.otf", - fontWeight = 600, - fontStyle = "normal", + "font-family.text" to FontTokenValue( + name = "SB Sans Text", + fonts = listOf( + FontToken.FontVariant( + link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + + "fonts/SBSansText.0.2.0/SBSansText-Regular.otf", + fontWeight = 300, + fontStyle = "normal", + ), + FontToken.FontVariant( + link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + + "fonts/SBSansText.0.2.0/SBSansText-Italic.otf", + fontWeight = 300, + fontStyle = "italic", + ), + FontToken.FontVariant( + link = "https://cdn-app.sberdevices.ru/shared-static/0.0.0/" + + "fonts/SBSansText.0.2.0/SBSansText-Bold.otf", + fontWeight = 600, + fontStyle = "normal", + ), ), ), ), diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGeneratorTest.kt index 628687f9fb..1bee21c46e 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/GradientTokenGeneratorTest.kt @@ -6,6 +6,7 @@ import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.GradientToken import com.sdds.plugin.themebuilder.internal.token.LinearGradientTokenValue import com.sdds.plugin.themebuilder.internal.token.RadialGradientTokenValue @@ -58,7 +59,10 @@ class GradientTokenGeneratorTest { ktFileBuilderFactory = KtFileBuilderFactory(PackageResolver("com.test")), gradientTokenValues = gradientTokenValues, palette = mockk(), - resourceReferenceProvider = ResourceReferenceProvider(resourcePrefix = "thmbldr", "TestTheme"), + resourceReferenceProvider = ResourceReferenceProvider( + resourcePrefix = "thmbldr", + "TestTheme", + ), ) } @@ -100,28 +104,30 @@ class GradientTokenGeneratorTest { private companion object { val gradientTokenValues = mapOf( - "dark.inverse.surface.accent" to listOf( - SweepGradientTokenValue( - colors = listOf("#000", "#fff"), - locations = listOf(0f, 0.7f), - centerX = 0.5f, - centerY = 0.5f, + Tenant.Default to mapOf( + "dark.inverse.surface.accent" to listOf( + SweepGradientTokenValue( + colors = listOf("#000", "#fff"), + locations = listOf(0f, 0.7f), + centerX = 0.5f, + centerY = 0.5f, + ), ), - ), - "light.on-dark.surface.tertiary" to listOf( - LinearGradientTokenValue( - colors = listOf("#000", "#fff"), - locations = listOf(0f, 0.7f), - angle = 90f, + "light.on-dark.surface.tertiary" to listOf( + LinearGradientTokenValue( + colors = listOf("#000", "#fff"), + locations = listOf(0f, 0.7f), + angle = 90f, + ), ), - ), - "light.on-dark.surface.secondary" to listOf( - RadialGradientTokenValue( - colors = listOf("#000", "#fff"), - locations = listOf(0f, 0.7f), - radius = 0.8f, - centerX = 0.5f, - centerY = 0.5f, + "light.on-dark.surface.secondary" to listOf( + RadialGradientTokenValue( + colors = listOf("#000", "#fff"), + locations = listOf(0f, 0.7f), + radius = 0.8f, + centerX = 0.5f, + centerY = 0.5f, + ), ), ), ) diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGeneratorTest.kt index 28281b6c5a..500f6f0456 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShadowTokenGeneratorTest.kt @@ -7,6 +7,7 @@ import com.sdds.plugin.themebuilder.internal.dimens.DimensAggregator import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.ShadowToken import com.sdds.plugin.themebuilder.internal.token.ShadowTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider @@ -100,20 +101,22 @@ class ShadowTokenGeneratorTest { private companion object { val shadowTokenValues = mapOf( - "down.hard.l" to listOf( - ShadowTokenValue( - color = "#00000099", - offsetX = 1.0f, - offsetY = 1.0f, - spreadRadius = 1.0f, - blurRadius = 1.0f, - ), - ShadowTokenValue( - color = "[general.black.1000]", - offsetX = 1.0f, - offsetY = 1.0f, - spreadRadius = 1.0f, - blurRadius = 1.0f, + Tenant.Default to mapOf( + "down.hard.l" to listOf( + ShadowTokenValue( + color = "#00000099", + offsetX = 1.0f, + offsetY = 1.0f, + spreadRadius = 1.0f, + blurRadius = 1.0f, + ), + ShadowTokenValue( + color = "[general.black.1000]", + offsetX = 1.0f, + offsetY = 1.0f, + spreadRadius = 1.0f, + blurRadius = 1.0f, + ), ), ), ) diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGeneratorTest.kt index f4436bf1fd..800c721a16 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/ShapeTokenGeneratorTest.kt @@ -10,6 +10,7 @@ import com.sdds.plugin.themebuilder.internal.dimens.DimensAggregator import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilderFactory import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.RoundedShapeTokenValue import com.sdds.plugin.themebuilder.internal.token.ShapeToken import com.sdds.plugin.themebuilder.internal.utils.FileProvider @@ -116,9 +117,11 @@ class ShapeTokenGeneratorTest { private companion object { val shapeTokenValues = mapOf( - "round.xs" to RoundedShapeTokenValue(cornerRadius = 6.0f), - "round.s" to RoundedShapeTokenValue(cornerRadius = 8.0f), - "round.l" to RoundedShapeTokenValue(cornerRadius = 16.0f), + Tenant.Default to mapOf( + "round.xs" to RoundedShapeTokenValue(cornerRadius = 6.0f), + "round.s" to RoundedShapeTokenValue(cornerRadius = 8.0f), + "round.l" to RoundedShapeTokenValue(cornerRadius = 16.0f), + ), ) } } diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGeneratorTest.kt index d2593c02a3..df1169e5b9 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/SpacingTokenGeneratorTest.kt @@ -7,6 +7,7 @@ import com.sdds.plugin.themebuilder.internal.builder.KtFileBuilder import com.sdds.plugin.themebuilder.internal.dimens.DimensAggregator import com.sdds.plugin.themebuilder.internal.factory.KtFileBuilderFactory import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.SpacingToken import com.sdds.plugin.themebuilder.internal.token.SpacingTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider @@ -92,7 +93,10 @@ class SpacingTokenGeneratorTest { ), result.viewTokens.map { it.tokenRefName }, ) - assertEquals(getResourceAsText("spacing-outputs/TestSpacingOutputKt.txt"), outputKt.toString()) + assertEquals( + getResourceAsText("spacing-outputs/TestSpacingOutputKt.txt"), + outputKt.toString(), + ) } @Test @@ -109,14 +113,19 @@ class SpacingTokenGeneratorTest { spacingTokens.forEach { underTest.addToken(it) } underTest.generate() - assertEquals(getResourceAsText("spacing-outputs/TestSpacingFromResourceOutputKt.txt"), outputKt.toString()) + assertEquals( + getResourceAsText("spacing-outputs/TestSpacingFromResourceOutputKt.txt"), + outputKt.toString(), + ) } private companion object { val spacingTokenValues = mapOf( - "spacing.0x" to SpacingTokenValue(0f), - "spacing.1x" to SpacingTokenValue(2f), - "spacing.2x" to SpacingTokenValue(4f), + Tenant.Default to mapOf( + "spacing.0x" to SpacingTokenValue(0f), + "spacing.1x" to SpacingTokenValue(2f), + "spacing.2x" to SpacingTokenValue(4f), + ), ) } } diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGeneratorTest.kt index 0f447778cf..63fc71c5a0 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/TypographyTokenGeneratorTest.kt @@ -10,6 +10,7 @@ import com.sdds.plugin.themebuilder.internal.factory.XmlResourcesDocumentBuilder import com.sdds.plugin.themebuilder.internal.fonts.FontData import com.sdds.plugin.themebuilder.internal.fonts.FontsAggregator import com.sdds.plugin.themebuilder.internal.serializer.Serializer +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.token.TypographyToken import com.sdds.plugin.themebuilder.internal.token.TypographyTokenValue import com.sdds.plugin.themebuilder.internal.utils.FileProvider @@ -184,53 +185,55 @@ class TypographyTokenGeneratorTest { ) val typographyTokenValues = mapOf( - "screen-l.display.l.normal" to TypographyTokenValue( - fontFamilyRef = "fontFamily.sans", - fontWeight = 300, - fontStyle = "normal", - textSize = 128f, - letterSpacing = 0.02f, - lineHeight = 128f, - ), - "screen-l.display.l.bold" to TypographyTokenValue( - fontFamilyRef = "fontFamily.sans", - fontWeight = 300, - fontStyle = "normal", - textSize = 128f, - letterSpacing = 0.02f, - lineHeight = 128f, - ), - "screen-s.text.l.normal" to TypographyTokenValue( - fontFamilyRef = "fontFamily.sans", - fontWeight = 400, - fontStyle = "normal", - textSize = 124f, - letterSpacing = 0.04f, - lineHeight = 124f, - ), - "screen-m.header.l.normal" to TypographyTokenValue( - fontFamilyRef = "fontFamily.sans", - fontWeight = 400, - fontStyle = "normal", - textSize = 124f, - letterSpacing = 0.04f, - lineHeight = 124f, - ), - "screen-m.display.l.normal" to TypographyTokenValue( - fontFamilyRef = "fontFamily.sans", - fontWeight = 300, - fontStyle = "normal", - textSize = 96f, - letterSpacing = 0.02f, - lineHeight = 96f, - ), - "screen-s.display.l.normal" to TypographyTokenValue( - fontFamilyRef = "fontFamily.sans", - fontWeight = 300, - fontStyle = "normal", - textSize = 72f, - letterSpacing = 0.02f, - lineHeight = 72f, + Tenant.Default to mapOf( + "screen-l.display.l.normal" to TypographyTokenValue( + fontFamilyRef = "fontFamily.sans", + fontWeight = 300, + fontStyle = "normal", + textSize = 128f, + letterSpacing = 0.02f, + lineHeight = 128f, + ), + "screen-l.display.l.bold" to TypographyTokenValue( + fontFamilyRef = "fontFamily.sans", + fontWeight = 300, + fontStyle = "normal", + textSize = 128f, + letterSpacing = 0.02f, + lineHeight = 128f, + ), + "screen-s.text.l.normal" to TypographyTokenValue( + fontFamilyRef = "fontFamily.sans", + fontWeight = 400, + fontStyle = "normal", + textSize = 124f, + letterSpacing = 0.04f, + lineHeight = 124f, + ), + "screen-m.header.l.normal" to TypographyTokenValue( + fontFamilyRef = "fontFamily.sans", + fontWeight = 400, + fontStyle = "normal", + textSize = 124f, + letterSpacing = 0.04f, + lineHeight = 124f, + ), + "screen-m.display.l.normal" to TypographyTokenValue( + fontFamilyRef = "fontFamily.sans", + fontWeight = 300, + fontStyle = "normal", + textSize = 96f, + letterSpacing = 0.02f, + lineHeight = 96f, + ), + "screen-s.display.l.normal" to TypographyTokenValue( + fontFamilyRef = "fontFamily.sans", + fontWeight = 300, + fontStyle = "normal", + textSize = 72f, + letterSpacing = 0.02f, + lineHeight = 72f, + ), ), ) } diff --git a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/ComposeThemeGeneratorTest.kt b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/ComposeThemeGeneratorTest.kt index a506e82b1c..3f6eb74a98 100644 --- a/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/ComposeThemeGeneratorTest.kt +++ b/sdds-core/plugin_theme_builder/src/test/kotlin/com/sdds/plugin/themebuilder/internal/generator/theme/ComposeThemeGeneratorTest.kt @@ -8,6 +8,7 @@ import com.sdds.plugin.themebuilder.internal.generator.data.ColorTokenResult.Tok import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult import com.sdds.plugin.themebuilder.internal.generator.data.TypographyTokenResult.TypographyInfo import com.sdds.plugin.themebuilder.internal.generator.theme.compose.ComposeThemeGenerator +import com.sdds.plugin.themebuilder.internal.tenant.Tenant import com.sdds.plugin.themebuilder.internal.utils.FileProvider import com.sdds.plugin.themebuilder.internal.utils.getResourceAsText import com.squareup.kotlinpoet.PropertySpec @@ -34,7 +35,8 @@ class ComposeThemeGeneratorTest { TypeSpec, FileProvider, ) - ktFileBuilderFactory = KtFileBuilderFactory(PackageResolver("com.sdds.playground.themebuilder")) + ktFileBuilderFactory = + KtFileBuilderFactory(PackageResolver("com.sdds.playground.themebuilder")) } @After @@ -75,12 +77,14 @@ class ComposeThemeGeneratorTest { themeName = "Test", DefaultThemeTypography.DYNAMIC, ) - underTest.setColorTokenData(TokenData(emptyMap(), emptyMap())) + underTest.setColorTokenData(mapOf(Tenant.Default to TokenData(emptyMap(), emptyMap()))) underTest.setTypographyTokenData( - TypographyTokenResult.ComposeTokenData( - emptyMap(), - emptyMap(), - emptyMap(), + mapOf( + Tenant.Default to TypographyTokenResult.ComposeTokenData( + emptyMap(), + emptyMap(), + emptyMap(), + ), ), ) underTest.generate() @@ -92,24 +96,28 @@ class ComposeThemeGeneratorTest { } private companion object { - val colorAttrsWithDefaultColors = TokenData( - light = mapOf( - "textPrimary" to TokenData.ColorInfo("TextPrimary"), - "textDefaultAccent" to TokenData.ColorInfo("TextDefaultAccent"), - ), - dark = mapOf( - "textPrimary" to TokenData.ColorInfo("TextPrimary"), - "textDefaultAccent" to TokenData.ColorInfo("TextDefaultAccent"), + val colorAttrsWithDefaultColors = mapOf( + Tenant.Default to TokenData( + light = mapOf( + "textPrimary" to TokenData.ColorInfo("TextPrimary"), + "textDefaultAccent" to TokenData.ColorInfo("TextDefaultAccent"), + ), + dark = mapOf( + "textPrimary" to TokenData.ColorInfo("TextPrimary"), + "textDefaultAccent" to TokenData.ColorInfo("TextDefaultAccent"), + ), ), ) - val typographyAttrs = TypographyTokenResult.ComposeTokenData( - small = emptyMap(), - medium = mapOf( - "headerH3Bold" to TypographyInfo("TypographyMediumTokens.HeaderH3Bold"), - "bodyMNormal" to TypographyInfo("TypographyMediumTokens.BodyMNormal"), + val typographyAttrs = mapOf( + Tenant.Default to TypographyTokenResult.ComposeTokenData( + small = emptyMap(), + medium = mapOf( + "headerH3Bold" to TypographyInfo("TypographyMediumTokens.HeaderH3Bold"), + "bodyMNormal" to TypographyInfo("TypographyMediumTokens.BodyMNormal"), + ), + large = emptyMap(), ), - large = emptyMap(), ) } } diff --git a/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/ColorsOutputKt.txt b/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/ColorsOutputKt.txt index db8669754c..6e506241a5 100644 --- a/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/ColorsOutputKt.txt +++ b/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/ColorsOutputKt.txt @@ -10,6 +10,7 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.structuralEqualityPolicy import androidx.compose.ui.graphics.Color +import com.sdds.playground.themebuilder.theme.ColorAttrOverrideScope import com.sdds.playground.themebuilder.theme.ColorOverrideScope import com.sdds.playground.themebuilder.theme.ThemeColors import com.sdds.playground.themebuilder.tokens.DarkColorTokens @@ -40,6 +41,16 @@ public class ThemeColors( val overrideMap = colorOverrideScope.overrideMap return ThemeColors(colors.mapValues { overrideMap[it.key] ?: it.value }) } + + /** + * Возвращает копию [ThemeColors]. Предоставляет возможность переопределять цвета. + */ + internal fun copyAttrs(overrideColors: ColorAttrOverrideScope.() -> Unit = {}): ThemeColors { + val colorOverrideScope = ColorAttrOverrideScope() + overrideColors.invoke(colorOverrideScope) + val overrideMap = colorOverrideScope.overrideMap + return ThemeColors(colors.mapValues { colors[overrideMap[it.key]] ?: it.value }) + } } /** @@ -63,6 +74,27 @@ public class ColorOverrideScope { } } +/** + * Скоуп переопределения цветов по арибутам + */ +internal class ColorAttrOverrideScope { + private val _overrideMap: MutableMap = mutableMapOf() + + internal val overrideMap: Map + get() = _overrideMap.toMap() + + public val textPrimary: String = "textPrimary" + + public val textTertiary: String = "textTertiary" + + /** + * Переопределяет аттрибут цвета. + */ + public infix fun String.overrideBy(color: String): Unit { + _overrideMap[this] = color + } +} + internal val LocalThemeColors: ProvidableCompositionLocal = staticCompositionLocalOf { lightThemeColors() } diff --git a/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/GradientsOutputKt.txt b/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/GradientsOutputKt.txt index 5749e12312..fd6ce70f03 100644 --- a/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/GradientsOutputKt.txt +++ b/sdds-core/plugin_theme_builder/src/test/resources/attrs-outputs/GradientsOutputKt.txt @@ -12,6 +12,7 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ShaderBrush import com.sdds.compose.uikit.graphics.Gradients +import com.sdds.playground.themebuilder.theme.GradientAttrOverrideScope import com.sdds.playground.themebuilder.theme.GradientOverrideScope import com.sdds.playground.themebuilder.theme.ThemeGradients import com.sdds.playground.themebuilder.tokens.DarkGradientTokens @@ -45,6 +46,17 @@ public class ThemeGradients( val overrideMap = gradientOverrideScope.overrideMap return ThemeGradients(gradients.mapValues { overrideMap[it.key] ?: it.value }) } + + /** + * Возвращает копию [ThemeGradients]. Предоставляет возможность переопределять цвета. + */ + internal fun copyAttrs(overrideGradients: GradientAttrOverrideScope.() -> Unit = {}): + ThemeGradients { + val gradientOverrideScope = GradientAttrOverrideScope() + overrideGradients.invoke(gradientOverrideScope) + val overrideMap = gradientOverrideScope.overrideMap + return ThemeGradients(gradients.mapValues { gradients[overrideMap[it.key]] ?: it.value }) + } } /** @@ -68,6 +80,27 @@ public class GradientOverrideScope { } } +/** + * Скоуп переопределения градиентов + */ +public class GradientAttrOverrideScope { + private val _overrideMap: MutableMap = mutableMapOf() + + internal val overrideMap: Map + get() = _overrideMap.toMap() + + public val textDefaultAccentGradient: String = "textDefaultAccentGradient" + + public val textDefaultGradientJoyActive: String = "textDefaultGradientJoyActive" + + /** + * Переопределяет аттрибут градиента. + */ + public infix fun String.overrideBy(gradient: String): Unit { + _overrideMap[this] = gradient + } +} + internal val LocalThemeGradients: ProvidableCompositionLocal = staticCompositionLocalOf { lightThemeGradients()