diff options
19 files changed, 186 insertions, 69 deletions
diff --git a/buildSrc/src/main/kotlin/kau/Versions.kt b/buildSrc/src/main/kotlin/kau/Versions.kt index ff815dc..4299984 100644 --- a/buildSrc/src/main/kotlin/kau/Versions.kt +++ b/buildSrc/src/main/kotlin/kau/Versions.kt @@ -74,7 +74,7 @@ object Versions { const val bugsnagPlugin="4.7.0" // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google - const val gradlePlugin = "3.5.0" + const val gradlePlugin = "3.6.0-beta01" // https://github.com/dcendents/android-maven-gradle-plugin/releases const val mavenPlugin = "2.1" // https://github.com/Triple-T/gradle-play-publisher/releases diff --git a/core/src/main/res/values/constraintLayout_attr.xml b/core/src/main/res/values/constraintLayout_attr.xml new file mode 100644 index 0000000..e3624e4 --- /dev/null +++ b/core/src/main/res/values/constraintLayout_attr.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!-- Resources missing; see https://issuetracker.google.com/issues/136103084 --> +<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="ResourceName"> + <attr name="flow_horizontalSeparator" /> + <attr name="flow_verticalSeparator" /> + <attr name="motionProgress" /> + <attr name="waveDecay" /> + <attr name="motionPathRotate" /> + <attr name="duration" /> +</resources>
\ No newline at end of file diff --git a/docs/Changelog.md b/docs/Changelog.md index f629f4c..37e355e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -7,6 +7,7 @@ * :core: Remove statusBarLight toggle * :core: Remove kau_status_bar_height; height should be found programmatically * :fastadapter: Migrate fastadapter to v4.x.x +* :fastadapter-viewbinding: Create helper items for ViewBinding ## v5.1.0 * :adapter: Moved fastadapter elements to new module, :fastadapter:. To migrate, simply rename the dependency. If you don't use fast adapter, no changes are necessary diff --git a/fastadapter-databinding/src/main/AndroidManifest.xml b/fastadapter-databinding/src/main/AndroidManifest.xml deleted file mode 100644 index acd1012..0000000 --- a/fastadapter-databinding/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ -<manifest package="ca.allanwang.kau.fastadapter.databinding" /> diff --git a/fastadapter-databinding/.gitignore b/fastadapter-viewbinding/.gitignore index 796b96d..796b96d 100644 --- a/fastadapter-databinding/.gitignore +++ b/fastadapter-viewbinding/.gitignore diff --git a/fastadapter-databinding/build.gradle b/fastadapter-viewbinding/build.gradle index aefb22e..a786edb 100644 --- a/fastadapter-databinding/build.gradle +++ b/fastadapter-viewbinding/build.gradle @@ -6,7 +6,7 @@ ext.kauSubModuleMinSdk = Versions.coreMinSdk apply from: '../android-lib.gradle' android { - dataBinding { + viewBinding { enabled = true } } diff --git a/fastadapter-databinding/consumer-rules.pro b/fastadapter-viewbinding/consumer-rules.pro index e69de29..e69de29 100644 --- a/fastadapter-databinding/consumer-rules.pro +++ b/fastadapter-viewbinding/consumer-rules.pro diff --git a/fastadapter-databinding/proguard-rules.pro b/fastadapter-viewbinding/proguard-rules.pro index f1b4245..f1b4245 100644 --- a/fastadapter-databinding/proguard-rules.pro +++ b/fastadapter-viewbinding/proguard-rules.pro diff --git a/fastadapter-viewbinding/src/main/AndroidManifest.xml b/fastadapter-viewbinding/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3c1cd7f --- /dev/null +++ b/fastadapter-viewbinding/src/main/AndroidManifest.xml @@ -0,0 +1 @@ +<manifest package="ca.allanwang.kau.fastadapter.viewbinding" /> diff --git a/fastadapter-databinding/src/main/kotlin/ca/allanwang/fastadapter/databinding/BindingItem.kt b/fastadapter-viewbinding/src/main/kotlin/ca/allanwang/fastadapter/viewbinding/BindingItem.kt index b2b0f26..a475615 100644 --- a/fastadapter-databinding/src/main/kotlin/ca/allanwang/fastadapter/databinding/BindingItem.kt +++ b/fastadapter-viewbinding/src/main/kotlin/ca/allanwang/fastadapter/viewbinding/BindingItem.kt @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ca.allanwang.fastadapter.databinding +package ca.allanwang.fastadapter.viewbinding import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.databinding.DataBindingUtil -import androidx.databinding.ViewDataBinding import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import ca.allanwang.kau.fastadapter.viewbinding.R import ca.allanwang.kau.logging.KL import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem @@ -32,44 +32,46 @@ interface VhModel { fun vh(): GenericItem } -abstract class BindingItem<Binding : ViewDataBinding>(open val data: Any?) : +/** + * Layout container. Should be implemented in a [BindingItem] companion. + */ +interface BindingLayout<Binding : ViewBinding> { + val layoutRes: Int +} + +abstract class BindingItem<Binding : ViewBinding>(open val data: Any?) : AbstractItem<BindingItem.ViewHolder>(), BindingLayout<Binding> { override val type: Int get() = layoutRes + abstract fun createBinding(layoutInflater: LayoutInflater, parent: ViewGroup?): Binding + override fun createView(ctx: Context, parent: ViewGroup?): View { - val binding: ViewDataBinding = DataBindingUtil.inflate( - LayoutInflater.from(ctx), - layoutRes, parent, - false - ) + val binding = createBinding(LayoutInflater.from(ctx), parent) + setBinding(binding.root, binding) return binding.root } - fun getBinding(holder: ViewHolder): Binding? = - DataBindingUtil.getBinding<Binding>(holder.itemView) - final override fun bindView(holder: ViewHolder, payloads: MutableList<Any>) { super.bindView(holder, payloads) - val binding = getBinding(holder) ?: return + val binding = holder.getBinding<Binding>() binding.bindView(holder, payloads) - binding.executePendingBindings() } abstract fun Binding.bindView(holder: ViewHolder, payloads: MutableList<Any>) final override fun unbindView(holder: ViewHolder) { super.unbindView(holder) - val binding = DataBindingUtil.getBinding<Binding>(holder.itemView) ?: return + val binding = holder.getBinding<Binding>() binding.unbindView(holder) - binding.unbind() } open fun Binding.unbindView(holder: ViewHolder) {} - final override fun getViewHolder(v: View): ViewHolder = ViewHolder(v, layoutRes) + final override fun getViewHolder(v: View): ViewHolder = + ViewHolder(v, layoutRes) override fun failedToRecycle(holder: ViewHolder): Boolean { KL.e { "Failed to recycle" } @@ -85,14 +87,28 @@ abstract class BindingItem<Binding : ViewDataBinding>(open val data: Any?) : override fun hashCode(): Int = data.hashCode() class ViewHolder(itemView: View, internal val layoutRes: Int) : - RecyclerView.ViewHolder(itemView) -} + RecyclerView.ViewHolder(itemView) { + + /** + * Retrieves a binding. + * + * It is assumed that the binding is set prior to this call, + * and that its type matches the supplied generic. + */ + fun <T> getBinding(): T = getBinding(itemView) + } -interface BindingLayout<Binding : ViewDataBinding> { - val layoutRes: Int + companion object { + fun setBinding(view: View, binding: Any) { + view.setTag(R.id.kau_view_binding_model, binding) + } + + @Suppress("UNCHECKED_CAST") + fun <T> getBinding(view: View): T = view.getTag(R.id.kau_view_binding_model) as T + } } -abstract class BindingClickEventHook<Binding : ViewDataBinding, Item : BindingItem<Binding>>(val identifier: BindingLayout<Binding>) : +abstract class BindingClickEventHook<Binding : ViewBinding, Item : BindingItem<Binding>>(val identifier: BindingLayout<Binding>) : ClickEventHook<Item>() { private fun RecyclerView.ViewHolder.binding(): Binding? { @@ -100,24 +116,31 @@ abstract class BindingClickEventHook<Binding : ViewDataBinding, Item : BindingIt if (holder.layoutRes != identifier.layoutRes) { return null } - return DataBindingUtil.getBinding(itemView) + return getBinding() } - final override fun onBind(viewHolder: RecyclerView.ViewHolder): View? = - viewHolder.binding()?.onBind(viewHolder) ?: super.onBind(viewHolder) + final override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { + val binding = viewHolder.binding() ?: return super.onBind(viewHolder) + val view = binding.onBind(viewHolder) ?: return super.onBind(viewHolder) + BindingItem.setBinding(view, binding) + return view + } open fun Binding.onBind(viewHolder: RecyclerView.ViewHolder): View? = super.onBind(viewHolder) - final override fun onBindMany(viewHolder: RecyclerView.ViewHolder): List<View>? = - viewHolder.binding()?.onBindMany(viewHolder) ?: super.onBindMany(viewHolder) + final override fun onBindMany(viewHolder: RecyclerView.ViewHolder): List<View>? { + val binding = viewHolder.binding() ?: return super.onBindMany(viewHolder) + val views = binding.onBindMany(viewHolder) ?: return super.onBindMany(viewHolder) + views.forEach { BindingItem.setBinding(it, binding) } + return views + } open fun Binding.onBindMany(viewHolder: RecyclerView.ViewHolder): List<View>? = super.onBindMany(viewHolder) final override fun onClick(v: View, position: Int, fastAdapter: FastAdapter<Item>, item: Item) { - val binding: Binding = DataBindingUtil.findBinding(v) ?: return - binding.onClick(v, position, fastAdapter, item) + BindingItem.getBinding<Binding>(v).onClick(v, position, fastAdapter, item) } abstract fun Binding.onClick(v: View, position: Int, fastAdapter: FastAdapter<Item>, item: Item) -} +}
\ No newline at end of file diff --git a/fastadapter-viewbinding/src/main/res/values/ids.xml b/fastadapter-viewbinding/src/main/res/values/ids.xml new file mode 100644 index 0000000..550ae02 --- /dev/null +++ b/fastadapter-viewbinding/src/main/res/values/ids.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <item name="kau_view_binding_model" type="id" /> + <item name="kau_view_binding_root" type="id" /> +</resources>
\ No newline at end of file diff --git a/kpref-activity/src/main/res/layout/kau_pref_header.xml b/kpref-activity/src/main/res/layout/kau_pref_header.xml index 65504a3..27ef74c 100644 --- a/kpref-activity/src/main/res/layout/kau_pref_header.xml +++ b/kpref-activity/src/main/res/layout/kau_pref_header.xml @@ -3,8 +3,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dip" - android:paddingEnd="?android:attr/listPreferredItemPaddingRight" + android:clickable="false" + android:focusable="false" android:paddingStart="?android:attr/listPreferredItemPaddingLeft" android:paddingTop="16dip" + android:paddingEnd="?android:attr/listPreferredItemPaddingRight" android:textColor="?colorAccent" android:textSize="14sp" />
\ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index ab98695..47baed2 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -28,6 +28,9 @@ android { multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + viewBinding { + enabled = true + } def releaseSigning = file("../files/kau.properties") def hasSigning = releaseSigning.exists() @@ -121,6 +124,7 @@ android { dependencies { implementation project(':about') implementation project(':fastadapter') + implementation project(':fastadapter-viewbinding') implementation project(':colorpicker') implementation project(':core') implementation project(':core-ui') diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt index a5ef8c3..50b3cf3 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt @@ -16,6 +16,7 @@ package ca.allanwang.kau.sample import android.os.Bundle +import ca.allanwang.kau.adapters.SingleFastAdapter import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.logging.KL import ca.allanwang.kau.permissions.PERMISSION_ACCESS_COARSE_LOCATION @@ -42,7 +43,7 @@ class AnimActivity : KauBaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val adapter = FastItemAdapter<PermissionCheckbox>() + val adapter = SingleFastAdapter() setContentView(fullLinearRecycler(adapter).apply { setBackgroundColor( KPrefSample.bgColor.withAlpha(255) @@ -53,15 +54,8 @@ class AnimActivity : KauBaseActivity() { PERMISSION_ACCESS_COARSE_LOCATION, PERMISSION_ACCESS_FINE_LOCATION, PERMISSION_CAMERA - ).map { PermissionCheckbox(it) }) - adapter.onClickListener = { _, _, item, _ -> - KL.d { "Perm Click" } - kauRequestPermissions(item.permission) { granted, _ -> - toast("${item.permission} enabled: $granted") - adapter.notifyAdapterDataSetChanged() - } - true - } + ).map { PermissionCheckboxModel(it).vh() }) + adapter.addEventHook(PermissionCheckboxViewBinding.clickHook()) kauSwipeOnCreate { edgeFlag = SWIPE_EDGE_LEFT } diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/PermissionCheckbox.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/PermissionCheckbox.kt index 68dde2a..40ad663 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/PermissionCheckbox.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/PermissionCheckbox.kt @@ -15,12 +15,26 @@ */ package ca.allanwang.kau.sample +import android.Manifest +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.CheckBox import android.widget.TextView import androidx.recyclerview.widget.RecyclerView +import ca.allanwang.fastadapter.viewbinding.BindingClickEventHook +import ca.allanwang.fastadapter.viewbinding.BindingItem +import ca.allanwang.fastadapter.viewbinding.BindingLayout +import ca.allanwang.fastadapter.viewbinding.VhModel import ca.allanwang.kau.iitems.KauIItem +import ca.allanwang.kau.logging.KL +import ca.allanwang.kau.permissions.kauRequestPermissions +import ca.allanwang.kau.sample.databinding.PermissionCheckboxBinding import ca.allanwang.kau.utils.hasPermission +import ca.allanwang.kau.utils.toast +import com.mikepenz.fastadapter.FastAdapter +import com.mikepenz.fastadapter.GenericItem +import com.mikepenz.fastadapter.listeners.EventHook /** * Created by Allan Wang on 2017-07-03. @@ -41,3 +55,56 @@ class PermissionCheckbox(val permission: String) : KauIItem<PermissionCheckbox.V val checkbox: CheckBox = v.findViewById(R.id.perm_checkbox) } } + +data class PermissionCheckboxModel(val permission: String) : VhModel { + override fun vh(): GenericItem = PermissionCheckboxViewBinding(this) +} + +class PermissionCheckboxViewBinding( + override val data: PermissionCheckboxModel +) : BindingItem<PermissionCheckboxBinding>(data), + BindingLayout<PermissionCheckboxBinding> by Companion { + + override fun createBinding( + layoutInflater: LayoutInflater, + parent: ViewGroup? + ): PermissionCheckboxBinding = + PermissionCheckboxBinding.inflate(layoutInflater, parent, false) + + override fun PermissionCheckboxBinding.bindView( + holder: ViewHolder, + payloads: MutableList<Any> + ) { + permText.text = data.permission + permCheckbox.apply { + isChecked = holder.itemView.context.hasPermission(data.permission) + isFocusable = false + isClickable = false + jumpDrawablesToCurrentState() // Cancel the animation + } + } + + companion object : BindingLayout<PermissionCheckboxBinding> { + override val layoutRes: Int + get() = R.layout.permission_checkbox + + fun clickHook(): EventHook<PermissionCheckboxViewBinding> = object : BindingClickEventHook<PermissionCheckboxBinding, PermissionCheckboxViewBinding>(this) { + override fun PermissionCheckboxBinding.onBind(viewHolder: RecyclerView.ViewHolder): View? = root + + override fun PermissionCheckboxBinding.onClick( + v: View, + position: Int, + fastAdapter: FastAdapter<PermissionCheckboxViewBinding>, + item: PermissionCheckboxViewBinding + ) { + KL.d { "Perm Click" } + with (v.context) { + kauRequestPermissions(item.data.permission) { granted, _ -> + toast("${item.data.permission} enabled: $granted") + fastAdapter.notifyAdapterDataSetChanged() + } + } + } + } + } +}
\ No newline at end of file diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/SwipeActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/SwipeActivity.kt index 5107e18..3976ae3 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/SwipeActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/SwipeActivity.kt @@ -18,6 +18,7 @@ package ca.allanwang.kau.sample import android.app.Activity import android.os.Bundle import ca.allanwang.kau.internal.KauBaseActivity +import ca.allanwang.kau.sample.databinding.ActivitySwipeBinding import ca.allanwang.kau.swipe.SWIPE_EDGE_BOTTOM import ca.allanwang.kau.swipe.SWIPE_EDGE_LEFT import ca.allanwang.kau.swipe.SWIPE_EDGE_RIGHT @@ -30,7 +31,6 @@ import ca.allanwang.kau.utils.navigationBarColor import ca.allanwang.kau.utils.rndColor import ca.allanwang.kau.utils.startActivity import ca.allanwang.kau.utils.statusBarColor -import kotlinx.android.synthetic.main.activity_swipe.* /** * Created by Allan Wang on 2017-08-05. @@ -45,29 +45,40 @@ fun Activity.startActivityWithEdge(flag: Int) { class SwipeActivity : KauBaseActivity() { + private lateinit var binding: ActivitySwipeBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_swipe) - listOf(swipe_from_left, swipe_from_right, swipe_from_top, swipe_from_bottom) - .zip(listOf(SWIPE_EDGE_LEFT, SWIPE_EDGE_RIGHT, SWIPE_EDGE_TOP, SWIPE_EDGE_BOTTOM)) - .forEach { (button, edge) -> button.setOnClickListener { startActivityWithEdge(edge) } } - val flag = intent.getIntExtra(SWIPE_EDGE, -1) - swipe_toolbar.title = when (flag) { - SWIPE_EDGE_LEFT -> "Left Edge Swipe" - SWIPE_EDGE_RIGHT -> "Right Edge Swipe" - SWIPE_EDGE_TOP -> "Top Edge Swipe" - SWIPE_EDGE_BOTTOM -> "Bottom Edge Swipe" - else -> "Invalid Edge Swipe" - } - setSupportActionBar(swipe_toolbar) - val headerColor = rndColor.darken(0.6f) - swipe_toolbar.setBackgroundColor(headerColor) - statusBarColor = headerColor - val bg = headerColor.darken(0.2f) - swipe_container.setBackgroundColor(bg) - navigationBarColor = bg - kauSwipeOnCreate { - edgeFlag = flag + binding = ActivitySwipeBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.apply { + mapOf( + swipeFromLeft to SWIPE_EDGE_LEFT, + swipeFromRight to SWIPE_EDGE_RIGHT, + swipeFromTop to SWIPE_EDGE_TOP, + swipeFromBottom to SWIPE_EDGE_BOTTOM + ).forEach { (button, edge) -> + button.setOnClickListener { startActivityWithEdge(edge) } + } + val flag = intent.getIntExtra(SWIPE_EDGE, -1) + swipeToolbar.title = when (flag) { + SWIPE_EDGE_LEFT -> "Left Edge Swipe" + SWIPE_EDGE_RIGHT -> "Right Edge Swipe" + SWIPE_EDGE_TOP -> "Top Edge Swipe" + SWIPE_EDGE_BOTTOM -> "Bottom Edge Swipe" + else -> "Invalid Edge Swipe" + } + setSupportActionBar(swipeToolbar) + val headerColor = rndColor.darken(0.6f) + swipeToolbar.setBackgroundColor(headerColor) + statusBarColor = headerColor + val bg = headerColor.darken(0.2f) + swipeContainer.setBackgroundColor(bg) + navigationBarColor = bg + kauSwipeOnCreate { + edgeFlag = flag + } } } diff --git a/sample/src/main/res/values/strings_sample.xml b/sample/src/main/res/values/strings_sample.xml index 46a8140..cd2b3d1 100644 --- a/sample/src/main/res/values/strings_sample.xml +++ b/sample/src/main/res/values/strings_sample.xml @@ -1,4 +1,4 @@ -<resources> +<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <string name="header">This is a header</string> <string name="desc">This is a description</string> <string name="checkbox_1">Checkbox 1</string> diff --git a/sample/src/main/res/xml/kau_changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index 5b4ff9c..d8c167f 100644 --- a/sample/src/main/res/xml/kau_changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -13,7 +13,7 @@ <item text=":core: Remove statusBarLight toggle" /> <item text=":core: Remove kau_status_bar_height; height should be found programmatically" /> <item text=":fastadapter: Migrate fastadapter to v4.x.x" /> - <item text="" /> + <item text=":fastadapter-viewbinding: Create helper items for ViewBinding" /> <item text="" /> <version title="v5.1.0" /> diff --git a/settings.gradle b/settings.gradle index 0ec0606..43c5974 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,7 +4,7 @@ include ':core', ':about', ':adapter', ':fastadapter', - ':fastadapter-databinding', + ':fastadapter-viewbinding', ':colorpicker', ':mediapicker', ':kpref-activity', |