Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/v.1.2.0 #86

Merged
merged 10 commits into from
Nov 2, 2021
12 changes: 7 additions & 5 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ ext {
buildToolsVersion: "29.0.3",
minSdkVersion : 14,
library : [
publishGroupId: 'io.github.vsukharew',
publishGroupId : 'io.github.vsukharew',
publishArtifactId: 'anytypeadapter',
versionName: "1.0.11",
versionCode: 1,
versionName : "1.2.0",
versionCode : 1,
],
sample : [
versionName: "1.0",
Expand Down Expand Up @@ -41,7 +41,8 @@ ext {
moxy : '2.1.2',
retrofit : '2.8.1',
leakcanary : '2.2',
junit : '4.12'
junit : '5.7.1',
mockito : '3.2.0',
]
androidx = [
appCompat : "androidx.appcompat:appcompat:${versions.androidx.appCompat}",
Expand Down Expand Up @@ -72,5 +73,6 @@ ext {
compiler: "com.google.dagger:dagger-compiler:${versions.dagger}",
dagger : "com.google.dagger:dagger:${versions.dagger}",
]
junit = "junit:junit:${versions.junit}"
junit = "org.junit.jupiter:junit-jupiter-engine:${versions.junit}"
mockito = "org.mockito.kotlin:mockito-kotlin:${versions.mockito}"
}
8 changes: 7 additions & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply from: '../dependencies.gradle'
apply from: "../scripts/publish-maven-central.gradle"
apply from: "../scripts/publishing.gradle"

android {
compileSdkVersion build.compileSdkVersion
Expand All @@ -26,6 +26,11 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
testOptions {
unitTests.all {
useJUnitPlatform()
}
}
}

dependencies {
Expand All @@ -37,6 +42,7 @@ dependencies {
implementation androidx.constraintLayout
implementation androidx.recyclerView
testImplementation junit
testImplementation mockito
androidTestImplementation androidx.testRunner
androidTestImplementation androidx.espresso
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ open class AnyTypeAdapter : RecyclerView.Adapter<AnyTypeViewHolder<Any, ViewBind
override fun getItemCount(): Int = anyTypeCollection.size

override fun getItemViewType(position: Int): Int {
return with(anyTypeCollection) {
findCurrentItemViewTypePosition(positionsRanges, position)
.also { currentItemViewTypePosition = it }
.let { currentItemViewTypeDelegate.getItemViewType() }
return anyTypeCollection.run {
findCurrentItemViewTypePosition(position).also { currentItemViewTypePosition = it }
currentItemViewTypeDelegate.getItemViewType()
}
}

Expand Down Expand Up @@ -88,26 +87,6 @@ open class AnyTypeAdapter : RecyclerView.Adapter<AnyTypeViewHolder<Any, ViewBind
}
}

/**
* Finds position inside [anyTypeCollection] for the current item view type
* given current [adapterPosition]
* @see [AnyTypeCollection.itemsMetaData]
*/
private fun findCurrentItemViewTypePosition(
positionsRanges: List<IntRange>,
adapterPosition: Int
): Int {
return with(positionsRanges) {
binarySearch {
when {
adapterPosition in it -> 0
adapterPosition < it.first -> 1
else -> -1
}
}
}
}

private class DiffUtilCallback(
private val oldList: List<AdapterItem<Any>>,
private val newList: List<AdapterItem<Any>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import vsukharev.anytypeadapter.item.AdapterItemMetaData
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import vsukharev.anytypeadapter.delegate.NoDataDelegate
import java.lang.IllegalStateException

/**
* Class that wraps items for [AnyTypeAdapter]
Expand All @@ -23,16 +24,43 @@ class AnyTypeCollection private constructor(
/**
* Saved position value provided in [RecyclerView.Adapter.getItemViewType]
*/
var currentItemViewTypePosition: Int = 0
internal var currentItemViewTypePosition: Int = NO_POSITION

/**
* Returns delegate at the given position in the [itemsMetaData] collection
*/
val currentItemViewTypeDelegate: AnyTypeDelegate<Any, ViewBinding, AnyTypeViewHolder<Any, ViewBinding>>
get() = itemsMetaData[currentItemViewTypePosition].delegate
get() {
return if (itemsMetaData.isNotEmpty()) {
itemsMetaData[currentItemViewTypePosition].delegate
} else {
throw IllegalStateException("Unable to get a delegate in an empty collection")
}
}

val size: Int = items.size

/**
* Finds position for the current item view type given current [adapterPosition]
* @see [AnyTypeCollection.itemsMetaData]
*/
fun findCurrentItemViewTypePosition(adapterPosition: Int): Int {
val currentPositionsRange = positionsRanges.getOrNull(currentItemViewTypePosition)
return if (currentPositionsRange?.contains(adapterPosition) == true) {
currentItemViewTypePosition
} else {
with(positionsRanges) {
binarySearch {
when {
adapterPosition in it -> 0
adapterPosition < it.first -> 1
else -> -1
}
}
}
}
}

class Builder {
private val items = mutableListOf<AdapterItem<Any>>()
private val itemsMetaData = mutableListOf<AdapterItemMetaData<Any, ViewBinding>>()
Expand Down Expand Up @@ -110,9 +138,9 @@ class AnyTypeCollection private constructor(
* Adds [items] and the corresponding [delegate] only if [predicate] is true
* @param predicate the condition determining whether the items and delegate should be added
*/
fun <T : Any, V : ViewBinding, H : AnyTypeViewHolder<List<T>, V>> addIf(
fun <T : Any, V : ViewBinding, H : AnyTypeViewHolder<T, V>> addIf(
items: List<T>,
delegate: AnyTypeDelegate<List<T>, V, H>,
delegate: AnyTypeDelegate<T, V, H>,
predicate: () -> Boolean
): Builder {
return apply {
Expand All @@ -137,30 +165,47 @@ class AnyTypeCollection private constructor(
}
}

/**
* Adds [item] and the corresponding [delegate] only if the item (which must be a collection) is not empty
*/
fun <T : Iterable<*>, V : ViewBinding, H : AnyTypeViewHolder<T, V>> addIfNotEmpty(
item: T,
delegate: AnyTypeDelegate<T, V, H>
): Builder {
return apply { addIf(item, delegate) { item.count() > 0 } }
}

/**
* Adds [items] and the corresponding [delegate] only if the list of items is not empty
*/
fun <T : Any, V : ViewBinding, H : AnyTypeViewHolder<List<T>, V>> addIfNotEmpty(
fun <T : Any, V : ViewBinding, H : AnyTypeViewHolder<T, V>> addIfNotEmpty(
items: List<T>,
delegate: AnyTypeDelegate<List<T>, V, H>
delegate: AnyTypeDelegate<T, V, H>
): Builder {
return apply { addIf(items, delegate) { items.isNotEmpty() } }
}

fun build(): AnyTypeCollection {
val positionsRanges = with(itemsMetaData) {
zipWithNext { first, second ->
first.position until second.position
} + when {
when {
isEmpty() -> emptyList()
else -> listOf(last().position until items.size)
else -> {
zipWithNext { first, second ->
first.position until second.position
} + listOf(last().position until items.size)
}
}
}
return AnyTypeCollection(items, itemsMetaData, positionsRanges).apply {
if (items.isNotEmpty()) {
currentItemViewTypePosition = 0
}
}
return AnyTypeCollection(items, itemsMetaData, positionsRanges)
}
}

companion object {
internal const val NO_POSITION = -1
val EMPTY = Builder().build()
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
package vsukharev.anytypeadapter.delegate

import android.view.LayoutInflater
import android.view.View
import androidx.viewbinding.ViewBinding
import vsukharev.anytypeadapter.holder.NoDataViewHolder
import vsukharev.anytypeadapter.adapter.AnyTypeAdapter
import vsukharev.anytypeadapter.holder.NoDataViewHolder
import java.util.*

/**
* [AnyTypeDelegate] that creates [NoDataViewHolder]
* This delegate can be used when creating list for [AnyTypeAdapter] without specifying data to bind
*/
abstract class NoDataDelegate<V: ViewBinding> : AnyTypeDelegate<Unit, V, NoDataViewHolder<V>>() {

override fun getItemId(item: Unit): String = ITEM_ID

private companion object {
/**
* This delegate has an "artificial" identifier because there is no data
*/
val ITEM_ID: String = UUID.randomUUID().toString()
}
/**
* This delegate has an artificial identifier because there is no data
*/
override fun getItemId(item: Unit): String = UUID.randomUUID().toString()
}
17 changes: 0 additions & 17 deletions library/src/test/java/vsukharev/anytypeadapter/ExampleUnitTest.kt

This file was deleted.

Loading