diff options
author | Allan Wang <me@allanwang.ca> | 2017-07-18 20:16:23 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-18 20:16:23 -0700 |
commit | 8f2b5ac043f47cc44f43c3788d1377083fb339a2 (patch) | |
tree | 8f91042414de211cbfe67a76298300884f46a765 | |
parent | 4eee8d59c21b2061b9f5fd0e805ca60ab84c3585 (diff) | |
download | kau-8f2b5ac043f47cc44f43c3788d1377083fb339a2.tar.gz kau-8f2b5ac043f47cc44f43c3788d1377083fb339a2.tar.bz2 kau-8f2b5ac043f47cc44f43c3788d1377083fb339a2.zip |
Dev 2.1 (#8)
* Rewrite animation interfaces
* Update changelog
* Add scale factor for slide
* Remove margins in iitems and replace with decorators
* Remove mutable list
* Switch cardiitem to use lambdas for click
* status
* Utils update and imagepicker fixes
* Remove stringholder
* Add fade in fade out
* Increment about version
* Rename fromedge to direction in javadocs
* More logging
* Add logging and docs
* Make card icons visible
* Update email builder and icon padding
* Create elastic recycler activity
* Fix card iitem
* Add lint check and plurals
* Inline all the things
* Format and sort xml
* Update dependencies and increment version
80 files changed, 1400 insertions, 685 deletions
diff --git a/.travis.yml b/.travis.yml index 7e0a791..fb97b18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ android: - extra-google-m2repository licenses: - '.+' -script: ./gradlew clean test +script: ./gradlew lintRelease test branches: except: - gh-pages @@ -20,7 +20,9 @@ To apply, add the following to your root build.gradle: allprojects { repositories { ... + jcenter() maven { url "https://jitpack.io" } + maven { url "https://maven.google.com" } } } ``` diff --git a/about/build.gradle b/about/build.gradle index bb51f9f..6898217 100644 --- a/about/build.gradle +++ b/about/build.gradle @@ -9,7 +9,7 @@ dependencies { compile project(':adapter') compile("com.mikepenz:aboutlibraries:${ABOUT_LIBRARIES}@aar") { - transitive = true + transitive = false } } diff --git a/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt b/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt index 90dbfd3..b3e3e41 100644 --- a/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt +++ b/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt @@ -13,7 +13,8 @@ import android.view.ViewGroup import ca.allanwang.kau.adapters.FastItemThemedAdapter import ca.allanwang.kau.adapters.ThemableIItemColors import ca.allanwang.kau.adapters.ThemableIItemColorsDelegate -import ca.allanwang.kau.animators.FadeScaleAnimator +import ca.allanwang.kau.animators.FadeScaleAnimatorAdd +import ca.allanwang.kau.animators.KauAnimator import ca.allanwang.kau.iitems.HeaderIItem import ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout import ca.allanwang.kau.ui.widgets.InkPageIndicator @@ -94,12 +95,9 @@ abstract class AboutActivityBase(val rClass: Class<*>?, val configBuilder: Confi indicator.setViewPager(pager) draggableFrame.addListener(object : ElasticDragDismissFrameLayout.SystemChromeFader(this) { override fun onDragDismissed() { - // if we drag dismiss downward then the default reversal of the enter - // transition would slide content upward which looks weird. So reverse it. - if (draggableFrame.translationY > 0) { - window.returnTransition = TransitionInflater.from(this@AboutActivityBase) - .inflateTransition(configs.transitionExitReversed) - } + window.returnTransition = TransitionInflater.from(this@AboutActivityBase) + .inflateTransition(if (draggableFrame.translationY > 0) configs.transitionExitBottom else configs.transitionExitTop) + libRecycler?.stopScroll() finishAfterTransition() } @@ -114,10 +112,9 @@ abstract class AboutActivityBase(val rClass: Class<*>?, val configBuilder: Confi var cutoutForeground: Int? = null var libPageTitleRes: Int = -1 var libPageTitle: String? = string(R.string.kau_about_libraries_intro) //This is in the string by default since it's lower priority - /** - * Transition to be called if the view is dragged down - */ - var transitionExitReversed: Int = R.transition.kau_about_return_downward + + var transitionExitTop: Int = R.transition.kau_exit_slide_top + var transitionExitBottom: Int = R.transition.kau_exit_slide_bottom } /** @@ -174,8 +171,9 @@ abstract class AboutActivityBase(val rClass: Class<*>?, val configBuilder: Confi val v = layoutInflater.inflate(R.layout.kau_recycler_detached_background, parent, false) val recycler = v.findViewById<RecyclerView>(R.id.kau_recycler_detached) libRecycler = recycler + recycler.withMarginDecoration(16, KAU_BOTTOM) recycler.adapter = libAdapter - recycler.itemAnimator = FadeScaleAnimator(itemDelayFactor = 0.2f).apply { addDuration = 300; interpolator = AnimHolder.decelerateInterpolator(this@AboutActivityBase) } + recycler.itemAnimator = KauAnimator(addAnimator = FadeScaleAnimatorAdd(scaleFactor = 0.7f, itemDelayFactor = 0.2f)).apply { addDuration = 300; interpolator = AnimHolder.decelerateInterpolator(this@AboutActivityBase) } val background = v.findViewById<View>(R.id.kau_recycler_detached_background) if (configs.backgroundColor != null) background.setBackgroundColor(configs.backgroundColor!!.colorToForeground()) doAsync { diff --git a/about/src/main/kotlin/ca/allanwang/kau/about/LibraryIItem.kt b/about/src/main/kotlin/ca/allanwang/kau/about/LibraryIItem.kt index b5e2c28..518cd54 100644 --- a/about/src/main/kotlin/ca/allanwang/kau/about/LibraryIItem.kt +++ b/about/src/main/kotlin/ca/allanwang/kau/about/LibraryIItem.kt @@ -49,6 +49,7 @@ class LibraryIItem(val lib: Library with(holder) { name.text = lib.libraryName creator.text = lib.author + @Suppress("DEPRECATION") description.text = if (lib.libraryDescription.isBlank()) lib.libraryDescription else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) Html.fromHtml(lib.libraryDescription, Html.FROM_HTML_MODE_LEGACY) diff --git a/about/src/main/res/layout/kau_iitem_library.xml b/about/src/main/res/layout/kau_iitem_library.xml index 1c3de5c..3ad4fb4 100644 --- a/about/src/main/res/layout/kau_iitem_library.xml +++ b/about/src/main/res/layout/kau_iitem_library.xml @@ -5,7 +5,6 @@ android:id="@+id/lib_item_card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/kau_padding_normal" android:background="?android:selectableItemBackground" android:clickable="true"> diff --git a/about/src/main/res/transition/kau_about_return_downward.xml b/about/src/main/res/transition/kau_about_return_downward.xml deleted file mode 100644 index b040b1b..0000000 --- a/about/src/main/res/transition/kau_about_return_downward.xml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright 2015 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - -<transitionSet - xmlns:android="http://schemas.android.com/apk/res/android" - android:transitionOrdering="together" - android:interpolator="@android:interpolator/fast_out_linear_in"> - - <slide - android:slideEdge="bottom" - android:duration="400"> - <targets> - <target android:excludeId="@android:id/navigationBarBackground" /> - <target android:excludeId="@android:id/statusBarBackground" /> - </targets> - </slide> - - <fade - android:startDelay="200" - android:duration="200"> - <targets> - <target android:targetId="@id/about_indicator" /> - <!--<target android:targetId="@id/libraries_intro" />--> - <!--<target android:targetId="@id/libs_list_background" />--> - </targets> - </fade> - - <fade android:duration="400"> - <targets> - <target android:targetId="@android:id/navigationBarBackground" /> - <target android:targetId="@android:id/statusBarBackground" /> - </targets> - </fade> - -</transitionSet> diff --git a/about/src/main/res/transition/kau_about_return_upwards.xml b/about/src/main/res/transition/kau_about_return_upwards.xml deleted file mode 100644 index 64b3f5e..0000000 --- a/about/src/main/res/transition/kau_about_return_upwards.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright 2015 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - -<transitionSet - xmlns:android="http://schemas.android.com/apk/res/android" - android:transitionOrdering="together" - android:interpolator="@android:interpolator/fast_out_linear_in"> - - <slide - android:slideEdge="top" - android:duration="400"> - <targets> - <target android:excludeId="@android:id/navigationBarBackground" /> - <target android:excludeId="@android:id/statusBarBackground" /> - </targets> - </slide> - - <fade - android:startDelay="200" - android:duration="200"> - <targets> - <target android:targetId="@id/about_indicator" /> - <!--<target android:targetId="@id/libraries_intro" />--> - <!--<target android:targetId="@id/libs_list_background" />--> - - </targets> - </fade> - - <fade android:duration="400"> - <targets> - <target android:targetId="@android:id/navigationBarBackground" /> - <target android:targetId="@android:id/statusBarBackground" /> - </targets> - </fade> - -</transitionSet> diff --git a/about/src/main/res/values/strings_about.xml b/about/src/main/res/values/strings_about.xml index 35ffeb2..f538e59 100644 --- a/about/src/main/res/values/strings_about.xml +++ b/about/src/main/res/values/strings_about.xml @@ -1,5 +1,5 @@ <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="ResourceName"> - <string name="library_kau_libraryVersion">1.5</string> + <string name="library_kau_libraryVersion">2.1</string> <string name="define_kau"/> <!-- Author section --> diff --git a/about/src/main/res/values/styles.xml b/about/src/main/res/values/styles.xml index 59b2470..f878950 100644 --- a/about/src/main/res/values/styles.xml +++ b/about/src/main/res/values/styles.xml @@ -1,9 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <style name="Kau.Translucent.About"> - <item name="android:windowEnterTransition">@transition/kau_enter_slide_top</item> - <item name="android:windowReturnTransition">@transition/kau_about_return_upwards</item> - </style> + <style name="Kau.Translucent.About" parent="Kau.Translucent.SlideTop"/> </resources>
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt b/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt index 1ceab3c..1349a35 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt +++ b/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt @@ -58,7 +58,7 @@ class FastItemThemedAdapter<Item : IItem<*, *>>( notifyAdapterDataSetChanged() } - override fun add(position: Int, items: MutableList<Item>): FastItemAdapter<Item> { + override fun add(position: Int, items: List<Item>): FastItemAdapter<Item> { injectTheme(items) return super.add(position, items) } @@ -73,13 +73,12 @@ class FastItemThemedAdapter<Item : IItem<*, *>>( return super.add(item) } - override fun add(items: MutableList<Item>): FastItemAdapter<Item> { - injectTheme(items) + override fun add(items: List<Item>?): FastItemAdapter<Item> { injectTheme(items) return super.add(items) } - override fun set(items: MutableList<Item>?): FastItemAdapter<Item> { + override fun set(items: List<Item>?): FastItemAdapter<Item> { injectTheme(items) return super.set(items) } @@ -89,17 +88,17 @@ class FastItemThemedAdapter<Item : IItem<*, *>>( return super.set(position, item) } - override fun setNewList(items: MutableList<Item>?, retainFilter: Boolean): FastItemAdapter<Item> { + override fun setNewList(items: List<Item>?, retainFilter: Boolean): FastItemAdapter<Item> { injectTheme(items) return super.setNewList(items, retainFilter) } - override fun setNewList(items: MutableList<Item>?): FastItemAdapter<Item> { + override fun setNewList(items: List<Item>?): FastItemAdapter<Item> { injectTheme(items) return super.setNewList(items) } - override fun <T, S> setSubItems(collapsible: T, subItems: MutableList<S>?): T where S : IItem<*, *>?, T : IItem<*, *>?, T : IExpandable<T, S>?, S : ISubItem<Item, T>? { + override fun <T, S> setSubItems(collapsible: T, subItems: List<S>?): T where S : IItem<*, *>?, T : IItem<*, *>?, T : IExpandable<T, S>?, S : ISubItem<Item, T>? { injectTheme(subItems) return super.setSubItems(collapsible, subItems) } @@ -176,8 +175,8 @@ class ThemableIItemDelegate : ThemableIItem, ThemableIItemColors by ThemableIIte } override fun bindBackgroundRipple(vararg views: View?) { - val foreground = accentColor ?: textColor ?: return val background = backgroundColor ?: return + val foreground = accentColor ?: textColor ?: backgroundColor ?: return //default to normal background val ripple = createSimpleRippleDrawable(foreground, background) views.forEach { it?.background = ripple } } diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/AnimatorInterfaces.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/AnimatorInterfaces.kt new file mode 100644 index 0000000..3cf13df --- /dev/null +++ b/adapter/src/main/kotlin/ca/allanwang/kau/animators/AnimatorInterfaces.kt @@ -0,0 +1,31 @@ +package ca.allanwang.kau.animators + +import android.support.v7.widget.RecyclerView +import android.view.View +import android.view.ViewPropertyAnimator + +/** + * Created by Allan Wang on 2017-07-11. + */ +class KauAnimatorException(message: String) : RuntimeException(message) + +interface KauAnimatorAdd { + fun animationPrepare(holder: RecyclerView.ViewHolder): View.() -> Unit + fun animation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit + fun animationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit + fun getDelay(remove: Long, move: Long, change: Long): Long + var itemDelayFactor: Float +} + +interface KauAnimatorRemove { + fun animation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit + fun animationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit + fun getDelay(remove: Long, move: Long, change: Long): Long + var itemDelayFactor: Float +} + +interface KauAnimatorChange { + fun changeOldAnimation(holder: RecyclerView.ViewHolder, changeInfo: BaseItemAnimator.ChangeInfo): ViewPropertyAnimator.() -> Unit + fun changeNewAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit + fun changeAnimationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit +} diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/BaseDelayAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/BaseDelayAnimator.kt deleted file mode 100644 index c649376..0000000 --- a/adapter/src/main/kotlin/ca/allanwang/kau/animators/BaseDelayAnimator.kt +++ /dev/null @@ -1,45 +0,0 @@ -package ca.allanwang.kau.animators - -import android.support.v7.widget.RecyclerView -import android.view.ViewPropertyAnimator - -/** - * Created by Allan Wang on 2017-06-27. - * - * Base for delayed animators - * item delay factor by default can be 0.125f - */ -abstract class BaseDelayAnimator(val itemDelayFactor: Float) : DefaultAnimator() { - - override abstract fun addAnimationPrepare(holder: RecyclerView.ViewHolder) - - override fun addAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return holder.itemView.animate().apply { - startDelay = Math.max(0L, (holder.adapterPosition * addDuration * itemDelayFactor).toLong()) - duration = this@BaseDelayAnimator.addDuration - interpolator = this@BaseDelayAnimator.interpolator - } - } - - - override abstract fun addAnimationCleanup(holder: RecyclerView.ViewHolder) - - override fun getAddDelay(remove: Long, move: Long, change: Long): Long = 0 - - override fun getRemoveDelay(remove: Long, move: Long, change: Long): Long = 0 - - /** - * Partial removal animation - * As of now, all it does it change the alpha - * To have it slide, add onto it in a sub class - */ - override fun removeAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return holder.itemView.animate().apply { - duration = this@BaseDelayAnimator.removeDuration - startDelay = Math.max(0L, (holder.adapterPosition * removeDuration * itemDelayFactor).toLong()) - interpolator = this@BaseDelayAnimator.interpolator - } - } - - override abstract fun removeAnimationCleanup(holder: RecyclerView.ViewHolder) -}
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/BaseSlideAlphaAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/BaseSlideAlphaAnimator.kt deleted file mode 100644 index a963358..0000000 --- a/adapter/src/main/kotlin/ca/allanwang/kau/animators/BaseSlideAlphaAnimator.kt +++ /dev/null @@ -1,52 +0,0 @@ -package ca.allanwang.kau.animators - -import android.support.v7.widget.RecyclerView -import android.view.ViewPropertyAnimator - -/** - * Created by Allan Wang on 2017-06-27. - * - * Base for sliding animators - * item delay factor by default can be 0.125f - */ -abstract class BaseSlideAlphaAnimator(itemDelayFactor: Float) : BaseDelayAnimator(itemDelayFactor) { - - override fun addAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return super.addAnimation(holder).apply { - translationY(0f) - translationX(0f) - alpha(1f) - } - } - - final override fun addAnimationCleanup(holder: RecyclerView.ViewHolder) { - with(holder.itemView) { - translationY = 0f - translationX = 0f - alpha = 1f - } - } - - override fun getAddDelay(remove: Long, move: Long, change: Long): Long = 0 - - override fun getRemoveDelay(remove: Long, move: Long, change: Long): Long = 0 - - /** - * Partial removal animation - * As of now, all it does it change the alpha - * To have it slide, add onto it in a sub class - */ - override fun removeAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return super.addAnimation(holder).apply { - alpha(0f) - } - } - - override final fun removeAnimationCleanup(holder: RecyclerView.ViewHolder) { - with(holder.itemView) { - translationY = 0f - translationX = 0f - alpha = 1f - } - } -}
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/FadeScaleAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/FadeScaleAnimator.kt index e968cda..cc73100 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/animators/FadeScaleAnimator.kt +++ b/adapter/src/main/kotlin/ca/allanwang/kau/animators/FadeScaleAnimator.kt @@ -1,51 +1,59 @@ package ca.allanwang.kau.animators import android.support.v7.widget.RecyclerView +import android.view.View import android.view.ViewPropertyAnimator /** - * Created by Allan Wang on 2017-06-29. + * Created by Allan Wang on 2017-07-11. */ -open class FadeScaleAnimator(val scaleFactor: Float = 0.7f, itemDelayFactor: Float = 0.125f) : BaseDelayAnimator(itemDelayFactor) { - - override fun addAnimationPrepare(holder: RecyclerView.ViewHolder) { - with(holder.itemView) { - scaleX = scaleFactor - scaleY = scaleFactor - alpha = 0f - } - } +class FadeScaleAnimatorAdd(val scaleFactor: Float = 1.0f, override var itemDelayFactor: Float = 0.125f) : KauAnimatorAdd { - override final fun addAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return super.addAnimation(holder).apply { - scaleX(1f) - scaleY(1f) - alpha(1f) - } + override fun animationPrepare(holder: RecyclerView.ViewHolder): View.() -> Unit = { + scaleX = scaleFactor + scaleY = scaleFactor + alpha = 0f } + override fun animation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit = { + scaleX(1f) + scaleY(1f) + alpha(1f) + } - final override fun addAnimationCleanup(holder: RecyclerView.ViewHolder) { - with(holder.itemView) { - scaleX = 1f - scaleY = 1f - alpha = 1f - } + override fun animationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit = { + scaleX = 1f + scaleY = 1f + alpha = 1f } - override fun removeAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return super.removeAnimation(holder).apply { - scaleX(scaleFactor) - scaleY(scaleFactor) - alpha(0f) - } + override fun getDelay(remove: Long, move: Long, change: Long): Long = 0L + +} + +class FadeScaleAnimatorRemove(val scaleFactor: Float = 1.0f, override var itemDelayFactor: Float = 0.125f) : KauAnimatorRemove { + + override fun animation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit = { + scaleX(scaleFactor) + scaleY(scaleFactor) + alpha(0f) } - override final fun removeAnimationCleanup(holder: RecyclerView.ViewHolder) { - with(holder.itemView) { - translationY = 0f - translationX = 0f - alpha = 1f - } + override fun animationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit = { + scaleX = 1f + scaleY = 1f + alpha = 1f } + + override fun getDelay(remove: Long, move: Long, change: Long): Long = 0L +} + +class FadeAnimatorChange : KauAnimatorChange { + + override fun changeOldAnimation(holder: RecyclerView.ViewHolder, changeInfo: BaseItemAnimator.ChangeInfo): ViewPropertyAnimator.() -> Unit = { alpha(0f) } + + override fun changeNewAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit = { alpha(1f) } + + override fun changeAnimationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit = { alpha = 1f } + }
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/KauAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/KauAnimator.kt new file mode 100644 index 0000000..5b36551 --- /dev/null +++ b/adapter/src/main/kotlin/ca/allanwang/kau/animators/KauAnimator.kt @@ -0,0 +1,76 @@ +package ca.allanwang.kau.animators + +import android.support.v7.widget.RecyclerView +import android.view.ViewPropertyAnimator +import ca.allanwang.kau.utils.KAU_BOTTOM +import ca.allanwang.kau.utils.KAU_RIGHT + +/** + * Created by Allan Wang on 2017-06-27. + */ +class KauAnimator( + val addAnimator: KauAnimatorAdd = SlideAnimatorAdd(KAU_BOTTOM), + val removeAnimator: KauAnimatorRemove = SlideAnimatorRemove(KAU_RIGHT), + val changeAnimator: KauAnimatorChange = FadeAnimatorChange() +) : BaseItemAnimator() { + + fun startDelay(holder: RecyclerView.ViewHolder, duration: Long, factor: Float) + = Math.max(0L, (holder.adapterPosition * duration * factor).toLong()) + + override fun removeAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { + return holder.itemView.animate().apply { + startDelay = startDelay(holder, removeDuration, removeAnimator.itemDelayFactor) + duration = removeDuration + interpolator = this@KauAnimator.interpolator + removeAnimator.animation(holder)() + } + } + + override fun removeAnimationCleanup(holder: RecyclerView.ViewHolder) { + holder.itemView.apply { removeAnimator.animationCleanup(holder)() } + } + + override fun getRemoveDelay(remove: Long, move: Long, change: Long): Long + = removeAnimator.getDelay(remove, move, change) + + override fun addAnimationPrepare(holder: RecyclerView.ViewHolder) { + holder.itemView.apply { addAnimator.animationPrepare(holder)() } + } + + override fun addAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { + return holder.itemView.animate().apply { + startDelay = startDelay(holder, addDuration, addAnimator.itemDelayFactor) + duration = addDuration + interpolator = this@KauAnimator.interpolator + addAnimator.animation(holder)() + } + } + + override fun addAnimationCleanup(holder: RecyclerView.ViewHolder) { + holder.itemView.apply { addAnimator.animationCleanup(holder)() } + } + + override fun getAddDelay(remove: Long, move: Long, change: Long): Long + = addAnimator.getDelay(remove, move, change) + + override fun changeOldAnimation(holder: RecyclerView.ViewHolder, changeInfo: ChangeInfo): ViewPropertyAnimator { + return holder.itemView.animate().apply { + duration = changeDuration + interpolator = this@KauAnimator.interpolator + changeAnimator.changeOldAnimation(holder, changeInfo)() + } + } + + override fun changeNewAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { + return holder.itemView.animate().apply { + duration = changeDuration + interpolator = this@KauAnimator.interpolator + changeAnimator.changeNewAnimation(holder)() + } + } + + override fun changeAnimationCleanup(holder: RecyclerView.ViewHolder) { + holder.itemView.apply { changeAnimator.changeAnimationCleanup(holder)() } + } + +}
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/SlideAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/SlideAnimator.kt new file mode 100644 index 0000000..f8f71a5 --- /dev/null +++ b/adapter/src/main/kotlin/ca/allanwang/kau/animators/SlideAnimator.kt @@ -0,0 +1,64 @@ +package ca.allanwang.kau.animators + +import android.support.v7.widget.RecyclerView +import android.view.View +import android.view.ViewPropertyAnimator +import ca.allanwang.kau.utils.KAU_BOTTOM +import ca.allanwang.kau.utils.KAU_LEFT +import ca.allanwang.kau.utils.KAU_RIGHT +import ca.allanwang.kau.utils.KAU_TOP + +/** + * Created by Allan Wang on 2017-07-11. + */ +class SlideAnimatorAdd(val fromEdge: Int, val slideFactor: Float = 1f, override var itemDelayFactor: Float = 0.125f) : KauAnimatorAdd { + + override fun animationPrepare(holder: RecyclerView.ViewHolder): View.() -> Unit = { + when (fromEdge) { + KAU_TOP -> translationY = slideFactor * -height + KAU_LEFT -> translationX = slideFactor * -width + KAU_BOTTOM -> translationY = slideFactor * height + KAU_RIGHT -> translationX = slideFactor * width + else -> throw KauAnimatorException("Invalid edge flag used in Slide Animator; use one of KAU_*") + } + alpha = 0f + } + + override fun animation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit = { + translationY(0f) + translationX(0f) + alpha(1f) + } + + override fun animationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit = { + translationY = 0f + translationX = 0f + alpha = 1f + } + + override fun getDelay(remove: Long, move: Long, change: Long): Long = 0L + +} + +class SlideAnimatorRemove(val fromEdge: Int, val slideFactor: Float = 1f, override var itemDelayFactor: Float = 0.125f) : KauAnimatorRemove { + override fun animation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator.() -> Unit = { + with(holder.itemView) { + when (fromEdge) { + KAU_TOP -> translationY(slideFactor * -height) + KAU_LEFT -> translationX(slideFactor * -width) + KAU_BOTTOM -> translationY(slideFactor * height) + KAU_RIGHT -> translationX(slideFactor * width) + else -> throw KauAnimatorException("Invalid edge flag used in Slide Animator; use one of KAU_*") + } + } + alpha(0f) + } + + override fun animationCleanup(holder: RecyclerView.ViewHolder): View.() -> Unit = { + translationY = 0f + translationX = 0f + alpha = 1f + } + + override fun getDelay(remove: Long, move: Long, change: Long): Long = 0L +}
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/SlideUpExitRightAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/SlideUpExitRightAnimator.kt deleted file mode 100644 index 8670493..0000000 --- a/adapter/src/main/kotlin/ca/allanwang/kau/animators/SlideUpExitRightAnimator.kt +++ /dev/null @@ -1,23 +0,0 @@ -package ca.allanwang.kau.animators - -import android.support.v7.widget.RecyclerView -import android.view.ViewPropertyAnimator - -/** - * Created by Allan Wang on 2017-06-27. - */ -class SlideUpExitRightAnimator(itemDelayFactor: Float = 0.125f) : BaseSlideAlphaAnimator(itemDelayFactor) { - - override fun addAnimationPrepare(holder: RecyclerView.ViewHolder) { - with(holder.itemView) { - translationY = height.toFloat() - alpha = 0f - } - } - - override fun removeAnimation(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { - return super.removeAnimation(holder).apply { - translationX(holder.itemView.width.toFloat()) - } - } -}
\ No newline at end of file diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt b/adapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt index 68b247c..85f86bd 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt +++ b/adapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt @@ -15,7 +15,6 @@ import ca.allanwang.kau.adapters.ThemableIItemDelegate import ca.allanwang.kau.utils.* import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.IItem -import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.listeners.ClickEventHook import com.mikepenz.iconics.typeface.IIcon @@ -25,22 +24,22 @@ import com.mikepenz.iconics.typeface.IIcon * Simple generic card item with an icon, title, description and button * The icon and button are hidden by default unless values are given */ -class CardIItem(val builder: Config.() -> Unit = {} -) : AbstractItem<CardIItem, CardIItem.ViewHolder>(), ThemableIItem by ThemableIItemDelegate() { +class CardIItem(val builder: Config.() -> Unit = {}) : KauIItem<CardIItem, CardIItem.ViewHolder>(R.layout.kau_iitem_card, { ViewHolder(it) }, R.id.kau_item_card), + ThemableIItem by ThemableIItemDelegate() { companion object { - @JvmStatic fun bindClickEvents(fastAdapter: FastAdapter<IItem<*,*>>) { - fastAdapter.withEventHook(object : ClickEventHook<IItem<*,*>>() { + @JvmStatic fun bindClickEvents(fastAdapter: FastAdapter<IItem<*, *>>) { + fastAdapter.withEventHook(object : ClickEventHook<IItem<*, *>>() { override fun onBindMany(viewHolder: RecyclerView.ViewHolder): List<View>? { return if (viewHolder is ViewHolder) listOf(viewHolder.card, viewHolder.button) else null } - override fun onClick(v: View, position: Int, adapter: FastAdapter<IItem<*,*>>, item: IItem<*,*>) { + override fun onClick(v: View, position: Int, adapter: FastAdapter<IItem<*, *>>, item: IItem<*, *>) { if (item !is CardIItem) return with(item.configs) { when (v.id) { - R.id.kau_card_container -> cardClick?.onClick(v) - R.id.kau_card_button -> buttonClick?.onClick(v) + R.id.kau_card_container -> cardClick?.invoke() + R.id.kau_card_button -> buttonClick?.invoke() else -> { } } @@ -59,37 +58,29 @@ class CardIItem(val builder: Config.() -> Unit = {} var descRes: Int = -1 var button: String? = null var buttonRes: Int = -1 - var buttonClick: View.OnClickListener? = null - var cardClick: View.OnClickListener? = null + var buttonClick: (() -> Unit)? = null + var cardClick: (() -> Unit)? = null var image: Drawable? = null var imageIIcon: IIcon? = null var imageIIconColor: Int = Color.WHITE var imageRes: Int = -1 } - - override fun getType(): Int = R.id.kau_item_card - - override fun getLayoutRes(): Int = R.layout.kau_iitem_card - override fun bindView(holder: ViewHolder, payloads: MutableList<Any>?) { super.bindView(holder, payloads) with(holder.itemView.context) context@ { with(configs) { holder.title.text = string(titleRes, title) - holder.description.text = string(descRes, desc) + val descText = string(descRes, desc) + if (descText != null) holder.description.visible().text = descText val buttonText = string(buttonRes, button) if (buttonText != null) { holder.bottomRow.visible() holder.button.text = buttonText - holder.button.setOnClickListener(buttonClick) } - holder.icon.setImageDrawable( - if (imageRes > 0) drawable(imageRes) - else if (imageIIcon != null) imageIIcon!!.toDrawable(this@context, sizeDp = 40, color = imageIIconColor) - else image - ) - holder.card.setOnClickListener(cardClick) + val icon = if (imageRes > 0) drawable(imageRes) + else imageIIcon?.toDrawable(this@context, sizeDp = 24, color = imageIIconColor) ?: image + if (icon != null) holder.icon.visible().setImageDrawable(icon) } with(holder) { bindTextColor(title) @@ -106,15 +97,13 @@ class CardIItem(val builder: Config.() -> Unit = {} with(holder) { icon.gone().setImageDrawable(null) title.text = null - description.text = null + description.gone().text = null bottomRow.gone() button.setOnClickListener(null) card.setOnClickListener(null) } } - override fun getViewHolder(v: View): ViewHolder = ViewHolder(v) - class ViewHolder(v: View) : RecyclerView.ViewHolder(v) { val card: CardView by bindView(R.id.kau_card_container) val icon: ImageView by bindView(R.id.kau_card_image) diff --git a/adapter/src/main/res/layout/kau_iitem_card.xml b/adapter/src/main/res/layout/kau_iitem_card.xml index 621da2e..249f3b8 100644 --- a/adapter/src/main/res/layout/kau_iitem_card.xml +++ b/adapter/src/main/res/layout/kau_iitem_card.xml @@ -8,29 +8,27 @@ android:id="@+id/kau_card_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/kau_padding_normal" android:background="?android:selectableItemBackground" android:minHeight="?android:listPreferredItemHeight"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="@dimen/kau_padding_normal" - android:paddingEnd="@dimen/kau_padding_normal" - android:paddingTop="@dimen/kau_padding_normal"> + android:padding="@dimen/kau_padding_normal"> <ImageView android:id="@+id/kau_card_image" - android:layout_width="@dimen/kau_avatar_bounds" - android:layout_height="@dimen/kau_avatar_bounds" - android:layout_marginEnd="@dimen/kau_avatar_margin" - android:layout_marginStart="@dimen/kau_avatar_margin" - android:padding="@dimen/kau_avatar_padding" + android:layout_width="56dp" + android:layout_height="56dp" + android:layout_marginBottom="4dp" + android:layout_marginTop="4dp" + android:paddingEnd="32dp" android:scaleType="fitCenter" android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0" /> <TextView android:id="@+id/kau_card_title" @@ -39,37 +37,34 @@ android:textAppearance="@style/TextAppearance.AppCompat.Subhead" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/kau_card_image" - app:layout_constraintTop_toTopOf="parent" - app:layout_goneMarginStart="@dimen/kau_padding_normal" /> + app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/kau_card_description" android:layout_width="0dp" android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/kau_card_image" - app:layout_constraintTop_toBottomOf="@id/kau_card_title" - app:layout_goneMarginStart="@dimen/kau_padding_normal" /> + app:layout_constraintTop_toBottomOf="@id/kau_card_title" /> <LinearLayout android:id="@+id/kau_card_bottom_row" - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="horizontal" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/kau_card_image" - app:layout_constraintTop_toBottomOf="@id/kau_card_description" - app:layout_goneMarginStart="@dimen/kau_padding_normal"> + app:layout_constraintTop_toBottomOf="@id/kau_card_description"> <Button android:id="@+id/kau_card_button" style="?android:borderlessButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/kau_spacing_normal" android:textColor="?attr/colorAccent" /> </LinearLayout> diff --git a/adapter/src/main/res/layout/kau_iitem_header.xml b/adapter/src/main/res/layout/kau_iitem_header.xml index fa5a595..db809eb 100644 --- a/adapter/src/main/res/layout/kau_iitem_header.xml +++ b/adapter/src/main/res/layout/kau_iitem_header.xml @@ -3,7 +3,6 @@ android:id="@+id/kau_header_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/kau_padding_normal" android:orientation="vertical"> <TextView diff --git a/android-lib.gradle b/android-lib.gradle index 558e99d..7eb6a79 100644 --- a/android-lib.gradle +++ b/android-lib.gradle @@ -29,8 +29,14 @@ android { } lintOptions { - abortOnError false - checkReleaseBuilds false + warningsAsErrors true + disable 'LogNotTimber', + 'UnusedResources', + 'ContentDescription', + 'RtlSymmetry', + 'RtlHardcoded', + 'RtlEnabled', + 'Overdraw' } sourceSets { diff --git a/build.gradle b/build.gradle index fcd2d23..b81cf56 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ task clean(type: Delete) { } task generateChangelogMd() { - def parsedProjectXml = (new XmlParser()).parse("$project.rootDir/sample/src/main/res/xml/changelog.xml") + def parsedProjectXml = (new XmlParser()).parse("$project.rootDir/sample/src/main/res/xml/kau_changelog.xml") def sw = new StringWriter() sw.append("# Changelog\n") parsedProjectXml.depthFirst().each { 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 04b26cb..d697c8b 100644 --- a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt +++ b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt @@ -24,10 +24,7 @@ import android.util.AttributeSet import android.view.Gravity import android.widget.FrameLayout import android.widget.Toast -import ca.allanwang.kau.utils.color -import ca.allanwang.kau.utils.getDip -import ca.allanwang.kau.utils.toColor -import ca.allanwang.kau.utils.toHSV +import ca.allanwang.kau.utils.* /** * Created by Allan Wang on 2017-06-10. @@ -82,7 +79,7 @@ class CircleView @JvmOverloads constructor(context: Context, attrs: AttributeSet } override fun setBackgroundResource(@ColorRes color: Int) { - setBackgroundColor(context.color(color)) + setBackgroundColorRes(color) } diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt new file mode 100644 index 0000000..1dcf14b --- /dev/null +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt @@ -0,0 +1,81 @@ +package ca.allanwang.kau.ui.activities + +import android.os.Bundle +import android.support.design.widget.AppBarLayout +import android.support.design.widget.CoordinatorLayout +import android.support.design.widget.FloatingActionButton +import android.support.v7.app.AppCompatActivity +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.Toolbar +import android.transition.TransitionInflater +import ca.allanwang.kau.ui.R +import ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout +import ca.allanwang.kau.utils.bindView + +/** + * Created by Allan Wang on 2017-07-17. + * + * A generic activity comprised of an ElasticDragDismissFrameLayout, CoordinatorLayout, Toolbar, RecyclerView, and Fab + * [ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout] + * [android.support.v7.widget.RecyclerView] + * + * The recyclerview defaults to a linearlayoutmanager, and the adapter is automatically bounded + * + * The exit animation is set to slide out, but the entrance must be defined yourself + */ +abstract class ElasticRecyclerActivity() : AppCompatActivity() { + + val appBar: AppBarLayout by bindView(R.id.kau_appbar) + val toolbar: Toolbar by bindView(R.id.kau_toolbar) + val coordinator: CoordinatorLayout by bindView(R.id.kau_coordinator) + val draggableFrame: ElasticDragDismissFrameLayout by bindView(R.id.kau_draggable) + val recycler: RecyclerView by bindView(R.id.kau_recycler) + val fab: FloatingActionButton by bindView(R.id.kau_fab) + val configs = Configs() + + class Configs { + var exitTransitionBottom = R.transition.kau_exit_slide_bottom + var exitTransitionTop = R.transition.kau_exit_slide_top + } + + override final fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.kau_elastic_recycler_activity) + setSupportActionBar(toolbar) + if (!onCreate(savedInstanceState, configs)) return + draggableFrame.addListener(object : ElasticDragDismissFrameLayout.SystemChromeFader(this) { + override fun onDragDismissed() { + window.returnTransition = TransitionInflater.from(this@ElasticRecyclerActivity) + .inflateTransition(if (draggableFrame.translationY > 0) configs.exitTransitionBottom else configs.exitTransitionTop) + recycler.stopScroll() + finishAfterTransition() + } + }) + } + + /** + * The replacement method for the original [onCreate] + * The configurations are passed and can be customized here + * Returns true (default) if we wish to continue with the remaining optional setup + * Return false if we wish to skip this (usually if we have more complez requirements) + */ + abstract fun onCreate(savedInstanceState: Bundle?, configs: Configs): Boolean + + /** + * Receive actions when the a click event is received outside of the coordinator + */ + fun setOutsideTapListener(listener: () -> Unit) { + draggableFrame.setOnClickListener { listener() } + } + + fun hideFabOnUpwardsScroll() { + recycler.addOnScrollListener(object :RecyclerView.OnScrollListener(){ + override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) { + if (dy > 0 && fab.isShown) fab.hide() + else if (dy < 0 && !fab.isShown) fab.show() + } + }) + } + +} + diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/BoundedCardView.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/BoundedCardView.kt index db002b9..5fc3e06 100644 --- a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/BoundedCardView.kt +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/BoundedCardView.kt @@ -1,10 +1,11 @@ package ca.allanwang.kau.ui.views import android.content.Context +import android.graphics.Rect import android.support.v7.widget.CardView import android.util.AttributeSet import ca.allanwang.kau.ui.R -import ca.allanwang.kau.utils.parentVisibleHeight +import ca.allanwang.kau.utils.parentViewGroup /** @@ -29,6 +30,8 @@ class BoundedCardView @JvmOverloads constructor( */ var maxHeightPercent: Float = -1.0f + private val parentFrame = Rect() + init { if (attrs != null) { val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.BoundedCardView) @@ -39,7 +42,8 @@ class BoundedCardView @JvmOverloads constructor( } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - var maxMeasureHeight = if (maxHeight > 0) maxHeight else parentVisibleHeight + parentViewGroup.getWindowVisibleDisplayFrame(parentFrame) + var maxMeasureHeight = if (maxHeight > 0) maxHeight else parentFrame.height() if (maxHeightPercent > 0f) maxMeasureHeight = (maxMeasureHeight * maxHeightPercent).toInt() val trueHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxMeasureHeight, MeasureSpec.AT_MOST) super.onMeasure(widthMeasureSpec, trueHeightMeasureSpec) diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/CutoutView.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/CutoutView.kt index 42f19b9..9e8ac11 100644 --- a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/CutoutView.kt +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/CutoutView.kt @@ -27,7 +27,7 @@ import android.view.View import ca.allanwang.kau.ui.R import ca.allanwang.kau.utils.dimenPixelSize import ca.allanwang.kau.utils.getFont -import ca.allanwang.kau.utils.parentVisibleHeight +import ca.allanwang.kau.utils.parentViewGroup import ca.allanwang.kau.utils.toBitmap /** @@ -66,6 +66,7 @@ class CutoutView @JvmOverloads constructor( private var heightPercentage: Float = 0f private var minHeight: Float = 0f private val maxTextSize: Float + private val parentFrame = Rect() init { if (attrs != null) { @@ -121,7 +122,8 @@ class CutoutView @JvmOverloads constructor( * If height percent is specified, ensure it is met */ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - val minHeight = Math.max(minHeight, heightPercentage * parentVisibleHeight) + parentViewGroup.getWindowVisibleDisplayFrame(parentFrame) + val minHeight = Math.max(minHeight, heightPercentage * parentFrame.height()) val trueHeightMeasureSpec = if (minHeight > 0) MeasureSpec.makeMeasureSpec(Math.max(minHeight.toInt(), measuredHeight), MeasureSpec.EXACTLY) else heightMeasureSpec diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt new file mode 100644 index 0000000..2627d13 --- /dev/null +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt @@ -0,0 +1,23 @@ +package ca.allanwang.kau.ui.views + +import android.content.Context +import android.util.AttributeSet +import android.widget.ImageView + +/** + * Created by Allan Wang on 2017-07-14. + */ +class MeasuredImageView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 +) : ImageView(context, attrs, defStyleAttr, defStyleRes), MeasureSpecContract by MeasureSpecDelegate() { + + init { + initAttrs(context, attrs) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val result = onMeasure(this, widthMeasureSpec, heightMeasureSpec) + super.onMeasure(result.first, result.second) + } + +}
\ No newline at end of file diff --git a/core-ui/src/main/res/drawable/kau_selectable_white.xml b/core-ui/src/main/res/drawable/kau_selectable_white.xml new file mode 100644 index 0000000..942f149 --- /dev/null +++ b/core-ui/src/main/res/drawable/kau_selectable_white.xml @@ -0,0 +1,6 @@ +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="#40ffffff"> + <item android:id="@android:id/mask"> + <color android:color="@android:color/white" /> + </item> +</ripple>
\ No newline at end of file diff --git a/core-ui/src/main/res/layout/kau_elastic_recycler_activity.xml b/core-ui/src/main/res/layout/kau_elastic_recycler_activity.xml new file mode 100644 index 0000000..055d61d --- /dev/null +++ b/core-ui/src/main/res/layout/kau_elastic_recycler_activity.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/kau_draggable" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:dragDismissDistance="@dimen/kau_drag_dismiss_distance_large" + app:dragDismissScale="0.95"> + + <android.support.design.widget.CoordinatorLayout + android:id="@+id/kau_coordinator" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginTop="@dimen/kau_drag_dismiss_distance" + android:background="?android:colorBackground" + android:orientation="vertical"> + + <android.support.design.widget.AppBarLayout + android:id="@+id/kau_appbar" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.v7.widget.Toolbar + android:id="@+id/kau_toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> + + </android.support.design.widget.AppBarLayout> + + <android.support.v7.widget.RecyclerView + android:id="@+id/kau_recycler" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:layoutManager="android.support.v7.widget.LinearLayoutManager" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/kau_fab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="@dimen/kau_fab_margin" + android:clickable="true" + android:visibility="gone" + app:backgroundTint="?colorAccent" + app:layout_anchor="@id/kau_recycler" + app:layout_anchorGravity="bottom|right|end" /> + + </android.support.design.widget.CoordinatorLayout> + +</ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout>
\ No newline at end of file diff --git a/core-ui/src/main/res/values/attr.xml b/core-ui/src/main/res/values/attr.xml index 49be8d9..271d132 100644 --- a/core-ui/src/main/res/values/attr.xml +++ b/core-ui/src/main/res/values/attr.xml @@ -1,41 +1,39 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8" standalone="no"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="ResourceName"> - <declare-styleable name="BoundedCardView"> - <attr name="maxHeight" format="dimension" /> - <attr name="maxHeightPercent" format="float" /> + <attr format="dimension" name="maxHeight"/> + <attr format="float" name="maxHeightPercent"/> </declare-styleable> - <declare-styleable name="TextSlider"> - <attr name="animation_type" format="enum"> - <enum name="none" value="1000" /> - <enum name="slide_horizontal" value="1001" /> - <enum name="slide_vertical" value="1002" /> - </attr> - </declare-styleable> - - <declare-styleable name="InkPageIndicator"> - <attr name="dotDiameter" format="dimension" /> - <attr name="dotGap" format="dimension" /> - <attr name="animationDuration" format="integer" /> - <attr name="pageIndicatorColor" format="color" /> - <attr name="currentPageIndicatorColor" format="color" /> + <declare-styleable name="CutoutView"> + <attr format="color" name="foregroundColor"/> + <attr name="android:text"/> + <attr name="android:drawable"/> + <attr name="android:minHeight"/> + <attr format="float" name="heightPercentageToScreen"/> + <attr name="font"/> </declare-styleable> <declare-styleable name="ElasticDragDismissFrameLayout"> - <attr name="dragDismissDistance" format="dimension" /> - <attr name="dragDismissFraction" format="float" /> - <attr name="dragDismissScale" format="float" /> - <attr name="dragElasticity" format="float" /> + <attr format="dimension" name="dragDismissDistance"/> + <attr format="float" name="dragDismissFraction"/> + <attr format="float" name="dragDismissScale"/> + <attr format="float" name="dragElasticity"/> </declare-styleable> - <declare-styleable name="CutoutView"> - <attr name="foregroundColor" format="color" /> - <attr name="android:text" /> - <attr name="android:drawable" /> - <attr name="android:minHeight" /> - <attr name="heightPercentageToScreen" format="float" /> - <attr name="font"/> + <declare-styleable name="InkPageIndicator"> + <attr format="dimension" name="dotDiameter"/> + <attr format="dimension" name="dotGap"/> + <attr format="integer" name="animationDuration"/> + <attr format="color" name="pageIndicatorColor"/> + <attr format="color" name="currentPageIndicatorColor"/> </declare-styleable> -</resources>
\ No newline at end of file + <declare-styleable name="TextSlider"> + <attr format="enum" name="animation_type"> + <enum name="none" value="1000"/> + <enum name="slide_horizontal" value="1001"/> + <enum name="slide_vertical" value="1002"/> + </attr> + </declare-styleable> +</resources> diff --git a/core-ui/src/main/res/values/colors.xml b/core-ui/src/main/res/values/colors.xml index 6d51597..273d6f1 100644 --- a/core-ui/src/main/res/values/colors.xml +++ b/core-ui/src/main/res/values/colors.xml @@ -1,6 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <resources> - <color name="kau_shadow_overlay">#80000000</color> - <color name="kau_about_page_indicator_dark">#80ffffff</color> <color name="kau_about_page_indicator_dark_selected">#fff</color> + <color name="kau_shadow_overlay">#80000000</color> </resources> diff --git a/core-ui/src/main/res/values/strings.xml b/core-ui/src/main/res/values/strings.xml new file mode 100644 index 0000000..80e6233 --- /dev/null +++ b/core-ui/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="kau_blurrable_imageview">Blurrable ImageView</string> +</resources>
\ No newline at end of file diff --git a/core-ui/src/main/res/values/styles.xml b/core-ui/src/main/res/values/styles.xml index f9fd7d4..dfbb6d3 100644 --- a/core-ui/src/main/res/values/styles.xml +++ b/core-ui/src/main/res/values/styles.xml @@ -1,7 +1,6 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8" standalone="no"?> <resources> - - <style name="Kau" parent="Theme.AppCompat.NoActionBar" /> + <style name="Kau" parent="Theme.AppCompat.NoActionBar"/> <style name="Kau.Translucent"> <item name="android:windowBackground">@color/kau_shadow_overlay</item> @@ -17,4 +16,13 @@ <item name="android:windowAnimationStyle">@null</item> </style> -</resources>
\ No newline at end of file + <style name="Kau.Translucent.SlideBottom"> + <item name="android:windowEnterTransition">@transition/kau_enter_slide_bottom</item> + <item name="android:windowReturnTransition">@transition/kau_exit_slide_bottom</item> + </style> + + <style name="Kau.Translucent.SlideTop"> + <item name="android:windowEnterTransition">@transition/kau_enter_slide_top</item> + <item name="android:windowReturnTransition">@transition/kau_exit_slide_top</item> + </style> +</resources> diff --git a/core/README.md b/core/README.md index db602b6..63313ac 100644 --- a/core/README.md +++ b/core/README.md @@ -86,6 +86,23 @@ There is an optional `customize` argument to modify the builder before showing t As mentioned, blank items will be ignored, so feel free to create a bunch of empty lines to facilitate updating the items in the future. +Here is a template xml changelog file: + +```xml +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <!-- + <version title="v"/> + <item text="" /> + --> + + <version title="v0.1" /> + <item text="Initial Changelog" /> + <item text="" /> +</resources> +``` + <a name="ripple-canvas"></a> ## Ripple Canvas diff --git a/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt b/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt index b03a620..88a0945 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt @@ -40,9 +40,9 @@ class EmailBuilder(val email: String, val subject: String) { if (deviceDetails) { val deviceItems = mutableMapOf( "OS Version" to "${System.getProperty("os.version")} (${Build.VERSION.INCREMENTAL})", - "OS API Level" to Build.DEVICE, - "Manufacturer" to Build.MANUFACTURER, - "Model (and Product)" to "${Build.MODEL} (${Build.PRODUCT})", + "OS SDK" to Build.VERSION.SDK_INT, + "Device (Manufacturer)" to "${Build.DEVICE} (${Build.MANUFACTURER})", + "Model (Product)" to "${Build.MODEL} (${Build.PRODUCT})", "Package Installer" to (context.installerPackageName ?: "None") ) if (context is Activity) { diff --git a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt index 6f93c9f..d6e17db 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt @@ -18,7 +18,7 @@ internal object PermissionManager { val pendingResults: MutableList<WeakReference<PermissionResult>> by lazy { mutableListOf<WeakReference<PermissionResult>>() } operator fun invoke(context: Context, permissions: Array<out String>, callback: (granted: Boolean, deniedPerm: String?) -> Unit) { - KL.d("Requesting permissions: ${permissions.contentToString()}") + KL.d("Permission manager for: ${permissions.contentToString()}") if (!buildIsMarshmallowAndUp) return callback(true, null) val missingPermissions = permissions.filter { !context.hasPermission(it) } if (missingPermissions.isEmpty()) return callback(true, null) @@ -31,10 +31,12 @@ internal object PermissionManager { @Synchronized internal fun requestPermissions(context: Context, permissions: Array<out String>) { val activity = (context as? Activity) ?: throw KauException("Context is not an instance of an activity; cannot request permissions") + KL.d("Requesting permissions ${permissions.contentToString()}") ActivityCompat.requestPermissions(activity, permissions, 1) } fun onRequestPermissionsResult(context: Context, permissions: Array<out String>, grantResults: IntArray) { + KL.d("On permission result: pending ${pendingResults.size}") val count = Math.min(permissions.size, grantResults.size) val iter = pendingResults.iterator() while (iter.hasNext()) { @@ -53,6 +55,7 @@ internal object PermissionManager { } requestPermissions(context, action.permissions.toTypedArray()) } + KL.d("Post on permission result: pending ${pendingResults.size}") } }
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt b/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt index fd43102..36ad52f 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt @@ -9,6 +9,12 @@ import android.content.Context * Created by Allan Wang on 2017-07-02. * * Bindings for the permission manager + * This is the only class you need to worry about when using KAU's manager + * + * MAKE SURE [kauOnRequestPermissionsResult] is added to your activities, + * and don't forget to request the permissions in your manifest. + * A collection of constants redirecting to the [Manifest.permission] counterparts + * are added for your convenience */ /** diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt new file mode 100644 index 0000000..edc1536 --- /dev/null +++ b/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt @@ -0,0 +1,107 @@ +package ca.allanwang.kau.ui.views + +import android.content.Context +import android.graphics.Rect +import android.util.AttributeSet +import android.view.View +import ca.allanwang.kau.R +import ca.allanwang.kau.utils.parentViewGroup + +/** + * Created by Allan Wang on 2017-07-14. + * + * Handles relative sizes for any view + */ +interface MeasureSpecContract { + + /** + * Width will be calculated as a percentage of the parent + * This takes precedence over relativeWidth + */ + var relativeWidthToParent: Float + /** + * Height will be calculated as a percentage of the parent + * This takes precedence over relativeHeight + */ + var relativeHeightToParent: Float + /** + * Width will be calculated based on the measured height + */ + var relativeWidth: Float + /** + * Height will be calculated based on the measure width + */ + var relativeHeight: Float + /** + * Width will be once again calculated from the current measured height + * This is the last step + */ + var postRelativeWidth: Float + /** + * Height will be once again calculated from the current measured width + * This is the last step + */ + var postRelativeHeight: Float + + /** + * Retrieves relative values from the [AttributeSet] + * Call this on init + */ + fun initAttrs(context: Context, attrs: AttributeSet?) + + /** + * Calculates the final measure specs + * Call this from [View.onMeasure] and send the Pair result as the specs + * The pair is of the format (width, height) + */ + fun onMeasure(view: View, widthMeasureSpec: Int, heightMeasureSpec: Int): Pair<Int, Int> +} + +class MeasureSpecDelegate : MeasureSpecContract { + + override var relativeWidth = -1f + override var relativeHeight = -1f + override var relativeWidthToParent = -1f + override var relativeHeightToParent = -1f + override var postRelativeWidth: Float = -1f + override var postRelativeHeight: Float = -1f + private val parentFrame = Rect() + + override fun initAttrs(context: Context, attrs: AttributeSet?) { + if (attrs == null) return + val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MeasureSpecDelegate) + relativeWidth = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidth, relativeWidth) + relativeHeight = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeight, relativeHeight) + relativeWidthToParent = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidthToParent, relativeWidthToParent) + relativeHeightToParent = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeightToParent, relativeHeightToParent) + postRelativeWidth = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeWidth, postRelativeWidth) + postRelativeHeight = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeHeight, postRelativeHeight) + styledAttrs.recycle() + } + + override fun onMeasure(view: View, widthMeasureSpec: Int, heightMeasureSpec: Int): Pair<Int, Int> { + view.parentViewGroup.getWindowVisibleDisplayFrame(parentFrame) + var width = View.MeasureSpec.getSize(widthMeasureSpec).toFloat() + var height = View.MeasureSpec.getSize(heightMeasureSpec).toFloat() + //first cycle - relative to parent + if (relativeHeightToParent > 0) + height = relativeHeightToParent * parentFrame.height() + if (relativeWidthToParent > 0) + width = relativeWidthToParent * parentFrame.width() + //second cycle - relative to each other + if (relativeHeight > 0) + height = relativeHeight * width + else if (relativeWidth > 0) + width = relativeWidth * height + //third cycle - relative to each other + if (postRelativeHeight > 0) + height = postRelativeHeight * width + else if (postRelativeWidth > 0) + width = postRelativeWidth * height + return Pair(width.measureSpec, height.measureSpec) + } + + private val Float.measureSpec: Int + get() = View.MeasureSpec.makeMeasureSpec(this.toInt(), View.MeasureSpec.EXACTLY) + +} diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt index 3b99c46..cd6e089 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt @@ -38,19 +38,19 @@ fun Activity.finishSlideOut() { overridePendingTransition(R.anim.kau_fade_in, R.anim.kau_slide_out_right_top) } -var Activity.navigationBarColor: Int +inline var Activity.navigationBarColor: Int get() = if (buildIsLollipopAndUp) window.navigationBarColor else Color.BLACK set(value) { if (buildIsLollipopAndUp) window.navigationBarColor = value } -var Activity.statusBarColor: Int +inline var Activity.statusBarColor: Int get() = if (buildIsLollipopAndUp) window.statusBarColor else Color.BLACK set(value) { if (buildIsLollipopAndUp) window.statusBarColor = value } -var Activity.statusBarLight: Boolean +inline var Activity.statusBarLight: Boolean @SuppressLint("InlinedApi") get() = if (buildIsMarshmallowAndUp) window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR > 0 else false @SuppressLint("InlinedApi") diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt index 81bf0d9..50d117c 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt @@ -65,7 +65,7 @@ fun Int.adjustAlpha(factor: Float): Int { return Color.argb(alpha, Color.red(this), Color.green(this), Color.blue(this)) } -val Int.isColorTransparent: Boolean +inline val Int.isColorTransparent: Boolean get() = Color.alpha(this) != 255 @ColorInt diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt index 3759c75..a8e0715 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt @@ -15,6 +15,7 @@ import android.support.v4.app.ActivityOptionsCompat import android.support.v4.content.ContextCompat import android.util.TypedValue import android.view.View +import android.view.animation.AnimationUtils import android.widget.Toast import ca.allanwang.kau.R import ca.allanwang.kau.logging.KL @@ -85,16 +86,18 @@ fun Context.toast(text: String, duration: Int = Toast.LENGTH_LONG) { } //Resource retrievers -fun Context.string(@StringRes id: Int): String = getString(id) - -fun Context.string(@StringRes id: Int, fallback: String?): String? = if (id > 0) string(id) else fallback -fun Context.string(holder: StringHolder?): String? = holder?.getString(this) -fun Context.color(@ColorRes id: Int): Int = ContextCompat.getColor(this, id) -fun Context.integer(@IntegerRes id: Int): Int = resources.getInteger(id) -fun Context.dimen(@DimenRes id: Int): Float = resources.getDimension(id) -fun Context.dimenPixelSize(@DimenRes id: Int): Int = resources.getDimensionPixelSize(id) -fun Context.drawable(@DrawableRes id: Int): Drawable = ContextCompat.getDrawable(this, id) -fun Context.drawable(@DrawableRes id: Int, fallback: Drawable?): Drawable? = if (id > 0) drawable(id) else fallback +inline fun Context.string(@StringRes id: Int): String = getString(id) + +inline fun Context.string(@StringRes id: Int, fallback: String?): String? = if (id > 0) string(id) else fallback +inline fun Context.color(@ColorRes id: Int): Int = ContextCompat.getColor(this, id) +inline fun Context.integer(@IntegerRes id: Int): Int = resources.getInteger(id) +inline fun Context.dimen(@DimenRes id: Int): Float = resources.getDimension(id) +inline fun Context.dimenPixelSize(@DimenRes id: Int): Int = resources.getDimensionPixelSize(id) +inline fun Context.drawable(@DrawableRes id: Int): Drawable = ContextCompat.getDrawable(this, id) +inline fun Context.drawable(@DrawableRes id: Int, fallback: Drawable?): Drawable? = if (id > 0) drawable(id) else fallback +inline fun Context.interpolator(@InterpolatorRes id: Int) = AnimationUtils.loadInterpolator(this, id) +inline fun Context.animation(@AnimRes id: Int) = AnimationUtils.loadAnimation(this, id) +inline fun Context.plural(@PluralsRes id: Int, quantity: Number) = resources.getQuantityString(id, quantity.toInt()) //Attr retrievers fun Context.resolveColor(@AttrRes attr: Int, fallback: Int = 0): Int { diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Either.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Either.kt deleted file mode 100644 index dab5810..0000000 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/Either.kt +++ /dev/null @@ -1,32 +0,0 @@ -package ca.allanwang.kau.utils - -/** - * Created by Allan Wang on 2017-06-17. - * - * Courtesy of adelnizamutdinov - * - * https://github.com/adelnizamutdinov/kotlin-either - */ -@Suppress("unused") -sealed class Either<out L, out R> - -data class Left<out T>(val value: T) : Either<T, Nothing>() -data class Right<out T>(val value: T) : Either<Nothing, T>() - -inline fun <L, R, T> Either<L, R>.fold(left: (L) -> T, right: (R) -> T): T = - when (this) { - is Left -> left(value) - is Right -> right(value) - } - -inline fun <L, R, T> Either<L, R>.flatMap(f: (R) -> Either<L, T>): Either<L, T> = - fold({ this as Left }, f) - -inline fun <L, R, T> Either<L, R>.map(f: (R) -> T): Either<L, T> = - flatMap { Right(f(it)) } - -val <T> Either<T, *>.isLeft: Boolean - get() = this is Left<T> - -val <T> Either<*, T>.isRight: Boolean - get() = this is Right<T>
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt index 247bbc7..3783931 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt @@ -114,21 +114,21 @@ fun <V : View> android.support.v4.app.Fragment.bindOptionalViews(vararg ids: Int fun <V : View> ViewHolder.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty<ViewHolder, List<V>> = optional(ids, viewFinder) -private val View.viewFinder: View.(Int) -> View? +private inline val View.viewFinder: View.(Int) -> View? get() = { findViewById(it) } -private val Activity.viewFinder: Activity.(Int) -> View? +private inline val Activity.viewFinder: Activity.(Int) -> View? get() = { findViewById(it) } -private val Dialog.viewFinder: Dialog.(Int) -> View? +private inline val Dialog.viewFinder: Dialog.(Int) -> View? get() = { findViewById(it) } -private val DialogFragment.viewFinder: DialogFragment.(Int) -> View? +private inline val DialogFragment.viewFinder: DialogFragment.(Int) -> View? get() = { dialog.findViewById(it) } -private val android.support.v4.app.DialogFragment.viewFinder: android.support.v4.app.DialogFragment.(Int) -> View? +private inline val android.support.v4.app.DialogFragment.viewFinder: android.support.v4.app.DialogFragment.(Int) -> View? get() = { dialog.findViewById(it) } -private val Fragment.viewFinder: Fragment.(Int) -> View? +private inline val Fragment.viewFinder: Fragment.(Int) -> View? get() = { view.findViewById(it) } -private val android.support.v4.app.Fragment.viewFinder: android.support.v4.app.Fragment.(Int) -> View? +private inline val android.support.v4.app.Fragment.viewFinder: android.support.v4.app.Fragment.(Int) -> View? get() = { view!!.findViewById(it) } -private val ViewHolder.viewFinder: ViewHolder.(Int) -> View? +private inline val ViewHolder.viewFinder: ViewHolder.(Int) -> View? get() = { itemView.findViewById(it) } private fun viewNotFound(id: Int, desc: KProperty<*>): Nothing = diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt index d04538c..89d64e5 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt @@ -22,22 +22,30 @@ import android.os.Build } } -val buildIsLollipopAndUp: Boolean +@KauUtils fun Context.isAppEnabled(packageName: String): Boolean { + try { + return packageManager.getApplicationInfo(packageName, 0).enabled + } catch (e: Exception) { + return false + } +} + +inline val buildIsLollipopAndUp: Boolean get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -val buildIsMarshmallowAndUp: Boolean +inline val buildIsMarshmallowAndUp: Boolean get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -val buildIsNougatAndUp: Boolean +inline val buildIsNougatAndUp: Boolean get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N const val INSTALLER_GOOGLE_PLAY_VENDING = "com.android.vending" const val INSTALLER_GOOGLE_PLAY_FEEDBACK = "com.google.android.feedback" -val Context.installerPackageName: String? +inline val Context.installerPackageName: String? get() = packageManager.getInstallerPackageName(packageName) -val Context.isFromGooglePlay: Boolean +inline val Context.isFromGooglePlay: Boolean get() { val installer = installerPackageName return arrayOf(INSTALLER_GOOGLE_PLAY_FEEDBACK, INSTALLER_GOOGLE_PLAY_VENDING).any { it == installer } diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt new file mode 100644 index 0000000..f80c85e --- /dev/null +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt @@ -0,0 +1,25 @@ +package ca.allanwang.kau.utils + +import android.graphics.Rect +import android.support.v7.widget.RecyclerView +import android.view.View + +/** + * Created by Allan Wang on 2017-07-11. + */ +fun RecyclerView.withMarginDecoration(sizeDp: Int, edgeFlags: Int) { + addItemDecoration(MarginItemDecoration(sizeDp, edgeFlags)) +} + +class MarginItemDecoration(sizeDp: Int, val edgeFlags: Int) : RecyclerView.ItemDecoration() { + + val sizePx = sizeDp.dpToPx + + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + super.getItemOffsets(outRect, view, parent, state) + if (edgeFlags and KAU_LEFT > 0) outRect.left += sizePx + if (edgeFlags and KAU_TOP > 0) outRect.top += sizePx + if (edgeFlags and KAU_RIGHT > 0) outRect.right += sizePx + if (edgeFlags and KAU_BOTTOM > 0) outRect.bottom += sizePx + } +}
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/StringHolder.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/StringHolder.kt deleted file mode 100644 index e70a2d1..0000000 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/StringHolder.kt +++ /dev/null @@ -1,22 +0,0 @@ -package ca.allanwang.kau.utils - -import android.content.Context -import android.support.annotation.StringRes - -/** - * Created by Allan Wang on 2017-06-08. - */ -class StringHolder { - var text: String? = null - var textRes: Int = 0 - - constructor(@StringRes textRes: Int) { - this.textRes = textRes - } - - constructor(text: String) { - this.text = text - } - - fun getString(context: Context) = context.string(textRes, text) -}
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt index a2043db..e8f385a 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt @@ -26,16 +26,16 @@ import java.text.DecimalFormat @DslMarker annotation class KauUtils -@KauUtils val Float.dpToPx: Float +@KauUtils inline val Float.dpToPx: Float get() = this * Resources.getSystem().displayMetrics.density -@KauUtils val Int.dpToPx: Int +@KauUtils inline val Int.dpToPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt() -@KauUtils val Float.pxToDp: Float +@KauUtils inline val Float.pxToDp: Float get() = this / Resources.getSystem().displayMetrics.density -@KauUtils val Int.pxToDp: Int +@KauUtils inline val Int.pxToDp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt() /** @@ -52,11 +52,9 @@ annotation class KauUtils */ @KauUtils fun Context.minuteToText(minutes: Long): String = with(minutes) { if (this < 0L) string(R.string.kau_none) - else if (this == 60L) string(R.string.kau_one_hour) - else if (this == 1440L) string(R.string.kau_one_day) - else if (this % 1440L == 0L) String.format(string(R.string.kau_x_days), this / 1440L) - else if (this % 60L == 0L) String.format(string(R.string.kau_x_hours), this / 60L) - else String.format(string(R.string.kau_x_minutes), this) + else if (this % 1440L == 0L) plural(R.plurals.kau_x_days, this / 1440L) + else if (this % 60L == 0L) plural(R.plurals.kau_x_hours, this / 60L) + else plural(R.plurals.kau_x_minutes, this) } @KauUtils fun Number.round(@IntRange(from = 1L) decimalCount: Int): String { diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt index 53d6d05..59ae204 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt @@ -1,9 +1,12 @@ +@file:Suppress("NOTHING_TO_INLINE") + package ca.allanwang.kau.utils +import android.animation.ValueAnimator import android.content.Context import android.graphics.Color -import android.graphics.Rect import android.support.annotation.ColorInt +import android.support.annotation.ColorRes import android.support.annotation.StringRes import android.support.annotation.TransitionRes import android.support.design.widget.FloatingActionButton @@ -58,6 +61,8 @@ import com.mikepenz.iconics.typeface.IIcon @KauUtils inline val View.isGone: Boolean get() = visibility == View.GONE +@KauUtils inline fun View.setBackgroundColorRes(@ColorRes color: Int) = setBackgroundColor(context.color(color)) + fun View.snackbar(text: String, duration: Int = Snackbar.LENGTH_LONG, builder: Snackbar.() -> Unit = {}): Snackbar { val snackbar = Snackbar.make(this, text, duration) snackbar.builder() @@ -85,12 +90,24 @@ fun FloatingActionButton.hideIf(hide: Boolean) = if (hide) hide() else show() @KauUtils fun ViewGroup.inflate(layoutId: Int, attachToRoot: Boolean = false): View = LayoutInflater.from(context).inflate(layoutId, this, attachToRoot) +/** + * Set left margin to a value in px + */ @KauUtils fun View.updateLeftMargin(margin: Int) = updateMargins(margin, KAU_LEFT) +/** + * Set top margin to a value in px + */ @KauUtils fun View.updateTopMargin(margin: Int) = updateMargins(margin, KAU_TOP) +/** + * Set right margin to a value in px + */ @KauUtils fun View.updateRightMargin(margin: Int) = updateMargins(margin, KAU_RIGHT) +/** + * Set bottom margin to a value in px + */ @KauUtils fun View.updateBottomMargin(margin: Int) = updateMargins(margin, KAU_BOTTOM) @KauUtils private fun View.updateMargins(margin: Int, flag: Int) { @@ -130,18 +147,11 @@ fun FloatingActionButton.hideIf(hide: Boolean) = if (hide) hide() else show() background = createSimpleRippleDrawable(foregroundColor, backgroundColor) } -@KauUtils val View.parentViewGroup: ViewGroup get() = parent as ViewGroup - -@KauUtils val View.parentVisibleHeight: Int - get() { - val r = Rect() - parentViewGroup.getWindowVisibleDisplayFrame(r) - return r.height() - } +@KauUtils inline val View.parentViewGroup: ViewGroup get() = parent as ViewGroup -val EditText.value: String get() = text.toString().trim() +inline val EditText.value: String get() = text.toString().trim() -val TextInputEditText.value: String get() = text.toString().trim() +inline val TextInputEditText.value: String get() = text.toString().trim() /** * Generates a recycler view with match parent and a linearlayoutmanager, since it's so commonly used @@ -153,4 +163,33 @@ fun Context.fullLinearRecycler(rvAdapter: RecyclerView.Adapter<*>? = null, confi if (rvAdapter != null) adapter = rvAdapter configs() } +} + +/** + * Animate a transition for a FloatinActionButton + * If it is not shown, the action will be invoked directly and the fab will be shown + * If it is already shown, scaling and alpha animations will be added to the action + */ +inline fun FloatingActionButton.transition(crossinline action: FloatingActionButton.() -> Unit) { + if (isHidden) { + action() + show() + } else { + var transitioned = false + ValueAnimator.ofFloat(1.0f, 0.0f, 1.0f).apply { + duration = 500L + addUpdateListener { + val x = it.animatedValue as Float + val scale = x * 0.3f + 0.7f + scaleX = scale + scaleY = scale + imageAlpha = (x * 255).toInt() + if (it.animatedFraction > 0.5f && !transitioned) { + transitioned = true + action() + } + } + start() + } + } }
\ No newline at end of file diff --git a/core/src/main/res/transition/kau_enter_slide_bottom.xml b/core/src/main/res/transition/kau_enter_slide_bottom.xml index 7eb2097..575e189 100644 --- a/core/src/main/res/transition/kau_enter_slide_bottom.xml +++ b/core/src/main/res/transition/kau_enter_slide_bottom.xml @@ -1,20 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright 2015 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="together" diff --git a/core/src/main/res/transition/kau_enter_slide_top.xml b/core/src/main/res/transition/kau_enter_slide_top.xml index 0089b84..8cf613b 100644 --- a/core/src/main/res/transition/kau_enter_slide_top.xml +++ b/core/src/main/res/transition/kau_enter_slide_top.xml @@ -1,20 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright 2015 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="together" diff --git a/core/src/main/res/transition/kau_exit_slide_bottom.xml b/core/src/main/res/transition/kau_exit_slide_bottom.xml new file mode 100644 index 0000000..e0967ec --- /dev/null +++ b/core/src/main/res/transition/kau_exit_slide_bottom.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<transitionSet + xmlns:android="http://schemas.android.com/apk/res/android" + android:transitionOrdering="together" + android:interpolator="@android:interpolator/fast_out_linear_in"> + + <slide + android:slideEdge="bottom" + android:duration="400"> + <targets> + <target android:excludeId="@android:id/navigationBarBackground" /> + <target android:excludeId="@android:id/statusBarBackground" /> + </targets> + </slide> + + <fade android:duration="400"> + <targets> + <target android:targetId="@android:id/navigationBarBackground" /> + <target android:targetId="@android:id/statusBarBackground" /> + </targets> + </fade> + +</transitionSet> diff --git a/core/src/main/res/transition/kau_exit_slide_top.xml b/core/src/main/res/transition/kau_exit_slide_top.xml new file mode 100644 index 0000000..a9849c0 --- /dev/null +++ b/core/src/main/res/transition/kau_exit_slide_top.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<transitionSet + xmlns:android="http://schemas.android.com/apk/res/android" + android:transitionOrdering="together" + android:interpolator="@android:interpolator/fast_out_linear_in"> + + <slide + android:slideEdge="top" + android:duration="400"> + <targets> + <target android:excludeId="@android:id/navigationBarBackground" /> + <target android:excludeId="@android:id/statusBarBackground" /> + </targets> + </slide> + + <fade android:duration="400"> + <targets> + <target android:targetId="@android:id/navigationBarBackground" /> + <target android:targetId="@android:id/statusBarBackground" /> + </targets> + </fade> + +</transitionSet> diff --git a/core/src/main/res/values/attr.xml b/core/src/main/res/values/attr.xml new file mode 100644 index 0000000..f02c219 --- /dev/null +++ b/core/src/main/res/values/attr.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="ResourceName"> + <declare-styleable name="MeasureSpecDelegate"> + <attr format="float" name="relativeWidth"/> + <attr format="float" name="relativeWidthToParent"/> + <attr format="float" name="postRelativeWidth"/> + <attr format="float" name="relativeHeight"/> + <attr format="float" name="relativeHeightToParent"/> + <attr format="float" name="postRelativeHeight"/> + </declare-styleable> +</resources> diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml index a459443..b7c237a 100644 --- a/core/src/main/res/values/dimens.xml +++ b/core/src/main/res/values/dimens.xml @@ -13,6 +13,7 @@ <dimen name="kau_status_bar_height">24dp</dimen> <dimen name="kau_drag_dismiss_distance">112dp</dimen> <!-- 2 * ?android:actionBarSize --> + <dimen name="kau_drag_dismiss_distance_large">168dp</dimen> <!-- 3 * ?android:actionBarSize --> <dimen name="kau_spacing_normal">8dp</dimen> <dimen name="kau_spacing_micro">4dp</dimen> diff --git a/core/src/main/res/values/ids.xml b/core/src/main/res/values/ids.xml index 0b4322c..003e8a7 100644 --- a/core/src/main/res/values/ids.xml +++ b/core/src/main/res/values/ids.xml @@ -1,19 +1,19 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8" standalone="no"?> <resources> - <item name="kau_item_account" type="id" /> - <item name="kau_item_pref_header" type="id" /> - <item name="kau_item_pref_text" type="id" /> - <item name="kau_item_pref_checkbox" type="id" /> - <item name="kau_item_pref_seekbar" type="id" /> - <item name="kau_item_pref_color_picker" type="id" /> - <item name="kau_item_pref_sub_item" type="id" /> - <item name="kau_item_pref_plain_text" type="id" /> - <item name="kau_item_search" type="id" /> - <item name="kau_item_cutout" type="id" /> - <item name="kau_item_header_big_margin_top" type="id" /> - <item name="kau_item_card" type="id" /> - <item name="kau_item_library" type="id" /> - <item name="kau_item_about_main" type="id" /> - <item name="kau_pref_inner_content" type="id" /> - <item name="kau_pref_lower_content" type="id" /> -</resources>
\ No newline at end of file + <item name="kau_item_about_main" type="id"/> + <item name="kau_item_account" type="id"/> + <item name="kau_item_card" type="id"/> + <item name="kau_item_cutout" type="id"/> + <item name="kau_item_header_big_margin_top" type="id"/> + <item name="kau_item_library" type="id"/> + <item name="kau_item_pref_checkbox" type="id"/> + <item name="kau_item_pref_color_picker" type="id"/> + <item name="kau_item_pref_header" type="id"/> + <item name="kau_item_pref_plain_text" type="id"/> + <item name="kau_item_pref_seekbar" type="id"/> + <item name="kau_item_pref_sub_item" type="id"/> + <item name="kau_item_pref_text" type="id"/> + <item name="kau_item_search" type="id"/> + <item name="kau_pref_inner_content" type="id"/> + <item name="kau_pref_lower_content" type="id"/> +</resources> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 5ea5a23..7ad6e38 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -1,15 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <resources> - <string name="kau_u2022">•</string> + <string name="kau_about_libraries_intro">This app would not be possible without the following great libraries.</string> <string name="kau_color_picker">Color Picker</string> - + <string name="kau_dependencies_used">Dependencies Used</string> + <string name="kau_kpref_title_placeholder">Title Placeholder</string> + <string name="kau_md_color_palette">Color Palette</string> <!--Color Picker--> <string name="kau_md_custom">Custom</string> <string name="kau_md_presets">Presets</string> - <string name="kau_md_color_palette">Color Palette</string> - - <string name="kau_kpref_title_placeholder">Title Placeholder</string> <string name="kau_pref_icon">Pref Icon</string> - - <string name="kau_about_libraries_intro">This app would not be possible without the following great libraries.</string> - <string name="kau_dependencies_used">Dependencies Used</string> + <string name="kau_u2022">•</string> </resources> diff --git a/core/src/main/res/values/strings_commons.xml b/core/src/main/res/values/strings_commons.xml index 389b8a2..560a478 100644 --- a/core/src/main/res/values/strings_commons.xml +++ b/core/src/main/res/values/strings_commons.xml @@ -1,8 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- A collection of common string values Most resources are verbatim and x represents a formatted item --> - <resources> <string name="kau_about_app">About App</string> <string name="kau_about_x">About %s</string> @@ -13,6 +13,7 @@ Most resources are verbatim and x represents a formatted item <string name="kau_changelog">Changelog</string> <string name="kau_close">Close</string> <string name="kau_contact_us">Contact Us</string> + <string name="kau_copy">Copy</string> <string name="kau_custom">Custom</string> <string name="kau_dark">Dark</string> <string name="kau_default">Default</string> @@ -38,8 +39,6 @@ Most resources are verbatim and x represents a formatted item <string name="kau_no_results_found">No Results Found</string> <string name="kau_none">None</string> <string name="kau_ok">@android:string/ok</string> - <string name="kau_one_day">1 day</string> - <string name="kau_one_hour">1 hour</string> <string name="kau_play_store">Play Store</string> <string name="kau_rate">Rate</string> <string name="kau_report_bug">Report A Bug</string> @@ -48,13 +47,25 @@ Most resources are verbatim and x represents a formatted item <string name="kau_send_via">Send via</string> <string name="kau_settings">Settings</string> <string name="kau_share">Share</string> + <string name="kau_text_copied">Text copied to clipboard.</string> <string name="kau_thank_you">Thank You</string> <string name="kau_uh_oh">Uh Oh</string> <string name="kau_warning">Warning</string> - <string name="kau_x_days">%d days</string> - <string name="kau_x_hours">%d hours</string> - <string name="kau_x_minutes">%d minutes</string> + <plurals name="kau_x_days"> + <item quantity="one">%d day</item> + <item quantity="other">%d days</item> + </plurals> + <plurals name="kau_x_hours"> + <item quantity="one">%d hour</item> + <item quantity="other">%d hours</item> + </plurals> + <plurals name="kau_x_minutes"> + <item quantity="one">%d minute</item> + <item quantity="other">%d minutes</item> + </plurals> + <plurals name="kau_x_seconds"> + <item quantity="one">%d second</item> + <item quantity="other">%d seconds</item> + </plurals> <string name="kau_yes">Yes</string> - <string name="kau_text_copied">Text copied to clipboard.</string> - <string name="kau_copy">Copy</string> </resources> diff --git a/core/src/main/res/values/styles_animations.xml b/core/src/main/res/values/styles_animations.xml index a991132..fc872bd 100644 --- a/core/src/main/res/values/styles_animations.xml +++ b/core/src/main/res/values/styles_animations.xml @@ -1,4 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <resources> + <style name="KauFadeIn" parent="@android:style/Animation.Activity"> + <item name="android:activityOpenEnterAnimation">@anim/kau_fade_in</item> + <item name="android:activityCloseEnterAnimation">@anim/kau_fade_in</item> + <item name="android:taskOpenEnterAnimation">@anim/kau_fade_in</item> + <item name="android:taskCloseEnterAnimation">@anim/kau_fade_in</item> + <item name="android:taskToFrontEnterAnimation">@anim/kau_fade_in</item> + <item name="android:windowEnterAnimation">@anim/kau_fade_in</item> + </style> + + <style name="KauFadeInFadeOut" parent="@style/KauFadeIn"> + <item name="android:activityOpenExitAnimation">@anim/kau_fade_out</item> + <item name="android:activityCloseExitAnimation">@anim/kau_fade_out</item> + <item name="android:taskOpenExitAnimation">@anim/kau_fade_out</item> + <item name="android:taskCloseExitAnimation">@anim/kau_fade_out</item> + <item name="android:taskToFrontExitAnimation">@anim/kau_fade_out</item> + <item name="android:windowExitAnimation">@anim/kau_fade_out</item> + </style> <style name="KauSlideIn" parent="@android:style/Animation.Activity"> <item name="android:activityOpenEnterAnimation">@anim/kau_slide_in_right</item> @@ -9,15 +27,6 @@ <item name="android:windowEnterAnimation">@anim/kau_slide_in_right</item> </style> - <style name="KauSlideInSlideOut" parent="@style/KauSlideIn"> - <item name="android:activityOpenExitAnimation">@anim/kau_slide_out_right</item> - <item name="android:activityCloseExitAnimation">@anim/kau_slide_out_right</item> - <item name="android:taskOpenExitAnimation">@anim/kau_slide_out_right</item> - <item name="android:taskCloseExitAnimation">@anim/kau_slide_out_right</item> - <item name="android:taskToFrontExitAnimation">@anim/kau_slide_out_right</item> - <item name="android:windowExitAnimation">@anim/kau_slide_out_right</item> - </style> - <style name="KauSlideInFadeOut" parent="@style/KauSlideIn"> <item name="android:activityOpenExitAnimation">@anim/kau_fade_out</item> <item name="android:activityCloseExitAnimation">@anim/kau_fade_out</item> @@ -27,4 +36,12 @@ <item name="android:windowExitAnimation">@anim/kau_fade_out</item> </style> + <style name="KauSlideInSlideOut" parent="@style/KauSlideIn"> + <item name="android:activityOpenExitAnimation">@anim/kau_slide_out_right</item> + <item name="android:activityCloseExitAnimation">@anim/kau_slide_out_right</item> + <item name="android:taskOpenExitAnimation">@anim/kau_slide_out_right</item> + <item name="android:taskCloseExitAnimation">@anim/kau_slide_out_right</item> + <item name="android:taskToFrontExitAnimation">@anim/kau_slide_out_right</item> + <item name="android:windowExitAnimation">@anim/kau_slide_out_right</item> + </style> </resources> diff --git a/core/src/main/res/xml/kau_changelog.xml b/core/src/main/res/xml/kau_changelog.xml deleted file mode 100644 index e570995..0000000 --- a/core/src/main/res/xml/kau_changelog.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - - <!--This is a template--> - - <!-- - <version title="v"/> - <item text="" /> - --> - - <version title="v0.1" /> - <item text="Initial Changelog" /> - <item text="" /> -</resources>
\ No newline at end of file diff --git a/docs/Changelog.md b/docs/Changelog.md index 75fc1d0..e958476 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,6 +1,18 @@ # Changelog ## v2.1 +* :adapter: Fix up CardIItem +* :adapter: Modularized kau animators +* :adapter: Switched from mutablelist to list inputs for themed animator +* :core-ui: Create ElasticRecyclerActivity +* :core-ui: Create MeasuredImageView +* :core: Create MeasureSpecDelegate +* :core: Improve PermissionManager logging +* :core: Inline all util variables with getters +* :core: Introduce fade animation style templates +* :core: Introduce slide transition style templates +* :core: Update utils and remove StringHolder +* :imagepicker: Create full image picker with blurrable selections ## v2.0 * Huge refactoring to separate functions to their own submodules diff --git a/gradle.properties b/gradle.properties index 8e2555e..102d6a7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,18 +23,19 @@ BUILD_TOOLS=26.0.0 ANDROID_SUPPORT_LIBS=26.0.0-beta2 KOTLIN=1.1.3-2 -MATERIAL_DIALOG=0.9.4.5 -ICONICS=2.8.9 -IICON_GOOGLE=3.0.1.1 -TIMBER=4.5.1 +ABOUT_LIBRARIES=5.9.7 +ANKO=0.10.1 +BLURRY=2.1.1 CONSTRAINT_LAYOUT=1.1.0-beta1 FAST_ADAPTER=2.6.2 FAST_ADAPTER_COMMONS=2.6.0 -ANKO=0.10.1 -RX_JAVA=2.1.1 -RX_KOTLIN=2.1.0 +GLIDE=4.0.0-RC1 +ICONICS=2.9.0 +IICON_GOOGLE=3.0.1.1 +MATERIAL_DIALOG=0.9.4.5 RX_ANDROID=2.0.1 RX_BINDING=2.0.0 -ABOUT_LIBRARIES=5.9.6 -GLIDE=4.0.0-RC1 +RX_JAVA=2.1.1 +RX_KOTLIN=2.1.0 +TIMBER=4.5.1 diff --git a/imagepicker/build.gradle b/imagepicker/build.gradle index 14c07ac..d63f5fd 100644 --- a/imagepicker/build.gradle +++ b/imagepicker/build.gradle @@ -10,6 +10,7 @@ dependencies { compile "com.github.bumptech.glide:glide:${GLIDE}" kapt "com.github.bumptech.glide:compiler:${GLIDE}" + compile "jp.wasabeef:blurry:${BLURRY}" } apply from: '../artifacts.gradle' diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt new file mode 100644 index 0000000..8fb5cf3 --- /dev/null +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt @@ -0,0 +1,166 @@ +package ca.allanwang.kau.imagepicker + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import android.widget.ImageView +import ca.allanwang.kau.ui.views.MeasureSpecContract +import ca.allanwang.kau.ui.views.MeasureSpecDelegate +import ca.allanwang.kau.utils.* +import com.mikepenz.google_material_typeface_library.GoogleMaterial +import com.mikepenz.iconics.IconicsDrawable +import jp.wasabeef.blurry.internal.BlurFactor +import jp.wasabeef.blurry.internal.BlurTask + +/** + * Created by Allan Wang on 2017-07-14. + * + * ImageView that is can be blurred and selected + * The frame is composed of three layers: the base, the blur, and the foreground + * Images should be placed in the base view, and the blur view should not be touched + * as the class will handle it + * The foreground by default contains a white checkmark, but can be customized or hidden depending on the situation + */ +class BlurredImageView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr, defStyleRes), MeasureSpecContract by MeasureSpecDelegate() { + + private var blurred = false + val imageBase: ImageView by bindView(R.id.image_base) + internal val imageBlur: ImageView by bindView(R.id.image_blur) + val imageForeground: ImageView by bindView(R.id.image_foreground) + + init { + inflate(R.layout.kau_blurred_imageview, true) + initAttrs(context, attrs) + imageForeground.setIcon(GoogleMaterial.Icon.gmd_check, 30) + } + + companion object { + const val ANIMATION_DURATION = 200L + const val ANIMATION_SCALE = 0.95f + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val result = onMeasure(this, widthMeasureSpec, heightMeasureSpec) + super.onMeasure(result.first, result.second) + } + + override fun clearAnimation() { + super.clearAnimation() + imageBase.clearAnimation() + imageBlur.clearAnimation() + imageForeground.clearAnimation() + } + + private fun View.scaleAnimate(scale: Float) = animate().scaleX(scale).scaleY(scale).setDuration(ANIMATION_DURATION) + private fun View.alphaAnimate(alpha: Float) = animate().alpha(alpha).setDuration(ANIMATION_DURATION) + + + fun isBlurred(): Boolean { + return blurred + } + + /** + * Applies a blur and fills the blur image asynchronously + * When ready, scales the image down and shows the blur & foreground + */ + fun blur() { + if (blurred) return + blurred = true + val factor = BlurFactor() + factor.width = width + factor.height = height + val task = BlurTask(imageBase, factor) { + imageBlur.setImageDrawable(it) + scaleAnimate(ANIMATION_SCALE).start() + imageBlur.alphaAnimate(1f).start() + imageForeground.alphaAnimate(1f).start() + } + task.execute() + } + + /** + * Clears animations and blurs the image without further animations + * This method is relatively instantaneous, as retrieving the blurred image + * is still asynchronous and takes time + */ + fun blurInstantly() { + blurred = true + clearAnimation() + val factor = BlurFactor() + factor.width = width + factor.height = height + BlurTask(imageBase, factor) { drawable -> + imageBlur.setImageDrawable(drawable) + scaleX = ANIMATION_SCALE + scaleY = ANIMATION_SCALE + imageBlur.alpha = 1f + imageForeground.alpha = 1f + }.execute() + } + + /** + * Animate view back to original state and remove drawable when finished + */ + fun removeBlur() { + if (!blurred) return + blurred = false + scaleAnimate(1.0f).start() + imageBlur.alphaAnimate(0f).withEndAction { imageBlur.setImageDrawable(null) }.start() + imageForeground.alphaAnimate(0f).start() + } + + + /** + * Clear all animations and unblur the image + */ + fun removeBlurInstantly() { + blurred = false + clearAnimation() + scaleX = 1.0f + scaleX = 1.0f + imageBlur.alpha = 0f + imageBlur.setImageDrawable(null) + imageForeground.alpha = 0f + } + + /** + * Switch blur state and apply transition + * + * @return true if new state is blurred; false otherwise + */ + fun toggleBlur(): Boolean { + if (blurred) removeBlur() + else blur() + return blurred + } + + /** + * Clears all of the blur effects to restore the original states + * If views were modified in other ways, this method won't affect it + */ + fun reset() { + removeBlurInstantly() + imageBase.setImageDrawable(null) + } + + /** + * Reset most of possible changes to the view + */ + fun fullReset() { + reset() + fullAction({ it.visible().background = null }) + imageForeground.setBackgroundColorRes(R.color.kau_blurred_image_selection_overlay) + imageForeground.setIcon(GoogleMaterial.Icon.gmd_check, 30, Color.WHITE) + } + + private fun fullAction(action: (View) -> Unit) { + action(this) + action(imageBase) + action(imageBlur) + action(imageForeground) + } +}
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt index 0b13a30..852e1e8 100644 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt @@ -1,18 +1,89 @@ package ca.allanwang.kau.imagepicker +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.Drawable import android.support.v7.widget.RecyclerView import android.view.View -import android.widget.ImageView import ca.allanwang.kau.iitems.KauIItem import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.gone +import com.bumptech.glide.Glide +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.mikepenz.fastadapter.FastAdapter +import com.mikepenz.google_material_typeface_library.GoogleMaterial +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.typeface.IIcon /** * Created by Allan Wang on 2017-07-04. */ -class ImageItem(data:String) - : KauIItem<ImageItem, ImageItem.ViewHolder>(R.layout.kau_iitem_card, { ViewHolder(it) }) { +class ImageItem(val data: ImageModel) + : KauIItem<ImageItem, ImageItem.ViewHolder>(R.layout.kau_iitem_image, { ViewHolder(it) }) { + + private var failedToLoad = false + + fun bindEvents(fastAdapter: FastAdapter<ImageItem>) { + fastAdapter.withMultiSelect(true) + fastAdapter.withSelectable(true) + fastAdapter.withOnClickListener { v, _, _, _ -> + val image = v as BlurredImageView + image.toggleBlur() + true + } + } + + override fun bindView(holder: ViewHolder, payloads: List<Any>?) { + super.bindView(holder, payloads) + holder.container.alpha = 0f + Glide.with(holder.itemView) + .load(data.data) + .listener(object : RequestListener<Drawable> { + override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Drawable>, isFirstResource: Boolean): Boolean { + failedToLoad = true; + holder.container.setIcon(GoogleMaterial.Icon.gmd_error); + holder.container.animate().alpha(1f).start(); + return true; + } + + override fun onResourceReady(resource: Drawable, model: Any, target: Target<Drawable>, dataSource: DataSource, isFirstResource: Boolean): Boolean { + holder.container.animate().alpha(1f).start(); + return false; + } + }) + .into(holder.container.imageBase) + } + + private fun BlurredImageView.setIcon(icon: IIcon) { + val sizePx = computeViewSize(context) + imageBase.setImageDrawable(IconicsDrawable(context, icon) + .sizePx(sizePx) + .paddingPx(sizePx / 3) + .color(Color.WHITE)) + //todo add background + imageBase.setBackgroundColor(ImagePickerActivityBase.accentColor) + imageForeground.gone() + } + + private fun computeViewSize(context: Context): Int { + val screenWidthPx = context.resources.displayMetrics.widthPixels + return screenWidthPx / ImagePickerActivityBase.computeColumnCount(context) + } + + override fun unbindView(holder: ViewHolder) { + super.unbindView(holder) + if (!failedToLoad) { + Glide.with(holder.itemView).clear(holder.container.imageBase) + holder.container.removeBlurInstantly() + } else { + holder.container.fullReset() + } + } class ViewHolder(v: View) : RecyclerView.ViewHolder(v) { - val image: ImageView by bindView(R.id.kau_image) + val container: BlurredImageView by bindView(R.id.kau_image) } }
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt new file mode 100644 index 0000000..26e4137 --- /dev/null +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt @@ -0,0 +1,21 @@ +package ca.allanwang.kau.imagepicker + +import android.database.Cursor +import android.provider.MediaStore +import android.support.annotation.NonNull + + +/** + * Created by Allan Wang on 2017-07-14. + */ +class ImageModel(@NonNull cursor: Cursor) { + + val size = cursor.getLong(MediaStore.Images.Media.SIZE) + val dateModified = cursor.getLong(MediaStore.Images.Media.DATE_MODIFIED) + val data = cursor.getString(MediaStore.Images.Media.DATA) + val displayName = cursor.getString(MediaStore.Images.Media.DISPLAY_NAME) + + private fun Cursor.getString(name: String) = getString(getColumnIndex(name)) + private fun Cursor.getLong(name: String) = getLong(getColumnIndex(name)) + +}
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt index 8dfbeab..24c2db7 100644 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt @@ -1,5 +1,7 @@ package ca.allanwang.kau.imagepicker +import android.Manifest +import android.content.Context import android.database.Cursor import android.os.Bundle import android.provider.MediaStore @@ -10,9 +12,10 @@ import android.support.v7.app.AppCompatActivity import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.RecyclerView import android.support.v7.widget.Toolbar -import ca.allanwang.kau.logging.KL +import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.dimenPixelSize import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter @@ -27,14 +30,37 @@ abstract class ImagePickerActivityBase : AppCompatActivity(), LoaderManager.Load val recycler: RecyclerView by bindView(R.id.kau_recycler) val imageAdapter = FastItemAdapter<ImageItem>() + companion object { + /** + * Given the dimensions of our device and a minimum image size, + * Computer the optimal column count for our grid layout + * + * @return column count + */ + fun computeColumnCount(context: Context): Int { + val minImageSizePx = context.dimenPixelSize(R.dimen.kau_image_minimum_size) + val screenWidthPx = context.resources.displayMetrics.widthPixels + return screenWidthPx / minImageSizePx + } + + var accentColor: Int = 0xff666666.toInt() + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.kau_activity_image_picker) - with(recycler) { - layoutManager = GridLayoutManager(this@ImagePickerActivityBase, 3) - adapter = this@ImagePickerActivityBase.imageAdapter + recycler.layoutManager = GridLayoutManager(this, computeColumnCount(this)) + recycler.adapter = imageAdapter + + with(imageAdapter) { + withPositionBasedStateManagement(false) + withMultiSelect(true) + withSelectable(true) + withOnClickListener { v, _, _, _ -> + (v as BlurredImageView).toggleBlur() + true + } } - imageAdapter.add(arrayOf("a", "b", "c").map { ImageItem(it) }) draggableFrame.addListener(object : ElasticDragDismissFrameLayout.SystemChromeFader(this) { override fun onDragDismissed() { if (draggableFrame.translationY < 0) { @@ -44,33 +70,45 @@ abstract class ImagePickerActivityBase : AppCompatActivity(), LoaderManager.Load finishAfterTransition() } }) + kauRequestPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) { + granted, _ -> + if (granted) { + supportLoaderManager.initLoader(42, null, this) + } + } } override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { val columns = arrayOf( MediaStore.Images.Media._ID, + MediaStore.Images.Media.TITLE, MediaStore.Images.Media.DATA, + MediaStore.Images.Media.SIZE, MediaStore.Images.Media.DISPLAY_NAME, - MediaStore.Images.Media.DATE_MODIFIED) - - return CursorLoader(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, null) + MediaStore.Images.Media.DATE_MODIFIED + ) + return CursorLoader(this, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + columns, + null, + null, + MediaStore.Images.Media.DATE_MODIFIED + " DESC") } - override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { - val dataIndex = data.getColumnIndex(MediaStore.Images.Media.DATA) - val alstPhotos = mutableListOf<String>() - - data.moveToLast() - while (!data.isBeforeFirst) { - val photoPath = data.getString(dataIndex) - KL.d(photoPath) - alstPhotos.add(photoPath) - data.moveToPrevious() + override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor?) { + reset() + if (data == null) return + if (data.moveToFirst()) { + do { + val img = ImageModel(data) + imageAdapter.add(ImageItem(img)) + } while (data.moveToNext()) } - imageAdapter.add(alstPhotos.map { ImageItem(it) }) } - override fun onLoaderReset(loader: Loader<Cursor>) { - imageAdapter.clear() + private fun reset() { + imageAdapter.clear(); } + + override fun onLoaderReset(loader: Loader<Cursor>) = reset() }
\ No newline at end of file diff --git a/imagepicker/src/main/res/layout/kau_blurred_imageview.xml b/imagepicker/src/main/res/layout/kau_blurred_imageview.xml new file mode 100644 index 0000000..e28cb9a --- /dev/null +++ b/imagepicker/src/main/res/layout/kau_blurred_imageview.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/image_base" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/kau_blurrable_imageview" + android:scaleType="centerCrop" /> + + <ImageView + android:id="@+id/image_blur" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:alpha="0" + android:contentDescription="@string/kau_blurrable_imageview" + android:scaleType="centerCrop" /> + + <ImageView + android:id="@+id/image_foreground" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:alpha="0" + android:background="@color/kau_blurred_image_selection_overlay" + android:contentDescription="@string/kau_blurrable_imageview" + android:scaleType="centerInside" /> + +</merge>
\ No newline at end of file diff --git a/imagepicker/src/main/res/layout/kau_iitem_image.xml b/imagepicker/src/main/res/layout/kau_iitem_image.xml index 22cc998..9d51d77 100644 --- a/imagepicker/src/main/res/layout/kau_iitem_image.xml +++ b/imagepicker/src/main/res/layout/kau_iitem_image.xml @@ -1,15 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" +<ca.allanwang.kau.imagepicker.BlurredImageView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/kau_image" android:layout_width="match_parent" - android:layout_height="match_parent"> - - <ImageView - android:id="@+id/kau_image" - android:layout_width="0dp" - android:layout_height="0dp" - android:scaleType="centerCrop" - android:background="#f0f" - app:layout_constraintDimensionRatio="1:1" /> - -</android.support.constraint.ConstraintLayout>
\ No newline at end of file + android:layout_height="match_parent" + android:layout_margin="2dp" + android:foreground="@drawable/kau_selectable_white" + app:relativeHeight="1" />
\ No newline at end of file diff --git a/imagepicker/src/main/res/values/colors.xml b/imagepicker/src/main/res/values/colors.xml new file mode 100644 index 0000000..ebaa3f7 --- /dev/null +++ b/imagepicker/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <color name="kau_blurred_image_selection_overlay">#30000000</color> + +</resources>
\ No newline at end of file diff --git a/imagepicker/src/main/res/values/dimens.xml b/imagepicker/src/main/res/values/dimens.xml new file mode 100644 index 0000000..3ff2dd7 --- /dev/null +++ b/imagepicker/src/main/res/values/dimens.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <dimen name="kau_image_minimum_size">120dp</dimen> + +</resources>
\ No newline at end of file diff --git a/imagepicker/src/main/res/values/styles.xml b/imagepicker/src/main/res/values/styles.xml index e2d7280..1fbb184 100644 --- a/imagepicker/src/main/res/values/styles.xml +++ b/imagepicker/src/main/res/values/styles.xml @@ -1,8 +1,5 @@ <resources> - <style name="Kau.Translucent.ImagePicker"> - <!--<item name="android:windowEnterTransition">@transition/kau_enter_slide_bottom</item>--> - <!--<item name="android:windowReturnTransition">@transition/kau_about_return_downward</item>--> - </style> + <style name="Kau.Translucent.ImagePicker" parent="Kau.Translucent.SlideBottom" /> </resources> diff --git a/kpref-activity/src/main/res/values/ids.xml b/kpref-activity/src/main/res/values/ids.xml index 0972706..3bd69ed 100644 --- a/kpref-activity/src/main/res/values/ids.xml +++ b/kpref-activity/src/main/res/values/ids.xml @@ -1,19 +1,19 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8" standalone="no"?> <resources> - <item name="kau_pref_barrier" type="id" /> - <item name="kau_pref_container" type="id" /> - <item name="kau_pref_desc" type="id" /> - <item name="kau_pref_icon" type="id" /> - <item name="kau_pref_inner_content" type="id" /> - <item name="kau_pref_inner_frame" type="id" /> - <item name="kau_pref_item_checkbox" type="id" /> - <item name="kau_pref_item_color_picker" type="id" /> - <item name="kau_pref_item_header" type="id" /> - <item name="kau_pref_item_plain_text" type="id" /> - <item name="kau_pref_item_seekbar" type="id" /> - <item name="kau_pref_item_sub_item" type="id" /> - <item name="kau_pref_item_text" type="id" /> - <item name="kau_pref_lower_content" type="id" /> - <item name="kau_pref_lower_frame" type="id" /> - <item name="kau_pref_title" type="id" /> -</resources>
\ No newline at end of file + <item name="kau_pref_barrier" type="id"/> + <item name="kau_pref_container" type="id"/> + <item name="kau_pref_desc" type="id"/> + <item name="kau_pref_icon" type="id"/> + <item name="kau_pref_inner_content" type="id"/> + <item name="kau_pref_inner_frame" type="id"/> + <item name="kau_pref_item_checkbox" type="id"/> + <item name="kau_pref_item_color_picker" type="id"/> + <item name="kau_pref_item_header" type="id"/> + <item name="kau_pref_item_plain_text" type="id"/> + <item name="kau_pref_item_seekbar" type="id"/> + <item name="kau_pref_item_sub_item" type="id"/> + <item name="kau_pref_item_text" type="id"/> + <item name="kau_pref_lower_content" type="id"/> + <item name="kau_pref_lower_frame" type="id"/> + <item name="kau_pref_title" type="id"/> +</resources> diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 66b73c3..ab5b6d8 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -31,6 +31,9 @@ <activity android:name=".ImageActivity" android:theme="@style/Kau.Translucent.ImagePicker" /> + <activity + android:name=".AdapterActivity" + android:theme="@style/Kau.Translucent.SlideBottom" /> </application> </manifest>
\ No newline at end of file diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt new file mode 100644 index 0000000..874e73b --- /dev/null +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt @@ -0,0 +1,51 @@ +package ca.allanwang.kau.sample + +import android.os.Bundle +import ca.allanwang.kau.iitems.CardIItem +import ca.allanwang.kau.ui.activities.ElasticRecyclerActivity +import ca.allanwang.kau.utils.toast +import com.mikepenz.fastadapter.IItem +import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter +import com.mikepenz.google_material_typeface_library.GoogleMaterial + +/** + * Created by Allan Wang on 2017-07-17. + */ +class AdapterActivity : ElasticRecyclerActivity() { + + val adapter = FastItemAdapter<IItem<*, *>>() + + override fun onCreate(savedInstanceState: Bundle?, configs: Configs): Boolean { + recycler.adapter = adapter + adapter.add(listOf( + CardIItem { + titleRes = R.string.kau_text_copied + descRes = R.string.kau_lorem_ipsum + imageIIcon = GoogleMaterial.Icon.gmd_file_download + }, + CardIItem { + titleRes = R.string.kau_text_copied + descRes = R.string.kau_lorem_ipsum + }, + CardIItem { + titleRes = R.string.kau_text_copied + imageIIcon = GoogleMaterial.Icon.gmd_file_download + cardClick = { toast("Card click") } + }, + CardIItem { + titleRes = R.string.kau_text_copied + descRes = R.string.kau_lorem_ipsum + imageIIcon = GoogleMaterial.Icon.gmd_file_download + button = "Test" + buttonClick = { toast("T") } + }, + CardIItem { + titleRes = R.string.kau_text_copied + button = "Test" + buttonClick = { toast("HI") } + } + )) + setOutsideTapListener { finishAfterTransition() } + return true + } +}
\ No newline at end of file diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt index 9a874cb..53ec745 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt @@ -154,12 +154,16 @@ class MainActivity : KPrefActivity() { descRes = R.string.sub_item_desc } - plainText(R.string.kau_lorem_ipsum) { - onClick = { - _, _, _ -> - startActivity(AboutActivity::class.java, transition = true) - false - } + plainText(R.string.gallery_showcase) { + onClick = { _, _, _ -> startActivity(ImageActivity::class.java, transition = true); false } + } + + plainText(R.string.adapter_showcase) { + onClick = { _, _, _ -> startActivity(AdapterActivity::class.java, transition = true); false } + } + + plainText(R.string.kau_about_app) { + onClick = { _, _, _ -> startActivity(AboutActivity::class.java, transition = true); false } } } @@ -215,7 +219,7 @@ class MainActivity : KPrefActivity() { noResultsFound = R.string.kau_no_results_found shouldClearOnClose = false onItemClick = { - position, key, content, searchView -> + _, _, content, searchView -> toast(content) searchView.revealClose() } diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 0be46ec..f3880b2 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -20,5 +20,7 @@ <string name="sub_item_desc">Press this to view the next subset of preferences</string> <string name="your_email">your.email@here.com</string> <string name="your_subject">Your subject</string> + <string name="gallery_showcase">Gallery Showcase</string> + <string name="adapter_showcase">Adapter Showcase</string> <string name="about_kau">KAU (Kotlin Android Utils) is a collection of common extension functions and complex UIs that can be used in almost all apps. It is meant to implement the shared components, so you can focus on what makes your app unique.</string> </resources> diff --git a/sample/src/main/res/xml/changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index d9bebfc..1599f08 100644 --- a/sample/src/main/res/xml/changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -7,12 +7,19 @@ --> <version title="v2.1"/> - <item text="" /> - <item text="" /> - <item text="" /> - <item text="" /> - <item text="" /> - <item text="" /> + <item text=":adapter: Fix up CardIItem" /> + <item text=":adapter: Modularized kau animators" /> + <item text=":adapter: Switched from mutablelist to list inputs for themed animator" /> + <item text=":core-ui: Create ElasticRecyclerActivity" /> + <item text=":core-ui: Create MeasuredImageView" /> + <item text=":core: Create MeasureSpecDelegate" /> + <item text=":core: Improve PermissionManager logging" /> + <item text=":core: Inline all util variables with getters" /> + <item text=":core: Introduce fade animation style templates" /> + <item text=":core: Introduce slide transition style templates" /> + <item text=":core: Update utils and remove StringHolder" /> + <item text=":imagepicker: Create full image picker with blurrable selections" /> + <item text="Update dependencies" /> <version title="v2.0"/> <item text="Huge refactoring to separate functions to their own submodules" /> diff --git a/searchview/src/main/res/values/dimens.xml b/searchview/src/main/res/values/dimens.xml index acf79cb..edab1ae 100644 --- a/searchview/src/main/res/values/dimens.xml +++ b/searchview/src/main/res/values/dimens.xml @@ -1,27 +1,21 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8" standalone="no"?> <resources> - - <dimen name="kau_search_height">46dp</dimen> - - <dimen name="kau_search_base_margin">4dp</dimen> <dimen name="kau_search_base_corners">2dp</dimen> - <dimen name="kau_search_key_line_8">8dp</dimen> - <dimen name="kau_search_key_line_16">16dp</dimen> + <dimen name="kau_search_base_margin">4dp</dimen> <dimen name="kau_search_divider">1dp</dimen> - - <dimen name="kau_search_item_margin_text">24dp</dimen> - <dimen name="kau_search_item_height">56dp</dimen> + <dimen name="kau_search_filter_margin_start">12dp</dimen> + <dimen name="kau_search_filter_margin_top">4dp</dimen> + <dimen name="kau_search_height">46dp</dimen> <dimen name="kau_search_icon">56dp</dimen> + <dimen name="kau_search_item_height">56dp</dimen> + <dimen name="kau_search_item_margin_text">24dp</dimen> + <dimen name="kau_search_key_line_16">16dp</dimen> + <dimen name="kau_search_key_line_8">8dp</dimen> + <dimen name="kau_search_menu_item_margin">1dp</dimen> + <dimen name="kau_search_menu_item_margin_left_right">2dp</dimen> <dimen name="kau_search_progress">24dp</dimen> + <dimen name="kau_search_reveal">24dp</dimen> + <dimen name="kau_search_text_medium">16sp</dimen> <dimen name="kau_search_text_micro">12sp</dimen> <dimen name="kau_search_text_small">14sp</dimen> - <dimen name="kau_search_text_medium">16sp</dimen> - <dimen name="kau_search_reveal">24dp</dimen> - - <dimen name="kau_search_filter_margin_top">4dp</dimen> - <dimen name="kau_search_filter_margin_start">12dp</dimen> - - <dimen name="kau_search_menu_item_margin">1dp</dimen> - <dimen name="kau_search_menu_item_margin_left_right">2dp</dimen> - -</resources>
\ No newline at end of file +</resources> diff --git a/searchview/src/main/res/values/ids.xml b/searchview/src/main/res/values/ids.xml index b77ad4e..0c00109 100644 --- a/searchview/src/main/res/values/ids.xml +++ b/searchview/src/main/res/values/ids.xml @@ -1,16 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8" standalone="no"?> <resources> - <item name="kau_search_cardview" type="id" /> - <item name="kau_search_clear" type="id" /> - <item name="kau_search_desc" type="id" /> - <item name="kau_search_divider" type="id" /> - <item name="kau_search_edit_text" type="id" /> - <item name="kau_search_extra" type="id" /> - <item name="kau_search_icon" type="id" /> - <item name="kau_search_item_frame" type="id" /> - <item name="kau_search_nav" type="id" /> - <item name="kau_search_progress" type="id" /> - <item name="kau_search_recycler" type="id" /> - <item name="kau_search_shadow" type="id" /> - <item name="kau_search_title" type="id" /> -</resources>
\ No newline at end of file + <item name="kau_search_cardview" type="id"/> + <item name="kau_search_clear" type="id"/> + <item name="kau_search_desc" type="id"/> + <item name="kau_search_divider" type="id"/> + <item name="kau_search_edit_text" type="id"/> + <item name="kau_search_extra" type="id"/> + <item name="kau_search_icon" type="id"/> + <item name="kau_search_item_frame" type="id"/> + <item name="kau_search_nav" type="id"/> + <item name="kau_search_progress" type="id"/> + <item name="kau_search_recycler" type="id"/> + <item name="kau_search_shadow" type="id"/> + <item name="kau_search_title" type="id"/> +</resources> |