diff options
author | Allan Wang <me@allanwang.ca> | 2018-02-23 20:52:21 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-23 20:52:21 -0500 |
commit | 3d7c85bd97261116a090a7202b0e0ed2625b5d73 (patch) | |
tree | f8d6409ef847a1ca0c0ba3640a27984703de470e | |
parent | 20f0d085d6940be30b076a8cff3de25fe4a6e21a (diff) | |
download | kau-3d7c85bd97261116a090a7202b0e0ed2625b5d73.tar.gz kau-3d7c85bd97261116a090a7202b0e0ed2625b5d73.tar.bz2 kau-3d7c85bd97261116a090a7202b0e0ed2625b5d73.zip |
Misc (#140)
* Nullify task
* Rewrite circle view
* Add better encapsulation
* Update annotations
* Update kpref annotations
* Begin writing tests for color picker
* Add color selection tests
* Update changelog
* Cleanup
19 files changed, 232 insertions, 160 deletions
diff --git a/android-lib.gradle b/android-lib.gradle index 86c0067..2be7c46 100644 --- a/android-lib.gradle +++ b/android-lib.gradle @@ -81,10 +81,10 @@ android { } dependencies { - androidTestImplementation("com.android.support.test:runner:${kau.testRunner}") { - exclude group: 'com.android.support', module: 'support-annotations' - } - androidTestImplementation kauDependency.kotlinTest testImplementation kauDependency.kotlinTest testImplementation kauDependency.junit + + androidTestImplementation kauDependency.kotlinTest + androidTestImplementation kauDependency.espresso + androidTestImplementation kauDependency.testRunner }
\ No newline at end of file diff --git a/buildSrc/src/main/groovy/ca/allanwang/kau/Dependencies.groovy b/buildSrc/src/main/groovy/ca/allanwang/kau/Dependencies.groovy index 368b0a8..ec3d208 100644 --- a/buildSrc/src/main/groovy/ca/allanwang/kau/Dependencies.groovy +++ b/buildSrc/src/main/groovy/ca/allanwang/kau/Dependencies.groovy @@ -7,4 +7,6 @@ class Dependencies { static def kotlin = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}" static def kotlinTest = "org.jetbrains.kotlin:kotlin-test-junit:${Versions.kotlin}" static def junit = "junit:junit:${Versions.junit}" + static def espresso = "com.android.support.test.espresso:espresso-core:${Versions.espresso}" + static def testRunner = "com.android.support.test:runner:${Versions.testRunner}" }
\ No newline at end of file diff --git a/buildSrc/src/main/groovy/ca/allanwang/kau/Versions.groovy b/buildSrc/src/main/groovy/ca/allanwang/kau/Versions.groovy index 36e444d..ac38509 100644 --- a/buildSrc/src/main/groovy/ca/allanwang/kau/Versions.groovy +++ b/buildSrc/src/main/groovy/ca/allanwang/kau/Versions.groovy @@ -25,9 +25,9 @@ class Versions { static def materialDialog = '0.9.6.0' - static def espresso = '3.0.0' + static def espresso = '3.0.1' static def junit = '4.12' - static def testRunner = '1.0.0' + static def testRunner = '1.0.1' static def gradlePlugin = '3.0.1' static def mavenPlugin = '2.0' diff --git a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt index c74cba1..fe7a7a6 100644 --- a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt +++ b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt @@ -45,6 +45,8 @@ class CircleView @JvmOverloads constructor(context: Context, attrs: AttributeSet private val outerPaint: Paint = Paint().apply { isAntiAlias = true } private val whitePaint: Paint = Paint().apply { isAntiAlias = true; color = Color.WHITE } private val innerPaint: Paint = Paint().apply { isAntiAlias = true } + val colorSelected: Boolean + get() = selected private var selected: Boolean = false var withBorder: Boolean = false set(value) { @@ -107,25 +109,16 @@ class CircleView @JvmOverloads constructor(context: Context, attrs: AttributeSet fun animateSelected(selected: Boolean) { if (this.selected == selected) return - this.selected = true // We need to draw the other bands + this.selected = selected // We need to draw the other bands val range = if (selected) Pair(-borderWidthSmall, borderWidthLarge) else Pair(borderWidthLarge, -borderWidthSmall) - val animator = ValueAnimator.ofFloat(range.first, range.second) - with(animator) { + ValueAnimator.ofFloat(range.first, range.second).apply { reverse() duration = 150L addUpdateListener { animation -> whiteOuterBound = animation.animatedValue as Float invalidate() + } - addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - this@CircleView.selected = selected - } - - override fun onAnimationCancel(animation: Animator) { - this@CircleView.selected = selected - } - }) start() } } diff --git a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt index a3dcc2d..ccebb71 100644 --- a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt +++ b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt @@ -31,19 +31,26 @@ class ColorBuilder : ColorContract { interface ColorContract { var title: String? - var titleRes: Int @StringRes set + @setparam:StringRes + var titleRes: Int var allowCustom: Boolean var allowCustomAlpha: Boolean var isAccent: Boolean - var defaultColor: Int @StringRes set - var doneText: Int @StringRes set - var backText: Int @StringRes set - var cancelText: Int @StringRes set + @setparam:StringRes + var defaultColor: Int + @setparam:StringRes + var doneText: Int + @setparam:StringRes + var backText: Int + @setparam:StringRes + var cancelText: Int + @setparam:StringRes var presetText: Int - @StringRes set - var customText: Int @StringRes set + @setparam:StringRes + var customText: Int var dynamicButtonColors: Boolean - var circleSizeRes: Int @DimenRes set + @setparam:DimenRes + var circleSizeRes: Int var colorCallback: ((selectedColor: Int) -> Unit)? var colorsTop: IntArray? var colorsSub: Array<IntArray>? diff --git a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerView.kt b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerView.kt index 778b775..dfb0773 100644 --- a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerView.kt +++ b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerView.kt @@ -26,21 +26,23 @@ import java.util.* 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 selectedColor: Int + get() = _selectedColor + private var _selectedColor: Int = -1 + private var isInSub: Boolean = false + private var isInCustom: Boolean = false + private var circleSize: Int = context.dimen(R.dimen.kau_color_circle_size).toInt() @SuppressLint("PrivateResource") - val backgroundColor = context.resolveColor(R.attr.md_background_color, + private val backgroundColor = context.resolveColor(R.attr.md_background_color, if (context.resolveColor(android.R.attr.textColorPrimary).isColorDark) Color.WHITE else 0xff424242.toInt()) - val backgroundColorTint = backgroundColor.colorToForeground() - lateinit var dialog: MaterialDialog - lateinit var builder: ColorContract - lateinit var colorsTop: IntArray - var colorsSub: Array<IntArray>? = null - var topIndex: Int = -1 - var subIndex: Int = -1 - var colorIndex: Int + private val backgroundColorTint = backgroundColor.colorToForeground() + private lateinit var dialog: MaterialDialog + private lateinit var builder: ColorContract + private lateinit var colorsTop: IntArray + private var colorsSub: Array<IntArray>? = null + private var topIndex: Int = -1 + private var subIndex: Int = -1 + private var colorIndex: Int get() = if (isInSub) subIndex else topIndex set(value) { if (isInSub) subIndex = value @@ -54,24 +56,29 @@ internal class ColorPickerView @JvmOverloads constructor( } } - 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) + private val gridView: FillGridView by bindView(R.id.md_grid) + private val customFrame: LinearLayout by bindView(R.id.md_colorChooserCustomFrame) + private val customColorIndicator: View by bindView(R.id.md_colorIndicator) + private val hexInput: EditText by bindView(R.id.md_hexInput) + private val alphaLabel: TextView by bindView(R.id.md_colorALabel) + private val alphaSeekbar: SeekBar by bindView(R.id.md_colorA) + private val alphaValue: TextView by bindView(R.id.md_colorAValue) + private val redSeekbar: SeekBar by bindView(R.id.md_colorR) + private val redValue: TextView by bindView(R.id.md_colorRValue) + private val greenSeekbar: SeekBar by bindView(R.id.md_colorG) + private val greenValue: TextView by bindView(R.id.md_colorGValue) + private val blueSeekbar: SeekBar by bindView(R.id.md_colorB) + private val blueValue: TextView by bindView(R.id.md_colorBValue) - var customHexTextWatcher: TextWatcher? = null - var customRgbListener: SeekBar.OnSeekBarChangeListener? = null + private var customHexTextWatcher: TextWatcher? = null + private var customRgbListener: SeekBar.OnSeekBarChangeListener? = null init { + init() + } + + @SuppressLint("PrivateResource") + private fun init() { View.inflate(context, R.layout.md_dialog_colorchooser, this) } @@ -79,29 +86,33 @@ internal class ColorPickerView @JvmOverloads constructor( this.builder = builder this.dialog = dialog this.colorsTop = with(builder) { - if (colorsTop != null) colorsTop!! - else if (isAccent) ColorPalette.ACCENT_COLORS - else ColorPalette.PRIMARY_COLORS + when { + colorsTop != null -> colorsTop!! + isAccent -> ColorPalette.ACCENT_COLORS + else -> ColorPalette.PRIMARY_COLORS + } } this.colorsSub = with(builder) { - if (colorsTop != null) colorsSub - else if (isAccent) ColorPalette.ACCENT_COLORS_SUB - else ColorPalette.PRIMARY_COLORS_SUB + when { + colorsTop != null -> colorsSub + isAccent -> ColorPalette.ACCENT_COLORS_SUB + else -> ColorPalette.PRIMARY_COLORS_SUB + } } - this.selectedColor = builder.defaultColor + this._selectedColor = builder.defaultColor if (builder.allowCustom) { if (!builder.allowCustomAlpha) { alphaLabel.gone() alphaSeekbar.gone() alphaValue.gone() - hexInput.hint = String.format("%06X", selectedColor) + hexInput.hint = String.format("%06X", _selectedColor) hexInput.filters = arrayOf(InputFilter.LengthFilter(6)) } else { - hexInput.hint = String.format("%08X", selectedColor) + 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 + if (findColor(_selectedColor) || !builder.allowCustom) isInCustom = true // when toggled this will be false toggleCustom() } @@ -127,21 +138,20 @@ internal class ColorPickerView @JvmOverloads constructor( override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - selectedColor = try { + _selectedColor = try { Color.parseColor("#$s") } catch (e: IllegalArgumentException) { Color.BLACK } - - customColorIndicator.setBackgroundColor(selectedColor) + customColorIndicator.setBackgroundColor(_selectedColor) if (alphaSeekbar.isVisible) { - val alpha = Color.alpha(selectedColor) + 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) + redSeekbar.progress = Color.red(_selectedColor) + greenSeekbar.progress = Color.green(_selectedColor) + blueSeekbar.progress = Color.blue(_selectedColor) isInSub = false topIndex = -1 subIndex = -1 @@ -150,7 +160,7 @@ internal class ColorPickerView @JvmOverloads constructor( override fun afterTextChanged(s: Editable?) {} } - hexInput.setText(selectedColor.toHexString(builder.allowCustomAlpha, false)) + hexInput.setText(_selectedColor.toHexString(builder.allowCustomAlpha, false)) hexInput.addTextChangedListener(customHexTextWatcher) customRgbListener = object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { @@ -181,11 +191,11 @@ internal class ColorPickerView @JvmOverloads constructor( blueSeekbar.setOnSeekBarChangeListener(customRgbListener) if (alphaSeekbar.isVisible) alphaSeekbar.setOnSeekBarChangeListener(customRgbListener) - hexInput.setText(selectedColor.toHexString(alphaSeekbar.isVisible, false)) + hexInput.setText(_selectedColor.toHexString(alphaSeekbar.isVisible, false)) gridView.fadeOut(onFinish = { gridView.gone() }) customFrame.fadeIn() } else { - findColor(selectedColor) + 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 = this::invalidateGrid) @@ -201,9 +211,9 @@ internal class ColorPickerView @JvmOverloads constructor( } 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 (!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) @@ -222,11 +232,8 @@ internal class ColorPickerView @JvmOverloads constructor( 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 + // First check for sub colors, then if the top color matches + if (findSubColor(color, index) || topColor == color) { topIndex = index return true } @@ -235,14 +242,8 @@ internal class ColorPickerView @JvmOverloads constructor( } private 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 + subIndex = colorsSub?.getOrNull(topIndex)?.indexOfFirst { color == it } ?: -1 + return subIndex != -1 } private fun invalidateGrid() { @@ -256,50 +257,53 @@ internal class ColorPickerView @JvmOverloads constructor( 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 - } + val (pos, color) = v.tagData ?: return + if (colorIndex == pos && isInSub) + return + circleAt(colorIndex)?.animateSelected(false) + _selectedColor = color + colorIndex = pos + refreshColors() + if (isInSub) + circleAt(colorIndex)?.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 + private fun circleAt(index: Int): CircleView? = + if (index == -1) null + else gridView.getChildAt(index) as? CircleView + + private val View.tagData: Pair<Int, Int>? + get() { + val tags = (tag as? String)?.split(":") ?: return null + val pos = tags[0].toIntOrNull() ?: return null + val color = tags[1].toIntOrNull() ?: return null + return pos to color } - return false + + override fun onLongClick(v: View): Boolean { + val (_, color) = v.tagData ?: return false + (v as? CircleView)?.showHint(color) ?: return false + return true } - override fun getItem(position: Int): Any = if (isInSub) colorsSub!![topIndex][position] else colorsTop[position] + override fun getItem(position: Int): Int = 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] + val view: CircleView = convertView as? CircleView ?: CircleView(context).apply { + layoutParams = AbsListView.LayoutParams(circleSize, circleSize) + setOnClickListener(this@ColorGridAdapter) + setOnLongClickListener(this@ColorGridAdapter) + } + val color: Int = getItem(position) return view.apply { setBackgroundColor(color) isSelected = colorIndex == position tag = "$position:$color" - setOnClickListener(this@ColorGridAdapter) - setOnLongClickListener(this@ColorGridAdapter) } } } diff --git a/core/build.gradle b/core/build.gradle index a2d1dd3..046a734 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,6 +5,7 @@ apply from: '../android-lib.gradle' dependencies { api kauDependency.kotlin + api "com.android.support:support-annotations:${kau.supportLibs}" api "com.android.support:appcompat-v7:${kau.supportLibs}" api "com.android.support:support-v13:${kau.supportLibs}" api "com.android.support:design:${kau.supportLibs}" diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt deleted file mode 100644 index 1a0eaac..0000000 --- a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package ca.allanwang.kau.xml - -import android.support.test.filters.MediumTest -import android.support.test.runner.AndroidJUnit4 -import org.junit.runner.RunWith - -/** - * Created by Allan Wang on 2017-07-31. - */ -@RunWith(AndroidJUnit4::class) -@MediumTest -class ChangelogTest { - - // @Test //todo internal function sharing is only available on gradle 3.0.0+ - fun simpleTest() { -// val data = parse(InstrumentationRegistry.getTargetContext(), R.xml.test_changelog) - } - -}
\ No newline at end of file diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt index c2ffa8a..b396985 100644 --- a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt @@ -19,10 +19,10 @@ class FaqTest { fun simpleTest() { InstrumentationRegistry.getTargetContext().kauParseFaq(R.xml.test_faq) { data -> assertEquals(2, data.size, "FAQ size is incorrect") - assertEquals("1. This is a question", data.first().first.toString(), "First question does not match") - assertEquals("This is an answer", data.first().second.toString(), "First answer does not match") - assertEquals("2. This is another question", data.last().first.toString(), "Second question does not match") - assertEquals("This is another answer", data.last().second.toString(), "Second answer does not match") + assertEquals("1. This is a question", data.first().question.toString(), "First question does not match") + assertEquals("This is an answer", data.first().answer.toString(), "First answer does not match") + assertEquals("2. This is another question", data.last().question.toString(), "Second question does not match") + assertEquals("This is another answer", data.last().answer.toString(), "Second answer does not match") } } @@ -30,10 +30,10 @@ class FaqTest { fun withoutNumbering() { InstrumentationRegistry.getTargetContext().kauParseFaq(R.xml.test_faq, false) { data -> assertEquals(2, data.size, "FAQ size is incorrect") - assertEquals("This is a question", data.first().first.toString(), "First question does not match") - assertEquals("This is an answer", data.first().second.toString(), "First answer does not match") - assertEquals("This is another question", data.last().first.toString(), "Second question does not match") - assertEquals("This is another answer", data.last().second.toString(), "Second answer does not match") + assertEquals("This is a question", data.first().question.toString(), "First question does not match") + assertEquals("This is an answer", data.first().answer.toString(), "First answer does not match") + assertEquals("This is another question", data.last().question.toString(), "Second question does not match") + assertEquals("This is another answer", data.last().answer.toString(), "Second answer does not match") } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt index 4c27e19..de5d148 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt @@ -40,7 +40,11 @@ open class Debouncer(var interval: Long) { * Call to cancel all pending requests and shutdown the thread pool * The debouncer cannot be used after this */ - fun terminate() = sched.shutdownNow() + fun terminate() { + task?.invalidate() + task = null + sched.shutdownNow() + } /** * Invalidate any pending tasks diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt index 7e0fe70..ab531bd 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt @@ -14,7 +14,6 @@ import android.view.animation.Interpolator * Items are retrieved using delegateName(context) * */ - fun lazyInterpolator(@InterpolatorRes id: Int) = lazyContext<Interpolator> { AnimationUtils.loadInterpolator(it, id) } fun lazyAnimation(@AnimRes id: Int) = lazyContext<Animation> { AnimationUtils.loadAnimation(it, id) } diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt index dc10e71..e37e59f 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt @@ -77,6 +77,10 @@ class ProgressAnimator private constructor(private vararg val values: Float) { override fun onAnimationEnd(animation: Animator?) { endActions.forEach { it() } } + + override fun onAnimationCancel(animation: Animator?) { + endActions.forEach { it() } + } }) extraConfigs() start() diff --git a/docs/Changelog.md b/docs/Changelog.md index 782db6e..d5b8d5b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,5 +1,13 @@ # Changelog +## v3.6.4 +* :core: Fix potential NPE in restart() +* :core: Create restartApplication() +* :colorpicker: Rewrote implementation to be null and parse safe +* :colorpicker: Added more encapsulation to CircleView (selected -> colorSelected; all others are private) +* :colorpicker: +* Update documentation + ## v3.6.3 * :core: Check for tablet in email builder * :kpref-activity: Simplify internal code and add better encapsulation @@ -211,5 +219,5 @@ ## v1.0 * Initial Changelog * Create many extension functions -* Port changelog builer +* Port changelog builder * Port ripple canvas diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefBinder.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefBinder.kt index 637af03..a9e21ff 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefBinder.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefBinder.kt @@ -77,7 +77,7 @@ class KPrefAdapterBuilder(val globalOptions: GlobalOptions) { getter: (() -> T), setter: ((value: T) -> Unit), builder: KPrefText.KPrefTextContract<T>.() -> Unit = {}) - = list.add(KPrefText<T>(KPrefText.KPrefTextBuilder<T>(globalOptions, title, getter, setter) + = list.add(KPrefText(KPrefText.KPrefTextBuilder(globalOptions, title, getter, setter) .apply { builder() })) @KPrefMarker diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt index 2afdd2e..992dd28 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.support.annotation.CallSuper import android.support.annotation.IdRes import android.support.annotation.LayoutRes +import android.support.annotation.StringRes import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View @@ -100,6 +101,7 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor val globalOptions: GlobalOptions val titleId: Int var titleFun: () -> Int + @setparam:StringRes var descRes: Int var descFun: () -> Int var iicon: IIcon? diff --git a/sample/build.gradle b/sample/build.gradle index 5bbdbb0..fb55b94 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -95,13 +95,17 @@ dependencies { implementation project(':searchview') implementation project(':mediapicker') - androidTestImplementation("com.android.support.test.espresso:espresso-core:${kau.espresso}") { - exclude group: 'com.android.support', module: 'support-annotations' - } - androidTestImplementation("com.android.support.test:runner:${kau.testRunner}") { - exclude group: 'com.android.support', module: 'support-annotations' - } - androidTestImplementation kauDependency.kotlinTest +// androidTestImplementation("com.android.support.test.espresso:espresso-core:${kau.espresso}") { +// exclude group: 'com.android.support', module: 'support-annotations' +// } +// androidTestImplementation("com.android.support.test:runner:${kau.testRunner}") { +// exclude group: 'com.android.support', module: 'support-annotations' +// } +// androidTestImplementation kauDependency.kotlinTest testImplementation kauDependency.kotlinTest testImplementation kauDependency.junit + + androidTestImplementation kauDependency.kotlinTest + androidTestImplementation kauDependency.espresso + androidTestImplementation kauDependency.testRunner } diff --git a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/ColorPickerTest.kt b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/ColorPickerTest.kt new file mode 100644 index 0000000..39aee93 --- /dev/null +++ b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/ColorPickerTest.kt @@ -0,0 +1,61 @@ +package ca.allanwang.kau.sample + +import android.support.test.espresso.DataInteraction +import android.support.test.espresso.Espresso.onData +import android.support.test.espresso.Espresso.onView +import android.support.test.espresso.ViewAssertion +import android.support.test.espresso.action.ViewActions.click +import android.support.test.espresso.matcher.ViewMatchers.withId +import android.support.test.espresso.matcher.ViewMatchers.withText +import android.support.test.filters.MediumTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import android.view.View +import ca.allanwang.kau.colorpicker.CircleView +import org.hamcrest.Matchers.anything +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals +import kotlin.test.fail + + +/** + * Created by Allan Wang on 22/02/2018. + */ +@RunWith(AndroidJUnit4::class) +@MediumTest +class ColorPickerTest { + + @get:Rule + val activity: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java) + + private fun DataInteraction.click(position: Int) = + atPosition(position).perform(click()) + + private fun View.colorSelected(selected: Boolean) { + val circle = this as? CircleView ?: fail("View is not a CircleView") + assertEquals(selected, circle.colorSelected, "CircleView ${circle.tag} ${if (selected) "is not" else "is"} actually selected") + } + + private val colorSelected = ViewAssertion { view, _ -> view.colorSelected(true) } + + private val colorNotSelected = ViewAssertion { view, _ -> view.colorSelected(false) } + + @Test + fun test() { + onView(withText(R.string.accent_color)).perform(click()) + val colors = onData(anything()).inAdapterView(withId(R.id.md_grid)) + + colors.click(0).check(colorNotSelected) // enter sub grid + colors.click(0).check(colorSelected) // click first grid item + colors.atPosition(1).check(colorNotSelected) + colors.atPosition(2).check(colorNotSelected) + .perform(click()).check(colorSelected) + colors.atPosition(0).check(colorNotSelected) + .perform(click()).check(colorSelected) + // first item is now selected + } + + +} diff --git a/sample/src/main/res/xml/kau_changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index 146042c..40ca6a0 100644 --- a/sample/src/main/res/xml/kau_changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -9,7 +9,9 @@ <version title="v3.6.4" /> <item text=":core: Fix potential NPE in restart()" /> <item text=":core: Create restartApplication()" /> - <item text="" /> + <item text=":colorpicker: Rewrote implementation to be null and parse safe" /> + <item text=":colorpicker: Added more encapsulation to CircleView (selected -> colorSelected; all others are private)" /> + <item text=":colorpicker:" /> <item text="Update documentation" /> <item text="" /> @@ -224,6 +226,6 @@ <version title="v1.0" /> <item text="Initial Changelog" /> <item text="Create many extension functions" /> - <item text="Port changelog builer" /> + <item text="Port changelog builder" /> <item text="Port ripple canvas" /> </resources>
\ No newline at end of file diff --git a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt index 19f1a36..52a88a0 100644 --- a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt +++ b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt @@ -230,7 +230,7 @@ class SearchView @JvmOverloads constructor( } private val configs = Configs() - //views + // views private val shadow: View by bindView(R.id.kau_search_shadow) private val card: BoundedCardView by bindView(R.id.kau_search_cardview) private val iconNav: ImageView by bindView(R.id.kau_search_nav) |