From 49dcbe4768f10f5e606e5ea2874fbc70826d55f7 Mon Sep 17 00:00:00 2001 From: manneohlund Date: Tue, 14 Jan 2020 20:43:08 +0100 Subject: [PATCH 1/8] [ADD] Better support for java kotlin interop data types --- .../java/smartadapter/SmartAdapterBuilder.kt | 5 +-- .../internal/extension/KClassExt.kt | 12 +++++++ .../internal/mapper/ViewHolderMapper.kt | 13 +++---- .../internal/ViewHolderMapperTest.kt | 36 +++++++++++++------ .../viewholders/JavaTestViewHolder.java | 28 +++++++++++++++ 5 files changed, 76 insertions(+), 18 deletions(-) create mode 100644 smartadapter/src/main/java/smartadapter/internal/extension/KClassExt.kt create mode 100644 smartadapter/src/test/java/smartadapter/viewholders/JavaTestViewHolder.java 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/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/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 { + + } +} From db0a22cc65afa48e144f96a77b948717f484cdf5 Mon Sep 17 00:00:00 2001 From: manneohlund Date: Tue, 14 Jan 2020 21:06:44 +0100 Subject: [PATCH 2/8] [FIX] Load more crash due to adapter inconsistency or invalid state while scrolling. [FIX] View holder view null pointer exception. [REFACTOR] Setters to public properties. --- .../ISmartEndlessScrollRecyclerAdapter.kt | 15 ++------ .../SmartEndlessScrollRecyclerAdapter.kt | 34 +++++++++---------- .../viewholder/LoadMoreViewHolder.kt | 33 +++++++++--------- 3 files changed, 36 insertions(+), 46 deletions(-) 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/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/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 } } From a61f38361ceb032e2679c86f1be8ecbd155157fe Mon Sep 17 00:00:00 2001 From: manneohlund Date: Tue, 14 Jan 2020 21:12:35 +0100 Subject: [PATCH 3/8] [UPDATE] Sample load more --- .../java/smartrecycleradapter/DemoActivity.kt | 63 ++++++++++++++++--- .../MovieCategoryDetailsActivity.kt | 2 +- .../feature/EndlessScrollActivity.kt | 36 ++++++++--- .../EndlessScrollLoadMoreButtonActivity.kt | 13 ++-- .../NestedSmartRecyclerAdaptersActivity.kt | 31 +++++++-- .../smartrecycleradapter/utils/ActivityExt.kt | 15 +++++ .../utils/ContextExtension.kt | 4 ++ .../main/res/layout/custom_load_more_view.xml | 13 ++++ 8 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 sample/src/main/java/smartrecycleradapter/utils/ActivityExt.kt create mode 100644 sample/src/main/res/layout/custom_load_more_view.xml 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/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 From 765b49b098214134f87ebdcb139fa8be968316f8 Mon Sep 17 00:00:00 2001 From: manneohlund Date: Wed, 15 Jan 2020 12:52:37 +0100 Subject: [PATCH 4/8] [FIX] Build types app names. --- sample/build.gradle | 3 +++ sample/src/main/AndroidManifest.xml | 3 +-- sample/src/main/res/values/strings.xml | 1 - smartadapter/src/main/AndroidManifest.xml | 10 +--------- smartadapter/src/main/res/values/strings.xml | 2 -- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/sample/build.gradle b/sample/build.gradle index 0e701c0..e369c37 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" } } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index e46ade2..ca94416 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -92,8 +92,7 @@ android:label="@string/title_activity_movie_category_details" android:theme="@style/AppTheme.NoActionBar" /> + android:name=".DemoActivity"> 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/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/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 From db1304fc70739327ac47636b4ea2b4a8d97c7926 Mon Sep 17 00:00:00 2001 From: manneohlund Date: Wed, 15 Jan 2020 12:56:31 +0100 Subject: [PATCH 5/8] [FIX] Dependency structures. --- build.gradle | 6 ++++++ sample/build.gradle | 11 +++++------ smartadapter/build.gradle | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 9ef6be0..d6fc029 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,12 @@ ext { 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 e369c37..c7351d2 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -84,12 +84,11 @@ 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" 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" From 8096f62acf990dcbc300b159e170aaf62f576a36 Mon Sep 17 00:00:00 2001 From: manneohlund Date: Wed, 15 Jan 2020 13:02:44 +0100 Subject: [PATCH 6/8] [BUMP] v4.1.0 --- README.md | 40 ++++++++++++++++++++-------------------- build.gradle | 4 ++-- sample/build.gradle | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) 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 d6fc029..49a1eb7 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,8 @@ 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 diff --git a/sample/build.gradle b/sample/build.gradle index c7351d2..4177010 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -94,6 +94,6 @@ dependencies { 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') } From 8ae217707da6fae17de74b6b895eb6bf9dad3fee Mon Sep 17 00:00:00 2001 From: manneohlund Date: Sun, 19 Jan 2020 20:42:25 +0100 Subject: [PATCH 7/8] [UPDATE] Demo manifest, nested adapter scrolling. --- sample/src/main/AndroidManifest.xml | 57 +++++++------------ .../viewholder/NestedRecyclerViewHolder.kt | 8 ++- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ca94416..ffadf6b 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -13,80 +13,61 @@ 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" /> Date: Sun, 19 Jan 2020 21:38:41 +0100 Subject: [PATCH 8/8] [FIX] Travis --- .travis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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: