From c52abda1c47115641e1fcbad23276a200547c51d Mon Sep 17 00:00:00 2001 From: N7k Date: Sun, 22 Mar 2020 21:04:23 +0200 Subject: [PATCH 01/12] Add RGBColorPickerSeekBar class --- .../codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt new file mode 100644 index 0000000..39a5830 --- /dev/null +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt @@ -0,0 +1,5 @@ +package codes.side.andcolorpicker.rgb + +class RGBColorPickerSeekBar { + +} From 97c90196f1cb58c90ecc136b340d07b87801b934 Mon Sep 17 00:00:00 2001 From: N7k Date: Tue, 24 Mar 2020 01:28:54 +0200 Subject: [PATCH 02/12] Add RGBColorFactory --- .../side/andcolorpicker/model/IntegerRGBColor.kt | 6 ++++++ .../andcolorpicker/model/factory/RGBColorFactory.kt | 13 +++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 andcolorpicker/src/main/java/codes/side/andcolorpicker/model/factory/RGBColorFactory.kt diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt index 3566945..51ec220 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt @@ -10,4 +10,10 @@ class IntegerRGBColor : IntegerColor(COMPONENTS_COUNT) { override val alpha: Float get() = TODO("Not yet implemented") + + override fun clone(): IntegerRGBColor { + return IntegerRGBColor().also { + it.setFrom(this) + } + } } diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/factory/RGBColorFactory.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/factory/RGBColorFactory.kt new file mode 100644 index 0000000..b8dcbaf --- /dev/null +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/factory/RGBColorFactory.kt @@ -0,0 +1,13 @@ +package codes.side.andcolorpicker.model.factory + +import codes.side.andcolorpicker.model.IntegerRGBColor + +class RGBColorFactory : ColorFactory() { + override fun create(): IntegerRGBColor { + return IntegerRGBColor() + } + + override fun createColorFrom(color: IntegerRGBColor): IntegerRGBColor { + return color.clone() + } +} From 8a3bf4fb7c9db4438439cd3e6ee9cfa523e63b72 Mon Sep 17 00:00:00 2001 From: N7k Date: Thu, 26 Mar 2020 02:21:30 +0200 Subject: [PATCH 03/12] Describe IntegerRGBColor model --- .../andcolorpicker/model/IntegerRGBColor.kt | 144 +++++++++++++++++- 1 file changed, 138 insertions(+), 6 deletions(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt index 51ec220..2e42a80 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt @@ -1,19 +1,151 @@ package codes.side.andcolorpicker.model -class IntegerRGBColor : IntegerColor(COMPONENTS_COUNT) { +class IntegerRGBColor : IntegerColor( + COMPONENTS_COUNT, + DEFAULT_RGB_VALUES +) { companion object { private const val TAG = "IntegerRGBColor" - private const val COMPONENTS_COUNT = 3 + private val COMPONENTS_COUNT = Component.values().size + + private val DEFAULT_RGB_VALUES = Component + .values().map { it.defaultValue }.toIntArray() } override val colorKey = ColorKey.RGB override val alpha: Float - get() = TODO("Not yet implemented") + get() { + return intA / Component.A.maxValue.toFloat() + } + var intA: Int + get() { + return intValues[Component.A.ordinal] + } + set(value) { + setValue( + Component.A.ordinal, + value, + Component.A.minValue, + Component.A.maxValue + ) + } - override fun clone(): IntegerRGBColor { - return IntegerRGBColor().also { - it.setFrom(this) + var floatR: Float + get() { + return intR.toFloat() + } + set(value) { + intR = value.toInt() + } + var intR: Int + get() { + return intValues[Component.R.ordinal] + } + set(value) { + setValue( + Component.R.ordinal, + value, + Component.R.minValue, + Component.R.maxValue + ) + } + + var floatG: Float + get() { + return intG.toFloat() + } + set(value) { + intG = value.toInt() + } + var intG: Int + get() { + return intValues[Component.G.ordinal] + } + set(value) { + setValue( + Component.G.ordinal, + value, + Component.G.minValue, + Component.G.maxValue + ) + } + + var floatB: Float + get() { + return intB.toFloat() } + set(value) { + intB = value.toInt() + } + var intB: Int + get() { + return intValues[Component.B.ordinal] + } + set(value) { + setValue( + Component.B.ordinal, + value, + Component.B.minValue, + Component.B.maxValue + ) + } + + override fun clone(): IntegerRGBColor { + return super.clone() as IntegerRGBColor + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as IntegerRGBColor + + if (colorKey != other.colorKey) return false + + return true + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + colorKey.hashCode() + return result + } + + // TODO: Make Component top-level? + // TODO: Make tree? + // TODO: Use range? + enum class Component( + val defaultValue: Int, + val minValue: Int, + val maxValue: Int + ) { + R( + 0, + 0, + 255 + ), + G( + 0, + 0, + 255 + ), + B( + 0, + 0, + 255 + ), + A( + 255, + 0, + 255 + ); + + // TODO: Adapt for non-zero min values + val normalizedDefaultValue: Float + get() { + return defaultValue / maxValue.toFloat() + } } } From 8d87a9ced5c3dc3878021170803b9855c5f3532c Mon Sep 17 00:00:00 2001 From: N7k Date: Thu, 26 Mar 2020 22:34:55 +0200 Subject: [PATCH 04/12] Add minor fixes --- .../andcolorpicker/model/IntegerHSLColor.kt | 2 +- .../andcolorpicker/model/IntegerRGBColor.kt | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerHSLColor.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerHSLColor.kt index 1fc837a..82f4efb 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerHSLColor.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerHSLColor.kt @@ -174,7 +174,7 @@ class IntegerHSLColor : IntegerColor( return ordinal } - // TODO: Adapt for non-zero min valies + // TODO: Adapt for non-zero min values val normalizedDefaultValue: Float get() { return defaultValue / maxValue.toFloat() diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt index 2e42a80..dea62e6 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/model/IntegerRGBColor.kt @@ -20,11 +20,11 @@ class IntegerRGBColor : IntegerColor( } var intA: Int get() { - return intValues[Component.A.ordinal] + return intValues[Component.A.index] } set(value) { setValue( - Component.A.ordinal, + Component.A.index, value, Component.A.minValue, Component.A.maxValue @@ -40,11 +40,11 @@ class IntegerRGBColor : IntegerColor( } var intR: Int get() { - return intValues[Component.R.ordinal] + return intValues[Component.R.index] } set(value) { setValue( - Component.R.ordinal, + Component.R.index, value, Component.R.minValue, Component.R.maxValue @@ -60,11 +60,11 @@ class IntegerRGBColor : IntegerColor( } var intG: Int get() { - return intValues[Component.G.ordinal] + return intValues[Component.G.index] } set(value) { setValue( - Component.G.ordinal, + Component.G.index, value, Component.G.minValue, Component.G.maxValue @@ -80,11 +80,11 @@ class IntegerRGBColor : IntegerColor( } var intB: Int get() { - return intValues[Component.B.ordinal] + return intValues[Component.B.index] } set(value) { setValue( - Component.B.ordinal, + Component.B.index, value, Component.B.minValue, Component.B.maxValue @@ -142,6 +142,12 @@ class IntegerRGBColor : IntegerColor( 255 ); + // TODO: Review approach + val index: Int + get() { + return ordinal + } + // TODO: Adapt for non-zero min values val normalizedDefaultValue: Float get() { From 4d1d2f67b1d39e4ed5db97ae420c999047109df0 Mon Sep 17 00:00:00 2001 From: N7k Date: Fri, 27 Mar 2020 01:40:11 +0200 Subject: [PATCH 05/12] Add IntegerRGBColorConverter --- .../converter/IntegerRGBColorConverter.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt new file mode 100644 index 0000000..70dabb2 --- /dev/null +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt @@ -0,0 +1,37 @@ +package codes.side.andcolorpicker.converter + +import codes.side.andcolorpicker.model.Color +import codes.side.andcolorpicker.model.IntegerRGBColor + +class IntegerRGBColorConverter : ColorConverter { + + override fun convertToOpaqueColorInt(color: Color): Int { + TODO("Not yet implemented") + } + + override fun convertToColorInt(color: Color): Int { + require(color is IntegerRGBColor) { "Unsupported color type supplied" } + + return android.graphics.Color.rgb( + color.floatR.toInt(), + color.floatG.toInt(), + color.floatB.toInt() + ) + } + + override fun convertToPureHueColorInt(color: Color): Int { + TODO("Not yet implemented") + } + + override fun setFromColorInt(color: Color, value: Int) { + require(color is IntegerRGBColor) { "Unsupported color type supplied" } + + color.copyValuesFrom( + intArrayOf( + android.graphics.Color.red(value), + android.graphics.Color.green(value), + android.graphics.Color.blue(value) + ) + ) + } +} From 9634ac8dd246ab1ded287fa0699db88ef3c9a135 Mon Sep 17 00:00:00 2001 From: N7k Date: Fri, 27 Mar 2020 21:22:57 +0200 Subject: [PATCH 06/12] Implement RGBColorPickerSeekBar --- .../converter/ColorConverterHub.kt | 4 + .../rgb/RGBColorPickerSeekBar.kt | 325 +++++++++++++++++- andcolorpicker/src/main/res/values/attrs.xml | 12 + .../src/main/res/values/strings.xml | 3 + 4 files changed, 343 insertions(+), 1 deletion(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/ColorConverterHub.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/ColorConverterHub.kt index 1960d74..b70b626 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/ColorConverterHub.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/ColorConverterHub.kt @@ -14,6 +14,10 @@ object ColorConverterHub { ColorKey.CMYK, IntegerCMYKColorConverter() ) + registerConverter( + ColorKey.RGB, + IntegerRGBColorConverter() + ) } fun getConverterByKey(key: ColorKey): ColorConverter { diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt index 39a5830..21188f0 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt @@ -1,5 +1,328 @@ package codes.side.andcolorpicker.rgb -class RGBColorPickerSeekBar { +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.GradientDrawable +import android.graphics.drawable.LayerDrawable +import android.util.AttributeSet +import androidx.core.graphics.ColorUtils +import codes.side.andcolorpicker.R +import codes.side.andcolorpicker.converter.IntegerRGBColorConverter +import codes.side.andcolorpicker.model.IntegerRGBColor +import codes.side.andcolorpicker.model.factory.RGBColorFactory +import codes.side.andcolorpicker.view.picker.GradientColorSeekBar +class RGBColorPickerSeekBar @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = androidx.appcompat.R.attr.seekBarStyle +) : + GradientColorSeekBar( + RGBColorFactory(), + context, + attrs, + defStyle + ) { + companion object { + private const val TAG = "RGBColorPickerSeekBar" + + private val DEFAULT_MODE = Mode.MODE_R + private val DEFAULT_COLORING_MODE = ColoringMode.PURE_COLOR + + private val PURE_RED_COLOR_CHECKPOINTS = intArrayOf( + Color.BLACK, + Color.RED + ) + private val PURE_GREEN_COLOR_CHECKPOINTS = intArrayOf( + Color.BLACK, + Color.GREEN + ) + private val PURE_BLUE_COLOR_CHECKPOINTS = intArrayOf( + Color.BLACK, + Color.BLUE + ) + + private val PLAIN_RED_COLOR_CHECKPOINTS = intArrayOf( + Color.RED, + Color.RED + ) + private val PLAIN_GREEN_COLOR_CHECKPOINTS = intArrayOf( + Color.GREEN, + Color.GREEN + ) + private val PLAIN_BLUE_COLOR_CHECKPOINTS = intArrayOf( + Color.BLUE, + Color.BLUE + ) + } + + override val colorConverter: IntegerRGBColorConverter + get() = super.colorConverter as IntegerRGBColorConverter + + private var modeInitialized = false + private var _mode: RGBColorPickerSeekBar.Mode? = null + var mode: RGBColorPickerSeekBar.Mode + get() { + return requireNotNull(_mode) { "Mode is not initialized yet" } + } + set(value) { + modeInitialized = true + if (_mode == value) { + return + } + _mode = value + refreshProperties() + refreshProgressFromCurrentColor() + refreshProgressDrawable() + refreshThumb() + } + + private var coloringModeInitialized = false + private var _coloringMode: ColoringMode? = null + var coloringMode: ColoringMode + get() { + return requireNotNull(_coloringMode) { "Coloring mode is not initialized yet" } + } + set(value) { + coloringModeInitialized = true + if (_coloringMode == value) { + return + } + _coloringMode = value + refreshProgressDrawable() + refreshThumb() + } + + init { + init(attrs) + } + + private fun init(attrs: AttributeSet? = null) { + val typedArray = context.theme.obtainStyledAttributes( + attrs, + R.styleable.RGBColorPickerSeekBar, + 0, + 0 + ) + + mode = Mode.values()[typedArray.getInteger( + R.styleable.RGBColorPickerSeekBar_rgbMode, + DEFAULT_MODE.ordinal + )] + coloringMode = ColoringMode.values()[typedArray.getInteger( + R.styleable.RGBColorPickerSeekBar_rgbColoringMode, + DEFAULT_COLORING_MODE.ordinal + )] + + typedArray.recycle() + } + + override fun setMin(min: Int) { + if (modeInitialized && min != mode.minProgress) { + throw IllegalArgumentException("Current mode supports ${mode.minProgress} min value only") + } + super.setMin(min) + } + + override fun setMax(max: Int) { + if (modeInitialized && max != mode.maxProgress) { + throw IllegalArgumentException("Current mode supports ${mode.maxProgress} max value only") + } + super.setMax(max) + } + + override fun updateInternalPickedColorFrom(value: IntegerRGBColor) { + super.updateInternalPickedColorFrom(value) + internalPickedColor.setFrom(value) + } + + override fun refreshProperties() { + super.refreshProperties() + if (!modeInitialized) { + return + } + max = mode.maxProgress + } + + override fun refreshProgressDrawable() { + super.refreshProgressDrawable() + + if (!coloringModeInitialized || !modeInitialized) { + return + } + + ((progressDrawable as LayerDrawable).getDrawable(0) as GradientDrawable).colors = when (mode) { + Mode.MODE_R -> { + when (coloringMode) { + ColoringMode.PURE_COLOR -> PURE_RED_COLOR_CHECKPOINTS + ColoringMode.OUTPUT_COLOR -> TODO() + ColoringMode.PLAIN_COLOR -> PLAIN_RED_COLOR_CHECKPOINTS + } + } + Mode.MODE_G -> { + when (coloringMode) { + ColoringMode.PURE_COLOR -> PURE_GREEN_COLOR_CHECKPOINTS + ColoringMode.OUTPUT_COLOR -> TODO() + ColoringMode.PLAIN_COLOR -> PLAIN_GREEN_COLOR_CHECKPOINTS + } + } + Mode.MODE_B -> { + when (coloringMode) { + ColoringMode.PURE_COLOR -> PURE_BLUE_COLOR_CHECKPOINTS + ColoringMode.OUTPUT_COLOR -> TODO() + ColoringMode.PLAIN_COLOR -> PLAIN_BLUE_COLOR_CHECKPOINTS + } + } + } + } + + override fun refreshThumb() { + super.refreshThumb() + + coloringDrawables.forEach { + when (it) { + is GradientDrawable -> { + paintThumbStroke(it) + } + is LayerDrawable -> { + paintThumbStroke(it.getDrawable(0) as GradientDrawable) + } + } + } + } + + override fun refreshInternalPickedColorFromProgress() { + super.refreshInternalPickedColorFromProgress() + + if (!modeInitialized) { + return + } + + val currentProgress = progress + // TODO: Use Atomic and compare/set? + val changed = when (mode) { + Mode.MODE_R -> { + val currentH = internalPickedColor.intR + if (currentH != currentProgress) { + internalPickedColor.intR = currentProgress + true + } else { + false + } + } + Mode.MODE_G -> { + val currentS = internalPickedColor.intG + if (currentS != currentProgress) { + internalPickedColor.intG = currentProgress + true + } else { + false + } + } + Mode.MODE_B -> { + val currentL = internalPickedColor.intB + if (currentL != currentProgress) { + internalPickedColor.intB = currentProgress + true + } else { + false + } + } + } + + if (changed) { + notifyListenersOnColorChanged() + } + } + + override fun refreshProgressFromCurrentColor() { + super.refreshProgressFromCurrentColor() + + if (!modeInitialized) { + return + } + + progress = when (mode) { + Mode.MODE_R -> { + internalPickedColor.intR + } + Mode.MODE_G -> { + internalPickedColor.intG + } + Mode.MODE_B -> { + internalPickedColor.intB + } + } + } + + // TODO: Refactor + private fun paintThumbStroke(drawable: GradientDrawable) { + if (!coloringModeInitialized || !modeInitialized) { + return + } + + val currentProgress = progress + drawable.setStroke( + thumbStrokeWidthPx, + when (mode) { + Mode.MODE_R -> { + when (coloringMode) { + ColoringMode.PURE_COLOR -> ColorUtils.blendARGB( + Color.BLACK, + Color.RED, + currentProgress / mode.maxProgress.toFloat() + ) + ColoringMode.OUTPUT_COLOR -> TODO() + ColoringMode.PLAIN_COLOR -> Color.RED + } + } + Mode.MODE_G -> { + when (coloringMode) { + ColoringMode.PURE_COLOR -> ColorUtils.blendARGB( + Color.BLACK, + Color.GREEN, + currentProgress / mode.maxProgress.toFloat() + ) + ColoringMode.OUTPUT_COLOR -> TODO() + ColoringMode.PLAIN_COLOR -> Color.GREEN + } + } + Mode.MODE_B -> { + when (coloringMode) { + ColoringMode.PURE_COLOR -> ColorUtils.blendARGB( + Color.BLACK, + Color.BLUE, + currentProgress / mode.maxProgress.toFloat() + ) + ColoringMode.OUTPUT_COLOR -> TODO() + ColoringMode.PLAIN_COLOR -> Color.BLUE + } + } + } + ) + } + + enum class ColoringMode { + PURE_COLOR, + OUTPUT_COLOR, + PLAIN_COLOR, + } + + enum class Mode( + val minProgress: Int, + val maxProgress: Int + ) { + MODE_R( + IntegerRGBColor.Component.R.minValue, + IntegerRGBColor.Component.R.maxValue + ), + MODE_G( + IntegerRGBColor.Component.G.minValue, + IntegerRGBColor.Component.G.maxValue + ), + MODE_B( + IntegerRGBColor.Component.B.minValue, + IntegerRGBColor.Component.B.maxValue + ), + } } diff --git a/andcolorpicker/src/main/res/values/attrs.xml b/andcolorpicker/src/main/res/values/attrs.xml index 5814363..4e105f3 100644 --- a/andcolorpicker/src/main/res/values/attrs.xml +++ b/andcolorpicker/src/main/res/values/attrs.xml @@ -23,4 +23,16 @@ + + + + + + + + + + + + diff --git a/andcolorpicker/src/main/res/values/strings.xml b/andcolorpicker/src/main/res/values/strings.xml index e7ef7b8..22fc4d8 100644 --- a/andcolorpicker/src/main/res/values/strings.xml +++ b/andcolorpicker/src/main/res/values/strings.xml @@ -8,6 +8,9 @@ Magenta Yellow Key + Red + Green + Blue [WIP] Pick a color Pick Cancel From bccd3ccaf827dee9ac6fdabd6991d93ba7d6e85d Mon Sep 17 00:00:00 2001 From: N7k Date: Fri, 27 Mar 2020 21:23:52 +0200 Subject: [PATCH 07/12] Add RGBSeekBarFragment --- .../app/activity/MainActivity.kt | 2 +- .../app/fragment/RGBSeekBarFragment.kt | 56 +++++++++++++ .../main/res/layout/fragment_rgb_seek_bar.xml | 82 +++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt create mode 100644 app/src/main/res/layout/fragment_rgb_seek_bar.xml diff --git a/app/src/main/java/codes/side/andcolorpicker/app/activity/MainActivity.kt b/app/src/main/java/codes/side/andcolorpicker/app/activity/MainActivity.kt index 51d15fc..dfa1cf0 100644 --- a/app/src/main/java/codes/side/andcolorpicker/app/activity/MainActivity.kt +++ b/app/src/main/java/codes/side/andcolorpicker/app/activity/MainActivity.kt @@ -211,7 +211,7 @@ class MainActivity : AppCompatActivity(), RGB_SEEK_BAR( "RGB SeekBar", MaterialDesignDx.Icon.gmf_space_bar, - { WipFragment() } + { RGBSeekBarFragment() } ), RGB_PLANE( "RGB Plane", diff --git a/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt b/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt new file mode 100644 index 0000000..1aeba66 --- /dev/null +++ b/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt @@ -0,0 +1,56 @@ +package codes.side.andcolorpicker.app.fragment + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import codes.side.andcolorpicker.app.R +import codes.side.andcolorpicker.group.PickerGroup +import codes.side.andcolorpicker.group.registerPickers +import codes.side.andcolorpicker.model.IntegerRGBColor +import codes.side.andcolorpicker.view.picker.ColorSeekBar +import kotlinx.android.synthetic.main.fragment_rgb_seek_bar.* + +class RGBSeekBarFragment : Fragment(R.layout.fragment_rgb_seek_bar) { + + companion object { + private const val TAG = "RGBSeekBarFragment" + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated( + view, + savedInstanceState + ) + + val pickerGroup = PickerGroup().also { + it.registerPickers( + redRGBColorPickerSeekBar, + greenRGBColorPickerSeekBar, + blueRGBColorPickerSeekBar + ) + } + + pickerGroup.addListener( + object : + ColorSeekBar.DefaultOnColorPickListener, IntegerRGBColor>() { + override fun onColorChanged( + picker: ColorSeekBar, + color: IntegerRGBColor, + value: Int + ) { + swatchView.setSwatchColor( + color + ) + } + } + ) + + pickerGroup.setColor( + IntegerRGBColor().also { + it.intR = 30 + it.intG = 130 + it.intB = 230 + } + ) + } +} diff --git a/app/src/main/res/layout/fragment_rgb_seek_bar.xml b/app/src/main/res/layout/fragment_rgb_seek_bar.xml new file mode 100644 index 0000000..a72d452 --- /dev/null +++ b/app/src/main/res/layout/fragment_rgb_seek_bar.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + From 564f2097ac86521401bff1c483c7ff3b8a7ff1e9 Mon Sep 17 00:00:00 2001 From: N7k Date: Fri, 27 Mar 2020 21:25:33 +0200 Subject: [PATCH 08/12] Fix CMYKColorPickerSeekBar setMin/setMax mode checks --- .../side/andcolorpicker/cmyk/CMYKColorPickerSeekBar.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/cmyk/CMYKColorPickerSeekBar.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/cmyk/CMYKColorPickerSeekBar.kt index 5d5b31d..632b2b8 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/cmyk/CMYKColorPickerSeekBar.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/cmyk/CMYKColorPickerSeekBar.kt @@ -95,15 +95,15 @@ class CMYKColorPickerSeekBar @JvmOverloads constructor( } override fun setMin(min: Int) { - if (min != 0) { - throw IllegalArgumentException("Current mode supports 0 min value only") + if (modeInitialized && min != mode.minProgress) { + throw IllegalArgumentException("Current mode supports ${mode.minProgress} min value only") } super.setMin(min) } override fun setMax(max: Int) { - if (max != 100) { - throw IllegalArgumentException("Current mode supports 100 max value only") + if (modeInitialized && max != mode.maxProgress) { + throw IllegalArgumentException("Current mode supports ${mode.maxProgress} max value only") } super.setMax(max) } From 978958d9a75e93835cfcdbb63460e302101b1cbe Mon Sep 17 00:00:00 2001 From: N7k Date: Sun, 29 Mar 2020 16:54:56 +0300 Subject: [PATCH 09/12] Refactor RGBColorPickerSeekBar --- .../rgb/RGBColorPickerSeekBar.kt | 144 +++++++----------- 1 file changed, 57 insertions(+), 87 deletions(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt index 21188f0..ff1a4cb 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt @@ -28,40 +28,14 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( private val DEFAULT_MODE = Mode.MODE_R private val DEFAULT_COLORING_MODE = ColoringMode.PURE_COLOR - - private val PURE_RED_COLOR_CHECKPOINTS = intArrayOf( - Color.BLACK, - Color.RED - ) - private val PURE_GREEN_COLOR_CHECKPOINTS = intArrayOf( - Color.BLACK, - Color.GREEN - ) - private val PURE_BLUE_COLOR_CHECKPOINTS = intArrayOf( - Color.BLACK, - Color.BLUE - ) - - private val PLAIN_RED_COLOR_CHECKPOINTS = intArrayOf( - Color.RED, - Color.RED - ) - private val PLAIN_GREEN_COLOR_CHECKPOINTS = intArrayOf( - Color.GREEN, - Color.GREEN - ) - private val PLAIN_BLUE_COLOR_CHECKPOINTS = intArrayOf( - Color.BLUE, - Color.BLUE - ) } override val colorConverter: IntegerRGBColorConverter get() = super.colorConverter as IntegerRGBColorConverter private var modeInitialized = false - private var _mode: RGBColorPickerSeekBar.Mode? = null - var mode: RGBColorPickerSeekBar.Mode + private var _mode: Mode? = null + var mode: Mode get() { return requireNotNull(_mode) { "Mode is not initialized yet" } } @@ -151,29 +125,15 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( return } - ((progressDrawable as LayerDrawable).getDrawable(0) as GradientDrawable).colors = when (mode) { - Mode.MODE_R -> { - when (coloringMode) { - ColoringMode.PURE_COLOR -> PURE_RED_COLOR_CHECKPOINTS - ColoringMode.OUTPUT_COLOR -> TODO() - ColoringMode.PLAIN_COLOR -> PLAIN_RED_COLOR_CHECKPOINTS + ((progressDrawable as LayerDrawable).getDrawable(0) as GradientDrawable).colors = + when (coloringMode) { + ColoringMode.PURE_COLOR, ColoringMode.PLAIN_COLOR -> mode.coloringModeCheckpointsMap[coloringMode] + ColoringMode.OUTPUT_COLOR -> when (mode) { + Mode.MODE_R -> TODO() + Mode.MODE_G -> TODO() + Mode.MODE_B -> TODO() } } - Mode.MODE_G -> { - when (coloringMode) { - ColoringMode.PURE_COLOR -> PURE_GREEN_COLOR_CHECKPOINTS - ColoringMode.OUTPUT_COLOR -> TODO() - ColoringMode.PLAIN_COLOR -> PLAIN_GREEN_COLOR_CHECKPOINTS - } - } - Mode.MODE_B -> { - when (coloringMode) { - ColoringMode.PURE_COLOR -> PURE_BLUE_COLOR_CHECKPOINTS - ColoringMode.OUTPUT_COLOR -> TODO() - ColoringMode.PLAIN_COLOR -> PLAIN_BLUE_COLOR_CHECKPOINTS - } - } - } } override fun refreshThumb() { @@ -255,7 +215,6 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( } } - // TODO: Refactor private fun paintThumbStroke(drawable: GradientDrawable) { if (!coloringModeInitialized || !modeInitialized) { return @@ -264,39 +223,19 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( val currentProgress = progress drawable.setStroke( thumbStrokeWidthPx, - when (mode) { - Mode.MODE_R -> { - when (coloringMode) { - ColoringMode.PURE_COLOR -> ColorUtils.blendARGB( - Color.BLACK, - Color.RED, - currentProgress / mode.maxProgress.toFloat() - ) - ColoringMode.OUTPUT_COLOR -> TODO() - ColoringMode.PLAIN_COLOR -> Color.RED - } + when (coloringMode) { + ColoringMode.PURE_COLOR, ColoringMode.PLAIN_COLOR -> { + val checkpoints = requireNotNull(mode.coloringModeCheckpointsMap[coloringMode]) + ColorUtils.blendARGB( + checkpoints.first(), + checkpoints.last(), + currentProgress / mode.maxProgress.toFloat() + ) } - Mode.MODE_G -> { - when (coloringMode) { - ColoringMode.PURE_COLOR -> ColorUtils.blendARGB( - Color.BLACK, - Color.GREEN, - currentProgress / mode.maxProgress.toFloat() - ) - ColoringMode.OUTPUT_COLOR -> TODO() - ColoringMode.PLAIN_COLOR -> Color.GREEN - } - } - Mode.MODE_B -> { - when (coloringMode) { - ColoringMode.PURE_COLOR -> ColorUtils.blendARGB( - Color.BLACK, - Color.BLUE, - currentProgress / mode.maxProgress.toFloat() - ) - ColoringMode.OUTPUT_COLOR -> TODO() - ColoringMode.PLAIN_COLOR -> Color.BLUE - } + ColoringMode.OUTPUT_COLOR -> when (mode) { + Mode.MODE_R -> TODO() + Mode.MODE_G -> TODO() + Mode.MODE_B -> TODO() } } ) @@ -310,19 +249,50 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( enum class Mode( val minProgress: Int, - val maxProgress: Int + val maxProgress: Int, + val coloringModeCheckpointsMap: HashMap ) { MODE_R( IntegerRGBColor.Component.R.minValue, - IntegerRGBColor.Component.R.maxValue + IntegerRGBColor.Component.R.maxValue, + hashMapOf( + ColoringMode.PURE_COLOR to intArrayOf( + Color.BLACK, + Color.RED + ), + ColoringMode.PLAIN_COLOR to intArrayOf( + Color.RED, + Color.RED + ) + ) ), MODE_G( IntegerRGBColor.Component.G.minValue, - IntegerRGBColor.Component.G.maxValue + IntegerRGBColor.Component.G.maxValue, + hashMapOf( + ColoringMode.PURE_COLOR to intArrayOf( + Color.BLACK, + Color.GREEN + ), + ColoringMode.PLAIN_COLOR to intArrayOf( + Color.GREEN, + Color.GREEN + ) + ) ), MODE_B( IntegerRGBColor.Component.B.minValue, - IntegerRGBColor.Component.B.maxValue - ), + IntegerRGBColor.Component.B.maxValue, + hashMapOf( + ColoringMode.PURE_COLOR to intArrayOf( + Color.BLACK, + Color.BLUE + ), + ColoringMode.PLAIN_COLOR to intArrayOf( + Color.BLUE, + Color.BLUE + ) + ) + ); } } From a214066a062b82ac9eafa7774e682ab217b53b9b Mon Sep 17 00:00:00 2001 From: N7k Date: Sun, 29 Mar 2020 17:16:30 +0300 Subject: [PATCH 10/12] Update RGBColorPickerSeekBar implementation --- .../rgb/RGBColorPickerSeekBar.kt | 87 +++++++------------ 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt index ff1a4cb..367dbf8 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/rgb/RGBColorPickerSeekBar.kt @@ -2,6 +2,7 @@ package codes.side.andcolorpicker.rgb import android.content.Context import android.graphics.Color +import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.LayerDrawable import android.util.AttributeSet @@ -10,6 +11,7 @@ import codes.side.andcolorpicker.R import codes.side.andcolorpicker.converter.IntegerRGBColorConverter import codes.side.andcolorpicker.model.IntegerRGBColor import codes.side.andcolorpicker.model.factory.RGBColorFactory +import codes.side.andcolorpicker.view.picker.ColorSeekBar import codes.side.andcolorpicker.view.picker.GradientColorSeekBar class RGBColorPickerSeekBar @JvmOverloads constructor( @@ -91,41 +93,30 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( typedArray.recycle() } - override fun setMin(min: Int) { - if (modeInitialized && min != mode.minProgress) { - throw IllegalArgumentException("Current mode supports ${mode.minProgress} min value only") - } - super.setMin(min) - } - override fun setMax(max: Int) { - if (modeInitialized && max != mode.maxProgress) { - throw IllegalArgumentException("Current mode supports ${mode.maxProgress} max value only") + if (modeInitialized && max != mode.absoluteProgress) { + throw IllegalArgumentException("Current mode supports ${mode.absoluteProgress} max value only, was $max") } super.setMax(max) } - override fun updateInternalPickedColorFrom(value: IntegerRGBColor) { - super.updateInternalPickedColorFrom(value) - internalPickedColor.setFrom(value) + override fun onUpdateColorFrom(color: IntegerRGBColor, value: IntegerRGBColor) { + color.setFrom(value) } - override fun refreshProperties() { - super.refreshProperties() + override fun onRefreshProperties() { if (!modeInitialized) { return } max = mode.maxProgress } - override fun refreshProgressDrawable() { - super.refreshProgressDrawable() - + override fun onRefreshProgressDrawable(progressDrawable: LayerDrawable) { if (!coloringModeInitialized || !modeInitialized) { return } - ((progressDrawable as LayerDrawable).getDrawable(0) as GradientDrawable).colors = + (progressDrawable.getDrawable(0) as GradientDrawable).colors = when (coloringMode) { ColoringMode.PURE_COLOR, ColoringMode.PLAIN_COLOR -> mode.coloringModeCheckpointsMap[coloringMode] ColoringMode.OUTPUT_COLOR -> when (mode) { @@ -136,10 +127,8 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( } } - override fun refreshThumb() { - super.refreshThumb() - - coloringDrawables.forEach { + override fun onRefreshThumb(thumbColoringDrawables: Set) { + thumbColoringDrawables.forEach { when (it) { is GradientDrawable -> { paintThumbStroke(it) @@ -151,66 +140,56 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( } } - override fun refreshInternalPickedColorFromProgress() { - super.refreshInternalPickedColorFromProgress() - + override fun onRefreshColorFromProgress(color: IntegerRGBColor, progress: Int): Boolean { if (!modeInitialized) { - return + return false } - val currentProgress = progress - // TODO: Use Atomic and compare/set? - val changed = when (mode) { + return when (mode) { Mode.MODE_R -> { - val currentH = internalPickedColor.intR - if (currentH != currentProgress) { - internalPickedColor.intR = currentProgress + val currentH = color.intR + if (currentH != progress) { + color.intR = progress true } else { false } } Mode.MODE_G -> { - val currentS = internalPickedColor.intG - if (currentS != currentProgress) { - internalPickedColor.intG = currentProgress + val currentS = color.intG + if (currentS != progress) { + color.intG = progress true } else { false } } Mode.MODE_B -> { - val currentL = internalPickedColor.intB - if (currentL != currentProgress) { - internalPickedColor.intB = currentProgress + val currentL = color.intB + if (currentL != progress) { + color.intB = progress true } else { false } } } - - if (changed) { - notifyListenersOnColorChanged() - } } - override fun refreshProgressFromCurrentColor() { - super.refreshProgressFromCurrentColor() - + override fun onRefreshProgressFromColor(color: IntegerRGBColor): Int? { if (!modeInitialized) { - return + return null } - progress = when (mode) { + return when (mode) { Mode.MODE_R -> { - internalPickedColor.intR + color.intR } Mode.MODE_G -> { - internalPickedColor.intG + color.intG } Mode.MODE_B -> { - internalPickedColor.intB + color.intB } } } @@ -248,10 +227,10 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( } enum class Mode( - val minProgress: Int, - val maxProgress: Int, + override val minProgress: Int, + override val maxProgress: Int, val coloringModeCheckpointsMap: HashMap - ) { + ) : ColorSeekBar.Mode { MODE_R( IntegerRGBColor.Component.R.minValue, IntegerRGBColor.Component.R.maxValue, @@ -293,6 +272,6 @@ class RGBColorPickerSeekBar @JvmOverloads constructor( Color.BLUE ) ) - ); + ) } } From 4a3a5f9d51719f6eb56b03e1839254ad0d8075a3 Mon Sep 17 00:00:00 2001 From: N7k Date: Sun, 29 Mar 2020 17:23:57 +0300 Subject: [PATCH 11/12] Make use of alpha in IntegerRGBColorConverter --- .../converter/IntegerRGBColorConverter.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt b/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt index 70dabb2..e5346db 100644 --- a/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt +++ b/andcolorpicker/src/main/java/codes/side/andcolorpicker/converter/IntegerRGBColorConverter.kt @@ -12,10 +12,11 @@ class IntegerRGBColorConverter : ColorConverter { override fun convertToColorInt(color: Color): Int { require(color is IntegerRGBColor) { "Unsupported color type supplied" } - return android.graphics.Color.rgb( - color.floatR.toInt(), - color.floatG.toInt(), - color.floatB.toInt() + return android.graphics.Color.argb( + color.intA, + color.intR, + color.intG, + color.intB ) } @@ -28,6 +29,7 @@ class IntegerRGBColorConverter : ColorConverter { color.copyValuesFrom( intArrayOf( + android.graphics.Color.alpha(value), android.graphics.Color.red(value), android.graphics.Color.green(value), android.graphics.Color.blue(value) From 94a05144721ffb50ff004e333325ccf96fbe5c71 Mon Sep 17 00:00:00 2001 From: N7k Date: Sun, 29 Mar 2020 20:31:48 +0300 Subject: [PATCH 12/12] Extend RGBSeekBarFragment with ColoringMode.PLAIN_COLOR --- .../app/fragment/RGBSeekBarFragment.kt | 26 +++++++++---- .../main/res/layout/fragment_rgb_seek_bar.xml | 38 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt b/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt index 1aeba66..fa85f8a 100644 --- a/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt +++ b/app/src/main/java/codes/side/andcolorpicker/app/fragment/RGBSeekBarFragment.kt @@ -7,6 +7,7 @@ import codes.side.andcolorpicker.app.R import codes.side.andcolorpicker.group.PickerGroup import codes.side.andcolorpicker.group.registerPickers import codes.side.andcolorpicker.model.IntegerRGBColor +import codes.side.andcolorpicker.rgb.RGBColorPickerSeekBar import codes.side.andcolorpicker.view.picker.ColorSeekBar import kotlinx.android.synthetic.main.fragment_rgb_seek_bar.* @@ -16,19 +17,19 @@ class RGBSeekBarFragment : Fragment(R.layout.fragment_rgb_seek_bar) { private const val TAG = "RGBSeekBarFragment" } + private val pickerGroup = PickerGroup() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated( view, savedInstanceState ) - val pickerGroup = PickerGroup().also { - it.registerPickers( - redRGBColorPickerSeekBar, - greenRGBColorPickerSeekBar, - blueRGBColorPickerSeekBar - ) - } + pickerGroup.registerPickers( + redRGBColorPickerSeekBar, + greenRGBColorPickerSeekBar, + blueRGBColorPickerSeekBar + ) pickerGroup.addListener( object : @@ -52,5 +53,16 @@ class RGBSeekBarFragment : Fragment(R.layout.fragment_rgb_seek_bar) { it.intB = 230 } ) + + val radioColoringModesMap = hashMapOf( + R.id.pureRadioButton to RGBColorPickerSeekBar.ColoringMode.PURE_COLOR, + R.id.plainRadioButton to RGBColorPickerSeekBar.ColoringMode.PLAIN_COLOR + ) + coloringModeRadioGroup.setOnCheckedChangeListener { _, checkedId -> + pickerGroup.forEach { + (it as? RGBColorPickerSeekBar)?.coloringMode = + requireNotNull(radioColoringModesMap[checkedId]) + } + } } } diff --git a/app/src/main/res/layout/fragment_rgb_seek_bar.xml b/app/src/main/res/layout/fragment_rgb_seek_bar.xml index a72d452..7b5d9c1 100644 --- a/app/src/main/res/layout/fragment_rgb_seek_bar.xml +++ b/app/src/main/res/layout/fragment_rgb_seek_bar.xml @@ -79,4 +79,42 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/blueRGBColorPickerSeekBar" /> + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b281d98..8d1f01f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ Coloring mode Pure Output + Plain Randomize Work In Progress :D Show dialog