diff --git a/build.gradle b/build.gradle index bcb0670..c344de9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,12 @@ buildscript { ext.versions = [ sdkMin : 14, - sdkTarget : 27, - buildTools : '27.0.1', - gradlePlugin : '3.0.1', - kotlin : '1.2.0', - support : '27.0.2' + sdkTarget : 28, + buildTools : '28.0.0', + gradlePlugin : '3.2.0-beta05', + kotlin : '1.2.60', + support : '27.1.1', + androidX : '1.0.0-beta01' ] repositories { google() diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d009205..f39769d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip diff --git a/lastadapter/src/main/java/com/github/nitrico/lastadapter/LastAdapter.kt b/lastadapter/src/main/java/com/github/nitrico/lastadapter/LastAdapter.kt index e6cc38e..fcf6608 100644 --- a/lastadapter/src/main/java/com/github/nitrico/lastadapter/LastAdapter.kt +++ b/lastadapter/src/main/java/com/github/nitrico/lastadapter/LastAdapter.kt @@ -26,7 +26,8 @@ import android.view.ViewGroup class LastAdapter(private val list: List, private val variable: Int? = null, - stableIds: Boolean = false) : RecyclerView.Adapter>() { + stableIds: Boolean = false +) : RecyclerView.Adapter>() { constructor(list: List) : this(list, null, false) constructor(list: List, variable: Int) : this(list, variable, false) @@ -35,7 +36,6 @@ class LastAdapter(private val list: List, private val DATA_INVALIDATION = Any() private val callback = ObservableListCallback(this) private var recyclerView: RecyclerView? = null - private var inflater: LayoutInflater? = null private val map = mutableMapOf, BaseType>() private var layoutHandler: LayoutHandler? = null @@ -85,15 +85,14 @@ class LastAdapter(private val list: List, fun into(recyclerView: RecyclerView) = apply { recyclerView.adapter = this } - - override fun onCreateViewHolder(view: ViewGroup, viewType: Int): Holder { + val inflater = LayoutInflater.from(view.context) val binding = DataBindingUtil.inflate(inflater, viewType, view, false) val holder = Holder(binding) binding.addOnRebindCallback(object : OnRebindCallback() { override fun onPreBind(binding: ViewDataBinding) = recyclerView?.isComputingLayout ?: false override fun onCanceled(binding: ViewDataBinding) { - if (recyclerView?.isComputingLayout ?: true) { + if (recyclerView?.isComputingLayout != false) { return } val position = holder.adapterPosition @@ -157,7 +156,6 @@ class LastAdapter(private val list: List, list.addOnListChangedCallback(callback) } recyclerView = rv - inflater = LayoutInflater.from(rv.context) } override fun onDetachedFromRecyclerView(rv: RecyclerView) { diff --git a/lastadapterx/.gitignore b/lastadapterx/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/lastadapterx/.gitignore @@ -0,0 +1 @@ +/build diff --git a/lastadapterx/build.gradle b/lastadapterx/build.gradle new file mode 100644 index 0000000..93c9fe1 --- /dev/null +++ b/lastadapterx/build.gradle @@ -0,0 +1,18 @@ +plugins { + id 'com.android.library' + id 'kotlin-android' +} + +android { + compileSdkVersion versions.sdkTarget + buildToolsVersion versions.buildTools + defaultConfig.minSdkVersion versions.sdkMin + dataBinding.enabled true +} + +dependencies { + implementation "androidx.recyclerview:recyclerview:$versions.androidX" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin" +} + +apply from: 'publish.gradle' diff --git a/lastadapterx/gradle.properties b/lastadapterx/gradle.properties new file mode 100644 index 0000000..ccb748f --- /dev/null +++ b/lastadapterx/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/lastadapterx/proguard-rules.pro b/lastadapterx/proguard-rules.pro new file mode 100644 index 0000000..5740c8d --- /dev/null +++ b/lastadapterx/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Android\SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/lastadapterx/publish.gradle b/lastadapterx/publish.gradle new file mode 100644 index 0000000..a427b07 --- /dev/null +++ b/lastadapterx/publish.gradle @@ -0,0 +1,74 @@ +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'com.jfrog.bintray' + +def libName = 'lastadapter' +def libGroup = 'com.github.nitrico.' + libName +def libSite = 'https://github.com/nitrico/' + libName +def libGit = libSite + '.git' +def libTracker = libSite + '/issues' +def libDesc = "Don't write any other RecyclerView adapter again. Not even a Holder!" +def libTags = ['android', 'recyclerview', 'adapter', 'data binding', 'kotlin'] + +group libGroup +version '2.3.0' + +Properties properties = new Properties() +properties.load(rootProject.file('local.properties').newDataInputStream()) + +bintray { + user properties.getProperty('bintray_user') + key properties.getProperty('bintray_key') + configurations = ['archives'] + pkg { + repo = 'maven' + name = libName + desc = libDesc + websiteUrl = libSite + issueTrackerUrl = libTracker + vcsUrl = libGit + labels = libTags + licenses = ['Apache-2.0'] + publish = true + publicDownloadNumbers = true + } +} + +install { + repositories.mavenInstaller { + pom.project { + packaging 'aar' + groupId libGroup + artifactId libName + name libName + description libDesc + url libSite + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + developers { + developer { + id 'moreno' + name 'Miguel Ángel Moreno' + email 'nitrico@gmail.com' + } + } + scm { + connection libGit + developerConnection libGit + url libSite + } + } + } +} + +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier 'sources' +} + +artifacts { + archives sourcesJar +} diff --git a/lastadapterx/src/main/AndroidManifest.xml b/lastadapterx/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1e08121 --- /dev/null +++ b/lastadapterx/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Holder.kt b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Holder.kt new file mode 100644 index 0000000..b63b25f --- /dev/null +++ b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Holder.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 Miguel Ángel Moreno + * + * 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 com.github.nitrico.lastadapterx + +import androidx.databinding.ViewDataBinding +import androidx.recyclerview.widget.RecyclerView + +open class Holder(val binding: B) : RecyclerView.ViewHolder(binding.root) { + internal var created = false +} diff --git a/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Interfaces.kt b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Interfaces.kt new file mode 100644 index 0000000..d86b850 --- /dev/null +++ b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Interfaces.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Miguel Ángel Moreno + * + * 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 com.github.nitrico.lastadapterx + +interface Handler + +interface TypeHandler : Handler { + fun getItemType(item: Any, position: Int): BaseType? +} + +interface LayoutHandler : Handler { + fun getItemLayout(item: Any, position: Int): Int +} + +interface StableId { + val stableId: Long +} diff --git a/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/LastAdapterX.kt b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/LastAdapterX.kt new file mode 100644 index 0000000..5fa9e77 --- /dev/null +++ b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/LastAdapterX.kt @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2016 Miguel Ángel Moreno + * + * 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 com.github.nitrico.lastadapterx + +import androidx.databinding.DataBindingUtil +import androidx.databinding.ObservableList +import androidx.databinding.OnRebindCallback +import androidx.databinding.ViewDataBinding +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView + +class LastAdapterX @JvmOverloads constructor( + private val list: List, + private val variable: Int? = null, + stableIds: Boolean = false) : RecyclerView.Adapter>() { + + constructor(list: List, variable: Int) : this(list, variable, false) + constructor(list: List, stableIds: Boolean) : this(list, null, stableIds) + + private val DATA_INVALIDATION = Any() + private val callback = ObservableListCallback(this) + private var recyclerView: RecyclerView? = null + private lateinit var inflater: LayoutInflater + + private val map = mutableMapOf, BaseType>() + private var layoutHandler: LayoutHandler? = null + private var typeHandler: TypeHandler? = null + + init { + setHasStableIds(stableIds) + } + + @JvmOverloads + fun map(clazz: Class, layout: Int, variable: Int? = null) = apply { map[clazz] = BaseType(layout, variable) } + + inline fun map(layout: Int, variable: Int? = null) = map(T::class.java, layout, variable) + + fun map(clazz: Class, type: AbsType<*>) = apply { map[clazz] = type } + + inline fun map(type: AbsType<*>) = map(T::class.java, type) + + inline fun map( + layout: Int, + variable: Int? = null, + noinline f: (Type.() -> Unit)? = null + ) = map(T::class.java, Type(layout, variable).apply { f?.invoke(this) }) + + fun handler(handler: Handler) = apply { + when (handler) { + is LayoutHandler -> { + if (variable == null) { + throw IllegalStateException("No variable specified in LastAdapterX constructor") + } + layoutHandler = handler + } + is TypeHandler -> typeHandler = handler + } + } + + inline fun layout(crossinline f: (Any, Int) -> Int) = handler(object : LayoutHandler { + override fun getItemLayout(item: Any, position: Int) = f(item, position) + }) + + inline fun type(crossinline f: (Any, Int) -> AbsType<*>?) = handler(object : TypeHandler { + override fun getItemType(item: Any, position: Int) = f(item, position) + }) + + fun into(recyclerView: RecyclerView) = apply { recyclerView.adapter = this } + + + override fun onCreateViewHolder(view: ViewGroup, viewType: Int): Holder { + val binding = DataBindingUtil.inflate(inflater, viewType, view, false) + val holder = Holder(binding) + binding.addOnRebindCallback(object : OnRebindCallback() { + override fun onPreBind(binding: ViewDataBinding) = recyclerView?.isComputingLayout + ?: false + + override fun onCanceled(binding: ViewDataBinding) { + if (recyclerView?.isComputingLayout != false) { + return + } + val position = holder.adapterPosition + if (position != RecyclerView.NO_POSITION) { + notifyItemChanged(position, DATA_INVALIDATION) + } + } + }) + return holder + } + + override fun onBindViewHolder(holder: Holder, position: Int) { + val type = getType(position)!! + holder.binding.setVariable(getVariable(type), list[position]) + holder.binding.executePendingBindings() + @Suppress("UNCHECKED_CAST") + if (type is AbsType<*>) { + if (!holder.created) { + notifyCreate(holder, type as AbsType) + } + notifyBind(holder, type as AbsType) + } + } + + override fun onBindViewHolder(holder: Holder, position: Int, payloads: List) { + if (isForDataBinding(payloads)) { + holder.binding.executePendingBindings() + } else { + super.onBindViewHolder(holder, position, payloads) + } + } + + override fun onViewRecycled(holder: Holder) { + val position = holder.adapterPosition + if (position != RecyclerView.NO_POSITION && position < list.size) { + val type = getType(position)!! + if (type is AbsType<*>) { + @Suppress("UNCHECKED_CAST") + notifyRecycle(holder, type as AbsType) + } + } + } + + override fun getItemId(position: Int): Long { + return if (hasStableIds()) { + val item = list[position] + if (item is StableId) { + item.stableId + } else { + throw IllegalStateException("${item.javaClass.simpleName} must implement StableId interface.") + } + } else { + super.getItemId(position) + } + } + + override fun getItemCount() = list.size + + override fun onAttachedToRecyclerView(rv: RecyclerView) { + if (recyclerView == null && list is ObservableList) { + list.addOnListChangedCallback(callback) + } + recyclerView = rv + inflater = LayoutInflater.from(rv.context) + } + + override fun onDetachedFromRecyclerView(rv: RecyclerView) { + if (recyclerView != null && list is ObservableList) { + list.removeOnListChangedCallback(callback) + } + recyclerView = null + } + + override fun getItemViewType(position: Int) = layoutHandler?.getItemLayout(list[position], position) + ?: typeHandler?.getItemType(list[position], position)?.layout + ?: getType(position)?.layout + ?: throw RuntimeException("Invalid object at position $position: ${list[position].javaClass}") + + private fun getType(position: Int) = typeHandler?.getItemType(list[position], position) + ?: map[list[position].javaClass] + + private fun getVariable(type: BaseType) = type.variable + ?: variable + ?: throw IllegalStateException("No variable specified for type ${type.javaClass.simpleName}") + + private fun isForDataBinding(payloads: List): Boolean { + if (payloads.isEmpty()) { + return false + } + payloads.forEach { + if (it != DATA_INVALIDATION) { + return false + } + } + return true + } + + private fun notifyCreate(holder: Holder, type: AbsType) { + when (type) { + is Type -> { + setClickListeners(holder, type) + type.onCreate?.invoke(holder) + } + is ItemType -> type.onCreate(holder) + } + holder.created = true + } + + private fun notifyBind(holder: Holder, type: AbsType) { + when (type) { + is Type -> type.onBind?.invoke(holder) + is ItemType -> type.onBind(holder) + } + } + + private fun notifyRecycle(holder: Holder, type: AbsType) { + when (type) { + is Type -> type.onRecycle?.invoke(holder) + is ItemType -> type.onRecycle(holder) + } + } + + private fun setClickListeners(holder: Holder, type: Type) { + val onClick = type.onClick + if (onClick != null) { + holder.itemView.setOnClickListener { + onClick(holder) + } + } + val onLongClick = type.onLongClick + if (onLongClick != null) { + holder.itemView.setOnLongClickListener { + onLongClick(holder) + true + } + } + } + +} diff --git a/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/ObservableListCallback.kt b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/ObservableListCallback.kt new file mode 100644 index 0000000..59078d6 --- /dev/null +++ b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/ObservableListCallback.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Miguel Ángel Moreno + * + * 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 com.github.nitrico.lastadapterx + +import androidx.databinding.ObservableList +import android.os.Looper +import androidx.recyclerview.widget.RecyclerView +import java.lang.ref.WeakReference + +class ObservableListCallback(adapter: RecyclerView.Adapter) + : ObservableList.OnListChangedCallback>() { + + private val reference = WeakReference>(adapter) + private val adapter: RecyclerView.Adapter? + get() { + if (Thread.currentThread() == Looper.getMainLooper().thread) return reference.get() + else throw IllegalStateException("You must modify the ObservableList on the main thread") + } + + override fun onChanged(list: ObservableList) { + adapter?.notifyDataSetChanged() + } + + override fun onItemRangeChanged(list: ObservableList, from: Int, count: Int) { + adapter?.notifyItemRangeChanged(from, count) + } + + override fun onItemRangeInserted(list: ObservableList, from: Int, count: Int) { + adapter?.notifyItemRangeInserted(from, count) + } + + override fun onItemRangeRemoved(list: ObservableList, from: Int, count: Int) { + adapter?.notifyItemRangeRemoved(from, count) + } + + override fun onItemRangeMoved(list: ObservableList, from: Int, to: Int, count: Int) { + adapter?.let { for (i in 0..count-1) it.notifyItemMoved(from+i, to+i) } + } + +} diff --git a/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Types.kt b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Types.kt new file mode 100644 index 0000000..8b70312 --- /dev/null +++ b/lastadapterx/src/main/java/com/github/nitrico/lastadapterx/Types.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Miguel Ángel Moreno + * + * 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 com.github.nitrico.lastadapterx + +import androidx.databinding.ViewDataBinding + +open class BaseType +@JvmOverloads constructor(open val layout: Int, open val variable: Int? = null) + +@Suppress("unused") +abstract class AbsType +@JvmOverloads constructor(layout: Int, variable: Int? = null) : BaseType(layout, variable) + +open class ItemType +@JvmOverloads constructor(layout: Int, variable: Int? = null) : AbsType(layout, variable) { + open fun onCreate(holder: Holder) { } + open fun onBind(holder: Holder) { } + open fun onRecycle(holder: Holder) { } +} + +open class Type +@JvmOverloads constructor(layout: Int, variable: Int? = null) : AbsType(layout, variable) { + internal var onCreate: Action? = null; private set + internal var onBind: Action? = null; private set + internal var onClick: Action? = null; private set + internal var onLongClick: Action? = null; private set + internal var onRecycle: Action? = null; private set + fun onCreate(action: Action?) = apply { onCreate = action } + fun onBind(action: Action?) = apply { onBind = action } + fun onClick(action: Action?) = apply { onClick = action } + fun onLongClick(action: Action?) = apply { onLongClick = action } + fun onRecycle(action: Action?) = apply { onRecycle = action } +} + +typealias Action = (Holder) -> Unit diff --git a/sample/.gitignore b/sample/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/sample/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sample/build.gradle b/sample/build.gradle new file mode 100644 index 0000000..4c1345f --- /dev/null +++ b/sample/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' +} + +android { + compileSdkVersion versions.sdkTarget + buildToolsVersion versions.buildTools + defaultConfig { + applicationId "com.github.nitrico.lastadapter_sample" + minSdkVersion versions.sdkMin + targetSdkVersion versions.sdkTarget + } + dataBinding.enabled true +} + +dependencies { + implementation "androidx.appcompat:appcompat:$versions.androidX" + implementation "androidx.cardview:cardview:$versions.androidX" + implementation "com.google.android.material:material:$versions.androidX" + implementation "androidx.recyclerview:recyclerview:$versions.androidX" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin" + implementation project(':lastadapterx') +} diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro new file mode 100644 index 0000000..5740c8d --- /dev/null +++ b/sample/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Android\SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml new file mode 100644 index 0000000..49f3333 --- /dev/null +++ b/sample/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Car.java b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Car.java new file mode 100644 index 0000000..7497e69 --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Car.java @@ -0,0 +1,28 @@ +package com.github.nitrico.lastadapter_sample.data; + +import com.github.nitrico.lastadapterx.StableId; + +public class Car implements StableId { + + private final Long serialNumber; + private final String model; + + public Car(Long serialNumber, String model) { + this.serialNumber = serialNumber; + this.model = model; + } + + public Long getSerialNumber() { + return serialNumber; + } + + public String getModel() { + return model; + } + + @Override + public long getStableId() { + return serialNumber; + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Data.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Data.kt new file mode 100644 index 0000000..6f1d7bb --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Data.kt @@ -0,0 +1,47 @@ +package com.github.nitrico.lastadapter_sample.data + +import androidx.databinding.ObservableArrayList + +object Data { + + val items = ObservableArrayList().apply { + add(Header("Header 1")) + add(Point(1, 1)) + add(Header("Header 2")) + add(Point(2, 1)) + add(Point(2, 2)) + add(Header("Header 3")) + add(Point(3, 1)) + add(Point(3, 2)) + add(Car(1899393, "911 Carrera")) + add(Point(3, 3)) + add(Header("Header 4")) + add(Point(4, 1)) + add(Point(4, 2)) + add(Point(4, 3)) + add(Person(99098, "Miguel Ángel", "Moreno")) + add(Point(4, 4)) + add(Header("Header 5")) + add(Point(5, 1)) + add(Point(5, 2)) + add(Point(5, 3)) + add(Point(5, 4)) + add(Point(5, 5)) + add(Header("Header 6")) + add(Point(6, 1)) + add(Point(6, 2)) + add(Point(6, 3)) + add(Point(6, 4)) + add(Point(6, 5)) + add(Point(6, 6)) + add(Header("Header 7")) + add(Point(7, 1)) + add(Point(7, 2)) + add(Point(7, 3)) + add(Point(7, 4)) + add(Point(7, 5)) + add(Point(7, 6)) + add(Point(7, 7)) + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Header.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Header.kt new file mode 100644 index 0000000..53d7186 --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Header.kt @@ -0,0 +1,17 @@ +package com.github.nitrico.lastadapter_sample.data + +import android.view.View +import android.widget.Toast + +class Header(val text: String) { + + fun onItemClick(v: View) { + Toast.makeText(v.context, "Click on Header $text", Toast.LENGTH_SHORT).show() + } + + fun onItemLongClick(v: View): Boolean { + Toast.makeText(v.context, "Long click on Header $text", Toast.LENGTH_SHORT).show() + return true + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Person.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Person.kt new file mode 100644 index 0000000..6360786 --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Person.kt @@ -0,0 +1,9 @@ +package com.github.nitrico.lastadapter_sample.data + +import com.github.nitrico.lastadapterx.StableId + +class Person(val id: Long, val name: String, val surname: String) : StableId { + + override val stableId = id + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Point.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Point.kt new file mode 100644 index 0000000..d3e089b --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/Point.kt @@ -0,0 +1,17 @@ +package com.github.nitrico.lastadapter_sample.data + +import android.view.View +import android.widget.Toast + +class Point(val x: Int, val y: Int) { + + fun onItemClick(v: View) { + Toast.makeText(v.context, "Click on Point ($x,$y)", Toast.LENGTH_SHORT).show() + } + + fun onItemLongClick(v: View): Boolean { + Toast.makeText(v.context, "Long click on Point ($x,$y)", Toast.LENGTH_SHORT).show() + return true + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/StableData.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/StableData.kt new file mode 100644 index 0000000..1cf3dae --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/data/StableData.kt @@ -0,0 +1,25 @@ +package com.github.nitrico.lastadapter_sample.data + +import androidx.databinding.ObservableArrayList + +object StableData { + + val items = ObservableArrayList().apply { + add(Car(1899393, "911 Carrera")) + add(Car(392840, "911 Carrera")) + add(Car(3928304, "911 Carrera")) + //add(Header("Header")) + add(Car(329, "911 Carrera")) + add(Car(95084, "911 Carrera")) + add(Car(466695, "911 Carrera")) + add(Car(908456, "911 Carrera")) + add(Car(49308, "911 Carrera")) + add(Person(10001, "Miguel Ángel", "Moreno")) + add(Person(10002, "Miguel Ángel", "Moreno")) + add(Person(10003, "Miguel Ángel", "Moreno")) + add(Person(10004, "Miguel Ángel", "Moreno")) + add(Person(10005, "Miguel Ángel", "Moreno")) + add(Person(10006, "Miguel Ángel", "Moreno")) + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/JavaListFragment.java b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/JavaListFragment.java new file mode 100644 index 0000000..be79a06 --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/JavaListFragment.java @@ -0,0 +1,209 @@ +package com.github.nitrico.lastadapter_sample.ui; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Toast; +import com.github.nitrico.lastadapterx.ItemType; +import com.github.nitrico.lastadapterx.LastAdapterX; +import com.github.nitrico.lastadapterx.LayoutHandler; +import com.github.nitrico.lastadapterx.BaseType; +import com.github.nitrico.lastadapterx.TypeHandler; +import com.github.nitrico.lastadapterx.Holder; +import com.github.nitrico.lastadapter_sample.BR; +import com.github.nitrico.lastadapter_sample.R; +import com.github.nitrico.lastadapter_sample.data.Car; +import com.github.nitrico.lastadapter_sample.data.Data; +import com.github.nitrico.lastadapter_sample.data.Header; +import com.github.nitrico.lastadapter_sample.data.Person; +import com.github.nitrico.lastadapter_sample.data.Point; +import com.github.nitrico.lastadapter_sample.data.StableData; +import com.github.nitrico.lastadapter_sample.databinding.ItemCarBinding; +import com.github.nitrico.lastadapter_sample.databinding.ItemHeaderBinding; +import com.github.nitrico.lastadapter_sample.databinding.ItemHeaderFirstBinding; +import com.github.nitrico.lastadapter_sample.databinding.ItemPersonBinding; +import com.github.nitrico.lastadapter_sample.databinding.ItemPointBinding; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; + +public class JavaListFragment extends ListFragment { + + public static final String TAG = JavaListFragment.class.getSimpleName(); + + private final ItemType typeHeaderFirst = new ItemType(R.layout.item_header_first) { + @Override + public void onCreate(@NotNull final Holder holder) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toast(getContext(), "Clicked " +holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }); + } + @Override + public void onBind(@NotNull Holder holder) { + Log.d(TAG, "Bound " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + @Override + public void onRecycle(@NotNull Holder holder) { + Log.d(TAG, "Recycled " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }; + + private final ItemType typeHeader = new ItemType(R.layout.item_header) { + @Override + public void onCreate(final @NotNull Holder holder) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toast(getContext(), "Clicked " +holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }); + } + @Override + public void onBind(@NotNull Holder holder) { + Log.d(TAG, "Bound " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + @Override + public void onRecycle(@NotNull Holder holder) { + Log.d(TAG, "Recycled " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }; + + private final ItemType typePoint = new ItemType(R.layout.item_point) { + @Override + public void onCreate(final @NotNull Holder holder) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toast(getContext(), "Clicked " +holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }); + } + @Override + public void onBind(@NotNull Holder holder) { + Log.d(TAG, "Bound " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + @Override + public void onRecycle(@NotNull Holder holder) { + Log.d(TAG, "Recycled " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }; + + private final ItemType typeCar = new ItemType(R.layout.item_car) { + @Override + public void onCreate(final @NotNull Holder holder) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toast(getContext(), "Clicked " +holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }); + } + @Override + public void onBind(@NotNull Holder holder) { + Log.d(TAG, "Bound " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + @Override + public void onRecycle(@NotNull Holder holder) { + Log.d(TAG, "Recycled " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }; + + private final ItemType typePerson = new ItemType(R.layout.item_person) { + @Override + public void onCreate(final @NotNull Holder holder) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toast(getContext(), "Clicked " +holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }); + } + @Override + public void onBind(@NotNull Holder holder) { + Log.d(TAG, "Bound " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + @Override + public void onRecycle(@NotNull Holder holder) { + Log.d(TAG, "Recycled " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }; + + + public JavaListFragment() { } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + List items = Data.INSTANCE.getItems(); + boolean stableIds = items == StableData.INSTANCE.getItems(); + + //setMapAdapter(items, stableIds); + //setMapAdapterWithListeners(items, stableIds); + //setLayoutHandlerAdapter(items, stableIds); + setTypeHandlerAdapter(items, stableIds); + } + + + private void setMapAdapter(List items, boolean stableIds) { + new LastAdapterX(items) + .map(Car.class, R.layout.item_car) + .map(Person.class, R.layout.item_person) + .map(Header.class, R.layout.item_header) + .map(Point.class, R.layout.item_point) + .into(list); + } + + private void setMapAdapterWithListeners(List items, boolean stableIds) { + new LastAdapterX(items, BR.item, stableIds) + .map(Car.class, typeCar) + .map(Person.class, typePerson) + .map(Point.class, new ItemType(R.layout.item_point) { + @Override + public void onBind(@NotNull Holder holder) { + Log.d(TAG, "Bound " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + @Override + public void onRecycle(@NotNull Holder holder) { + Log.d(TAG, "Recycled " + holder.getBinding().getItem() + " at #" + holder.getAdapterPosition()); + } + }) + .map(Header.class, typeHeader) + .into(list); + } + + private void setLayoutHandlerAdapter(List items, boolean stableIds) { + new LastAdapterX(items, BR.item, stableIds).handler(new LayoutHandler() { + @Override + public int getItemLayout(@NotNull Object item, int position) { + if (item instanceof Header) return position == 0 ? R.layout.item_header_first : R.layout.item_header; + else if (item instanceof Point) return R.layout.item_point; + else if (item instanceof Person) return R.layout.item_person; + else if (item instanceof Car) return R.layout.item_car; + else return -1; + } + }).into(list); + } + + private void setTypeHandlerAdapter(List items, boolean stableIds) { + new LastAdapterX(items, BR.item, stableIds).handler(new TypeHandler() { + @Override + public BaseType getItemType(@NotNull Object item, int position) { + if (item instanceof Header) return position == 0 ? typeHeaderFirst : typeHeader; + else if (item instanceof Point) return typePoint; + else if (item instanceof Person) return typePerson; + else if (item instanceof Car) return typeCar; + return null; + } + }).into(list); + } + + private static void toast(Context context, String text) { + Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/KotlinListFragment.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/KotlinListFragment.kt new file mode 100644 index 0000000..b7fe567 --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/KotlinListFragment.kt @@ -0,0 +1,118 @@ +package com.github.nitrico.lastadapter_sample.ui + +import android.content.Context +import android.os.Bundle +import android.widget.Toast +import com.github.nitrico.lastadapterx.LastAdapterX +import com.github.nitrico.lastadapterx.Type +import com.github.nitrico.lastadapter_sample.BR +import com.github.nitrico.lastadapter_sample.R +import com.github.nitrico.lastadapter_sample.data.* +import com.github.nitrico.lastadapter_sample.databinding.* + +class KotlinListFragment : ListFragment() { + + private val typeHeader = Type(R.layout.item_header) + .onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + .onRecycle { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + .onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + .onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + + private val typeHeaderFirst = Type(R.layout.item_header_first) + .onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + .onRecycle { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + .onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + .onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + + private val typePoint = Type(R.layout.item_point) + .onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + .onRecycle { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + .onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + .onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + + private val typeCar = Type(R.layout.item_car) + .onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + .onRecycle { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + .onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + .onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + + private val typePerson = Type(R.layout.item_person) + .onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + .onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + .onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + val items = Data.items + val stableIds = items == StableData.items + + //setMapAdapter(items, stableIds) + //setMapAdapterWithListeners(items, stableIds) + //setLayoutHandlerAdapter(items, stableIds) + setTypeHandlerAdapter(items, stableIds) + } + + private fun setMapAdapter(items: List, stableIds: Boolean) { + LastAdapterX(items, BR.item, stableIds) + .map(R.layout.item_person) + .map(R.layout.item_car) + .map
(R.layout.item_header) + .map(R.layout.item_point) + .into(list) + } + + private fun setMapAdapterWithListeners(items: List, stableIds: Boolean) { + list.adapter = LastAdapterX(items, BR.item, stableIds) + .map(R.layout.item_header) + .map(typePoint) + .map(Type(R.layout.item_car) + .onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + .onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + .onRecycle { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + .onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + .onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + ) + .map(R.layout.item_person) { + onCreate { println("Created ${it.binding.item} at #${it.adapterPosition}") } + onBind { println("Bound ${it.binding.item} at #${it.adapterPosition}") } + onRecycle { println("Recycled ${it.binding.item} at #${it.adapterPosition}") } + onClick { activity.toast("Clicked #${it.adapterPosition}: ${it.binding.item}") } + onLongClick { activity.toast("Long-clicked #${it.adapterPosition}: ${it.binding.item}") } + } + .into(list) + } + + private fun setLayoutHandlerAdapter(items: List, stableIds: Boolean) { + LastAdapterX(items, BR.item, stableIds).layout { item, position -> + when (item) { + is Header -> if (position == 0) R.layout.item_header_first else R.layout.item_header + is Person -> R.layout.item_person + is Point -> R.layout.item_point + is Car -> R.layout.item_car + else -> -1 + } + }.into(list) + } + + private fun setTypeHandlerAdapter(items: List, stableIds: Boolean) { + LastAdapterX(items, BR.item, stableIds).type { item, position -> + when (item) { + is Header -> if (position == 0) typeHeaderFirst else typeHeader + is Point -> typePoint + is Person -> typePerson + is Car -> typeCar + else -> null + } + }.into(list) + } + + private fun Context?.toast(text: String) = this?.let { Toast.makeText(it, text, Toast.LENGTH_SHORT).show() } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/ListFragment.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/ListFragment.kt new file mode 100644 index 0000000..9806fa2 --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/ListFragment.kt @@ -0,0 +1,30 @@ +package com.github.nitrico.lastadapter_sample.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.github.nitrico.lastadapter_sample.R + +open class ListFragment : Fragment() { + + protected lateinit var list: RecyclerView + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + list = view.findViewById(R.id.list) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + list.layoutManager = LinearLayoutManager(activity) + } + +} diff --git a/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/MainActivity.kt b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/MainActivity.kt new file mode 100644 index 0000000..40dbbfc --- /dev/null +++ b/sample/src/main/java/com/github/nitrico/lastadapter_sample/ui/MainActivity.kt @@ -0,0 +1,72 @@ +package com.github.nitrico.lastadapter_sample.ui + +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import androidx.viewpager.widget.ViewPager +import com.github.nitrico.lastadapter_sample.R +import com.github.nitrico.lastadapter_sample.data.Data +import com.github.nitrico.lastadapter_sample.data.Header +import com.google.android.material.tabs.TabLayout +import java.util.* + +class MainActivity : AppCompatActivity() { + + private val random = Random() + + private var randomPosition: Int = 0 + get() = random.nextInt(Data.items.size-1) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + val toolbar = findViewById(R.id.toolbar) + val pager = findViewById(R.id.pager) + val tabs = findViewById(R.id.tabs) + + setSupportActionBar(toolbar) + pager.adapter = ViewPagerAdapter(supportFragmentManager) + tabs.setupWithViewPager(pager) + } + + override fun onCreateOptionsMenu(menu: Menu) = consume { menuInflater.inflate(R.menu.main, menu) } + + override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { + R.id.addFirst -> consume { + Data.items.add(0, Header("New Header")) + } + R.id.addLast -> consume { + Data.items.add(Data.items.size, Header("New header")) + } + R.id.addRandom -> consume { + Data.items.add(randomPosition, Header("New Header")) + } + R.id.removeFirst -> consume { + if (Data.items.isNotEmpty()) Data.items.removeAt(0) + } + R.id.removeLast -> consume { + if (Data.items.isNotEmpty()) Data.items.removeAt(Data.items.size-1) + } + R.id.removeRandom -> consume { + if (Data.items.isNotEmpty()) Data.items.removeAt(randomPosition) + } + else -> super.onOptionsItemSelected(item) + } + + private fun consume(f: () -> Unit): Boolean { + f() + return true + } + + class ViewPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) { + override fun getCount() = 2 + override fun getItem(i: Int) = if (i == 0) KotlinListFragment() else JavaListFragment() + override fun getPageTitle(i: Int) = if (i == 0) "Kotlin" else "Java" + } + +} diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..caa8d95 --- /dev/null +++ b/sample/src/main/res/layout/activity_main.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/fragment_list.xml b/sample/src/main/res/layout/fragment_list.xml new file mode 100644 index 0000000..a15cbff --- /dev/null +++ b/sample/src/main/res/layout/fragment_list.xml @@ -0,0 +1,8 @@ + diff --git a/sample/src/main/res/layout/item_car.xml b/sample/src/main/res/layout/item_car.xml new file mode 100644 index 0000000..44dc787 --- /dev/null +++ b/sample/src/main/res/layout/item_car.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/item_header.xml b/sample/src/main/res/layout/item_header.xml new file mode 100644 index 0000000..2a1ce1d --- /dev/null +++ b/sample/src/main/res/layout/item_header.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/item_header_first.xml b/sample/src/main/res/layout/item_header_first.xml new file mode 100644 index 0000000..52e8462 --- /dev/null +++ b/sample/src/main/res/layout/item_header_first.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/item_person.xml b/sample/src/main/res/layout/item_person.xml new file mode 100644 index 0000000..e92d6ea --- /dev/null +++ b/sample/src/main/res/layout/item_person.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/item_point.xml b/sample/src/main/res/layout/item_point.xml new file mode 100644 index 0000000..9a13976 --- /dev/null +++ b/sample/src/main/res/layout/item_point.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + diff --git a/sample/src/main/res/menu/main.xml b/sample/src/main/res/menu/main.xml new file mode 100644 index 0000000..db068bf --- /dev/null +++ b/sample/src/main/res/menu/main.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/sample/src/main/res/mipmap-hdpi/ic_launcher.png b/sample/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/sample/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/sample/src/main/res/mipmap-mdpi/ic_launcher.png b/sample/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/sample/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/sample/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..aee44e1 Binary files /dev/null and b/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml new file mode 100644 index 0000000..b94b907 --- /dev/null +++ b/sample/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #607D8B + #455A64 + #FFC107 + + diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/sample/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml new file mode 100644 index 0000000..08fe223 --- /dev/null +++ b/sample/src/main/res/values/strings.xml @@ -0,0 +1,13 @@ + + + LastAdapter + + Add first + Add last + Add random + + Remove first + Remove last + Remove random + + diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml new file mode 100644 index 0000000..0eb88fe --- /dev/null +++ b/sample/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/settings.gradle b/settings.gradle index c79e0c5..678760c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':lastadapter' +include ':app', ':lastadapter', 'sample', 'lastadapterx'