Skip to content

Commit

Permalink
Extract Dimension class to its own file
Browse files Browse the repository at this point in the history
  • Loading branch information
mahozad committed Aug 15, 2021
1 parent 55ad542 commit c7b1b5e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 57 deletions.
Expand Up @@ -13,6 +13,7 @@ import androidx.test.uiautomator.UiDevice
import de.mannodermaus.junit5.ActivityScenarioExtension
import de.mannodermaus.junit5.condition.DisabledIfBuildConfigValue
import ir.mahozad.android.PieChart.Slice
import ir.mahozad.android.unit.dp
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
Expand Down
@@ -0,0 +1,53 @@
package ir.mahozad.android.unit

import ir.mahozad.android.unit.Dimension.*
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.util.FloatComparator
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments.arguments
import org.junit.jupiter.params.provider.MethodSource

/**
* NOTE: The dimensions and the tests depend on the device and its display density.
*/
@TestInstance(PER_CLASS)
class DimensionTest {

@DisplayName("Dimensions and their conversions should be correct")
@ParameterizedTest(name = "#{index} with Dimension: {0}")
@MethodSource("argumentProvider")
fun dimensionsAndTheirConversionsShouldBeCorrect(
dimension: Dimension,
expectedPxValue: Float,
expectedDpValue: Float,
expectedSpValue: Float,
) {
assertThat(dimension.px)
.usingComparator(FloatComparator(0.01f))
.isEqualTo(expectedPxValue)
assertThat(dimension.dp)
.usingComparator(FloatComparator(0.01f))
.isEqualTo(expectedDpValue)
assertThat(dimension.sp)
.usingComparator(FloatComparator(0.01f))
.isEqualTo(expectedSpValue)
}

/**
* Could also have used Kotlin [Triple].
*/
private fun argumentProvider() = listOf(
arguments(PX(0f), 0f, 0f, 0f),
arguments(PX(10f), 10f, 3.8f, 3.8f),
arguments(PX(47f), 47f, 17.86f, 17.86f),
arguments(DP(0f), 0f, 0f, 0f),
arguments(DP(10f), 26.31f, 10f, 10f),
arguments(DP(47f), 123.67f, 47f, 47f),
arguments(SP(0f), 0f, 0f, 0f),
arguments(SP(10f), 26.31f, 10f, 10f),
arguments(SP(47f), 123.67f, 47f, 47f),
)
}
4 changes: 2 additions & 2 deletions piechart/src/main/kotlin/ir/mahozad/android/PieChart.kt
Expand Up @@ -11,7 +11,6 @@ import android.graphics.Typeface.DEFAULT
import android.util.AttributeSet
import android.view.View
import androidx.annotation.*
import androidx.annotation.Dimension
import androidx.annotation.Dimension.*
import androidx.annotation.IntRange
import androidx.core.content.res.ResourcesCompat
Expand All @@ -27,6 +26,7 @@ import ir.mahozad.android.PieChart.SlicePointer
import ir.mahozad.android.component.*
import ir.mahozad.android.component.DrawDirection.LTR
import ir.mahozad.android.component.Icon
import ir.mahozad.android.unit.px
import ir.mahozad.android.util.calculatePieDimensions
import ir.mahozad.android.util.getColorArray
import ir.mahozad.android.util.getIconTint
Expand Down Expand Up @@ -674,7 +674,7 @@ class PieChart @JvmOverloads constructor(
holeRatio = getFloat(R.styleable.PieChart_holeRatio, DEFAULT_HOLE_RATIO)
overlayRatio = getFloat(R.styleable.PieChart_overlayRatio, DEFAULT_OVERLAY_RATIO)
overlayAlpha = getFloat(R.styleable.PieChart_overlayAlpha, DEFAULT_OVERLAY_ALPHA)
gap = ir.mahozad.android.Dimension.PX(getDimension(R.styleable.PieChart_gap, DEFAULT_GAP.px))
gap = ir.mahozad.android.unit.Dimension.PX(getDimension(R.styleable.PieChart_gap, DEFAULT_GAP.px))
labelsSize = getDimension(R.styleable.PieChart_labelsSize, spToPx(DEFAULT_LABELS_SIZE))
labelsOffset = getFloat(R.styleable.PieChart_labelsOffset, DEFAULT_LABELS_OFFSET)
labelsColor = getColor(R.styleable.PieChart_labelsColor, DEFAULT_LABELS_COLOR)
Expand Down
57 changes: 2 additions & 55 deletions piechart/src/main/kotlin/ir/mahozad/android/Properties.kt
@@ -1,9 +1,9 @@
package ir.mahozad.android

import android.content.Context
import android.content.res.Resources
import androidx.core.content.ContextCompat
import ir.mahozad.android.Dimension.PX
import ir.mahozad.android.unit.Dimension
import ir.mahozad.android.unit.Dimension.PX
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty

Expand Down Expand Up @@ -57,56 +57,3 @@ class DimensionResource(backingProperty: KMutableProperty0<Dimension>) :
PropertyResource<Dimension>(0, backingProperty) {
override fun resolveResourceValue(context: Context) = PX(context.resources.getDimension(resId))
}

/**
* See [#57](https://github.com/mahozad/android-pie-chart/issues/57).
*/
sealed class Dimension {

// TODO: Is it safe to use `Resources.getSystem().displayMetrics`
// instead of using `context.resources.displayMetrics`which requires context?
// See https://stackoverflow.com/a/17880012/ and https://stackoverflow.com/a/62433235

/**
* The pixel value of the dimension.
*/
abstract val px: Float
/**
* The dp value of the dimension.
*/
abstract val dp: Float
/**
* The sp value of the dimension.
*/
abstract val sp: Float

class PX(val value: Float) : Dimension() {
override val px = value
override val dp = value / Resources.getSystem().displayMetrics.density
override val sp = value / Resources.getSystem().displayMetrics.scaledDensity
}

class DP(val value: Float) : Dimension() {
override val px = value * Resources.getSystem().displayMetrics.density
override val dp = value
override val sp = PX(px).sp
}

class SP(val value: Float) : Dimension() {
override val px = value * Resources.getSystem().displayMetrics.scaledDensity
override val dp = PX(px).dp
override val sp = value
}
}

inline val Int.dp: Dimension get() = Dimension.DP(this.toFloat())
inline val Float.dp: Dimension get() = Dimension.DP(this)
inline val Double.dp: Dimension get() = Dimension.DP(this.toFloat())

inline val Int.sp: Dimension get() = Dimension.SP(this.toFloat())
inline val Float.sp: Dimension get() = Dimension.SP(this)
inline val Double.sp: Dimension get() = Dimension.SP(this.toFloat())

inline val Int.px: Dimension get() = PX(this.toFloat())
inline val Float.px: Dimension get() = PX(this)
inline val Double.px: Dimension get() = PX(this.toFloat())
57 changes: 57 additions & 0 deletions piechart/src/main/kotlin/ir/mahozad/android/unit/Dimension.kt
@@ -0,0 +1,57 @@
package ir.mahozad.android.unit

import android.content.res.Resources

/**
* See [#57](https://github.com/mahozad/android-pie-chart/issues/57).
*/
sealed class Dimension {

// TODO: Is it safe to use `Resources.getSystem().displayMetrics`
// instead of `context.resources.displayMetrics` which requires context?
// See https://stackoverflow.com/a/17880012/ and https://stackoverflow.com/a/62433235

protected abstract val value: Float
/**
* The pixel value of the dimension.
*/
abstract val px: Float
/**
* The dp value of the dimension.
*/
abstract val dp: Float
/**
* The sp value of the dimension.
*/
abstract val sp: Float

override fun toString() = "${this::class.simpleName}: $value${this::class.simpleName?.lowercase()}"

class PX(override val value: Float) : Dimension() {
override val px = value
override val dp = value / Resources.getSystem().displayMetrics.density
override val sp = value / Resources.getSystem().displayMetrics.scaledDensity
}

class DP(override val value: Float) : Dimension() {
override val px = value * Resources.getSystem().displayMetrics.density
override val dp = value
override val sp = PX(px).sp
}

class SP(override val value: Float) : Dimension() {
override val px = value * Resources.getSystem().displayMetrics.scaledDensity
override val dp = PX(px).dp
override val sp = value
}
}

inline val Int.dp: Dimension get() = Dimension.DP(this.toFloat())
inline val Float.dp: Dimension get() = Dimension.DP(this)
inline val Double.dp: Dimension get() = Dimension.DP(this.toFloat())
inline val Int.sp: Dimension get() = Dimension.SP(this.toFloat())
inline val Float.sp: Dimension get() = Dimension.SP(this)
inline val Double.sp: Dimension get() = Dimension.SP(this.toFloat())
inline val Int.px: Dimension get() = Dimension.PX(this.toFloat())
inline val Float.px: Dimension get() = Dimension.PX(this)
inline val Double.px: Dimension get() = Dimension.PX(this.toFloat())

0 comments on commit c7b1b5e

Please sign in to comment.