diff --git a/api-logansquare/build.gradle b/api-logansquare/build.gradle index aa39db6..9daa9da 100644 --- a/api-logansquare/build.gradle +++ b/api-logansquare/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - api project(":components-storable") + api project(":storable") api 'net.danlew:android.joda:2.9.9.4' implementation "com.android.support:support-annotations:$versions.supportLibrary" diff --git a/kotlin-extensions/.gitignore b/kotlin-extensions/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/kotlin-extensions/.gitignore @@ -0,0 +1 @@ +/build diff --git a/kotlin-extensions/build.gradle b/kotlin-extensions/build.gradle new file mode 100644 index 0000000..bcc6129 --- /dev/null +++ b/kotlin-extensions/build.gradle @@ -0,0 +1,16 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion versions.compileSdk + + defaultConfig { + minSdkVersion versions.minSdk + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation "com.android.support:recyclerview-v7:$versions.supportLibrary" +} diff --git a/kotlin-extensions/src/main/AndroidManifest.xml b/kotlin-extensions/src/main/AndroidManifest.xml new file mode 100644 index 0000000..25060ad --- /dev/null +++ b/kotlin-extensions/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/Delegates.kt b/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/Delegates.kt new file mode 100644 index 0000000..050bd6b --- /dev/null +++ b/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/Delegates.kt @@ -0,0 +1,24 @@ +package ru.touchin.roboswag.components.extensions + +import kotlin.properties.Delegates +import kotlin.properties.ObservableProperty +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/** + * Simple observable delegate only for notification of new value. + */ +inline fun Delegates.observable( + initialValue: T, + crossinline onChange: (newValue: T) -> Unit +): ReadWriteProperty = object : ObservableProperty(initialValue) { + override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(newValue) +} + +inline fun Delegates.distinctUntilChanged( + initialValue: T, + crossinline onChange: (newValue: T) -> Unit +): ReadWriteProperty = object : ObservableProperty(initialValue) { + override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = + if (newValue != null && oldValue != newValue) onChange(newValue) else Unit +} diff --git a/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/View.kt b/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/View.kt new file mode 100644 index 0000000..9f4ddca --- /dev/null +++ b/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/View.kt @@ -0,0 +1,20 @@ +package ru.touchin.roboswag.components.extensions + +import android.os.Build +import android.view.View + +private const val RIPPLE_EFFECT_DELAY = 150L + +/** + * Sets click listener to view. On click it will call something after delay. + * + * @param delay Delay after which click listener will be called; + * @param listener Click listener. + */ +fun View.setOnRippleClickListener(delay: Long = RIPPLE_EFFECT_DELAY, listener: (View) -> Unit) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setOnClickListener { view -> postDelayed({ if (hasWindowFocus()) listener(view) }, delay) } + } else { + setOnClickListener(listener) + } +} diff --git a/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/ViewHolder.kt b/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/ViewHolder.kt new file mode 100644 index 0000000..db7165f --- /dev/null +++ b/kotlin-extensions/src/main/java/ru/touchin/roboswag/components/extensions/ViewHolder.kt @@ -0,0 +1,32 @@ +package ru.touchin.roboswag.components.extensions + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.drawable.Drawable +import android.support.annotation.ColorInt +import android.support.annotation.ColorRes +import android.support.annotation.DrawableRes +import android.support.annotation.IdRes +import android.support.annotation.StringRes +import android.support.v4.content.ContextCompat +import android.support.v7.widget.RecyclerView +import android.view.View + +fun RecyclerView.ViewHolder.findViewById(@IdRes resId: Int): T = itemView.findViewById(resId) + +val RecyclerView.ViewHolder.context: Context + get() = itemView.context + +fun RecyclerView.ViewHolder.getText(@StringRes resId: Int): CharSequence = context.getText(resId) + +fun RecyclerView.ViewHolder.getString(@StringRes resId: Int): String = context.getString(resId) + +@SuppressWarnings("SpreadOperator") // it's OK for small arrays +fun RecyclerView.ViewHolder.getString(@StringRes resId: Int, vararg args: Any): String = context.getString(resId, *args) + +@ColorInt +fun RecyclerView.ViewHolder.getColor(@ColorRes resId: Int): Int = ContextCompat.getColor(context, resId) + +fun RecyclerView.ViewHolder.getColorStateList(@ColorRes resId: Int): ColorStateList? = ContextCompat.getColorStateList(context, resId) + +fun RecyclerView.ViewHolder.getDrawable(@DrawableRes resId: Int): Drawable? = ContextCompat.getDrawable(context, resId) diff --git a/lifecycle-common/build.gradle b/lifecycle-common/build.gradle index 76f9f0c..e7ab339 100644 --- a/lifecycle-common/build.gradle +++ b/lifecycle-common/build.gradle @@ -15,7 +15,7 @@ android { } dependencies { - api project(":components-navigation") + api project(":navigation") compileOnly "javax.inject:javax.inject:1" diff --git a/lifecycle-rx/build.gradle b/lifecycle-rx/build.gradle index 67f0308..0956030 100644 --- a/lifecycle-rx/build.gradle +++ b/lifecycle-rx/build.gradle @@ -10,8 +10,8 @@ android { } dependencies { - api project(":components-utils") - api project(":components-logging") + api project(":utils") + api project(":logging") implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" diff --git a/modules.gradle b/modules.gradle index fa997e9..9b11a59 100644 --- a/modules.gradle +++ b/modules.gradle @@ -5,20 +5,24 @@ if (gradle.ext.has('componentsRoot')) { rootDir = settingsDir } -include ':components-logging' -include ':components-utils' -include ':components-navigation' -include ':components-storable' -include ':components-api-logansquare' -include ':components-lifecycle-common' -include ':components-lifecycle-rx' -include ':components-views' +include ':logging' +include ':utils' +include ':navigation' +include ':storable' +include ':api-logansquare' +include ':lifecycle-common' +include ':lifecycle-rx' +include ':views' +include ':recyclerview-adapters' +include ':kotlin-extensions' -project(':components-utils').projectDir = new File(rootDir, 'utils') -project(':components-logging').projectDir = new File(rootDir, 'logging') -project(':components-navigation').projectDir = new File(rootDir, 'navigation') -project(':components-storable').projectDir = new File(rootDir, 'storable') -project(':components-api-logansquare').projectDir = new File(rootDir, 'api-logansquare') -project(':components-lifecycle-common').projectDir = new File(rootDir, 'lifecycle-common') -project(':components-lifecycle-rx').projectDir = new File(rootDir, 'lifecycle-rx') -project(':components-views').projectDir = new File(rootDir, 'views') +project(':utils').projectDir = new File(rootDir, 'utils') +project(':logging').projectDir = new File(rootDir, 'logging') +project(':navigation').projectDir = new File(rootDir, 'navigation') +project(':storable').projectDir = new File(rootDir, 'storable') +project(':api-logansquare').projectDir = new File(rootDir, 'api-logansquare') +project(':lifecycle-common').projectDir = new File(rootDir, 'lifecycle-common') +project(':lifecycle-rx').projectDir = new File(rootDir, 'lifecycle-rx') +project(':views').projectDir = new File(rootDir, 'views') +project(':recyclerview-adapters').projectDir = new File(rootDir, 'recyclerview-adapters') +project(':kotlin-extensions').projectDir = new File(rootDir, 'kotlin-extensions') diff --git a/navigation/build.gradle b/navigation/build.gradle index 43b0e28..8a95e1c 100644 --- a/navigation/build.gradle +++ b/navigation/build.gradle @@ -15,8 +15,8 @@ android { } dependencies { - api project(":components-utils") - api project(":components-logging") + api project(":utils") + api project(":logging") implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" diff --git a/recyclerview-adapters/.gitignore b/recyclerview-adapters/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/recyclerview-adapters/.gitignore @@ -0,0 +1 @@ +/build diff --git a/recyclerview-adapters/build.gradle b/recyclerview-adapters/build.gradle new file mode 100644 index 0000000..12fc082 --- /dev/null +++ b/recyclerview-adapters/build.gradle @@ -0,0 +1,18 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion versions.compileSdk + + defaultConfig { + minSdkVersion versions.minSdk + } +} + +dependencies { + api project(':kotlin-extensions') + + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation "com.android.support:recyclerview-v7:$versions.supportLibrary" +} diff --git a/recyclerview-adapters/src/main/AndroidManifest.xml b/recyclerview-adapters/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2228245 --- /dev/null +++ b/recyclerview-adapters/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java new file mode 100644 index 0000000..25be0c9 --- /dev/null +++ b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * 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. + * + */ + +package ru.touchin.roboswag.components.adapters; + +import android.support.annotation.NonNull; +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.RecyclerView; +import android.view.ViewGroup; + +import java.util.List; + +/** + * Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders. + * Default {@link #getItemViewType} is generating on construction of object. + * + * @param Type of {@link RecyclerView.ViewHolder} of delegate. + */ +public abstract class AdapterDelegate { + + private final int defaultItemViewType = ViewCompat.generateViewId(); + + /** + * Unique ID of AdapterDelegate. + * + * @return Unique ID. + */ + public int getItemViewType() { + return defaultItemViewType; + } + + /** + * Returns if object is processable by this delegate. + * + * @param items Items to check; + * @param adapterPosition Position of item in adapter; + * @param collectionPosition Position of item in collection; + * @return True if item is processable by this delegate. + */ + public abstract boolean isForViewType(@NonNull final List items, final int adapterPosition, final int collectionPosition); + + /** + * Returns unique ID of item to support stable ID's logic of RecyclerView's adapter. + * + * @param items Items in adapter; + * @param adapterPosition Position of item in adapter; + * @param collectionPosition Position of item in collection; + * @return Unique item ID. + */ + public long getItemId(@NonNull final List items, final int adapterPosition, final int collectionPosition) { + return 0; + } + + /** + * Creates ViewHolder to bind item to it later. + * + * @param parent Container of ViewHolder's view. + * @return New ViewHolder. + */ + @NonNull + public abstract TViewHolder onCreateViewHolder(@NonNull final ViewGroup parent); + + /** + * Binds item to created by this object ViewHolder. + * + * @param holder ViewHolder to bind item to; + * @param items Items in adapter; + * @param adapterPosition Position of item in adapter; + * @param collectionPosition Position of item in collection that contains item; + * @param payloads Payloads; + */ + public abstract void onBindViewHolder( + @NonNull final RecyclerView.ViewHolder holder, + @NonNull final List items, + final int adapterPosition, + final int collectionPosition, + @NonNull final List payloads + ); + +} diff --git a/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/DelegatesManager.kt b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/DelegatesManager.kt new file mode 100644 index 0000000..e3ba14f --- /dev/null +++ b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/DelegatesManager.kt @@ -0,0 +1,52 @@ +package ru.touchin.roboswag.components.adapters + +import android.support.v7.widget.RecyclerView +import android.util.SparseArray +import android.view.ViewGroup + +/** + * Manager for delegation callbacks from [RecyclerView.Adapter] to delegates. + */ +class DelegatesManager { + + private val delegates = SparseArray>() + + fun getItemViewType(items: List<*>, adapterPosition: Int, collectionPosition: Int): Int { + for (index in 0 until delegates.size()) { + val delegate = delegates.valueAt(index) + if (delegate.isForViewType(items, adapterPosition, collectionPosition)) { + return delegate.itemViewType + } + } + throw IllegalStateException("Delegate not found for adapterPosition: $adapterPosition") + } + + fun getItemId(items: List<*>, adapterPosition: Int, collectionPosition: Int): Long { + val delegate = getDelegate(getItemViewType(items, adapterPosition, collectionPosition)) + return delegate.getItemId(items, adapterPosition, collectionPosition) + } + + fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = getDelegate(viewType).onCreateViewHolder(parent) + + fun onBindViewHolder(holder: RecyclerView.ViewHolder, items: List<*>, adapterPosition: Int, collectionPosition: Int, payloads: List) { + val delegate = getDelegate(getItemViewType(items, adapterPosition, collectionPosition)) + delegate.onBindViewHolder(holder, items, adapterPosition, collectionPosition, payloads) + } + + /** + * Adds [PositionAdapterDelegate] to adapter. + * + * @param delegate Delegate to add. + */ + fun addDelegate(delegate: AdapterDelegate<*>) = delegates.put(delegate.itemViewType, delegate) + + /** + * Removes [AdapterDelegate] from adapter. + * + * @param delegate Delegate to remove. + */ + fun removeDelegate(delegate: AdapterDelegate<*>) = delegates.remove(delegate.itemViewType) + + private fun getDelegate(viewType: Int) = delegates[viewType] ?: throw IllegalStateException("No AdapterDelegate added for view type: $viewType") + +} diff --git a/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/DelegationListAdapter.kt b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/DelegationListAdapter.kt new file mode 100644 index 0000000..094b298 --- /dev/null +++ b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/DelegationListAdapter.kt @@ -0,0 +1,89 @@ +package ru.touchin.roboswag.components.adapters + +import android.support.v7.recyclerview.extensions.AsyncDifferConfig +import android.support.v7.recyclerview.extensions.AsyncListDiffer +import android.support.v7.util.DiffUtil +import android.support.v7.widget.RecyclerView +import android.view.ViewGroup +import ru.touchin.roboswag.components.extensions.setOnRippleClickListener + +/** + * Base adapter with delegation and diff computing on background thread. + */ +open class DelegationListAdapter(config: AsyncDifferConfig) : RecyclerView.Adapter() { + + constructor(diffCallback: DiffUtil.ItemCallback) : this(AsyncDifferConfig.Builder(diffCallback).build()) + + var itemClickListener: ((TItem, RecyclerView.ViewHolder) -> Unit)? = null + + private val delegatesManager = DelegatesManager() + private var differ = AsyncListDiffer(OffsetAdapterUpdateCallback(this, ::getHeadersCount), config) + + open fun getHeadersCount() = 0 + + open fun getFootersCount() = 0 + + override fun getItemCount() = getHeadersCount() + getList().size + getFootersCount() + + override fun getItemViewType(position: Int) = delegatesManager.getItemViewType(getList(), position, getCollectionPosition(position)) + + override fun getItemId(position: Int) = delegatesManager.getItemId(getList(), position, getCollectionPosition(position)) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = delegatesManager.onCreateViewHolder(parent, viewType) + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List) { + val collectionPosition = getCollectionPosition(position) + if (collectionPosition in 0 until getList().size) { + if (itemClickListener != null) { + holder.itemView.setOnRippleClickListener { + itemClickListener?.invoke(getList()[getCollectionPosition(holder.adapterPosition)], holder) + } + } else { + holder.itemView.setOnClickListener(null) + } + } + delegatesManager.onBindViewHolder(holder, getList(), position, collectionPosition, payloads) + } + + final override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) = Unit + + /** + * Adds [AdapterDelegate] to adapter. + * + * @param delegate Delegate to add. + */ + fun addDelegate(delegate: AdapterDelegate<*>) = delegatesManager.addDelegate(delegate) + + /** + * Removes [AdapterDelegate] from adapter. + * + * @param delegate Delegate to remove. + */ + fun removeDelegate(delegate: AdapterDelegate<*>) = delegatesManager.removeDelegate(delegate) + + /** + * Submits a new list to be diffed, and displayed. + * + * If a list is already being displayed, a diff will be computed on a background thread, which + * will dispatch Adapter.notifyItem events on the main thread. + * + * @param list The new list to be displayed. + */ + fun submitList(list: List) = differ.submitList(list) + + /** + * Get the current List - any diffing to present this list has already been computed and + * dispatched via the ListUpdateCallback. + *

+ * If a null List, or no List has been submitted, an empty list will be returned. + *

+ * The returned list may not be mutated - mutations to content must be done through + * {@link #submitList(List)}. + * + * @return current List. + */ + fun getList(): List = differ.currentList + + fun getCollectionPosition(adapterPosition: Int) = adapterPosition - getHeadersCount() + +} diff --git a/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/ItemAdapterDelegate.java b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/ItemAdapterDelegate.java new file mode 100644 index 0000000..324bcf4 --- /dev/null +++ b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/ItemAdapterDelegate.java @@ -0,0 +1,85 @@ +package ru.touchin.roboswag.components.adapters; + +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; + +import java.util.List; + +/** + * Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders. + * Such delegates are creating and binding ViewHolders for specific items. + * Default {@link #getItemViewType} is generating on construction of object. + * + * @param Type of {@link RecyclerView.ViewHolder} of delegate; + * @param Type of items to bind to {@link RecyclerView.ViewHolder}s. + */ +public abstract class ItemAdapterDelegate extends AdapterDelegate { + + @Override + public boolean isForViewType(@NonNull final List items, final int adapterPosition, final int collectionPosition) { + return collectionPosition >= 0 + && collectionPosition < items.size() + && isForViewType(items.get(collectionPosition), adapterPosition, collectionPosition); + } + + /** + * Returns if object is processable by this delegate. + * This item will be casted to {@link TItem} and passes to {@link #onBindViewHolder(TViewHolder, TItem, int, int, List)}. + * + * @param item Item to check; + * @param adapterPosition Position of item in adapter; + * @param collectionPosition Position of item in collection that contains item; + * @return True if item is processable by this delegate. + */ + public boolean isForViewType(@NonNull final Object item, final int adapterPosition, final int collectionPosition) { + return true; + } + + @Override + public long getItemId(@NonNull final List items, final int adapterPosition, final int collectionPosition) { + //noinspection unchecked + return getItemId((TItem) items.get(collectionPosition), adapterPosition, collectionPosition); + } + + /** + * Returns unique ID of item to support stable ID's logic of RecyclerView's adapter. + * + * @param item Item in adapter; + * @param adapterPosition Position of item in adapter; + * @param collectionPosition Position of item in collection that contains item; + * @return Unique item ID. + */ + public long getItemId(@NonNull final TItem item, final int adapterPosition, final int collectionPosition) { + return 0; + } + + @Override + public void onBindViewHolder( + @NonNull final RecyclerView.ViewHolder holder, + @NonNull final List items, + final int adapterPosition, + final int collectionPosition, + @NonNull final List payloads + ) { + //noinspection unchecked + onBindViewHolder((TViewHolder) holder, (TItem) items.get(collectionPosition), adapterPosition, collectionPosition, payloads); + } + + /** + * Binds item with payloads to created by this object ViewHolder. + * + * @param holder ViewHolder to bind item to; + * @param item Item in adapter; + * @param adapterPosition Position of item in adapter; + * @param collectionPosition Position of item in collection that contains item; + * @param payloads Payloads; + */ + public abstract void onBindViewHolder( + @NonNull final TViewHolder holder, + @NonNull final TItem item, + final int adapterPosition, + final int collectionPosition, + @NonNull final List payloads + ); + +} diff --git a/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/OffsetAdapterUpdateCallback.kt b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/OffsetAdapterUpdateCallback.kt new file mode 100644 index 0000000..9715eb2 --- /dev/null +++ b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/OffsetAdapterUpdateCallback.kt @@ -0,0 +1,24 @@ +package ru.touchin.roboswag.components.adapters + +import android.support.v7.util.ListUpdateCallback +import android.support.v7.widget.RecyclerView + +class OffsetAdapterUpdateCallback(private val adapter: RecyclerView.Adapter<*>, private val offsetProvider: () -> Int) : ListUpdateCallback { + + override fun onInserted(position: Int, count: Int) { + adapter.notifyItemRangeInserted(position + offsetProvider(), count) + } + + override fun onRemoved(position: Int, count: Int) { + adapter.notifyItemRangeRemoved(position + offsetProvider(), count) + } + + override fun onMoved(fromPosition: Int, toPosition: Int) { + adapter.notifyItemMoved(fromPosition + offsetProvider(), toPosition + offsetProvider()) + } + + override fun onChanged(position: Int, count: Int, payload: Any?) { + adapter.notifyItemRangeChanged(position + offsetProvider(), count, payload) + } + +} diff --git a/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/PositionAdapterDelegate.java b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/PositionAdapterDelegate.java new file mode 100644 index 0000000..ada8888 --- /dev/null +++ b/recyclerview-adapters/src/main/java/ru/touchin/roboswag/components/adapters/PositionAdapterDelegate.java @@ -0,0 +1,68 @@ +package ru.touchin.roboswag.components.adapters; + +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; + +import java.util.List; + +/** + * Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders. + * Such delegates are creating and binding ViewHolders by position in adapter. + * Default {@link #getItemViewType} is generating on construction of object. + * + * @param Type of {@link RecyclerView.ViewHolder} of delegate. + */ +public abstract class PositionAdapterDelegate extends AdapterDelegate { + + @Override + public boolean isForViewType(@NonNull final List items, final int adapterPosition, final int collectionPosition) { + return isForViewType(adapterPosition); + } + + /** + * Returns if object is processable by this delegate. + * + * @param adapterPosition Position of item in adapter; + * @return True if item is processable by this delegate. + */ + public abstract boolean isForViewType(final int adapterPosition); + + @Override + public long getItemId(@NonNull final List objects, final int adapterPosition, final int itemsOffset) { + return getItemId(adapterPosition); + } + + /** + * Returns unique ID of item to support stable ID's logic of RecyclerView's adapter. + * + * @param adapterPosition Position of item in adapter; + * @return Unique item ID. + */ + public long getItemId(final int adapterPosition) { + return 0; + } + + @Override + public void onBindViewHolder( + @NonNull final RecyclerView.ViewHolder holder, + @NonNull final List items, + final int adapterPosition, + final int collectionPosition, + @NonNull final List payloads + ) { + //noinspection unchecked + onBindViewHolder((TViewHolder) holder, adapterPosition, payloads); + } + + /** + * Binds position with payloads to ViewHolder. + * + * @param holder ViewHolder to bind position to; + * @param adapterPosition Position of item in adapter; + * @param payloads Payloads. + */ + public void onBindViewHolder(@NonNull final TViewHolder holder, final int adapterPosition, @NonNull final List payloads) { + //do nothing by default + } + +} diff --git a/storable/build.gradle b/storable/build.gradle index 3afe4ee..18cb730 100644 --- a/storable/build.gradle +++ b/storable/build.gradle @@ -14,8 +14,8 @@ android { } dependencies { - api project(":components-utils") - api project(":components-logging") + api project(":utils") + api project(":logging") implementation "com.android.support:support-annotations:$versions.supportLibrary" diff --git a/views/build.gradle b/views/build.gradle index 992dbea..9ea4f9e 100644 --- a/views/build.gradle +++ b/views/build.gradle @@ -14,8 +14,8 @@ android { } dependencies { - api project(":components-utils") - api project(":components-logging") + api project(":utils") + api project(":logging") implementation "com.android.support:design:$versions.supportLibrary" }