diff options
26 files changed, 254 insertions, 163 deletions
diff --git a/.travis.yml b/.travis.yml index fcbb2d3..c0469ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,33 @@ language: android jdk: - oraclejdk8 +env: + global: + - ANDROID_API=27 + - EMULATOR_API=24 + - ANDROID_BUILD_TOOLS=27.0.2 android: components: - tools -# - android-21 + - android-$EMULATOR_API - platform-tools - tools - - build-tools-27.0.2 - - android-27 + - build-tools-$ANDROID_BUILD_TOOLS + - android-$ANDROID_API - extra-android-support - extra-android-m2repository - extra-google-m2repository + - sys-img-armeabi-v7a-android-$EMULATOR_API licenses: - ".+" -before_install: -- yes | sdkmanager "platforms;android-27" -#before_script: -#- echo no | android create avd --force -n test -t android-21 --abi armeabi-v7a -#- emulator -avd test -no-audio -no-window & -#- android-wait-for-emulator -#- adb shell input keyevent 82 & +before_script: +- echo "y" | android update sdk -a --no-ui --filter android-$EMULATOR_API +- echo "y" | android update sdk -a --no-ui --filter sys-img-armeabi-v7a-android-$EMULATOR_API +- android list targets | grep -E '^id:' | awk -F '"' '{$1=""; print $2}' # list all targets +- echo no | android create avd --force -n test -t android-$EMULATOR_API --abi armeabi-v7a +- emulator -avd test -no-skin -no-window & +- android-wait-for-emulator +- adb shell input keyevent 82 & script: - chmod +x gradlew - if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gradlew lintRelease publishRelease; else ./gradlew lintRelease test; fi @@ -37,11 +44,12 @@ notifications: on_failure: always cache: directories: - - "$HOME/.m2" + - $HOME/.m2 - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ - $HOME/.android/build-cache before_install: +- yes | sdkmanager "platforms;android-27" - openssl aes-256-cbc -K $encrypted_12e8842891a3_key -iv $encrypted_12e8842891a3_iv -in files/kau.tar.enc -out kau.tar -d - tar xvf kau.tar
\ No newline at end of file @@ -9,6 +9,7 @@ This library contains small helper functions used throughout almost all of my ot <a href='https://play.google.com/store/apps/details?id=ca.allanwang.kau.sample&utm_source=github'><img alt='Get it on Google Play' width="30%" src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/></a> [Changelog](docs/Changelog.md) +[Migration](docs/Migration.md) ------------ diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt index 8b59539..7e0fe70 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt @@ -1,7 +1,7 @@ package ca.allanwang.kau.kotlin import android.content.Context -import android.support.annotation.AnimatorRes +import android.support.annotation.AnimRes import android.support.annotation.InterpolatorRes import android.view.animation.Animation import android.view.animation.AnimationUtils @@ -11,14 +11,15 @@ import android.view.animation.Interpolator * Created by Allan Wang on 2017-05-30. * * Lazy retrieval of context based items - * Items are retrieved using delegateName[context] + * Items are retrieved using delegateName(context) * */ fun lazyInterpolator(@InterpolatorRes id: Int) = lazyContext<Interpolator> { AnimationUtils.loadInterpolator(it, id) } -fun lazyAnimation(@AnimatorRes id: Int) = lazyContext<Animation> { AnimationUtils.loadAnimation(it, id) } -fun <T : Any> lazyContext(initializer: (context: Context) -> T): LazyContext<T> = LazyContext<T>(initializer) +fun lazyAnimation(@AnimRes id: Int) = lazyContext<Animation> { AnimationUtils.loadAnimation(it, id) } + +fun <T : Any> lazyContext(initializer: (context: Context) -> T): LazyContext<T> = LazyContext(initializer) class LazyContext<out T : Any>(private val initializer: (context: Context) -> T, lock: Any? = null) { @Volatile private var _value: Any = UNINITIALIZED diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt index 8a582d8..ca3701b 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt @@ -84,7 +84,7 @@ class KPrefDelegate<T : Any> internal constructor( else -> throw KPrefException(t) } editor.apply() - postSetter.invoke(t) + postSetter(t) } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt index 065f4bb..a8e8ec3 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt @@ -30,11 +30,11 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs get() = this /** * Threshold of scroll, we will close the activity, when scrollPercent over - * this value; + * this value */ override var scrollThreshold = DEFAULT_SCROLL_THRESHOLD set(value) { - if (value >= 1.0f || value <= 0) throw IllegalArgumentException("Threshold value should be between 0 and 1.0") + if (value >= 1.0f || value <= 0f) throw IllegalArgumentException("Threshold value should be between 0.0 and 1.0") field = value } 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 3620a4a..f6a541b 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt @@ -259,7 +259,7 @@ fun FloatingActionButton.hideOnDownwardsScroll(recycler: RecyclerView) { recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - if (newState == android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE && !isShown) show(); + if (newState == android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE && !isShown) show() } override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { diff --git a/docs/Changelog.md b/docs/Changelog.md index 6a032e8..2d09855 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,5 +1,12 @@ # Changelog +## v3.6.0 +* :core: Created BundleUtils +* :core: [Breaking] Refactored startActivity functions +* :kpref-activity: [Breaking] Simplified listener function parameters +* :kpref-activity: [Breaking] Added dynamic string loading options +* (See Migrations.md for further details on breaking changes) + ## v3.5.1 * Add Portuguese translations * Add Galician translations diff --git a/docs/Migration.md b/docs/Migration.md new file mode 100644 index 0000000..1d8cd9d --- /dev/null +++ b/docs/Migration.md @@ -0,0 +1,35 @@ +# Migrations + +Below are some highlights on major refactoring/breaking changes + +# v3.6.0 + +## startActivity + +Before, startActivity attempted to bind a lot of options with defaults. +Instead, we will now rely on the builder pattern so users may supply their own. +Attributes like `transition` have been replaced with bundle functions such as `withSceneTransitionAnimation(context)`. +The ordering of the builder functions have also been unified so that `bundleBuilder` is always before `intentBuilder`. + +## kpref-activity + +### Click Events + +Instead of passing parameters through the click functions, which were often unused, +they will now be provided through extensions from `KClick`. + +`KClick` holds the same values you'd expect (`itemView`, `innerView` (renamed), `item`), +and adds on `context` and is loaded lazily where possible. + +### Title Res + +In an attempt to make kprefs functional and thus easy to configure, +two new functions, `titleFun` and `descFun` have been introduced. +They will be triggered whenever kprefs are updated to get an up to date stringRes +based on whatever conditions you specify. Most conditions are passed through anyways, +which is why these functions supply no additional information. + +You are still free to use the original `descRes` +and the constructor title, which has been renamed to `titleId` to emphasis its immutability. +Reloading kprefs are always done through the original `titleId`, +regardless of the actual resource currently used.
\ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6376084..2dd7002 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,12 +27,12 @@ VERSION_NAME=3.5.1.0 KOTLIN=1.2.0 ABOUT_LIBRARIES=6.0.0 -ANKO=0.10.2 +ANKO=0.10.3 BLURRY=2.1.1 -CONSTRAINT_LAYOUT=1.1.0-beta3 +CONSTRAINT_LAYOUT=1.1.0-beta4 FAST_ADAPTER=3.0.4 FAST_ADAPTER_COMMONS=3.0.3 -GLIDE=4.3.1 +GLIDE=4.4.0 ICONICS=3.0.0 IICON_GOOGLE=3.0.1.2 MATERIAL_DIALOG=0.9.6.0 diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KClick.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KClick.kt new file mode 100644 index 0000000..c02b024 --- /dev/null +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KClick.kt @@ -0,0 +1,27 @@ +package ca.allanwang.kau.kpref.activity + +import android.content.Context +import android.view.View +import ca.allanwang.kau.kpref.activity.items.KPrefItemBase + +/** + * Created by Allan Wang on 10/12/17. + */ +interface KClick<T> { + + val context: Context + /** + * Base view container from ViewHolder + */ + val itemView: View + + /** + * Optional inner view which differs per element + */ + val innerView: View? + + /** + * The item holding the data + */ + val item: KPrefItemBase<T> +}
\ No newline at end of file diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt index 2b75328..0f88ea0 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt @@ -70,7 +70,7 @@ abstract class KPrefActivity : KauBaseActivity(), KPrefActivityContract { globalOptions = GlobalOptions(core, this) recycler.withLinearAdapter(adapter) adapter.withSelectable(false) - .withOnClickListener { v, _, item, _ -> item.onClick(v, v.findViewById(R.id.kau_pref_inner_content)) } + .withOnClickListener { v, _, item, _ -> item.onClick(v); true } showNextPrefs(R.string.kau_settings, onCreateKPrefs(savedInstanceState), true) } @@ -141,7 +141,7 @@ abstract class KPrefActivity : KauBaseActivity(), KPrefActivityContract { override fun reloadByTitle(@StringRes vararg title: Int) { if (title.isEmpty()) return adapter.adapterItems.forEachIndexed { index, item -> - if (title.any { item.core.titleRes == it }) + if (title.any { item.core.titleId == it }) adapter.notifyItemChanged(index) } } diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefCheckbox.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefCheckbox.kt index 5738022..88692c4 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefCheckbox.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefCheckbox.kt @@ -3,6 +3,7 @@ package ca.allanwang.kau.kpref.activity.items import android.support.v7.widget.AppCompatCheckBox import android.view.View import android.widget.CheckBox +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R import ca.allanwang.kau.utils.tint @@ -14,10 +15,9 @@ import ca.allanwang.kau.utils.tint */ open class KPrefCheckbox(builder: BaseContract<Boolean>) : KPrefItemBase<Boolean>(builder) { - override fun defaultOnClick(itemView: View, innerContent: View?): Boolean { + override fun KClick<Boolean>.defaultOnClick() { pref = !pref - (innerContent as AppCompatCheckBox).isChecked = pref - return true + (innerView as AppCompatCheckBox).isChecked = pref } override fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) { diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefColorPicker.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefColorPicker.kt index 1950589..e0bea4f 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefColorPicker.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefColorPicker.kt @@ -1,12 +1,13 @@ package ca.allanwang.kau.kpref.activity.items -import android.view.View import ca.allanwang.kau.colorpicker.CircleView import ca.allanwang.kau.colorpicker.ColorBuilder import ca.allanwang.kau.colorpicker.ColorContract import ca.allanwang.kau.colorpicker.colorPickerDialog import ca.allanwang.kau.kpref.activity.GlobalOptions +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R +import ca.allanwang.kau.utils.string /** * Created by Allan Wang on 2017-06-07. @@ -19,10 +20,8 @@ open class KPrefColorPicker(open val builder: KPrefColorContract) : KPrefItemBas override fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) { super.onPostBindView(viewHolder, textColor, accentColor) builder.apply { - titleRes = core.titleRes - colorCallback = { - pref = it - } + titleRes = core.titleFun() + colorCallback = { pref = it } } if (builder.showPreview) { val preview = viewHolder.bindInnerView<CircleView>(R.layout.kau_pref_color) @@ -33,18 +32,16 @@ open class KPrefColorPicker(open val builder: KPrefColorContract) : KPrefItemBas pref = it if (builder.showPreview) preview.setBackgroundColor(it) + viewHolder.updateTitle() + viewHolder.updateDesc() } } } } - - override fun defaultOnClick(itemView: View, innerContent: View?): Boolean { - builder.apply { - defaultColor = pref //update color - } - itemView.context.colorPickerDialog(builder).show() - return true + override fun KClick<Int>.defaultOnClick() { + builder.defaultColor = pref + context.colorPickerDialog(builder).show() } /** @@ -58,10 +55,10 @@ open class KPrefColorPicker(open val builder: KPrefColorContract) : KPrefItemBas * Default implementation of [KPrefColorContract] */ class KPrefColorBuilder(globalOptions: GlobalOptions, - override var titleRes: Int, + titleId: Int, getter: () -> Int, setter: (value: Int) -> Unit - ) : KPrefColorContract, BaseContract<Int> by BaseBuilder<Int>(globalOptions, titleRes, getter, setter), + ) : KPrefColorContract, BaseContract<Int> by BaseBuilder(globalOptions, titleId, getter, setter), ColorContract by ColorBuilder() { override var showPreview: Boolean = true } diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefHeader.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefHeader.kt index 6f565ae..3135bb3 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefHeader.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefHeader.kt @@ -17,8 +17,6 @@ open class KPrefHeader(builder: CoreContract) : KPrefItemCore(builder) { if (accentColor != null) viewHolder.title.setTextColor(accentColor) } - override fun onClick(itemView: View, innerContent: View?): Boolean = true - override fun getType() = R.id.kau_item_pref_header }
\ No newline at end of file diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemBase.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemBase.kt index c3f0290..344df5c 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemBase.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemBase.kt @@ -3,6 +3,7 @@ package ca.allanwang.kau.kpref.activity.items import android.support.annotation.CallSuper import android.view.View import ca.allanwang.kau.kpref.activity.GlobalOptions +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R import ca.allanwang.kau.utils.resolveDrawable @@ -14,42 +15,50 @@ import ca.allanwang.kau.utils.resolveDrawable abstract class KPrefItemBase<T>(val base: BaseContract<T>) : KPrefItemCore(base) { open var pref: T - get() = base.getter.invoke() + get() = base.getter() set(value) { - base.setter.invoke(value) + base.setter(value) } var enabled: Boolean = true init { - if (base.onClick == null) base.onClick = { - itemView, innerContent, _ -> - defaultOnClick(itemView, innerContent) - } + if (base.onClick == null) base.onClick = { defaultOnClick() } } - abstract fun defaultOnClick(itemView: View, innerContent: View?): Boolean - @CallSuper override fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) { - enabled = base.enabler.invoke() + enabled = base.enabler() with(viewHolder) { if (!enabled) container?.background = null container?.alpha = if (enabled) 1.0f else 0.3f } } - override final fun onClick(itemView: View, innerContent: View?): Boolean { - return if (enabled) base.onClick?.invoke(itemView, innerContent, this) ?: false - else base.onDisabledClick?.invoke(itemView, innerContent, this) ?: false + override final fun onClick(itemView: View) { + val kclick = object : KClick<T> { + override val context = itemView.context + override val itemView = itemView + override val innerView: View? by lazy { itemView.findViewById<View>(R.id.kau_pref_inner_content) } + override val item = this@KPrefItemBase + } + if (enabled) { + val onClick = base.onClick ?: return + kclick.onClick() + } else { + val onClick = base.onDisabledClick ?: return + kclick.onClick() + } } + abstract fun KClick<T>.defaultOnClick() + override fun unbindView(holder: ViewHolder) { super.unbindView(holder) - with(holder) { - container?.isEnabled = true - container?.background = itemView.context.resolveDrawable(android.R.attr.selectableItemBackground) - container?.alpha = 1.0f + holder.container?.apply { + isEnabled = true + background = holder.itemView.context.resolveDrawable(android.R.attr.selectableItemBackground) + alpha = 1.0f } } @@ -62,8 +71,8 @@ abstract class KPrefItemBase<T>(val base: BaseContract<T>) : KPrefItemCore(base) */ interface BaseContract<T> : CoreContract { var enabler: () -> Boolean - var onClick: ((itemView: View, innerContent: View?, item: KPrefItemBase<T>) -> Boolean)? - var onDisabledClick: ((itemView: View, innerContent: View?, item: KPrefItemBase<T>) -> Boolean)? + var onClick: (KClick<T>.() -> Unit)? + var onDisabledClick: (KClick<T>.() -> Unit)? val getter: () -> T val setter: (value: T) -> Unit } @@ -72,13 +81,13 @@ abstract class KPrefItemBase<T>(val base: BaseContract<T>) : KPrefItemCore(base) * Default implementation of [BaseContract] */ class BaseBuilder<T>(globalOptions: GlobalOptions, - titleRes: Int, + titleId: Int, override val getter: () -> T, override val setter: (value: T) -> Unit - ) : CoreContract by CoreBuilder(globalOptions, titleRes), BaseContract<T> { + ) : CoreContract by CoreBuilder(globalOptions, titleId), BaseContract<T> { override var enabler: () -> Boolean = { true } - override var onClick: ((itemView: View, innerContent: View?, item: KPrefItemBase<T>) -> Boolean)? = null - override var onDisabledClick: ((itemView: View, innerContent: View?, item: KPrefItemBase<T>) -> Boolean)? = null + override var onClick: (KClick<T>.() -> Unit)? = null + override var onDisabledClick: (KClick<T>.() -> Unit)? = null } }
\ No newline at end of file diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt index dc74c97..734824b 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefItemCore.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.support.annotation.CallSuper import android.support.annotation.IdRes import android.support.annotation.LayoutRes -import android.support.annotation.StringRes import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View @@ -32,17 +31,25 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor override final fun getViewHolder(v: View) = ViewHolder(v) + protected fun ViewHolder.updateDesc() { + val descRes = core.descFun() + if (descRes > 0) + desc?.visible()?.setText(descRes) + else + desc?.gone() + } + + protected fun ViewHolder.updateTitle() { + title.setText(core.titleFun()) + } + @SuppressLint("NewApi") @CallSuper override fun bindView(viewHolder: ViewHolder, payloads: List<Any>) { super.bindView(viewHolder, payloads) with(viewHolder) { - val context = itemView.context - title.text = context.string(core.titleRes) - if (core.descRes > 0) - desc?.visible()?.setText(core.descRes) - else - desc?.gone() + updateTitle() + updateDesc() if (core.iicon != null) icon?.visible()?.setIcon(core.iicon, 24) else icon?.gone() innerFrame?.removeAllViews() @@ -61,7 +68,7 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor abstract fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) - abstract fun onClick(itemView: View, innerContent: View?): Boolean + open fun onClick(itemView: View) = Unit override fun unbindView(holder: ViewHolder) { super.unbindView(holder) @@ -80,14 +87,15 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor @KPrefMarker interface CoreContract { val globalOptions: GlobalOptions - @get:StringRes val titleRes: Int + val titleId: Int + var titleFun: () -> Int var descRes: Int - @StringRes get + var descFun: () -> Int var iicon: IIcon? var visible: () -> Boolean /** - * Attempts to reload current item by identifying it with its [titleRes] + * Attempts to reload current item by identifying it with its [titleId] */ fun reloadSelf() } @@ -96,13 +104,19 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor * Default implementation of [CoreContract] */ class CoreBuilder(override val globalOptions: GlobalOptions, - override @param:StringRes val titleRes: Int) : CoreContract { + override val titleId: Int) : CoreContract { override var descRes: Int = -1 + set(value) { + field = value + descFun = { field } + } + override var descFun = { -1 } override var iicon: IIcon? = null - override var visible: () -> Boolean = { true } + override var visible = { true } + override var titleFun = { titleId } override fun reloadSelf() { - globalOptions.reloadByTitle(titleRes) + globalOptions.reloadByTitle(titleId) } } @@ -113,7 +127,7 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor val icon: ImageView? by bindOptionalView(R.id.kau_pref_icon) val innerFrame: LinearLayout? by bindOptionalView(R.id.kau_pref_inner_frame) val lowerFrame: LinearLayout? by bindOptionalView(R.id.kau_pref_lower_frame) - val innerContent: View? + val innerView: View? get() = itemView.findViewById(R.id.kau_pref_inner_content) val lowerContent: View? get() = itemView.findViewById(R.id.kau_pref_lower_content) @@ -121,22 +135,22 @@ abstract class KPrefItemCore(val core: CoreContract) : AbstractItem<KPrefItemCor inline fun <reified T : View> bindInnerView(@LayoutRes id: Int) = bindInnerView(id) { _: T -> } inline fun <reified T : View> bindInnerView(@LayoutRes id: Int, onFirstBind: (T) -> Unit): T { - if (innerFrame == null) throw IllegalStateException("Cannot bind inner view when innerFrame does not exist") - if (innerContent !is T) { - innerFrame!!.removeAllViews() - LayoutInflater.from(innerFrame!!.context).inflate(id, innerFrame) - onFirstBind(innerContent as T) + val innerFrame = this.innerFrame ?: throw IllegalStateException("Cannot bind inner view when innerFrame does not exist") + if (innerView !is T) { + innerFrame.removeAllViews() + LayoutInflater.from(innerFrame.context).inflate(id, innerFrame) + onFirstBind(innerView as T) } - return innerContent as T + return innerView as T } inline fun <reified T : View> bindLowerView(@LayoutRes id: Int) = bindLowerView(id) { _: T -> } inline fun <reified T : View> bindLowerView(@LayoutRes id: Int, onFirstBind: (T) -> Unit): T { - if (lowerFrame == null) throw IllegalStateException("Cannot bind inner view when lowerContent does not exist") + val lowerFrame = this.lowerFrame ?: throw IllegalStateException("Cannot bind inner view when lowerContent does not exist") if (lowerContent !is T) { - lowerFrame!!.removeAllViews() - LayoutInflater.from(lowerFrame!!.context).inflate(id, lowerFrame) + lowerFrame.removeAllViews() + LayoutInflater.from(lowerFrame.context).inflate(id, lowerFrame) onFirstBind(lowerContent as T) } return lowerContent as T diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefPlainText.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefPlainText.kt index d2e49d8..40bf284 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefPlainText.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefPlainText.kt @@ -1,7 +1,7 @@ package ca.allanwang.kau.kpref.activity.items -import android.view.View import ca.allanwang.kau.kpref.activity.GlobalOptions +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R /** @@ -14,15 +14,12 @@ import ca.allanwang.kau.kpref.activity.R */ open class KPrefPlainText(open val builder: KPrefPlainTextBuilder) : KPrefItemBase<Unit>(builder) { - override fun defaultOnClick(itemView: View, innerContent: View?): Boolean { - //nothing - return true - } + override fun KClick<Unit>.defaultOnClick() = Unit class KPrefPlainTextBuilder( globalOptions: GlobalOptions, - titleRes: Int - ) : BaseContract<Unit> by BaseBuilder(globalOptions, titleRes, {}, {}) + titleId: Int + ) : BaseContract<Unit> by BaseBuilder(globalOptions, titleId, {}, {}) override fun getType(): Int = R.id.kau_item_pref_plain_text diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSeekbar.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSeekbar.kt index 3afa614..b27b2ae 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSeekbar.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSeekbar.kt @@ -1,9 +1,9 @@ package ca.allanwang.kau.kpref.activity.items -import android.view.View import android.widget.SeekBar import android.widget.TextView import ca.allanwang.kau.kpref.activity.GlobalOptions +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R import ca.allanwang.kau.utils.tint @@ -15,8 +15,7 @@ import ca.allanwang.kau.utils.tint */ open class KPrefSeekbar(val builder: KPrefSeekbarContract) : KPrefItemBase<Int>(builder) { - - override fun defaultOnClick(itemView: View, innerContent: View?): Boolean = false + override fun KClick<Int>.defaultOnClick() = Unit override fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) { super.onPostBindView(viewHolder, textColor, accentColor) @@ -66,10 +65,10 @@ open class KPrefSeekbar(val builder: KPrefSeekbarContract) : KPrefItemBase<Int>( */ class KPrefSeekbarBuilder( globalOptions: GlobalOptions, - titleRes: Int, + titleId: Int, getter: () -> Int, setter: (value: Int) -> Unit - ) : KPrefSeekbarContract, BaseContract<Int> by BaseBuilder(globalOptions, titleRes, getter, setter) { + ) : KPrefSeekbarContract, BaseContract<Int> by BaseBuilder(globalOptions, titleId, getter, setter) { override var min: Int = 0 diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSubItems.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSubItems.kt index 7c2979c..5d5db96 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSubItems.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefSubItems.kt @@ -14,9 +14,8 @@ import ca.allanwang.kau.kpref.activity.R */ open class KPrefSubItems(open val builder: KPrefSubItemsContract) : KPrefItemCore(builder) { - override fun onClick(itemView: View, innerContent: View?): Boolean { - builder.globalOptions.showNextPrefs(builder.titleRes, builder.itemBuilder) - return true + override fun onClick(itemView: View) { + builder.globalOptions.showNextPrefs(builder.titleFun(), builder.itemBuilder) } override fun getLayoutRes(): Int = R.layout.kau_pref_core @@ -34,9 +33,9 @@ open class KPrefSubItems(open val builder: KPrefSubItemsContract) : KPrefItemCor */ class KPrefSubItemsBuilder( globalOptions: GlobalOptions, - titleRes: Int, + titleId: Int, override val itemBuilder: KPrefAdapterBuilder.() -> Unit - ) : KPrefSubItemsContract, CoreContract by CoreBuilder(globalOptions, titleRes) + ) : KPrefSubItemsContract, CoreContract by CoreBuilder(globalOptions, titleId) override fun getType(): Int = R.id.kau_item_pref_sub_item diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefText.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefText.kt index 29dd007..fa45b04 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefText.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefText.kt @@ -1,8 +1,8 @@ package ca.allanwang.kau.kpref.activity.items -import android.view.View import android.widget.TextView import ca.allanwang.kau.kpref.activity.GlobalOptions +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R import ca.allanwang.kau.utils.toast @@ -20,22 +20,21 @@ open class KPrefText<T>(open val builder: KPrefTextContract<T>) : KPrefItemBase< * Automatically reload on set */ override var pref: T - get() = base.getter.invoke() + get() = base.getter() set(value) { - base.setter.invoke(value) + base.setter(value) builder.reloadSelf() } - override fun defaultOnClick(itemView: View, innerContent: View?): Boolean { - itemView.context.toast("No click function set") - return true + override fun KClick<T>.defaultOnClick() { + context.toast("No click function set") } override fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) { super.onPostBindView(viewHolder, textColor, accentColor) val textview = viewHolder.bindInnerView<TextView>(R.layout.kau_pref_text) if (textColor != null) textview.setTextColor(textColor) - textview.text = builder.textGetter.invoke(pref) + textview.text = builder.textGetter(pref) } /** @@ -50,10 +49,10 @@ open class KPrefText<T>(open val builder: KPrefTextContract<T>) : KPrefItemBase< */ class KPrefTextBuilder<T>( globalOptions: GlobalOptions, - titleRes: Int, + titleId: Int, getter: () -> T, setter: (value: T) -> Unit - ) : KPrefTextContract<T>, BaseContract<T> by BaseBuilder<T>(globalOptions, titleRes, getter, setter) { + ) : KPrefTextContract<T>, BaseContract<T> by BaseBuilder<T>(globalOptions, titleId, getter, setter) { override var textGetter: (T) -> String? = { it?.toString() } } diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefTimePicker.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefTimePicker.kt index d4f854b..f6fc40a 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefTimePicker.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/items/KPrefTimePicker.kt @@ -1,9 +1,9 @@ package ca.allanwang.kau.kpref.activity.items import android.app.TimePickerDialog -import android.view.View import android.widget.TimePicker import ca.allanwang.kau.kpref.activity.GlobalOptions +import ca.allanwang.kau.kpref.activity.KClick import ca.allanwang.kau.kpref.activity.R import java.util.* @@ -17,19 +17,24 @@ import java.util.* */ open class KPrefTimePicker(override val builder: KPrefTimeContract) : KPrefText<Int>(builder) { - interface KPrefTimeContract : KPrefText.KPrefTextContract<Int> { + interface KPrefTimeContract : KPrefText.KPrefTextContract<Int>, TimePickerDialog.OnTimeSetListener { var use24HourFormat: Boolean } + override fun KClick<Int>.defaultOnClick() { + val (hour, min) = pref.splitTime + TimePickerDialog(itemView.context, builder, hour, min, builder.use24HourFormat).show() + } + /** * Default implementation of [KPrefTimeContract] */ class KPrefTimeBuilder( globalOptions: GlobalOptions, - titleRes: Int, + titleId: Int, getter: () -> Int, setter: (value: Int) -> Unit - ) : KPrefTimeContract, BaseContract<Int> by BaseBuilder<Int>(globalOptions, titleRes, getter, setter), TimePickerDialog.OnTimeSetListener { + ) : KPrefTimeContract, BaseContract<Int> by BaseBuilder<Int>(globalOptions, titleId, getter, setter) { override var use24HourFormat: Boolean = false @@ -46,19 +51,14 @@ open class KPrefTimePicker(override val builder: KPrefTimeContract) : KPrefText< String.format(Locale.CANADA, "%d:%02d %s", hour % 12, min, if (hour >= 12) "PM" else "AM") } - override var onClick: ((itemView: View, innerContent: View?, item: KPrefItemBase<Int>) -> Boolean)? = { itemView, _, item -> - val (hour, min) = item.pref.splitTime - TimePickerDialog(itemView.context, this, hour, min, use24HourFormat).show() - true - } - - private val Int.splitTime: Pair<Int, Int> - get() = Pair(this / 100, this % 100) - - private val Pair<Int, Int>.mergeTime: Int - get() = first * 100 + second } override fun getType(): Int = R.id.kau_item_pref_time_picker -}
\ No newline at end of file +} + +private val Int.splitTime: Pair<Int, Int> + get() = Pair(this / 100, this % 100) + +private val Pair<Int, Int>.mergeTime: Int + get() = first * 100 + second
\ No newline at end of file diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt index 6171470..0cf6340 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt @@ -30,7 +30,7 @@ class MediaActionItem( super.bindView(holder, payloads) holder.image.apply { setImageDrawable(MediaPickerCore.getIconDrawable(context, action.iicon(this@MediaActionItem), action.color)) - setOnClickListener { action.invoke(context, this@MediaActionItem) } + setOnClickListener { action(context, this@MediaActionItem) } } } @@ -46,7 +46,7 @@ class MediaActionItem( interface MediaAction { var color: Int fun iicon(item: MediaActionItem): IIcon - fun invoke(c: Context, item: MediaActionItem) + operator fun invoke(c: Context, item: MediaActionItem) } internal const val MEDIA_ACTION_REQUEST_CAMERA = 100 @@ -71,9 +71,8 @@ abstract class MediaActionCamera( MediaType.VIDEO -> GoogleMaterial.Icon.gmd_videocam } - override fun invoke(c: Context, item: MediaActionItem) { - c.kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { - granted, _ -> + override operator fun invoke(c: Context, item: MediaActionItem) { + c.kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ -> if (granted) { val intent = Intent(item.mediaType.captureType) if (intent.resolveActivity(c.packageManager) == null) { @@ -109,7 +108,7 @@ class MediaActionCameraVideo( override var color: Int = MediaPickerCore.accentColor ) : MediaAction { override fun iicon(item: MediaActionItem) = GoogleMaterial.Icon.gmd_videocam - override fun invoke(c: Context, item: MediaActionItem) { + override operator fun invoke(c: Context, item: MediaActionItem) { val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE) if (intent.resolveActivity(c.packageManager) == null) { c.materialDialog { @@ -136,9 +135,8 @@ class MediaActionGallery( MediaType.VIDEO -> GoogleMaterial.Icon.gmd_video_library } - override fun invoke(c: Context, item: MediaActionItem) { - c.kauRequestPermissions(PERMISSION_READ_EXTERNAL_STORAGE) { - granted, _ -> + override operator fun invoke(c: Context, item: MediaActionItem) { + c.kauRequestPermissions(PERMISSION_READ_EXTERNAL_STORAGE) { granted, _ -> if (granted) { val intent = Intent().apply { type = item.mediaType.mimeType diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt index 486ee31..b2cfa46 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt @@ -35,7 +35,7 @@ class MediaItem(val data: MediaModel) override fun isSelectable(): Boolean = !failedToLoad - override fun bindView(holder: ViewHolder, payloads: List<Any>?) { + override fun bindView(holder: ViewHolder, payloads: List<Any>) { super.bindView(holder, payloads) glide(holder.itemView) .load(data.data) @@ -44,13 +44,13 @@ class MediaItem(val data: MediaModel) override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Drawable>, isFirstResource: Boolean): Boolean { failedToLoad = true holder.container.imageBase.setImageDrawable(MediaPickerCore.getErrorDrawable(holder.itemView.context)) - return true; + return true } override fun onResourceReady(resource: Drawable, model: Any, target: Target<Drawable>, dataSource: DataSource, isFirstResource: Boolean): Boolean { holder.container.imageBase.setImageDrawable(resource) if (isSelected) holder.container.blurInstantly() - return true; + return true } }) .into(holder.container.imageBase) diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt index fb2d383..1fa18aa 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt @@ -34,7 +34,7 @@ class MediaItemBasic(val data: MediaModel) override fun isSelectable(): Boolean = false - override fun bindView(holder: ViewHolder, payloads: List<Any>?) { + override fun bindView(holder: ViewHolder, payloads: List<Any>) { super.bindView(holder, payloads) glide(holder.itemView) .load(data.data) @@ -42,7 +42,7 @@ class MediaItemBasic(val data: MediaModel) .listener(object : RequestListener<Drawable> { override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Drawable>, isFirstResource: Boolean): Boolean { holder.image.setImageDrawable(MediaPickerCore.getErrorDrawable(holder.itemView.context)) - return true; + return true } override fun onResourceReady(resource: Drawable, model: Any, target: Target<Drawable>, dataSource: DataSource, isFirstResource: Boolean): Boolean { 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 dd81ce1..e735b38 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt @@ -107,10 +107,7 @@ class MainActivity : KPrefActivity() { checkbox(R.string.checkbox_3, { KPrefSample.check3 }, { KPrefSample.check3 = it }) { descRes = R.string.desc_dependent enabler = { KPrefSample.check2 } - onDisabledClick = { itemView, _, _ -> - itemView.context.toast("I am still disabled") - true - } + onDisabledClick = { itemView.context.toast("I am still disabled") } } colorPicker(R.string.text_color, { KPrefSample.textColor }, { KPrefSample.textColor = it; reload() }) { @@ -139,13 +136,13 @@ class MainActivity : KPrefActivity() { text(R.string.text, { KPrefSample.text }, { KPrefSample.text = it }) { descRes = R.string.text_desc - onClick = { itemView, _, item -> + onClick = { itemView.context.materialDialog { title("Type Text") input("Type here", item.pref, { _, input -> item.pref = input.toString() }) inputRange(0, 20) } - true + } } @@ -161,28 +158,26 @@ class MainActivity : KPrefActivity() { } plainText(R.string.swipe_showcase) { - onClick = { _, _, _ -> startActivityWithEdge(SWIPE_EDGE_LEFT); false } + onClick = { startActivityWithEdge(SWIPE_EDGE_LEFT) } } plainText(R.string.image_showcase) { - onClick = { _, _, _ -> kauLaunchMediaPicker(ImagePickerActivity::class.java, REQUEST_MEDIA); false } + onClick = { kauLaunchMediaPicker(ImagePickerActivity::class.java, REQUEST_MEDIA) } } plainText(R.string.video_overlay_showcase) { - onClick = { _, _, _ -> kauLaunchMediaPicker(VideoPickerActivityOverlay::class.java, REQUEST_MEDIA); false } + onClick = { kauLaunchMediaPicker(VideoPickerActivityOverlay::class.java, REQUEST_MEDIA) } } plainText(R.string.adapter_showcase) { - onClick = { _, _, _ -> - startActivity(AdapterActivity::class.java, bundleBuilder = { + onClick = { startActivity(AdapterActivity::class.java, bundleBuilder = { withSceneTransitionAnimation(this@MainActivity) }) - false } } plainText(R.string.kau_about_app) { - onClick = { _, _, _ -> kauLaunchAbout(AboutActivity::class.java); false } + onClick = { kauLaunchAbout(AboutActivity::class.java) } } header(R.string.long_prefs) @@ -211,7 +206,7 @@ class MainActivity : KPrefActivity() { fun subPrefs(): KPrefAdapterBuilder.() -> Unit = { text(R.string.text, { KPrefSample.text }, { KPrefSample.text = it }) { descRes = R.string.text_desc - onClick = { itemView, _, item -> + onClick = { itemView.context.materialDialog { title("Type Text") input("Type here", item.pref, { _, input -> @@ -220,7 +215,6 @@ class MainActivity : KPrefActivity() { }) inputRange(0, 20) } - true } } } diff --git a/sample/src/main/res/xml/kau_changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index db01fae..f57f8c4 100644 --- a/sample/src/main/res/xml/kau_changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -6,13 +6,21 @@ <item text="" /> --> + <version title="v3.6.0" /> + <item text=":core: Created BundleUtils" /> + <item text=":core: [Breaking] Refactored startActivity functions" /> + <item text=":kpref-activity: [Breaking] Simplified listener function parameters" /> + <item text=":kpref-activity: [Breaking] Added dynamic string loading options" /> + <item text="" /> + <item text="(See Migrations.md for further details on breaking changes)" /> + <version title="v3.5.1" /> <item text="Add Portuguese translations" /> <item text="Add Galician translations" /> <item text="Add some minor util elements" /> <item text="Update dependencies (sdk 27)" /> - <version title="v3.5.0" /> + <version title="v3.5.0" /> <item text="Update dependencies, many of which with major version increments" /> <item text="Add Vietnamese translations" /> <item text="Add Italian translations" /> @@ -21,8 +29,8 @@ <item text=":adapter: Add helper methods to enhance FastAdapter for Kotlin" /> <item text=":core: Create ProgressAnimator class" /> <item text=":searchview: Add searchview holder interface" /> - - <version title="v3.4.5" /> + + <version title="v3.4.5" /> <item text="Add French translations" /> <item text="Add Spanish translations" /> <item text="Add German translations" /> |