diff --git a/.travis.yml b/.travis.yml index 799eeed..da6752b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: android -dist: trusty android: components: # Uncomment the lines below if you want to @@ -8,17 +7,15 @@ android: - platform-tools - extra-android-support - build-tools-29.0.2 - - build-tools-28.0.3 - android-29 - - android-28 + - sys-img-armeabi-v7a-android-18 licenses: - 'android-sdk-preview-license-52d11cd2' - 'android-sdk-license-.+' - 'google-gdk-license-.+' before_install: - - yes | sdkmanager "platforms;android-28" + - yes | sdkmanager "platforms;android-29" - yes | sdkmanager "build-tools;29.0.2" - - yes | sdkmanager "build-tools;28.0.3" jdk: - oraclejdk8 before_script: diff --git a/README.md b/README.md index 9aef572..85c9c2b 100644 --- a/README.md +++ b/README.md @@ -12,31 +12,31 @@ This library will make it easy and painless to map your data item with a target # Features ###### OnViewEventListener -* Smart OnClick / OnLongClickListener SimpleItemOnClickOnLongClickActivity -* State holding with OnItemSelectedListener MultipleViewTypesResolverActivity -* Custom View Events CustomViewEventActivity +* Smart OnClick / OnLongClickListener SimpleItemOnClickOnLongClickActivity +* State holding with OnItemSelectedListener MultipleViewTypesResolverActivity +* Custom View Events CustomViewEventActivity ###### ItemTouchHelper Swipe, Drag & Drop extensions -* Drag & drop DragAndDropItemActivity -* Drag & drop with handle DragAndDropHandleItemActivity -* Swipe to remove item SwipeRemoveItemActivity -* Drag & drop, Swipe, View Events MultipleEventsAndExtensionsActivity -* Grid + Drag & drop GridActivity +* Drag & drop DragAndDropItemActivity +* Drag & drop with handle DragAndDropHandleItemActivity +* Swipe to remove item SwipeRemoveItemActivity +* Drag & drop, Swipe, View Events MultipleEventsAndExtensionsActivity +* Grid + Drag & drop GridActivity ###### ViewTypeResolver -* Multiple ViewHolder types resolver MultipleViewTypesResolverActivity +* Multiple ViewHolder types resolver MultipleViewTypesResolverActivity ###### SmartStateHolder -* Multiple items select MultiSelectItemsActivity -* Single RadioButton select SingleSelectRadioButtonItemActivity -* Multiple CheckBox select MultiSelectCheckBoxItemsActivity -* Multiple Switch select MultiSelectSwitchItemsActivity -* Multiple Expandable items MultipleExpandableItemActivity -* Single Expandable item SingleExpandableItemActivity +* Multiple items select MultiSelectItemsActivity +* Single RadioButton select SingleSelectRadioButtonItemActivity +* Multiple CheckBox select MultiSelectCheckBoxItemsActivity +* Multiple Switch select MultiSelectSwitchItemsActivity +* Multiple Expandable items MultipleExpandableItemActivity +* Single Expandable item SingleExpandableItemActivity ###### Nested adapter -* Nested SmartRecyclerAdapter NestedSmartRecyclerAdaptersActivity +* Nested SmartRecyclerAdapter NestedSmartRecyclerAdaptersActivity ###### Pagination -* Endless scroll EndlessScrollActivity -* Endless scroll with load more button EndlessScrollLoadMoreButtonActivity +* Endless scroll EndlessScrollActivity +* Endless scroll with load more button EndlessScrollLoadMoreButtonActivity ###### DiffUtil -* Diff Util extension DiffUtilActivity +* Diff Util extension DiffUtilActivity #### Release overview @@ -48,7 +48,7 @@ This library will make it easy and painless to map your data item with a target Add `jcenter()` or `maven { url "https://dl.bintray.com/manneohlund/maven" }` to your `build.gradle` under `repositories` ```groovy dependencies { - implementation 'io.github.manneohlund:smart-recycler-adapter:4.0.0' + implementation 'io.github.manneohlund:smart-recycler-adapter:4.1.0' } ``` diff --git a/build.gradle b/build.gradle index 9ef6be0..49a1eb7 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,17 @@ ext { ARTIFACT_NAME = 'smart-recycler-adapter' - VERSION_CODE = 10 - VERSION_NAME = '4.0.0' + VERSION_CODE = 11 + VERSION_NAME = '4.1.0' TARGET_SDK_VERSION = 28 BUILD_TOOLS_VERSION = '29.0.2' MIN_SDK_VERSION = 14 + + appcompat_version = '1.1.0' + recyclerview_version = '1.1.0' + material_version = '1.2.0-alpha03' + constraintlayout_version = '1.1.3' + annotation_version = '1.1.0' } buildscript { diff --git a/sample/build.gradle b/sample/build.gradle index 0e701c0..4177010 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -36,11 +36,13 @@ android { shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release + resValue "string", "app_name", "SmartAdapter" } debug { applicationIdSuffix ".debug" debuggable true minifyEnabled false + resValue "string", "app_name", "Debug" } beta { initWith debug @@ -50,6 +52,7 @@ android { shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' matchingFallbacks = ['debug'] + resValue "string", "app_name", "Beta" } } @@ -81,17 +84,16 @@ dependencies { testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" testImplementation 'junit:junit:4.12' - implementation 'androidx.annotation:annotation:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'com.google.android.material:material:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'com.google.android.material:material:1.1.0-alpha09' + implementation "androidx.annotation:annotation:$annotation_version" + implementation "androidx.constraintlayout:constraintlayout:$constraintlayout_version" + implementation "androidx.appcompat:appcompat:$appcompat_version" + implementation "androidx.recyclerview:recyclerview:$recyclerview_version" + implementation "com.google.android.material:material:$material_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.github.bumptech.glide:glide:4.9.0' - //implementation 'io.github.manneohlund:smart-recycler-adapter:3.0.0' + //implementation 'io.github.manneohlund:smart-recycler-adapter:4.1.0' implementation project(':smartadapter') } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index e46ade2..ffadf6b 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -13,87 +13,67 @@ android:theme="@style/AppTheme"> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> - + android:theme="@style/AppTheme.NoActionBar" /> + android:name=".DemoActivity"> diff --git a/sample/src/main/java/smartrecycleradapter/DemoActivity.kt b/sample/src/main/java/smartrecycleradapter/DemoActivity.kt index 1e2605a..222d3d4 100644 --- a/sample/src/main/java/smartrecycleradapter/DemoActivity.kt +++ b/sample/src/main/java/smartrecycleradapter/DemoActivity.kt @@ -16,16 +16,63 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.recyclerview.widget.RecyclerView -import smartadapter.* +import smartadapter.Position +import smartadapter.SmartEndlessScrollRecyclerAdapter +import smartadapter.SmartRecyclerAdapter +import smartadapter.SmartViewHolderType +import smartadapter.ViewEventId +import smartadapter.ViewId import smartadapter.listener.OnItemClickListener import smartadapter.listener.onItemClickListener import smartadapter.listener.onViewEventListener import smartrecycleradapter.data.MovieDataItems import smartrecycleradapter.extension.PreCachingLinearLayoutManager -import smartrecycleradapter.feature.* -import smartrecycleradapter.models.* -import smartrecycleradapter.viewholder.* -import java.util.* +import smartrecycleradapter.feature.CustomViewEventActivity +import smartrecycleradapter.feature.DiffUtilActivity +import smartrecycleradapter.feature.DragAndDropHandleItemActivity +import smartrecycleradapter.feature.DragAndDropItemActivity +import smartrecycleradapter.feature.EndlessScrollActivity +import smartrecycleradapter.feature.EndlessScrollLoadMoreButtonActivity +import smartrecycleradapter.feature.GridActivity +import smartrecycleradapter.feature.MultiSelectCheckBoxItemsActivity +import smartrecycleradapter.feature.MultiSelectItemsActivity +import smartrecycleradapter.feature.MultiSelectSwitchItemsActivity +import smartrecycleradapter.feature.MultipleEventsAndExtensionsActivity +import smartrecycleradapter.feature.MultipleExpandableItemActivity +import smartrecycleradapter.feature.MultipleViewTypesResolverActivity +import smartrecycleradapter.feature.NestedSmartRecyclerAdaptersActivity +import smartrecycleradapter.feature.SimpleItemActivity +import smartrecycleradapter.feature.SimpleItemOnClickOnLongClickActivity +import smartrecycleradapter.feature.SingleExpandableItemActivity +import smartrecycleradapter.feature.SingleSelectRadioButtonItemActivity +import smartrecycleradapter.feature.SwipeRemoveItemActivity +import smartrecycleradapter.models.ActionMoviesModel +import smartrecycleradapter.models.AdventureMoviesModel +import smartrecycleradapter.models.AnimatedMoviesModel +import smartrecycleradapter.models.ComingSoonMoviesModel +import smartrecycleradapter.models.CopyrightModel +import smartrecycleradapter.models.MovieBannerModel +import smartrecycleradapter.models.MovieModel +import smartrecycleradapter.models.MoviePosterModel +import smartrecycleradapter.models.MyWatchListModel +import smartrecycleradapter.models.RecentlyPlayedMoviesModel +import smartrecycleradapter.models.SciFiMoviesModel +import smartrecycleradapter.viewholder.ActionMoviesViewHolder +import smartrecycleradapter.viewholder.AdventureMoviesViewHolder +import smartrecycleradapter.viewholder.AnimatedMoviesViewHolder +import smartrecycleradapter.viewholder.BannerViewHolder +import smartrecycleradapter.viewholder.ComingSoonMoviesViewHolder +import smartrecycleradapter.viewholder.CopyrightViewHolder +import smartrecycleradapter.viewholder.HeaderViewHolder +import smartrecycleradapter.viewholder.LargeThumbViewHolder +import smartrecycleradapter.viewholder.MyWatchListViewHolder +import smartrecycleradapter.viewholder.PosterViewHolder +import smartrecycleradapter.viewholder.RecentlyPlayedMoviesViewHolder +import smartrecycleradapter.viewholder.SampleFabViewHolder +import smartrecycleradapter.viewholder.SciFiMoviesViewHolder +import smartrecycleradapter.viewholder.SmallThumbViewHolder +import smartrecycleradapter.viewholder.ThumbViewHolder +import java.util.Locale import kotlin.reflect.KClass class DemoActivity : AppCompatActivity() { @@ -162,7 +209,7 @@ class DemoActivity : AppCompatActivity() { // Endless pagination mainSmartMovieAdapter.autoLoadMoreEnabled = false - mainSmartMovieAdapter.setOnLoadMoreListener { loadMoreViewHolder -> + mainSmartMovieAdapter.onLoadMoreListener = { loadMoreViewHolder -> val indexBeforeCopyright = 2 Handler().postDelayed({ mainSmartMovieAdapter.addItem( @@ -206,10 +253,10 @@ class DemoActivity : AppCompatActivity() { comingSoonSmartMovieAdapter.autoLoadMoreEnabled = true // Set custom load more view - comingSoonSmartMovieAdapter.setCustomLoadMoreLayoutResource(R.layout.custom_loadmore_view) + comingSoonSmartMovieAdapter.loadMoreLayoutResource = R.layout.custom_loadmore_view // Pagination ends after 3 loads - comingSoonSmartMovieAdapter.setOnLoadMoreListener { + comingSoonSmartMovieAdapter.onLoadMoreListener = { Handler().postDelayed({ comingSoonSmartMovieAdapter.addItems( comingSoonSmartMovieAdapter.itemCount - 1, diff --git a/sample/src/main/java/smartrecycleradapter/MovieCategoryDetailsActivity.kt b/sample/src/main/java/smartrecycleradapter/MovieCategoryDetailsActivity.kt index 48c6e93..c31b8fa 100644 --- a/sample/src/main/java/smartrecycleradapter/MovieCategoryDetailsActivity.kt +++ b/sample/src/main/java/smartrecycleradapter/MovieCategoryDetailsActivity.kt @@ -90,7 +90,7 @@ class MovieCategoryDetailsActivity : AppCompatActivity() { .into(recyclerView) endlessScrollAdapter.autoLoadMoreEnabled = true - endlessScrollAdapter.setOnLoadMoreListener { + endlessScrollAdapter.onLoadMoreListener = { if (!endlessScrollAdapter.isLoading) { endlessScrollAdapter.isLoading = true diff --git a/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollActivity.kt b/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollActivity.kt index b232b0a..d14c610 100644 --- a/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollActivity.kt +++ b/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollActivity.kt @@ -6,33 +6,53 @@ package smartrecycleradapter.feature */ import android.os.Bundle -import android.os.Handler import kotlinx.android.synthetic.main.activity_simple_item.* import smartadapter.SmartEndlessScrollRecyclerAdapter +import smartrecycleradapter.R import smartrecycleradapter.feature.simpleitem.SimpleItemViewHolder +import smartrecycleradapter.utils.runDelayed +import smartrecycleradapter.utils.showToast class EndlessScrollActivity : BaseSampleActivity() { + var itemCount = 50 + lateinit var smartAdapter: SmartEndlessScrollRecyclerAdapter + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportActionBar?.title = "Endless Scroll Sample" - var itemCount = 50 val items: MutableList = (0..itemCount).toMutableList() - val smartAdapter: SmartEndlessScrollRecyclerAdapter = SmartEndlessScrollRecyclerAdapter + smartAdapter = SmartEndlessScrollRecyclerAdapter .items(items) .map(Integer::class, SimpleItemViewHolder::class) .into(recyclerView) smartAdapter.autoLoadMoreEnabled = true - smartAdapter.setOnLoadMoreListener { - Handler().postDelayed({ - smartAdapter.addItems((itemCount + 1..itemCount + 50).toList()) - itemCount += 50 - }, 800) + smartAdapter.loadMoreLayoutResource = R.layout.custom_load_more_view + + smartAdapter.onLoadMoreListener = { + when { + itemCount < 100 -> addMoreStuff() + else -> disableScroll() + } + } + } + + private fun addMoreStuff() { + runDelayed { + smartAdapter.addItems((itemCount + 1..itemCount + 20).toList()) + itemCount += 20 + } + } + + private fun disableScroll() { + runDelayed { + smartAdapter.isEndlessScrollEnabled = false + showToast("No more items to load") } } } diff --git a/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollLoadMoreButtonActivity.kt b/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollLoadMoreButtonActivity.kt index 500001b..3b6264f 100644 --- a/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollLoadMoreButtonActivity.kt +++ b/sample/src/main/java/smartrecycleradapter/feature/EndlessScrollLoadMoreButtonActivity.kt @@ -6,10 +6,10 @@ package smartrecycleradapter.feature */ import android.os.Bundle -import android.os.Handler import kotlinx.android.synthetic.main.activity_simple_item.* import smartadapter.SmartEndlessScrollRecyclerAdapter import smartrecycleradapter.feature.simpleitem.SimpleItemViewHolder +import smartrecycleradapter.utils.runDelayed class EndlessScrollLoadMoreButtonActivity : BaseSampleActivity() { @@ -27,11 +27,12 @@ class EndlessScrollLoadMoreButtonActivity : BaseSampleActivity() { .into(recyclerView) smartAdapter.autoLoadMoreEnabled = false - smartAdapter.setOnLoadMoreListener { - Handler().postDelayed({ - smartAdapter.addItems((itemCount + 1..itemCount + 50).toList()) - itemCount += 50 - }, 800) + + smartAdapter.onLoadMoreListener = { + runDelayed { + smartAdapter.addItems((itemCount + 1..itemCount + 20).toList()) + itemCount += 20 + } } } } diff --git a/sample/src/main/java/smartrecycleradapter/feature/NestedSmartRecyclerAdaptersActivity.kt b/sample/src/main/java/smartrecycleradapter/feature/NestedSmartRecyclerAdaptersActivity.kt index b188a9f..89e6d20 100644 --- a/sample/src/main/java/smartrecycleradapter/feature/NestedSmartRecyclerAdaptersActivity.kt +++ b/sample/src/main/java/smartrecycleradapter/feature/NestedSmartRecyclerAdaptersActivity.kt @@ -13,9 +13,28 @@ import smartrecycleradapter.BuildConfig import smartrecycleradapter.DemoActivity.Companion.getActionName import smartrecycleradapter.R import smartrecycleradapter.data.MovieDataItems -import smartrecycleradapter.models.* -import smartrecycleradapter.viewholder.* -import java.util.* +import smartrecycleradapter.models.ActionMoviesModel +import smartrecycleradapter.models.AdventureMoviesModel +import smartrecycleradapter.models.AnimatedMoviesModel +import smartrecycleradapter.models.ComingSoonMoviesModel +import smartrecycleradapter.models.CopyrightModel +import smartrecycleradapter.models.MovieModel +import smartrecycleradapter.models.MoviePosterModel +import smartrecycleradapter.models.MyWatchListModel +import smartrecycleradapter.models.RecentlyPlayedMoviesModel +import smartrecycleradapter.models.SciFiMoviesModel +import smartrecycleradapter.viewholder.ActionMoviesViewHolder +import smartrecycleradapter.viewholder.AdventureMoviesViewHolder +import smartrecycleradapter.viewholder.AnimatedMoviesViewHolder +import smartrecycleradapter.viewholder.ComingSoonMoviesViewHolder +import smartrecycleradapter.viewholder.CopyrightViewHolder +import smartrecycleradapter.viewholder.LargeThumbViewHolder +import smartrecycleradapter.viewholder.MyWatchListViewHolder +import smartrecycleradapter.viewholder.PosterViewHolder +import smartrecycleradapter.viewholder.RecentlyPlayedMoviesViewHolder +import smartrecycleradapter.viewholder.SciFiMoviesViewHolder +import smartrecycleradapter.viewholder.ThumbViewHolder +import java.util.Locale /* * Created by Manne Öhlund on 2019-08-14. @@ -98,11 +117,13 @@ class NestedSmartRecyclerAdaptersActivity : BaseSampleActivity() { .addViewEventListener(onThumbnailClickListener) .create() + comingSoonSmartMovieAdapter.autoLoadMoreEnabled = true + // Set custom load more view - comingSoonSmartMovieAdapter.setCustomLoadMoreLayoutResource(R.layout.custom_loadmore_view) + comingSoonSmartMovieAdapter.loadMoreLayoutResource = R.layout.custom_loadmore_view // Pagination ends after 3 loads - comingSoonSmartMovieAdapter.setOnLoadMoreListener { + comingSoonSmartMovieAdapter.onLoadMoreListener = { Handler().postDelayed({ comingSoonSmartMovieAdapter.addItems( comingSoonSmartMovieAdapter.itemCount - 1, diff --git a/sample/src/main/java/smartrecycleradapter/utils/ActivityExt.kt b/sample/src/main/java/smartrecycleradapter/utils/ActivityExt.kt new file mode 100644 index 0000000..6a12937 --- /dev/null +++ b/sample/src/main/java/smartrecycleradapter/utils/ActivityExt.kt @@ -0,0 +1,15 @@ +package smartrecycleradapter.utils + +import android.os.Handler + + +/* + * Created by Manne Öhlund on 2019-12-12. + * Copyright (c) All rights reserved. + */ + + inline fun runDelayed(crossinline action: () -> Unit) { + Handler().postDelayed({ + action.invoke() + }, 800) + } \ No newline at end of file diff --git a/sample/src/main/java/smartrecycleradapter/utils/ContextExtension.kt b/sample/src/main/java/smartrecycleradapter/utils/ContextExtension.kt index ea774f4..5e8276f 100644 --- a/sample/src/main/java/smartrecycleradapter/utils/ContextExtension.kt +++ b/sample/src/main/java/smartrecycleradapter/utils/ContextExtension.kt @@ -1,6 +1,7 @@ package smartrecycleradapter.utils import android.content.Context +import android.widget.Toast /* * Created by Manne Öhlund on 2019-06-23. @@ -12,3 +13,6 @@ val Context.displayWidth: Int val Context.displayHeight: Int get() = resources.displayMetrics.heightPixels + +fun Context.showToast(message: String, duration: Int = Toast.LENGTH_LONG) = + Toast.makeText(this, message, duration).show() \ No newline at end of file diff --git a/sample/src/main/java/smartrecycleradapter/viewholder/NestedRecyclerViewHolder.kt b/sample/src/main/java/smartrecycleradapter/viewholder/NestedRecyclerViewHolder.kt index f67b3a9..514dbb8 100644 --- a/sample/src/main/java/smartrecycleradapter/viewholder/NestedRecyclerViewHolder.kt +++ b/sample/src/main/java/smartrecycleradapter/viewholder/NestedRecyclerViewHolder.kt @@ -13,7 +13,11 @@ import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager.HORIZONTAL import androidx.recyclerview.widget.RecyclerView -import smartadapter.* +import smartadapter.Position +import smartadapter.SmartRecyclerAdapter +import smartadapter.SmartViewHolderType +import smartadapter.ViewEventId +import smartadapter.ViewId import smartadapter.listener.OnItemClickListener import smartadapter.viewholder.SmartAdapterHolder import smartadapter.viewholder.SmartViewHolder @@ -35,6 +39,8 @@ open class NestedRecyclerViewHolder(parentView: ViewGroup) : field = value recyclerView.layoutManager = LinearLayoutManager(recyclerView.context, HORIZONTAL, false) recyclerView.adapter = value + recyclerView.isNestedScrollingEnabled = false + recyclerView.setHasFixedSize(true) } private val title: TextView = itemView.findViewById(R.id.title) diff --git a/sample/src/main/res/layout/custom_load_more_view.xml b/sample/src/main/res/layout/custom_load_more_view.xml new file mode 100644 index 0000000..7d6314d --- /dev/null +++ b/sample/src/main/res/layout/custom_load_more_view.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 4f6acdf..c063c51 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -1,4 +1,3 @@ - smart-recycler-adapter MovieCategoryDetails diff --git a/smartadapter/build.gradle b/smartadapter/build.gradle index 65f3e9a..754050c 100644 --- a/smartadapter/build.gradle +++ b/smartadapter/build.gradle @@ -65,8 +65,8 @@ dependencies { testImplementation 'org.mockito:mockito-core:2.28.2' testImplementation 'org.robolectric:robolectric:4.3' - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation "androidx.appcompat:appcompat:$appcompat_version" + implementation "androidx.recyclerview:recyclerview:$recyclerview_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" diff --git a/smartadapter/src/main/AndroidManifest.xml b/smartadapter/src/main/AndroidManifest.xml index e3d9945..0fe4769 100644 --- a/smartadapter/src/main/AndroidManifest.xml +++ b/smartadapter/src/main/AndroidManifest.xml @@ -1,9 +1 @@ - - - - - - - + \ No newline at end of file diff --git a/smartadapter/src/main/java/smartadapter/ISmartEndlessScrollRecyclerAdapter.kt b/smartadapter/src/main/java/smartadapter/ISmartEndlessScrollRecyclerAdapter.kt index fdecbaf..3b1f502 100644 --- a/smartadapter/src/main/java/smartadapter/ISmartEndlessScrollRecyclerAdapter.kt +++ b/smartadapter/src/main/java/smartadapter/ISmartEndlessScrollRecyclerAdapter.kt @@ -5,7 +5,6 @@ package smartadapter * Copyright (c) All rights reserved. */ -import androidx.annotation.LayoutRes import smartadapter.listener.OnLoadMoreListener /** @@ -24,12 +23,6 @@ interface ISmartEndlessScrollRecyclerAdapter { */ var isLoading: Boolean - /** - * Used to determine if loading view should show or not. - * If [.isEndlessScrollEnabled] returns true this returns 1. - */ - var endlessScrollOffset: Int - /** * Enables or disables the auto load more view. * @@ -39,15 +32,13 @@ interface ISmartEndlessScrollRecyclerAdapter { var autoLoadMoreEnabled: Boolean /** - * Setter for [OnLoadMoreListener] callback for listening on when the [SmartEndlessScrollRecyclerAdapter] + * [OnLoadMoreListener] callback for listening on when the [SmartEndlessScrollRecyclerAdapter] * is showing the [smartadapter.viewholder.LoadMoreViewHolder]. - * @param onLoadMoreListener load more callback */ - fun setOnLoadMoreListener(onLoadMoreListener: OnLoadMoreListener) + val onLoadMoreListener: OnLoadMoreListener? /** * Enables customization of the layout for the [smartadapter.viewholder.LoadMoreViewHolder]. - * @param loadMoreLayoutResource layout resource */ - fun setCustomLoadMoreLayoutResource(@LayoutRes loadMoreLayoutResource: Int) + val loadMoreLayoutResource: Int } diff --git a/smartadapter/src/main/java/smartadapter/SmartAdapterBuilder.kt b/smartadapter/src/main/java/smartadapter/SmartAdapterBuilder.kt index 7e8d924..7e9d1c4 100644 --- a/smartadapter/src/main/java/smartadapter/SmartAdapterBuilder.kt +++ b/smartadapter/src/main/java/smartadapter/SmartAdapterBuilder.kt @@ -8,12 +8,13 @@ package smartadapter import android.content.Context import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import smartadapter.internal.extension.name import smartadapter.internal.factory.SmartRecyclerAdapterExtensionFactory import smartadapter.internal.mapper.ViewEventMapper import smartadapter.listener.OnItemSelectedListener import smartadapter.listener.OnViewEventListener import smartadapter.widget.ViewTypeResolver -import java.util.* +import java.util.HashMap import kotlin.reflect.KClass /** @@ -28,7 +29,7 @@ class SmartAdapterBuilder internal constructor(private val smartRecyclerAdapter: private val smartRecyclerAdapterExtensionFactory = SmartRecyclerAdapterExtensionFactory() fun map(itemType: KClass<*>, viewHolderType: SmartViewHolderType): SmartAdapterBuilder { - viewHolderMapper[itemType.java.name] = viewHolderType + viewHolderMapper[itemType.name] = viewHolderType return this } diff --git a/smartadapter/src/main/java/smartadapter/SmartEndlessScrollRecyclerAdapter.kt b/smartadapter/src/main/java/smartadapter/SmartEndlessScrollRecyclerAdapter.kt index a085fd4..d2c5a11 100644 --- a/smartadapter/src/main/java/smartadapter/SmartEndlessScrollRecyclerAdapter.kt +++ b/smartadapter/src/main/java/smartadapter/SmartEndlessScrollRecyclerAdapter.kt @@ -5,7 +5,6 @@ package smartadapter * Copyright (c) All rights reserved. */ -import android.view.View import android.view.ViewGroup import androidx.annotation.LayoutRes import io.github.manneohlund.smartrecycleradapter.R @@ -22,16 +21,19 @@ class SmartEndlessScrollRecyclerAdapter(items: MutableList) : SmartRecycler private val VIEW_TYPE_LOADING = Integer.MAX_VALUE + private val endlessScrollOffset: Int + get() = if (isEndlessScrollEnabled) 1 else 0 + override var isEndlessScrollEnabled: Boolean = true - set(value) { - field = value + set(enable) { + field = enable smartNotifyItemChanged(itemCount) } override var isLoading: Boolean = false - override var endlessScrollOffset: Int = if (isEndlessScrollEnabled) 1 else 0 override var autoLoadMoreEnabled: Boolean = false - private var onLoadMoreListener: OnLoadMoreListener? = null - private var loadMoreLayoutResource = R.layout.load_more_view + override var onLoadMoreListener: OnLoadMoreListener? = null + @LayoutRes + override var loadMoreLayoutResource = R.layout.load_more_view override fun getItemViewType(position: Position): ViewType { return if (isEndlessScrollEnabled && position == itemCount - endlessScrollOffset) { @@ -59,25 +61,21 @@ class SmartEndlessScrollRecyclerAdapter(items: MutableList) : SmartRecycler super.onViewAttachedToWindow(holder) if (holder is LoadMoreViewHolder) { if (autoLoadMoreEnabled) { - onLoadMoreListener?.invoke(holder) + holder.itemView.post { + onLoadMoreListener?.invoke(holder) + } } else { holder.toggleLoading(false) - holder.itemView.findViewById(R.id.loadMoreButton).setOnClickListener { - onLoadMoreListener?.invoke(holder) - holder.toggleLoading(true) + holder.loadMoreButton?.setOnClickListener { + holder.itemView.post { + onLoadMoreListener?.invoke(holder) + holder.toggleLoading(true) + } } } } } - override fun setOnLoadMoreListener(onLoadMoreListener: OnLoadMoreListener) { - this.onLoadMoreListener = onLoadMoreListener - } - - override fun setCustomLoadMoreLayoutResource(@LayoutRes loadMoreLayoutResource: Int) { - this.loadMoreLayoutResource = loadMoreLayoutResource - } - companion object { /** diff --git a/smartadapter/src/main/java/smartadapter/internal/extension/KClassExt.kt b/smartadapter/src/main/java/smartadapter/internal/extension/KClassExt.kt new file mode 100644 index 0000000..d467e88 --- /dev/null +++ b/smartadapter/src/main/java/smartadapter/internal/extension/KClassExt.kt @@ -0,0 +1,12 @@ +package smartadapter.internal.extension + +import kotlin.reflect.KClass + + +/* + * Created by Manne Öhlund on 2020-01-08. + * Copyright (c) All rights reserved. + */ + + internal val KClass.name + get() = qualifiedName ?: java.name \ No newline at end of file diff --git a/smartadapter/src/main/java/smartadapter/internal/mapper/ViewHolderMapper.kt b/smartadapter/src/main/java/smartadapter/internal/mapper/ViewHolderMapper.kt index 077740e..09c9568 100644 --- a/smartadapter/src/main/java/smartadapter/internal/mapper/ViewHolderMapper.kt +++ b/smartadapter/src/main/java/smartadapter/internal/mapper/ViewHolderMapper.kt @@ -10,11 +10,12 @@ import android.view.ViewGroup import smartadapter.Position import smartadapter.SmartRecyclerAdapter import smartadapter.SmartViewHolderType +import smartadapter.internal.extension.name import smartadapter.internal.utils.ReflectionUtils import smartadapter.viewholder.SmartAdapterHolder import smartadapter.viewholder.SmartViewHolder import smartadapter.widget.ViewTypeResolver -import java.util.* +import java.util.HashMap import kotlin.reflect.KClass import kotlin.reflect.KFunction @@ -45,7 +46,7 @@ class ViewHolderMapper { fun getItemViewType(viewTypeResolver: ViewTypeResolver?, item: Any, position: Position): Int { smartViewHolderClass = viewTypeResolver?.invoke(item, position) if (smartViewHolderClass == null) { - smartViewHolderClass = dataTypeViewHolderMapper[item.javaClass.name] + smartViewHolderClass = dataTypeViewHolderMapper[item::class.name] } else { viewHolderConstructorMapper.add(smartViewHolderClass!!) } @@ -53,7 +54,7 @@ class ViewHolderMapper { return viewTypeMapper.put(smartViewHolderClass!!) } - throw RuntimeException(String.format("Fatal error! Mapping of ViewHolder to item '%s' does not exist", item.javaClass.name)) + throw RuntimeException(String.format("Fatal error! Mapping of ViewHolder to item '%s' does not exist", item::class.name)) } /** @@ -92,7 +93,7 @@ class ViewHolderMapper { } fun addMapping(itemType: KClass<*>, viewHolderType: SmartViewHolderType) { - dataTypeViewHolderMapper[itemType.java.name] = viewHolderType + dataTypeViewHolderMapper[itemType.name] = viewHolderType viewHolderConstructorMapper.add(viewHolderType) } @@ -106,8 +107,8 @@ class ViewHolderMapper { } } -fun SparseArray.put(value: E): Int { - val key = value.java.name.hashCode() +private fun SparseArray.put(value: E): Int { + val key = value.name.hashCode() put(key, value) return key } diff --git a/smartadapter/src/main/java/smartadapter/viewholder/LoadMoreViewHolder.kt b/smartadapter/src/main/java/smartadapter/viewholder/LoadMoreViewHolder.kt index 08b52af..2e3a66b 100644 --- a/smartadapter/src/main/java/smartadapter/viewholder/LoadMoreViewHolder.kt +++ b/smartadapter/src/main/java/smartadapter/viewholder/LoadMoreViewHolder.kt @@ -19,31 +19,32 @@ import io.github.manneohlund.smartrecycleradapter.R * Default implementation of load more view holder. */ class LoadMoreViewHolder( - parentView: View, @param:LayoutRes private val loadingViewRes: Int, + parentView: View, + @param:LayoutRes private val loadingViewRes: Int, isAutoLoadEnabled: Boolean ) : SmartViewHolder( - LayoutInflater.from(parentView.context).inflate( - loadingViewRes, - parentView as ViewGroup, - false - ) + LayoutInflater.from(parentView.context) + .inflate( + loadingViewRes, + parentView as ViewGroup, + false + ) ) { + val loadMoreButton: AppCompatButton? = itemView.findViewById(R.id.loadMoreButton) + val progressBar: ProgressBar? = itemView.findViewById(R.id.progressBar) + init { toggleLoading(isAutoLoadEnabled) } fun toggleLoading(isLoading: Boolean) { - if (loadingViewRes == R.layout.load_more_view) { - val loadMoreButton = itemView.findViewById(R.id.loadMoreButton) - val progressBar = itemView.findViewById(R.id.progressBar) - if (isLoading) { - progressBar.visibility = View.VISIBLE - loadMoreButton.visibility = View.GONE - } else { - progressBar.visibility = View.INVISIBLE - loadMoreButton.visibility = View.VISIBLE - } + if (isLoading) { + progressBar?.visibility = View.VISIBLE + loadMoreButton?.visibility = View.GONE + } else { + progressBar?.visibility = View.INVISIBLE + loadMoreButton?.visibility = View.VISIBLE } } diff --git a/smartadapter/src/main/res/values/strings.xml b/smartadapter/src/main/res/values/strings.xml index 9bc896f..740db04 100644 --- a/smartadapter/src/main/res/values/strings.xml +++ b/smartadapter/src/main/res/values/strings.xml @@ -1,5 +1,3 @@ - smart-recycler-adapter - Load more diff --git a/smartadapter/src/test/java/smartadapter/internal/ViewHolderMapperTest.kt b/smartadapter/src/test/java/smartadapter/internal/ViewHolderMapperTest.kt index 7fd8795..40c3fd3 100644 --- a/smartadapter/src/test/java/smartadapter/internal/ViewHolderMapperTest.kt +++ b/smartadapter/src/test/java/smartadapter/internal/ViewHolderMapperTest.kt @@ -12,8 +12,10 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.validateMockitoUsage import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +import smartadapter.internal.extension.name import smartadapter.internal.mapper.ViewHolderMapper import smartadapter.viewholder.SmartViewHolder +import smartadapter.viewholders.JavaTestViewHolder import smartadapter.widget.ViewTypeResolver /* @@ -30,6 +32,7 @@ class ViewHolderMapperTest { @Before fun setUp() { mapper = ViewHolderMapper() + mapper.addMapping(Float::class, JavaTestViewHolder::class) mapper.addMapping(String::class, TestViewHolder::class) mapper.addMapping(Int::class, TestViewHolder2::class) } @@ -65,17 +68,17 @@ class ViewHolderMapperTest { assertEquals(TestViewHolder3::class, mapper.createViewHolder>(mock(ViewGroup::class.java), id4)::class) assertEquals(TestViewHolder4::class, mapper.createViewHolder>(mock(ViewGroup::class.java), id5)::class) - assertEquals(TestViewHolder::class.java.name.hashCode(), id) - assertEquals(TestViewHolder::class.java.name.hashCode(), id2) - assertEquals(TestViewHolder2::class.java.name.hashCode(), id3) - assertEquals(TestViewHolder3::class.java.name.hashCode(), id4) - assertEquals(TestViewHolder4::class.java.name.hashCode(), id5) + assertEquals(TestViewHolder::class.name.hashCode(), id) + assertEquals(TestViewHolder::class.name.hashCode(), id2) + assertEquals(TestViewHolder2::class.name.hashCode(), id3) + assertEquals(TestViewHolder3::class.name.hashCode(), id4) + assertEquals(TestViewHolder4::class.name.hashCode(), id5) } @Test(expected = RuntimeException::class) fun getItemViewType_error() { // When - mapper.getItemViewType(null, 1.1f, 0) + mapper.getItemViewType(null, 1.1, 0) } @Test @@ -93,21 +96,34 @@ class ViewHolderMapperTest { val id3 = mapper.getItemViewType(viewTypeResolver, 2, 2) // Then - assertEquals(TestViewHolder::class.java.name.hashCode(), id) - assertEquals(TestViewHolder::class.java.name.hashCode(), id2) - assertEquals(TestViewHolder2::class.java.name.hashCode(), id3) + assertEquals(TestViewHolder::class.name.hashCode(), id) + assertEquals(TestViewHolder::class.name.hashCode(), id2) + assertEquals(TestViewHolder2::class.name.hashCode(), id3) } @Test fun createViewHolder() { // When mapper.getItemViewType(null, "Hello", 0) - val viewHolder = mapper.createViewHolder>(mock(RecyclerView::class.java), TestViewHolder::class.java.name.hashCode()) + val viewHolder = mapper.createViewHolder>(mock(RecyclerView::class.java), TestViewHolder::class.name.hashCode()) // Then assertTrue(viewHolder is TestViewHolder) } + @Test + fun createJavaViewHolder() { + // Given + mapper.addMapping(Float::class.java.kotlin, JavaTestViewHolder::class) + + // When + val viewType = mapper.getItemViewType(null, 3.3f, 0) + val viewHolder = mapper.createViewHolder>(mock(RecyclerView::class.java), viewType) + + // Then + assertTrue(viewHolder is JavaTestViewHolder) + } + inner class TestViewHolder(view: ViewGroup) : SmartViewHolder(view) { override fun bind(item: Any) { } } diff --git a/smartadapter/src/test/java/smartadapter/viewholders/JavaTestViewHolder.java b/smartadapter/src/test/java/smartadapter/viewholders/JavaTestViewHolder.java new file mode 100644 index 0000000..9cc5746 --- /dev/null +++ b/smartadapter/src/test/java/smartadapter/viewholders/JavaTestViewHolder.java @@ -0,0 +1,28 @@ +package smartadapter.viewholders; + +/* + * Created by Manne Öhlund on 2019-12-16. + * Copyright (c) All rights reserved. + */ + +import android.view.View; + +import org.jetbrains.annotations.NotNull; + +import smartadapter.viewholder.SmartViewHolder; + +public class JavaTestViewHolder extends SmartViewHolder { + + public JavaTestViewHolder(@NotNull View view) { + super(view); + } + + @Override + public void bind(@NotNull Object item) { + + } + + public static class Abc { + + } +}