Skip to content

Commit

Permalink
feat(sdds-acore/theme-builder): Color, gradients, typography tokens g…
Browse files Browse the repository at this point in the history
…enerators were implemented for compose.
  • Loading branch information
malilex committed Mar 12, 2024
1 parent 6d9efe3 commit 7aa954e
Show file tree
Hide file tree
Showing 32 changed files with 1,113 additions and 275 deletions.
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ test-androidX-rules = "1.5.0"
test-androidX-runner = "1.5.2"

kotlinSerialization = "1.4.0"
kotlinPoet = "1.12.0"

plugin-androidCacheFix = "3.0.1"
plugin-gradleNexusPublish = "1.3.0"
plugin-gradlePluginPublish = "1.2.1"
material = "1.11.0"

[libraries]
base-androidX-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidX-appcompat" }
Expand All @@ -40,6 +42,7 @@ base-androidX-compose-uiTooling-preview = { module = "androidx.compose.ui:ui-too

base-kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "global-kotlin" }
base-kotlin-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" }
base-kotlin-poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet"}

base-staticAnalysis-ktlint = { module = "com.pinterest:ktlint", version.ref = "staticAnalysis-ktlint" }
base-staticAnalysis-detekt-api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "staticAnalysis-detekt" }
Expand Down Expand Up @@ -68,6 +71,7 @@ base-gradle-paparazzi = { module = "app.cash.paparazzi:paparazzi-gradle-plugin",
base-gradle-spotless= { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "staticAnalysis-spotless" }
base-gradle-cacheFix= { module = "org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin", version.ref = "plugin-androidCacheFix" }
base-gradle-nexusPublish= { module = "io.github.gradle-nexus:publish-plugin", version.ref = "plugin-gradleNexusPublish" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }


[plugins]
Expand Down
12 changes: 12 additions & 0 deletions playground/theme-builder/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,15 @@ configure<ThemeBuilderExtension> {
themeUrl.set("file://${projectDir.path}/new_theme_scheme.json")
target.set(ThemeBuilderTarget.COMPOSE.value)
}

dependencies {
implementation("sdds-core:uikit")
implementation("sdds-core:uikit-compose")

implementation(libs.base.androidX.core)
implementation(libs.base.androidX.appcompat)

val composeBom = platform(libs.base.androidX.compose.bom)
implementation(composeBom)
implementation(libs.base.androidX.compose.foundation)
}
69 changes: 66 additions & 3 deletions playground/theme-builder/new_theme_scheme.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
],
"type": "sweep-gradient",
"value" : {
"locations": [ 0, 0.3, 0.7, 1 ],
"locations": [ 0, 0.7, 1 ],
"colors" : ["#000", "#fff"],
"startAngle": 0,
"endAngle" : 360
"endAngle" : 360,
"centerX": 0.5,
"centerY": 0.5
},
"description": "Цвет текста",
"description": "Акцентный sweep градиент поверхности",
"enabled": true
},
{
Expand All @@ -53,6 +55,46 @@
"description": "Прозрачная акцентная поверхность",
"enabled": true
},
{
"displayName": "surfaceTertiary",
"name": "light.on-dark.surface.tertiary",
"platform": "android",
"tags": [
"light",
"on-dark",
"surface",
"tertiary"
],
"type": "linear-gradient",
"value" : {
"locations": [ 0, 0.7, 1 ],
"colors" : ["#000", "#fff"],
"angle": 90
},
"description": "Третичный линейный градиент поверхности",
"enabled": true
},
{
"displayName": "surfaceSecondary",
"name": "light.on-dark.surface.secondary",
"platform": "android",
"tags": [
"light",
"on-dark",
"text",
"gradient"
],
"type": "radial-gradient",
"value" : {
"locations": [ 0, 0.7, 1 ],
"colors" : ["#000", "#fff"],
"radius": 0.8,
"centerX": 0.5,
"centerY": 0.5
},
"description": "Вторичный радиальный градиент поверхности",
"enabled": true
},
{
"displayName": "textAccent",
"name": "on-dark.text.accent",
Expand Down Expand Up @@ -163,6 +205,27 @@
},
"description": "шрифт android",
"enabled": true
},
{
"displayName": "displayL",
"name": "screen-s.display.l",
"platform": "android",
"tags": [
"screen-s",
"display",
"l"
],
"type": "typography",
"value": {
"fontFamily": "sans",
"fontWeight": 300,
"fontStyle": "normal",
"textSize": 72,
"letterSpacing": 0.02,
"lineHeight": 72
},
"description": "шрифт android",
"enabled": true
}
]
}
Expand Down
7 changes: 7 additions & 0 deletions playground/theme-builder/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<style name="Sdds"/>

<style name="Sdds.My" parent="Sdds.TextAppearance.DisplayL"/>
</resources>
1 change: 1 addition & 0 deletions sdds-core/plugin_theme_builder/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ publishing {
dependencies {
implementation(libs.base.kotlin.serialization.json)
implementation(libs.base.gradle.android)
implementation(libs.base.kotlin.poet)
testImplementation(libs.base.test.unit.jUnit)
testImplementation(libs.base.test.unit.mockk)
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ internal abstract class FetchThemeTask : DefaultTask() {
throw it
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
package com.sdds.plugin.themebuilder

import com.android.build.gradle.AppExtension
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.LibraryPlugin
import com.sdds.plugin.themebuilder.internal.builder.XmlDocumentBuilder
import com.sdds.plugin.themebuilder.internal.builder.XmlDocumentBuilderFactory
import com.sdds.plugin.themebuilder.internal.dimens.DimensAggregator
import com.sdds.plugin.themebuilder.internal.generator.ColorGenerator
import com.sdds.plugin.themebuilder.internal.generator.DimenGenerator
import com.sdds.plugin.themebuilder.internal.generator.GradientGenerator
import com.sdds.plugin.themebuilder.internal.generator.TypographyGenerator
import com.sdds.plugin.themebuilder.internal.factory.GeneratorFactory
import com.sdds.plugin.themebuilder.internal.serializer.Serializer
import com.sdds.plugin.themebuilder.internal.token.ColorToken
import com.sdds.plugin.themebuilder.internal.token.LinearGradientToken
import com.sdds.plugin.themebuilder.internal.token.RadialGradientToken
import com.sdds.plugin.themebuilder.internal.token.ShadowToken
import com.sdds.plugin.themebuilder.internal.token.SweepGradientToken
import com.sdds.plugin.themebuilder.internal.token.Theme
import com.sdds.plugin.themebuilder.internal.token.Token
import com.sdds.plugin.themebuilder.internal.token.TypographyToken
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
Expand All @@ -33,42 +19,49 @@ import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction

/**
*
* Gradle-задача для генерации темы
* @author Малышев Александр on 05.03.2024
*/
abstract class GenerateThemeTask : DefaultTask() {

/**
* Путь до json-файла с темой
*/
@get:InputFile
abstract val themeFile: RegularFileProperty

/**
* Директория для сохранения kt-файлов токенов
*/
@get:OutputDirectory
abstract val outputDir: DirectoryProperty

/**
* Директория для сохранения xml-файлов токенов
*/
@get:OutputDirectory
abstract val outputResDir: DirectoryProperty


private val mainSourceSet = when {
project.plugins.hasPlugin(AppPlugin::class.java) ->
project.extensions.getByType(AppExtension::class.java).sourceSets.maybeCreate("main")
project.plugins.hasPlugin(LibraryPlugin::class.java) ->
project.extensions.getByType(LibraryExtension::class.java).sourceSets.maybeCreate("main")
else -> throw IllegalStateException("The project must have either AppPlugin or LibraryPlugin applied.")
private val dimensAggregator by lazy { DimensAggregator() }
private val generatorFactory by lazy {
GeneratorFactory(
outputDir.get().asFile,
outputResDir.get().asFile,
ThemeBuilderTarget.ALL,
dimensAggregator,
)
}

private val colorGenerator by lazy { generatorFactory.createColorGenerator() }
private val gradientGenerator by lazy { generatorFactory.createGradientGenerator() }
private val typographyGenerator by lazy { generatorFactory.createTypographyGenerator() }
private val dimensGenerator by lazy { generatorFactory.createDimensGenerator() }

/**
* Генерирует файлы с токенами
*/
@TaskAction
fun generate() {
// val outputDir = project.layout.buildDirectory.dir("theme-builder").get().asFile
val outputDir = outputDir.get().asFile
val dimensAggregator = DimensAggregator()
val colorGenerator = ColorGenerator(outputDir, XmlDocumentBuilderFactory)
val gradientGenerator = GradientGenerator(outputDir, XmlDocumentBuilderFactory)
val typographyGenerator = TypographyGenerator(outputDir, dimensAggregator, XmlDocumentBuilderFactory)
val dimensGenerator = DimenGenerator(
outputDir,
dimensAggregator,
XmlDocumentBuilderFactory
)

decodeTheme().tokens.onEach {
when (it) {
is ColorToken -> colorGenerator.addToken(it)
Expand All @@ -89,7 +82,7 @@ abstract class GenerateThemeTask : DefaultTask() {
private fun decodeTheme(): Theme {
val readFile = themeFile.get().asFile.readText()
val theme = Serializer.instance.decodeFromString<Theme>(readFile)
println("Decoded object $theme")
logger.debug("decoded theme $theme")
return theme
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import com.android.build.gradle.AppPlugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.LibraryPlugin
import com.android.build.gradle.tasks.MergeResources
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType

/**
* Плагин для генерации тем и токенов ДС
Expand All @@ -23,9 +24,12 @@ class ThemeBuilderPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create("theme-builder", ThemeBuilderExtension::class.java)
val themeOutputFile = project.layout.buildDirectory.file("theme-builder/theme.json")

val fetchThemeTask = project.registerThemeFetcher(extension, themeOutputFile)
project.registerThemeGenerator(themeOutputFile, fetchThemeTask)
val generateThemeTask = project.registerThemeGenerator(themeOutputFile, fetchThemeTask)

project.tasks.withType(MergeResources::class).configureEach {
dependsOn(generateThemeTask)
}

project.plugins.all {
when (this) {
Expand All @@ -37,27 +41,34 @@ class ThemeBuilderPlugin : Plugin<Project> {

private fun Project.registerThemeFetcher(
extension: ThemeBuilderExtension,
output: Provider<RegularFile>): TaskProvider<FetchThemeTask> {
output: Provider<RegularFile>,
): TaskProvider<FetchThemeTask> {
return project.tasks.register<FetchThemeTask>("fetchTheme") {
if (extension.themeUrl.orNull == null) throw GradleException("Property themeUrl must be set")
url.set(extension.themeUrl)
themeFile.set(output)
}
}

private fun Project.registerThemeGenerator(input: Provider<RegularFile>, fetchTask: Any) {
project.tasks.register<GenerateThemeTask>("generateTheme") {
private fun Project.registerThemeGenerator(
input: Provider<RegularFile>,
fetchTask: Any,
): TaskProvider<GenerateThemeTask> {
return project.tasks.register<GenerateThemeTask>("generateTheme") {
themeFile.set(input)
outputDir.set(project.layout.projectDirectory.dir(OUTPUT_RESOURCE_PATH))
outputDir.set(project.layout.projectDirectory.dir(OUTPUT_PATH))
outputResDir.set(project.layout.projectDirectory.dir(OUTPUT_RESOURCE_PATH))
dependsOn(fetchTask)
}
}

private fun BaseExtension.configureSourceSets() {
this.sourceSets.maybeCreate("main").res.srcDir(OUTPUT_RESOURCE_PATH)
this.sourceSets.maybeCreate("main").kotlin.srcDir(OUTPUT_PATH)
}

companion object {
private companion object {
const val OUTPUT_RESOURCE_PATH = "build/generated/theme-builder-res"
const val OUTPUT_PATH = "build/generated/theme-builder"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,17 @@ enum class ThemeBuilderTarget(val value: String) {
else -> ALL
}
}

/**
* Возвращает true если текущий таргет - Compose или все фреймворки
*/
val ThemeBuilderTarget.isComposeOrAll: Boolean
get() = this == COMPOSE || this == ALL

/**
* Возвращает true если текущий таргет - ViewSystem или все фреймворки
*/
val ThemeBuilderTarget.isViewSystemOrAll: Boolean
get() = this == VIEW_SYSTEM || this == ALL
}
}
}
Loading

0 comments on commit 7aa954e

Please sign in to comment.