aboutsummaryrefslogtreecommitdiff
path: root/library/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/main/kotlin')
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerDialog.kt297
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerView.kt301
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefActivity.kt37
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBinder.kt6
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt2
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefCheckbox.kt16
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefColorPicker.kt7
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefHeader.kt8
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemBase.kt2
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemCore.kt9
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt4
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt18
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt13
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt19
14 files changed, 410 insertions, 329 deletions
diff --git a/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerDialog.kt b/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerDialog.kt
index 4931913..0ce236c 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerDialog.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerDialog.kt
@@ -2,302 +2,10 @@ package ca.allanwang.kau.dialogs.color
import android.content.Context
import android.graphics.Color
-import android.support.annotation.ColorInt
-import android.support.v4.content.res.ResourcesCompat
-import android.text.Editable
-import android.text.InputFilter
-import android.text.TextWatcher
-import android.util.AttributeSet
-import android.view.View
-import android.view.ViewGroup
-import android.widget.*
import ca.allanwang.kau.R
import ca.allanwang.kau.utils.*
-import com.afollestad.materialdialogs.DialogAction
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.Theme
-import com.afollestad.materialdialogs.color.FillGridView
-import java.util.*
-
-/**
- * Created by Allan Wang on 2017-06-08.
- */
-internal class ColorPickerView @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
-) : ScrollView(context, attrs, defStyleAttr) {
- var selectedColor: Int = -1
- var isInSub: Boolean = false
- var isInCustom: Boolean = false
- var circleSize: Int = context.dimen(R.dimen.kau_color_circle_size).toInt()
- val backgroundColor = context.resolveColor(R.attr.md_background_color,
- if (context.resolveColor(android.R.attr.textColorPrimary).isColorDark()) Color.WHITE else 0xff424242.toInt())
- val backgroundColorTint = if (backgroundColor.isColorDark()) backgroundColor.lighten(0.2f) else backgroundColor.darken(0.2f)
- lateinit var dialog: MaterialDialog
- lateinit var builder: Builder
- lateinit var colorsTop: IntArray
- var colorsSub: Array<IntArray>? = null
- var topIndex: Int = -1
- var subIndex: Int = -1
- var colorIndex: Int
- get() = if (isInSub) subIndex else topIndex
- set(value) {
- if (isInSub) subIndex = value
- else {
- topIndex = value
- if (colorsSub != null && colorsSub!!.size > value) {
- dialog.setActionButton(DialogAction.NEGATIVE, builder.backText)
- isInSub = true
- invalidateGrid()
- }
- }
- }
-
-
- val gridView: FillGridView by bindView(R.id.md_grid)
- val customFrame: LinearLayout by bindView(R.id.md_colorChooserCustomFrame)
- val customColorIndicator: View by bindView(R.id.md_colorIndicator)
- val hexInput: EditText by bindView(R.id.md_hexInput)
- val alphaLabel: TextView by bindView(R.id.md_colorALabel)
- val alphaSeekbar: SeekBar by bindView(R.id.md_colorA)
- val alphaValue: TextView by bindView(R.id.md_colorAValue)
- val redSeekbar: SeekBar by bindView(R.id.md_colorR)
- val redValue: TextView by bindView(R.id.md_colorRValue)
- val greenSeekbar: SeekBar by bindView(R.id.md_colorG)
- val greenValue: TextView by bindView(R.id.md_colorGValue)
- val blueSeekbar: SeekBar by bindView(R.id.md_colorB)
- val blueValue: TextView by bindView(R.id.md_colorBValue)
-
- var customHexTextWatcher: TextWatcher? = null
- var customRgbListener: SeekBar.OnSeekBarChangeListener? = null
-
- init {
- View.inflate(context, R.layout.md_dialog_colorchooser, this)
- }
-
- fun bind(builder: Builder, dialog: MaterialDialog) {
- this.builder = builder
- this.dialog = dialog
- this.colorsTop = builder.colorsTop()
- this.colorsSub = builder.colorsSub()
- this.selectedColor = builder.defaultColor
- if (builder.allowCustom) {
- if (!builder.allowCustomAlpha) {
- alphaLabel.gone()
- alphaSeekbar.gone()
- alphaValue.gone()
- hexInput.hint = String.format("%06X", selectedColor)
- hexInput.filters = arrayOf(InputFilter.LengthFilter(6))
- } else {
- hexInput.hint = String.format("%08X", selectedColor)
- hexInput.filters = arrayOf(InputFilter.LengthFilter(8))
- }
- }
- if (findColor(builder.defaultColor) || !builder.allowCustom) isInCustom = true //when toggled this will be false
- toggleCustom()
- }
-
- fun backOrCancel() {
- if (isInSub) {
- dialog.setActionButton(DialogAction.NEGATIVE, builder.cancelText)
- //to top
- isInSub = false
- subIndex = -1
- invalidateGrid()
- } else {
- dialog.cancel()
- }
- }
-
- fun toggleCustom() {
- isInCustom = !isInCustom
- if (isInCustom) {
- isInSub = false
- if (builder.allowCustom) dialog.setActionButton(DialogAction.NEUTRAL, builder.presetText)
- dialog.setActionButton(DialogAction.NEGATIVE, builder.cancelText)
- customHexTextWatcher = object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
- try {
- selectedColor = Color.parseColor("#" + s.toString())
- } catch (e: IllegalArgumentException) {
- selectedColor = Color.BLACK
- }
-
- customColorIndicator.setBackgroundColor(selectedColor)
- if (alphaSeekbar.isVisible()) {
- val alpha = Color.alpha(selectedColor)
- alphaSeekbar.progress = alpha
- alphaValue.text = String.format(Locale.CANADA, "%d", alpha)
- }
- redSeekbar.progress = Color.red(selectedColor)
- greenSeekbar.progress = Color.green(selectedColor)
- blueSeekbar.progress = Color.blue(selectedColor)
- isInSub = false
- topIndex = -1
- subIndex = -1
- refreshColors()
- }
-
- override fun afterTextChanged(s: Editable?) {}
- }
- hexInput.setText(selectedColor.toHexString(builder.allowCustomAlpha, false))
- hexInput.addTextChangedListener(customHexTextWatcher)
- customRgbListener = object : SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
- if (fromUser) {
- val color = if (builder.allowCustomAlpha)
- Color.argb(alphaSeekbar.progress,
- redSeekbar.progress,
- greenSeekbar.progress,
- blueSeekbar.progress)
- else Color.rgb(redSeekbar.progress,
- greenSeekbar.progress,
- blueSeekbar.progress)
-
- hexInput.setText(color.toHexString(builder.allowCustomAlpha, false))
- }
- if (builder.allowCustomAlpha) alphaValue.text = alphaSeekbar.progress.toString()
- redValue.text = redSeekbar.progress.toString()
- greenValue.text = greenSeekbar.progress.toString()
- blueValue.text = blueSeekbar.progress.toString()
- }
-
- override fun onStartTrackingTouch(seekBar: SeekBar) {}
-
- override fun onStopTrackingTouch(seekBar: SeekBar) {}
- }
- redSeekbar.setOnSeekBarChangeListener(customRgbListener)
- greenSeekbar.setOnSeekBarChangeListener(customRgbListener)
- blueSeekbar.setOnSeekBarChangeListener(customRgbListener)
- if (alphaSeekbar.isVisible())
- alphaSeekbar.setOnSeekBarChangeListener(customRgbListener)
- hexInput.setText(selectedColor.toHexString(alphaSeekbar.isVisible(), false))
- gridView.fadeOut(onFinish = { gridView.gone() })
- customFrame.fadeIn()
- } else {
- findColor(selectedColor)
- if (builder.allowCustom) dialog.setActionButton(DialogAction.NEUTRAL, builder.customText)
- dialog.setActionButton(DialogAction.NEGATIVE, if (isInSub) builder.backText else builder.cancelText)
- gridView.fadeIn(onStart = { invalidateGrid() })
- customFrame.fadeOut(onFinish = { customFrame.gone() })
- hexInput.removeTextChangedListener(customHexTextWatcher)
- customHexTextWatcher = null
- alphaSeekbar.setOnSeekBarChangeListener(null)
- redSeekbar.setOnSeekBarChangeListener(null)
- greenSeekbar.setOnSeekBarChangeListener(null)
- blueSeekbar.setOnSeekBarChangeListener(null)
- customRgbListener = null
- }
- }
-
- fun refreshColors() {
- if (!isInCustom) findColor(selectedColor)
- //Ensure that our tinted color is still visible against the background
- val visibleColor = if (selectedColor.isColorVisibleOn(backgroundColor)) selectedColor else backgroundColorTint
- if (builder.dynamicButtonColors) {
- dialog.getActionButton(DialogAction.POSITIVE).setTextColor(visibleColor)
- dialog.getActionButton(DialogAction.NEGATIVE).setTextColor(visibleColor)
- dialog.getActionButton(DialogAction.NEUTRAL).setTextColor(visibleColor)
- }
- if (!builder.allowCustom || !isInCustom) return
- if (builder.allowCustomAlpha)
- alphaSeekbar.visible().tint(visibleColor)
- redSeekbar.tint(visibleColor)
- greenSeekbar.tint(visibleColor)
- blueSeekbar.tint(visibleColor)
- hexInput.tint(visibleColor)
- }
-
- fun findColor(@ColorInt color: Int): Boolean {
- topIndex = -1
- subIndex = -1
- colorsTop.forEachIndexed {
- index, topColor ->
- if (findSubColor(color, index)) {
- topIndex = index
- return true
- }
- if (topColor == color) { // If no sub colors exists and top color matches
- topIndex = index
- return true
- }
- }
- return false
- }
-
- fun findSubColor(@ColorInt color: Int, topIndex: Int): Boolean {
- if (colorsSub == null || colorsSub!!.size <= topIndex) return false
- colorsSub!![topIndex].forEachIndexed {
- index, subColor ->
- if (subColor == color) {
- subIndex = index
- return true
- }
- }
- return false
- }
-
- fun invalidateGrid() {
- if (gridView.adapter == null) {
- gridView.adapter = ColorGridAdapter()
- gridView.selector = ResourcesCompat.getDrawable(resources, R.drawable.kau_transparent, null)
- } else {
- (gridView.adapter as BaseAdapter).notifyDataSetChanged()
- }
- }
-
- inner class ColorGridAdapter : BaseAdapter(), OnClickListener, OnLongClickListener {
- override fun onClick(v: View) {
- if (v.tag != null && v.tag is String) {
- val tags = (v.tag as String).split(":")
- if (colorIndex == tags[0].toInt()) {
- colorIndex = tags[0].toInt() //Go to sub list if exists
- return
- }
- if (colorIndex != -1) (gridView.getChildAt(colorIndex) as CircleView).animateSelected(false)
- selectedColor = tags[1].toInt()
- refreshColors()
- val currentSub = isInSub
- colorIndex = tags[0].toInt()
- if (currentSub == isInSub) (gridView.getChildAt(colorIndex) as CircleView).animateSelected(true)
- //Otherwise we are invalidating our grid, so there is no point in animating
- }
- }
-
- override fun onLongClick(v: View): Boolean {
- if (v.tag != null && v.tag is String) {
- val tag = (v.tag as String).split(":")
- val color = tag[1].toInt()
- (v as CircleView).showHint(color)
- return true
- }
- return false
- }
-
- override fun getItem(position: Int): Any = if (isInSub) colorsSub!![topIndex][position] else colorsTop[position]
-
- override fun getCount(): Int = if (isInSub) colorsSub!![topIndex].size else colorsTop.size
-
- override fun getItemId(position: Int): Long = position.toLong()
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val view: CircleView = if (convertView == null)
- CircleView(context).apply { layoutParams = AbsListView.LayoutParams(circleSize, circleSize) }
- else
- convertView as CircleView
- val color: Int = if (isInSub) colorsSub!![topIndex][position] else colorsTop[position]
- return view.apply {
- setBackgroundColor(color)
- isSelected = colorIndex == position
- tag = "$position:$color"
- setOnClickListener(this@ColorGridAdapter)
- setOnLongClickListener(this@ColorGridAdapter)
- }
- }
-
- }
-}
class Builder {
var title: String? = null
@@ -332,7 +40,10 @@ class Builder {
fun applyNestedBuilder(action: Builder.() -> Unit) = this.action()
}
-
+/**
+ * This is the extension that allows us to initialize the dialog
+ * Note that this returns just the dialog; you still need to call .show() to show it
+ */
fun Context.colorPickerDialog(action: Builder.() -> Unit): MaterialDialog {
val b = Builder()
b.action()
diff --git a/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerView.kt b/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerView.kt
new file mode 100644
index 0000000..9d0c9c1
--- /dev/null
+++ b/library/src/main/kotlin/ca/allanwang/kau/dialogs/color/ColorPickerView.kt
@@ -0,0 +1,301 @@
+package ca.allanwang.kau.dialogs.color
+
+import android.content.Context
+import android.graphics.Color
+import android.support.annotation.ColorInt
+import android.support.v4.content.res.ResourcesCompat
+import android.text.Editable
+import android.text.InputFilter
+import android.text.TextWatcher
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.widget.*
+import ca.allanwang.kau.R
+import ca.allanwang.kau.utils.*
+import com.afollestad.materialdialogs.DialogAction
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.color.FillGridView
+import java.util.*
+
+/**
+ * Created by Allan Wang on 2017-06-08.
+ *
+ * ColorPicker component of the ColorPickerDialog
+ */
+internal class ColorPickerView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : ScrollView(context, attrs, defStyleAttr) {
+ var selectedColor: Int = -1
+ var isInSub: Boolean = false
+ var isInCustom: Boolean = false
+ var circleSize: Int = context.dimen(R.dimen.kau_color_circle_size).toInt()
+ val backgroundColor = context.resolveColor(R.attr.md_background_color,
+ if (context.resolveColor(android.R.attr.textColorPrimary).isColorDark()) Color.WHITE else 0xff424242.toInt())
+ val backgroundColorTint = if (backgroundColor.isColorDark()) backgroundColor.lighten(0.2f) else backgroundColor.darken(0.2f)
+ lateinit var dialog: MaterialDialog
+ lateinit var builder: Builder
+ lateinit var colorsTop: IntArray
+ var colorsSub: Array<IntArray>? = null
+ var topIndex: Int = -1
+ var subIndex: Int = -1
+ var colorIndex: Int
+ get() = if (isInSub) subIndex else topIndex
+ set(value) {
+ if (isInSub) subIndex = value
+ else {
+ topIndex = value
+ if (colorsSub != null && colorsSub!!.size > value) {
+ dialog.setActionButton(DialogAction.NEGATIVE, builder.backText)
+ isInSub = true
+ invalidateGrid()
+ }
+ }
+ }
+
+
+ val gridView: FillGridView by bindView(R.id.md_grid)
+ val customFrame: LinearLayout by bindView(R.id.md_colorChooserCustomFrame)
+ val customColorIndicator: View by bindView(R.id.md_colorIndicator)
+ val hexInput: EditText by bindView(R.id.md_hexInput)
+ val alphaLabel: TextView by bindView(R.id.md_colorALabel)
+ val alphaSeekbar: SeekBar by bindView(R.id.md_colorA)
+ val alphaValue: TextView by bindView(R.id.md_colorAValue)
+ val redSeekbar: SeekBar by bindView(R.id.md_colorR)
+ val redValue: TextView by bindView(R.id.md_colorRValue)
+ val greenSeekbar: SeekBar by bindView(R.id.md_colorG)
+ val greenValue: TextView by bindView(R.id.md_colorGValue)
+ val blueSeekbar: SeekBar by bindView(R.id.md_colorB)
+ val blueValue: TextView by bindView(R.id.md_colorBValue)
+
+ var customHexTextWatcher: TextWatcher? = null
+ var customRgbListener: SeekBar.OnSeekBarChangeListener? = null
+
+ init {
+ View.inflate(context, R.layout.md_dialog_colorchooser, this)
+ }
+
+ fun bind(builder: Builder, dialog: MaterialDialog) {
+ this.builder = builder
+ this.dialog = dialog
+ this.colorsTop = builder.colorsTop()
+ this.colorsSub = builder.colorsSub()
+ this.selectedColor = builder.defaultColor
+ if (builder.allowCustom) {
+ if (!builder.allowCustomAlpha) {
+ alphaLabel.gone()
+ alphaSeekbar.gone()
+ alphaValue.gone()
+ hexInput.hint = String.format("%06X", selectedColor)
+ hexInput.filters = arrayOf(InputFilter.LengthFilter(6))
+ } else {
+ hexInput.hint = String.format("%08X", selectedColor)
+ hexInput.filters = arrayOf(InputFilter.LengthFilter(8))
+ }
+ }
+ if (findColor(builder.defaultColor) || !builder.allowCustom) isInCustom = true //when toggled this will be false
+ toggleCustom()
+ }
+
+ fun backOrCancel() {
+ if (isInSub) {
+ dialog.setActionButton(DialogAction.NEGATIVE, builder.cancelText)
+ //to top
+ isInSub = false
+ subIndex = -1
+ invalidateGrid()
+ } else {
+ dialog.cancel()
+ }
+ }
+
+ fun toggleCustom() {
+ isInCustom = !isInCustom
+ if (isInCustom) {
+ isInSub = false
+ if (builder.allowCustom) dialog.setActionButton(DialogAction.NEUTRAL, builder.presetText)
+ dialog.setActionButton(DialogAction.NEGATIVE, builder.cancelText)
+ customHexTextWatcher = object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ try {
+ selectedColor = Color.parseColor("#" + s.toString())
+ } catch (e: IllegalArgumentException) {
+ selectedColor = Color.BLACK
+ }
+
+ customColorIndicator.setBackgroundColor(selectedColor)
+ if (alphaSeekbar.isVisible()) {
+ val alpha = Color.alpha(selectedColor)
+ alphaSeekbar.progress = alpha
+ alphaValue.text = String.format(Locale.CANADA, "%d", alpha)
+ }
+ redSeekbar.progress = Color.red(selectedColor)
+ greenSeekbar.progress = Color.green(selectedColor)
+ blueSeekbar.progress = Color.blue(selectedColor)
+ isInSub = false
+ topIndex = -1
+ subIndex = -1
+ refreshColors()
+ }
+
+ override fun afterTextChanged(s: Editable?) {}
+ }
+ hexInput.setText(selectedColor.toHexString(builder.allowCustomAlpha, false))
+ hexInput.addTextChangedListener(customHexTextWatcher)
+ customRgbListener = object : SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ if (fromUser) {
+ val color = if (builder.allowCustomAlpha)
+ Color.argb(alphaSeekbar.progress,
+ redSeekbar.progress,
+ greenSeekbar.progress,
+ blueSeekbar.progress)
+ else Color.rgb(redSeekbar.progress,
+ greenSeekbar.progress,
+ blueSeekbar.progress)
+
+ hexInput.setText(color.toHexString(builder.allowCustomAlpha, false))
+ }
+ if (builder.allowCustomAlpha) alphaValue.text = alphaSeekbar.progress.toString()
+ redValue.text = redSeekbar.progress.toString()
+ greenValue.text = greenSeekbar.progress.toString()
+ blueValue.text = blueSeekbar.progress.toString()
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {}
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {}
+ }
+ redSeekbar.setOnSeekBarChangeListener(customRgbListener)
+ greenSeekbar.setOnSeekBarChangeListener(customRgbListener)
+ blueSeekbar.setOnSeekBarChangeListener(customRgbListener)
+ if (alphaSeekbar.isVisible())
+ alphaSeekbar.setOnSeekBarChangeListener(customRgbListener)
+ hexInput.setText(selectedColor.toHexString(alphaSeekbar.isVisible(), false))
+ gridView.fadeOut(onFinish = { gridView.gone() })
+ customFrame.fadeIn()
+ } else {
+ findColor(selectedColor)
+ if (builder.allowCustom) dialog.setActionButton(DialogAction.NEUTRAL, builder.customText)
+ dialog.setActionButton(DialogAction.NEGATIVE, if (isInSub) builder.backText else builder.cancelText)
+ gridView.fadeIn(onStart = { invalidateGrid() })
+ customFrame.fadeOut(onFinish = { customFrame.gone() })
+ hexInput.removeTextChangedListener(customHexTextWatcher)
+ customHexTextWatcher = null
+ alphaSeekbar.setOnSeekBarChangeListener(null)
+ redSeekbar.setOnSeekBarChangeListener(null)
+ greenSeekbar.setOnSeekBarChangeListener(null)
+ blueSeekbar.setOnSeekBarChangeListener(null)
+ customRgbListener = null
+ }
+ }
+
+ fun refreshColors() {
+ if (!isInCustom) findColor(selectedColor)
+ //Ensure that our tinted color is still visible against the background
+ val visibleColor = if (selectedColor.isColorVisibleOn(backgroundColor)) selectedColor else backgroundColorTint
+ if (builder.dynamicButtonColors) {
+ dialog.getActionButton(DialogAction.POSITIVE).setTextColor(visibleColor)
+ dialog.getActionButton(DialogAction.NEGATIVE).setTextColor(visibleColor)
+ dialog.getActionButton(DialogAction.NEUTRAL).setTextColor(visibleColor)
+ }
+ if (!builder.allowCustom || !isInCustom) return
+ if (builder.allowCustomAlpha)
+ alphaSeekbar.visible().tint(visibleColor)
+ redSeekbar.tint(visibleColor)
+ greenSeekbar.tint(visibleColor)
+ blueSeekbar.tint(visibleColor)
+ hexInput.tint(visibleColor)
+ }
+
+ fun findColor(@ColorInt color: Int): Boolean {
+ topIndex = -1
+ subIndex = -1
+ colorsTop.forEachIndexed {
+ index, topColor ->
+ if (findSubColor(color, index)) {
+ topIndex = index
+ return true
+ }
+ if (topColor == color) { // If no sub colors exists and top color matches
+ topIndex = index
+ return true
+ }
+ }
+ return false
+ }
+
+ fun findSubColor(@ColorInt color: Int, topIndex: Int): Boolean {
+ if (colorsSub == null || colorsSub!!.size <= topIndex) return false
+ colorsSub!![topIndex].forEachIndexed {
+ index, subColor ->
+ if (subColor == color) {
+ subIndex = index
+ return true
+ }
+ }
+ return false
+ }
+
+ fun invalidateGrid() {
+ if (gridView.adapter == null) {
+ gridView.adapter = ColorGridAdapter()
+ gridView.selector = ResourcesCompat.getDrawable(resources, R.drawable.kau_transparent, null)
+ } else {
+ (gridView.adapter as BaseAdapter).notifyDataSetChanged()
+ }
+ }
+
+ inner class ColorGridAdapter : BaseAdapter(), OnClickListener, OnLongClickListener {
+ override fun onClick(v: View) {
+ if (v.tag != null && v.tag is String) {
+ val tags = (v.tag as String).split(":")
+ if (colorIndex == tags[0].toInt()) {
+ colorIndex = tags[0].toInt() //Go to sub list if exists
+ return
+ }
+ if (colorIndex != -1) (gridView.getChildAt(colorIndex) as CircleView).animateSelected(false)
+ selectedColor = tags[1].toInt()
+ refreshColors()
+ val currentSub = isInSub
+ colorIndex = tags[0].toInt()
+ if (currentSub == isInSub) (gridView.getChildAt(colorIndex) as CircleView).animateSelected(true)
+ //Otherwise we are invalidating our grid, so there is no point in animating
+ }
+ }
+
+ override fun onLongClick(v: View): Boolean {
+ if (v.tag != null && v.tag is String) {
+ val tag = (v.tag as String).split(":")
+ val color = tag[1].toInt()
+ (v as CircleView).showHint(color)
+ return true
+ }
+ return false
+ }
+
+ override fun getItem(position: Int): Any = if (isInSub) colorsSub!![topIndex][position] else colorsTop[position]
+
+ override fun getCount(): Int = if (isInSub) colorsSub!![topIndex].size else colorsTop.size
+
+ override fun getItemId(position: Int): Long = position.toLong()
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val view: CircleView = if (convertView == null)
+ CircleView(context).apply { layoutParams = AbsListView.LayoutParams(circleSize, circleSize) }
+ else
+ convertView as CircleView
+ val color: Int = if (isInSub) colorsSub!![topIndex][position] else colorsTop[position]
+ return view.apply {
+ setBackgroundColor(color)
+ isSelected = colorIndex == position
+ tag = "$position:$color"
+ setOnClickListener(this@ColorGridAdapter)
+ setOnLongClickListener(this@ColorGridAdapter)
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefActivity.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefActivity.kt
new file mode 100644
index 0000000..eb9202d
--- /dev/null
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefActivity.kt
@@ -0,0 +1,37 @@
+package ca.allanwang.kau.kpref
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.Toolbar
+import android.view.View
+import ca.allanwang.kau.R
+import ca.allanwang.kau.kpref.items.KPrefItemCore
+import ca.allanwang.kau.utils.bindView
+import ca.allanwang.kau.utils.resolveColor
+import ca.allanwang.kau.views.RippleCanvas
+import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter
+
+
+abstract class KPrefActivity : AppCompatActivity() {
+
+ lateinit var adapter: FastItemAdapter<KPrefItemCore>
+ val recycler: RecyclerView by bindView(R.id.kau_recycler)
+ val bgCanvas: RippleCanvas by bindView(R.id.kau_ripple)
+ val toolbarCanvas: RippleCanvas by bindView(R.id.kau_toolbar_ripple)
+ val toolbar: Toolbar by bindView(R.id.kau_toolbar)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.kau_activity_kpref)
+ setSupportActionBar(toolbar)
+ window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ window.statusBarColor = 0x30000000
+ toolbarCanvas.set(resolveColor(R.attr.colorPrimary))
+ bgCanvas.set(resolveColor(android.R.attr.colorBackground))
+ adapter = recycler.setKPrefAdapter(onCreateKPrefs(savedInstanceState))
+ }
+
+ abstract fun onCreateKPrefs(savedInstanceState: Bundle?): KPrefAdapterBuilder.() -> Unit
+
+}
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBinder.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBinder.kt
index acbb9a9..57f4cb9 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBinder.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBinder.kt
@@ -1,6 +1,5 @@
package ca.allanwang.kau.kpref
-import android.support.annotation.ColorInt
import android.support.annotation.StringRes
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
@@ -29,7 +28,12 @@ fun RecyclerView.setKPrefAdapter(builder: KPrefAdapterBuilder.() -> Unit): FastI
class KPrefAdapterBuilder {
var textColor: Int? = null
+ get() = textColorGetter?.invoke() ?: field
var accentColor: Int? = null
+ get() = accentColorGetter?.invoke() ?: field
+
+ var textColorGetter: (() -> Int)? = null
+ var accentColorGetter: (() -> Int)? = null
fun header(@StringRes title: Int) = list.add(KPrefHeader(this, title))
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt
index 9638904..5c6caa9 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt
@@ -60,7 +60,7 @@ class KPrefDelegate<T : Any> internal constructor(private val key: String, priva
override fun isInitialized(): Boolean = _value !== UNINITIALIZED
- override fun toString(): String = if (isInitialized()) value.toString() else "Lazy pref $key not initialized yet."
+ override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet."
operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) {
_value = t
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefCheckbox.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefCheckbox.kt
index 9961df9..474c3e5 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefCheckbox.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefCheckbox.kt
@@ -5,11 +5,15 @@ import android.view.View
import android.widget.CheckBox
import ca.allanwang.kau.R
import ca.allanwang.kau.kpref.KPrefAdapterBuilder
+import ca.allanwang.kau.logging.SL
import ca.allanwang.kau.utils.tint
import com.mikepenz.iconics.typeface.IIcon
/**
* Created by Allan Wang on 2017-06-07.
+ *
+ * Checkbox preference
+ * When clicked, will toggle the preference and the apply the result to the checkbox
*/
class KPrefCheckbox(builder: KPrefAdapterBuilder,
@StringRes title: Int,
@@ -19,11 +23,6 @@ class KPrefCheckbox(builder: KPrefAdapterBuilder,
getter: () -> Boolean,
setter: (value: Boolean) -> Unit) : KPrefItemBase<Boolean>(builder, title, description, iicon, enabled, getter, setter) {
- override fun onPostBindView(viewHolder: KPrefItemCore.ViewHolder) {
- super.onPostBindView(viewHolder)
- viewHolder.addInnerView(R.layout.kau_preference_checkbox)
- (viewHolder[R.id.kau_pref_checkbox] as CheckBox).isChecked = pref
- }
override fun onClick(itemView: View): Boolean {
val checkbox = itemView.findViewById(R.id.kau_pref_checkbox) as CheckBox
@@ -32,11 +31,14 @@ class KPrefCheckbox(builder: KPrefAdapterBuilder,
return true
}
- override fun setColors(viewHolder: ViewHolder, builder: KPrefAdapterBuilder) {
- super.setColors(viewHolder, builder)
+ override fun onPostBindView(viewHolder: ViewHolder, builder: KPrefAdapterBuilder) {
+ super.onPostBindView(viewHolder, builder)
+ viewHolder.addInnerView(R.layout.kau_preference_checkbox)
if (builder.accentColor != null) {
val checkbox = viewHolder.itemView.findViewById(R.id.kau_pref_checkbox) as CheckBox
checkbox.tint(builder.accentColor!!)
+ checkbox.isChecked = pref //Checkbox tick needs to be delayed since notifyDataSetChanged will cancel the animation
+ //It seems to work well here
}
}
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefColorPicker.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefColorPicker.kt
index 38a12e2..a9926ef 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefColorPicker.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefColorPicker.kt
@@ -10,6 +10,9 @@ import com.mikepenz.iconics.typeface.IIcon
/**
* Created by Allan Wang on 2017-06-07.
+ *
+ * ColorPicker preference
+ * When a color is successfully selected in the dialog, it will be saved as an int
*/
class KPrefColorPicker(builder: KPrefAdapterBuilder,
@StringRes title: Int,
@@ -20,8 +23,8 @@ class KPrefColorPicker(builder: KPrefAdapterBuilder,
setter: (value: Int) -> Unit,
val configs: Builder.() -> Unit = {}) : KPrefItemBase<Int>(builder, title, description, iicon, enabled, getter, setter) {
- override fun onPostBindView(viewHolder: KPrefItemCore.ViewHolder) {
- super.onPostBindView(viewHolder)
+ override fun onPostBindView(viewHolder: KPrefItemCore.ViewHolder, builder: KPrefAdapterBuilder) {
+ super.onPostBindView(viewHolder, builder)
//TODO add color circle view
}
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefHeader.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefHeader.kt
index 4d3952e..1175fc2 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefHeader.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefHeader.kt
@@ -7,13 +7,17 @@ import ca.allanwang.kau.kpref.KPrefAdapterBuilder
/**
* Created by Allan Wang on 2017-06-07.
+ *
+ * Header preference
+ * This view just holds a title and is not clickable. It is styled using the accent color
*/
-class KPrefHeader(builder:KPrefAdapterBuilder, @StringRes title: Int) : KPrefItemCore(builder, title = title) {
+class KPrefHeader(builder: KPrefAdapterBuilder, @StringRes title: Int) : KPrefItemCore(builder, title = title) {
override fun getLayoutRes(): Int = R.layout.kau_preference_header
- override fun onPostBindView(viewHolder: ViewHolder) {
+ override fun onPostBindView(viewHolder: ViewHolder, builder: KPrefAdapterBuilder) {
viewHolder.itemView.isClickable = false
+ if (builder.accentColor != null) viewHolder.title.setTextColor(builder.accentColor!!)
}
override fun onClick(itemView: View): Boolean = true
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemBase.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemBase.kt
index b5e0254..adcbc8a 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemBase.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemBase.kt
@@ -28,7 +28,7 @@ abstract class KPrefItemBase<T>(builder: KPrefAdapterBuilder,
}
@CallSuper
- override fun onPostBindView(viewHolder: ViewHolder) {
+ override fun onPostBindView(viewHolder: ViewHolder, builder: KPrefAdapterBuilder) {
viewHolder.itemView.isEnabled = enabled
viewHolder.itemView.alpha = if (enabled) 1.0f else 0.3f
}
diff --git a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemCore.kt b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemCore.kt
index 112365a..98e977e 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemCore.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/kpref/items/KPrefItemCore.kt
@@ -45,13 +45,12 @@ abstract class KPrefItemCore(val builder: KPrefAdapterBuilder,
icon?.setIcon(iicon, 48)
} else iconFrame?.gone()
innerFrame?.removeAllViews()
- onPostBindView(this)
- setColors(this, builder)
+ setColors(this)
+ onPostBindView(this, builder)
}
}
- @CallSuper
- open fun setColors(viewHolder: ViewHolder, builder: KPrefAdapterBuilder) {
+ fun setColors(viewHolder: ViewHolder) {
with(viewHolder) {
if (builder.textColor != null) {
title.setTextColor(builder.textColor!!)
@@ -63,7 +62,7 @@ abstract class KPrefItemCore(val builder: KPrefAdapterBuilder,
}
}
- abstract fun onPostBindView(viewHolder: ViewHolder)
+ abstract fun onPostBindView(viewHolder: ViewHolder, builder: KPrefAdapterBuilder)
abstract fun onClick(itemView: View): Boolean
diff --git a/library/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt b/library/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt
index 325a8af..35681b0 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt
@@ -82,12 +82,12 @@ fun String.toColor(): Int {
//Get ColorStateList
fun Context.colorStateList(@ColorInt color: Int): ColorStateList {
- val disabledColor = getDisabledColor()
+ val disabledColor = color.adjustAlpha(0.3f)
return ColorStateList(arrayOf(intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked),
intArrayOf(-android.R.attr.state_enabled, -android.R.attr.state_checked),
intArrayOf(-android.R.attr.state_enabled, android.R.attr.state_checked)),
- intArrayOf(this.resolveColor(R.attr.colorControlNormal), color, disabledColor, disabledColor))
+ intArrayOf(color.adjustAlpha(0.8f), color, disabledColor, disabledColor))
}
/*
diff --git a/library/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt b/library/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt
index 16804a5..5547fe1 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt
@@ -3,6 +3,7 @@ package ca.allanwang.kau.utils
import android.app.Activity
import android.content.Context
import android.content.Intent
+import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
import android.os.Handler
@@ -29,6 +30,12 @@ fun Activity.restart(extras: ((Intent) -> Unit)? = null) {
overridePendingTransition(0, 0)
}
+var Activity.navigationBarColor: Int
+ get() = if (buildIsLollipopAndUp) window.navigationBarColor else Color.BLACK
+ set(value) {
+ if (buildIsLollipopAndUp) window.navigationBarColor = value
+ }
+
//Toast helpers
fun Context.toast(@StringRes id: Int, duration: Int = Toast.LENGTH_LONG) = toast(this.string(id), duration)
@@ -86,10 +93,11 @@ fun Context.showChangelog(@XmlRes xmlRes: Int) {
}).start()
}
-fun Context.isNetworkAvailable(): Boolean {
- val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
- val activeNetworkInfo = connectivityManager.activeNetworkInfo
- return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting
-}
+val Context.isNetworkAvailable: Boolean
+ get() {
+ val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val activeNetworkInfo = connectivityManager.activeNetworkInfo
+ return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting
+ }
fun Context.getDip(value: Float): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, resources.displayMetrics) \ No newline at end of file
diff --git a/library/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt b/library/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt
index 79f80f3..e00891d 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt
@@ -1,11 +1,20 @@
package ca.allanwang.kau.utils
import android.content.res.Resources
+import android.os.Build
/**
* Created by Allan Wang on 2017-05-28.
*/
-fun Int.dpToPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
+val Int.dpToPx: Int
+ get() = (this * Resources.getSystem().displayMetrics.density).toInt()
-fun Int.pxToDp(px: Int) = (px / android.content.res.Resources.getSystem().displayMetrics.density).toInt() \ No newline at end of file
+val Int.pxToDp: Int
+ get() = (this / Resources.getSystem().displayMetrics.density).toInt()
+
+val buildIsLollipopAndUp: Boolean
+ get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+
+val buildIsMarshmallowAndUp: Boolean
+ get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M \ No newline at end of file
diff --git a/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt b/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt
index 9444ef9..eaa9121 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt
@@ -72,16 +72,18 @@ class RippleCanvas @JvmOverloads constructor(
}
fun ripple(color: Int, startX: Float = 0f, startY: Float = 0f, duration: Int = 1000, fade: Boolean = Color.alpha(color) != 255) {
- var x = startX
- var y = startY
val w = width.toFloat()
val h = height.toFloat()
- if (x == MIDDLE)
- x = w / 2
- else if (x > w) x = 0f
- if (y == MIDDLE)
- y = h / 2
- else if (y > h) y = 0f
+ val x = when (startX) {
+ MIDDLE -> w/2
+ END -> w
+ else -> startX
+ }
+ val y = when (startY) {
+ MIDDLE -> h/2
+ END -> h
+ else -> startY
+ }
val maxRadius = Math.hypot(Math.max(x, w - x).toDouble(), Math.max(y, h - y).toDouble()).toFloat()
val ripple = Ripple(color, x, y, 0f, maxRadius, fade)
ripples.add(ripple)
@@ -109,6 +111,7 @@ class RippleCanvas @JvmOverloads constructor(
companion object {
const val MIDDLE = -1.0f
+ const val END = -2.0f
const val FADE_PIVOT = 0.5f
}
}