Skip to content

Commit

Permalink
Merge pull request #286 from LouisCAD/styled-resources-fix
Browse files Browse the repository at this point in the history
Fix inline styled resources
  • Loading branch information
LouisCAD authored Aug 3, 2021
2 parents 6d5d218 + 8028431 commit ae8aaa4
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 20 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Change log for Splitties

## [Unreleased] Version 3.0.0-rc02 (2021-08-03)

Compiled with Kotlin 1.5.21 and kotlinx.coroutines 1.5.1-native-mt.

### Resources

#### Fixes

By resolving a subtle issue that could break IDE preview, the version 3.0.0-alpha07 of Splitties also broke the `styledColor` function and some other in come cases. If you had a color theme attribute and had a theme that was setting its value, pointing to another color resource, you'd be in luck. However, if the color value was set inline, right into the theme, it'd crash ([as you can see in this issue](https://github.com/LouisCAD/Splitties/issues/258)). This release fixes this kind of problem for all the
affected functions:
- `styledColor`
- `styledColorSL`
- `styledDimen`
- `styledDimenPxSize`
- `styledDimenPxOffset`
- `styledBool`
- `styledInt`
- `styledTxt`
- `styledStr`

## Version 3.0.0-rc01 (2021-08-01)

Compiled with Kotlin 1.5.21 and kotlinx.coroutines 1.5.1-native-mt.
Expand Down
11 changes: 9 additions & 2 deletions Releasing.main.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@file:Repository("https://repo.maven.apache.org/maven2/")
//@file:Repository("https://oss.sonatype.org/content/repositories/snapshots")
//@file:Repository("file:///Users/louiscad/.m2/repository")
@file:DependsOn("com.louiscad.incubator:lib-publishing-helpers:0.2.2")
@file:DependsOn("com.louiscad.incubator:lib-publishing-helpers:0.2.3")

import Releasing_main.CiReleaseFailureCause.*
import java.io.File
Expand Down Expand Up @@ -288,9 +288,16 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
}
`Request PR merge` -> {
requestManualAction("Merge the pull request for the new version on GitHub.")
printInfo("Now that the pull request has been merged into the release branch on GitHub,")
printInfo("we are going to update our local release branch")
requestUserConfirmation("Ready?")
git.updateBranchFromOrigin(targetBranch = "release")
}
`Request GitHub release publication` -> {
requestManualAction("Publish release on GitHub with the changelog.")
printInfo("It's now time to publish the release on GitHub, so people get notified.")
printInfo("Copy the section of this release from the CHANGELOG file, and head over to the following url to proceed:")
printInfo("https://github.com/LouisCAD/Splitties/releases/new")
requestManualAction("Publish the release ${OngoingRelease.newVersion} on GitHub with the changelog.")
}
`Change this library version back to a SNAPSHOT` -> {
val newVersion = Version(OngoingRelease.newVersion)
Expand Down
2 changes: 2 additions & 0 deletions modules/resources/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ kotlin {
sourceSets {
androidMain.dependencies {
api(AndroidX.annotation)
api(splitties("experimental"))
compileOnly(AndroidX.fragment)
implementation(splitties("appctx"))
implementation(splitties("mainthread"))
implementation(splitties("exceptions"))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
*/

@file:Suppress("NOTHING_TO_INLINE")
@file:OptIn(InternalSplittiesApi::class)

package splitties.resources

import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Build.VERSION.SDK_INT
import android.util.TypedValue
import android.view.View
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.fragment.app.Fragment
import splitties.exceptions.illegalArg
import splitties.experimental.InternalSplittiesApi
import splitties.init.appCtx

/**
Expand All @@ -28,6 +31,7 @@ fun Context.color(@ColorRes colorRes: Int): Int = if (SDK_INT >= 23) getColor(co

inline fun Fragment.color(@ColorRes colorRes: Int) = context!!.color(colorRes)
inline fun View.color(@ColorRes colorRes: Int) = context.color(colorRes)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -37,6 +41,7 @@ inline fun View.color(@ColorRes colorRes: Int) = context.color(colorRes)
*/
inline fun appColor(@ColorRes colorRes: Int) = appCtx.color(colorRes)


/**
* @see [androidx.core.content.ContextCompat.getColorStateList]
*/
Expand All @@ -49,6 +54,7 @@ fun Context.colorSL(@ColorRes colorRes: Int): ColorStateList {

inline fun Fragment.colorSL(@ColorRes colorRes: Int) = context!!.colorSL(colorRes)
inline fun View.colorSL(@ColorRes colorRes: Int) = context.colorSL(colorRes)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -58,15 +64,25 @@ inline fun View.colorSL(@ColorRes colorRes: Int) = context.colorSL(colorRes)
*/
inline fun appColorSL(@ColorRes colorRes: Int) = appCtx.colorSL(colorRes)

// Styled resources below

private inline val defaultColor get() = Color.RED
// Styled resources below

@ColorInt
fun Context.styledColor(@AttrRes attr: Int): Int = color(resolveThemeAttribute(attr))
fun Context.styledColor(@AttrRes attr: Int): Int = withResolvedThemeAttribute(attr) {
when (type) {
in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT -> data
TypedValue.TYPE_STRING -> {
if (string.startsWith("res/color/")) color(resourceId)
else illegalArg(unexpectedThemeAttributeTypeErrorMessage(expectedKind = "color"))
}
else -> illegalArg(unexpectedThemeAttributeTypeErrorMessage(expectedKind = "color"))
}
}

inline fun Fragment.styledColor(@AttrRes attr: Int) = context!!.styledColor(attr)
inline fun View.styledColor(@AttrRes attr: Int) = context.styledColor(attr)


/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -76,10 +92,26 @@ inline fun View.styledColor(@AttrRes attr: Int) = context.styledColor(attr)
*/
inline fun appStyledColor(@AttrRes attr: Int) = appCtx.styledColor(attr)

fun Context.styledColorSL(@AttrRes attr: Int): ColorStateList = colorSL(resolveThemeAttribute(attr))
fun Context.styledColorSL(@AttrRes attr: Int): ColorStateList = withResolvedThemeAttribute(attr) {
when (resourceId) {
0 -> {
require(type in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT) {
unexpectedThemeAttributeTypeErrorMessage(expectedKind = "color")
}
ColorStateList.valueOf(data)
}
else -> {
require(type == TypedValue.TYPE_STRING && string.startsWith("res/color/")) {
unexpectedThemeAttributeTypeErrorMessage(expectedKind = "color")
}
colorSL(resourceId)
}
}
}

inline fun Fragment.styledColorSL(@AttrRes attr: Int) = context!!.styledColorSL(attr)
inline fun View.styledColorSL(@AttrRes attr: Int) = context.styledColorSL(attr)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@
*/

@file:Suppress("NOTHING_TO_INLINE")
@file:OptIn(InternalSplittiesApi::class)

package splitties.resources

import android.content.Context
import android.util.TypedValue
import android.view.View
import androidx.annotation.AttrRes
import androidx.annotation.DimenRes
import androidx.fragment.app.Fragment
import splitties.experimental.InternalSplittiesApi
import splitties.init.appCtx

inline fun Context.dimen(@DimenRes dimenResId: Int): Float = resources.getDimension(dimenResId)
inline fun Fragment.dimen(@DimenRes dimenResId: Int) = context!!.dimen(dimenResId)
inline fun View.dimen(@DimenRes dimenResId: Int) = context.dimen(dimenResId)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -25,12 +29,14 @@ inline fun View.dimen(@DimenRes dimenResId: Int) = context.dimen(dimenResId)
*/
inline fun appDimen(@DimenRes dimenResId: Int) = appCtx.dimen(dimenResId)


inline fun Context.dimenPxSize(
@DimenRes dimenResId: Int
): Int = resources.getDimensionPixelSize(dimenResId)

inline fun Fragment.dimenPxSize(@DimenRes dimenResId: Int) = context!!.dimenPxSize(dimenResId)
inline fun View.dimenPxSize(@DimenRes dimenResId: Int) = context.dimenPxSize(dimenResId)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -40,12 +46,14 @@ inline fun View.dimenPxSize(@DimenRes dimenResId: Int) = context.dimenPxSize(dim
*/
inline fun appDimenPxSize(@DimenRes dimenResId: Int) = appCtx.dimenPxSize(dimenResId)


inline fun Context.dimenPxOffset(
@DimenRes dimenResId: Int
): Int = resources.getDimensionPixelOffset(dimenResId)

inline fun Fragment.dimenPxOffset(@DimenRes dimenResId: Int) = context!!.dimenPxOffset(dimenResId)
inline fun View.dimenPxOffset(@DimenRes dimenResId: Int) = context.dimenPxOffset(dimenResId)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -55,11 +63,24 @@ inline fun View.dimenPxOffset(@DimenRes dimenResId: Int) = context.dimenPxOffset
*/
inline fun appDimenPxOffset(@DimenRes dimenResId: Int) = appCtx.dimenPxOffset(dimenResId)


private fun TypedValue.checkOfDimensionType() {
require(type == TypedValue.TYPE_DIMENSION) {
unexpectedThemeAttributeTypeErrorMessage(expectedKind = "dimension")
}
}


// Styled resources below

fun Context.styledDimen(@AttrRes attr: Int): Float = dimen(resolveThemeAttribute(attr))
fun Context.styledDimen(@AttrRes attr: Int): Float = withResolvedThemeAttribute(attr) {
checkOfDimensionType()
TypedValue.complexToDimension(data, resources.displayMetrics)
}

inline fun Fragment.styledDimen(@AttrRes attr: Int) = context!!.styledDimen(attr)
inline fun View.styledDimen(@AttrRes attr: Int) = context.styledDimen(attr)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -69,9 +90,15 @@ inline fun View.styledDimen(@AttrRes attr: Int) = context.styledDimen(attr)
*/
inline fun appStyledDimen(@AttrRes attr: Int) = appCtx.styledDimen(attr)

fun Context.styledDimenPxSize(@AttrRes attr: Int): Int = dimenPxSize(resolveThemeAttribute(attr))

fun Context.styledDimenPxSize(@AttrRes attr: Int): Int = withResolvedThemeAttribute(attr) {
checkOfDimensionType()
TypedValue.complexToDimensionPixelSize(data, resources.displayMetrics)
}

inline fun Fragment.styledDimenPxSize(@AttrRes attr: Int) = context!!.styledDimenPxSize(attr)
inline fun View.styledDimenPxSize(@AttrRes attr: Int) = context.styledDimenPxSize(attr)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand All @@ -81,12 +108,17 @@ inline fun View.styledDimenPxSize(@AttrRes attr: Int) = context.styledDimenPxSiz
*/
inline fun appStyledDimenPxSize(@AttrRes attr: Int) = appCtx.styledDimenPxSize(attr)


fun Context.styledDimenPxOffset(
@AttrRes attr: Int
): Int = dimenPxOffset(resolveThemeAttribute(attr))
): Int = withResolvedThemeAttribute(attr) {
checkOfDimensionType()
TypedValue.complexToDimensionPixelOffset(data, resources.displayMetrics)
}

inline fun Fragment.styledDimenPxOffset(@AttrRes attr: Int) = context!!.styledDimenPxOffset(attr)
inline fun View.styledDimenPxOffset(@AttrRes attr: Int) = context.styledDimenPxOffset(attr)

/**
* Use this method for non configuration dependent resources when you don't have a [Context]
* or when you're calling it from an Activity or a Fragment member (as the Context is not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ inline fun View.drawable(@DrawableRes drawableResId: Int) = context.drawable(dra
*/
inline fun appDrawable(@DrawableRes drawableResId: Int) = appCtx.drawable(drawableResId)


// Styled resources below

fun Context.styledDrawable(@AttrRes attr: Int): Drawable? = drawable(resolveThemeAttribute(attr))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
*/

@file:Suppress("NOTHING_TO_INLINE")
@file:OptIn(InternalSplittiesApi::class)

package splitties.resources

import android.content.Context
import android.util.TypedValue
import android.view.View
import androidx.annotation.ArrayRes
import androidx.annotation.AttrRes
import androidx.annotation.BoolRes
import androidx.annotation.IntegerRes
import androidx.fragment.app.Fragment
import splitties.experimental.InternalSplittiesApi
import splitties.init.appCtx

inline fun Context.bool(@BoolRes boolResId: Int): Boolean = resources.getBoolean(boolResId)
Expand All @@ -27,6 +30,7 @@ inline fun View.bool(@BoolRes boolResId: Int) = context.bool(boolResId)
*/
inline fun appBool(@BoolRes boolResId: Int) = appCtx.bool(boolResId)


inline fun Context.int(@IntegerRes intResId: Int): Int = resources.getInteger(intResId)
inline fun Fragment.int(@IntegerRes intResId: Int) = context!!.int(intResId)
inline fun View.int(@IntegerRes intResId: Int) = context.int(intResId)
Expand All @@ -39,6 +43,7 @@ inline fun View.int(@IntegerRes intResId: Int) = context.int(intResId)
*/
inline fun appInt(@IntegerRes intResId: Int) = appCtx.int(intResId)


inline fun Context.intArray(
@ArrayRes intArrayResId: Int
): IntArray = resources.getIntArray(intArrayResId)
Expand All @@ -54,9 +59,19 @@ inline fun View.intArray(@ArrayRes intArrayResId: Int) = context.intArray(intArr
*/
inline fun appIntArray(@ArrayRes intArrayResId: Int) = appCtx.intArray(intArrayResId)


// Styled resources below

fun Context.styledBool(@AttrRes attr: Int): Boolean = bool(resolveThemeAttribute(attr))
fun Context.styledBool(@AttrRes attr: Int): Boolean = withResolvedThemeAttribute(attr) {
require(type == TypedValue.TYPE_INT_BOOLEAN) {
unexpectedThemeAttributeTypeErrorMessage(expectedKind = "bool")
}
when (val value = data) {
0 -> false
1 -> true
else -> error("Expected 0 or 1 but got $value")
}
}

inline fun Fragment.styledBool(@AttrRes attr: Int) = context!!.styledBool(attr)
inline fun View.styledBool(@AttrRes attr: Int) = context.styledBool(attr)
Expand All @@ -69,7 +84,14 @@ inline fun View.styledBool(@AttrRes attr: Int) = context.styledBool(attr)
*/
inline fun appStyledBool(@AttrRes attr: Int) = appCtx.styledBool(attr)

fun Context.styledInt(@AttrRes attr: Int): Int = int(resolveThemeAttribute(attr))

fun Context.styledInt(@AttrRes attr: Int): Int = withResolvedThemeAttribute(attr) {
require(type == TypedValue.TYPE_INT_DEC || type == TypedValue.TYPE_INT_HEX) {
unexpectedThemeAttributeTypeErrorMessage(expectedKind = "int")
}
data
}

inline fun Fragment.styledInt(@AttrRes attr: Int) = context!!.styledInt(attr)
inline fun View.styledInt(@AttrRes attr: Int) = context.styledInt(attr)
/**
Expand Down
Loading

0 comments on commit ae8aaa4

Please sign in to comment.