themr
Theme concatenation via gradle plugin
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.github.ouchadam.themr:<latest-version>"
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.github.ouchadam.themr'
Usage
res/values/themr.xml
<style name="PaletteLight">
<item name="brandColor">#008577</item>
</style>
<style name="PaletteDark">
<item name="brandColor">#000000</item>
</style>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">?attr/brandColor</item>
</style>
build.gradle
themr {
combinations = ["AppTheme": ["PaletteLight", "PaletteDark"]]
}
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(ThemR.get(R.style.PaletteDark, R.style.AppTheme))
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
What is this?
A gradle plugin to generate combinations of themes based on a color palette. This is done by simplying inlining a palette style into a theme style.
The example above will generate
<style name="PaletteLight_AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="brandColor">#008577</item>
<item name="colorPrimary">?attr/brandColor</item>
</style>
<style name="PaletteDark_AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="brandColor">#000000</item>
<item name="colorPrimary">?attr/brandColor</item>
</style>
Why is this useful?
When an app uses mulitple themes
<style name="HomeTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/blue</item>
<item name="android:textColor">@color/black</item>
</style>
<style name="DetailsTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/red</item>
<item name="android:textColor">@color/white</item>
</style>
and different palettes are required such as a dark mode, management starts to get tricky, especially when more palettes are introduced. This can be achieved by copying all of the themes for each palette, rearchitecting the theme hierarchy or by programatically applying the colours.
<style name="HomeTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/blue</item>
<item name="android:textColor">@color/black</item>
</style>
<style name="DarkHomeTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/dark_blue</item>
<item name="android:textColor">@color/grey</item>
</style>
fun bindView(view) {
val themeWrapper = createThemeWrapperFor(Configuration.DARK_MODE) // find all the dark mode attributes
view.text.setTextColor(themeWrapper.colorPrimary)
}
themr
reduces the need for this boiler plate by allowing the palettes and themes to be decoupled and the combinations auto generated.
Combinations are declared as part of the plugin extension
themr {
combinations = [
"HomeTheme": ["LightMode", "DarkMode"],
"DetailsTheme": ["LightMode", "DarkMode"]
]
}
<style name="LightMode">
<item name="brandColor">@color/blue</item>
<item name="brandColorSecondary">@color/red</item>
<item name="brandTextColor">@color/black</item>
<item name="brandTextColorInverse">@color/white</item>
</style>
<style name="DarkMode">
<item name="brandColor">@color/dark_blue</item>
<item name="brandColorSecondary">@color/blue</item>
<item name="brandTextColor">@color/grey</item>
<item name="brandTextColorInverse">@color/black</item>
</style>
<style name="HomeTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">?attr/brandColor</item>
<item name="android:textColor">?attr/brandTextColor</item>
</style>
<style name="DetailsTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">?attr/brandColorSecondary</item>
<item name="android:textColor">?attr/brandTextColorInverse</item>
</style>
themr
will generate styles to buildDir/generated/res/themr
which the app can then consume via id, a resources.getIdentifier
lookup
or via generated helper ThemR.get(paletteId, themeId)
{Palette}_{Theme}
LightMode_HomeTheme
DarkMode_HomeTheme
LightMode_DetailsTheme
DarkMode_DetailsTheme