diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..d6325aeb3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +# Thanks to https://github.com/coil-kt/coil/blob/master/.github/workflows/ci.yml + +name: CI +on: + push: + branches: + - master + pull_request: +jobs: + ci: + name: Build + Test + runs-on: macOS-latest + steps: + - uses: actions/checkout@v2 + + # Ensure .gradle/caches is empty before writing to it. + # This helps us stay within Github's cache size limits. + - name: Clean Cache + run: rm -rf ~/.gradle/caches + + # Restore the cache. + # Intentionally don't set 'restore-keys' so the cache never contains redundant dependencies. + - uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: gradle-${{ runner.os }}-${{ hashFiles('**/build.gradle') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} }} + + - name: Build + run: ./gradlew clean build + + - name: Test + run: ./gradlew test + + - name: Detekt + run: ./gradlew detekt \ No newline at end of file diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml new file mode 100644 index 000000000..c354d4621 --- /dev/null +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -0,0 +1,10 @@ +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gradle/wrapper-validation-action@v1 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fdfb61dd6..000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: android -android: - components: - - tools - - platform-tools - - build-tools-29.0.2 - - android-29 - - sys-img-armeabi-v7a-android-18 -before_install: - - yes | sdkmanager "platforms;android-29" - - yes | sdkmanager "build-tools;29.0.2" -jdk: - - oraclejdk8 -script: - - ./gradlew clean test detekt -branches: - except: - - gh-pages -notifications: - email: false -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock -cache: - directories: - - $HOME/.m2 - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ diff --git a/MIGRATION.md b/MIGRATION.md index 493de11fe..ed7ac3e96 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,5 +1,27 @@ ### Upgrade Notes +#### v5.x.y + +v5 brings some general API cleanup which should make the usage easier. Removed generic type to simplify code. + +- Usages of the `FastAdapter.with()` method have been simplified + +```kotlin +// old +FastAdapter.with>(itemAdapter) +// v5 +FastAdapter.with(itemAdapter) +``` + +- Correct API specification for the bind method. (The payload for bindView should be immutable) + +```kotlin +// old +override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList) +// v5 +override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List) +``` + #### v4.x.y v4 is a huge release changing most of the codebase to Kotlin. This comes with many refactors, and as a result of that with many breaking API changes. diff --git a/README.md b/README.md index 01f642faa..8e16ef9ab 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,21 @@ -# FastAdapter [ ![Download](https://api.bintray.com/packages/mikepenz/maven/com.mikepenz%3Afastadapter/images/download.svg) ](https://bintray.com/mikepenz/maven/com.mikepenz%3Afastadapter/_latestVersion) +# FastAdapter [![Status](https://travis-ci.org/mikepenz/FastAdapter.svg?branch=develop)](https://travis-ci.org/mikepenz/FastAdapter) [![Download](https://api.bintray.com/packages/mikepenz/maven/com.mikepenz%3Afastadapter/images/download.svg)](https://bintray.com/mikepenz/maven/com.mikepenz%3Afastadapter/_latestVersion) -> The RecyclerView is one of the most used widgets in the Android world, and with it you have to implement an Adapter which provides the items for the view. Most use cases require the same base logic, but require you to write everything again and again. +The FastAdapter is here to simplify creating adapters for RecyclerViews. Don't worry about the adapter anymore. Just write the logic for how your view/item should look like, and you are done. +It's blazingly fast, minimizing the code you need to write, and is easy to extend. -The FastAdapter is here to simplify this process. You don't have to worry about the adapter anymore. Just write the logic for how your view/item should look like, and you are done. -This library has a fast and highly optimized core which provides core functionality, most apps require. It also prevents common mistakes by taking away those steps from the devs. -Beside being blazing fast, minimizing the code you need to write, it is also really easy to extend. Just provide another adapter implementation, hook into the adapter chain, custom select / deselection behaviors. Everything is possible. +------- -## A quick overview: +

+ What's included πŸš€ • + Setup πŸ› οΈ • + Migration Guide 🧬 • + Used by • + Sample App +

+ +------- + +### What's included πŸš€ - Core module 100% in Kotlin - Click / Long-Click listeners - Selection / Multi-Selection ([MultiselectSample](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt), [CheckBoxSample](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/CheckBoxSampleActivity.kt), [RadioButtonSample](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/RadioButtonSampleActivity.kt)) @@ -26,26 +35,24 @@ Beside being blazing fast, minimizing the code you need to write, it is also rea - Comes with useful Helpers - ActionModeHelper ([MultiselectSample](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt)) - UndoHelper ([MultiselectSample](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt)) - - More to come... - FastScroller (external lib) ([SimpleItemListSample](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/SimpleItemListActivity.kt)) - Paging (via Jetpack paging lib) ([PagedActivity](https://github.com/mikepenz/FastAdapter/blob/develop/app/src/main/java/com/mikepenz/fastadapter/app/PagedActivity.kt)) + - More to come... # Preview -## Demo -You can try it out here [Google Play](https://play.google.com/store/apps/details?id=com.mikepenz.fastadapter.app) (or download the latest release from GitHub) -## Screenshots +## Screenshots πŸŽ‰ ![Image](https://raw.githubusercontent.com/mikepenz/FastAdapter/develop/DEV/github/screenshots1.jpg) +# Setup -# Include in your project -## Latest releases +## Latest releases πŸ›  -- Kotlin | [v4.1.2](https://github.com/mikepenz/FastAdapter/tree/v4.1.2) +- Kotlin | [v5.2.4](https://github.com/mikepenz/FastAdapter/tree/v5.2.4) - Java && AndroidX | [v3.3.1](https://github.com/mikepenz/FastAdapter/tree/v3.3.1) - Java && AppCompat | [v3.2.9](https://github.com/mikepenz/FastAdapter/tree/v3.2.9) -## Using Maven +## Provide the gradle dependency The library is split up into core, commons, and extensions. The core functions are included in the following dependency. ```gradle @@ -57,31 +64,26 @@ implementation "androidx.recyclerview:recyclerview:${androidX}" Expandable support is included and can be added via this ```gradle implementation "com.mikepenz:fastadapter-extensions-expandable:${latestFastAdapterRelease}" -//The tiny Materialize library used for its useful helper classes -implementation "com.mikepenz:materialize:${latestVersion}" // at least 1.2.0 ``` Many helper classes are included in the following dependency. ```gradle +implementation "com.mikepenz:fastadapter-extensions-binding:${latestFastAdapterRelease}" // view binding helpers implementation "com.mikepenz:fastadapter-extensions-diff:${latestFastAdapterRelease}" // diff util helpers implementation "com.mikepenz:fastadapter-extensions-drag:${latestFastAdapterRelease}" // drag support implementation "com.mikepenz:fastadapter-extensions-paged:${latestFastAdapterRelease}" // paging support -implementation "com.mikepenz:fastadapter-extensions-scroll${latestFastAdapterRelease}" // scroll helpers +implementation "com.mikepenz:fastadapter-extensions-scroll:${latestFastAdapterRelease}" // scroll helpers implementation "com.mikepenz:fastadapter-extensions-swipe:${latestFastAdapterRelease}" // swipe support implementation "com.mikepenz:fastadapter-extensions-ui:${latestFastAdapterRelease}" // pre-defined ui components implementation "com.mikepenz:fastadapter-extensions-utils:${latestFastAdapterRelease}" // needs the `expandable`, `drag` and `scroll` extension. // required for the ui components and the utils implementation "com.google.android.material:material:${androidX}" -//The tiny Materialize library used for its useful helper classes -implementation "com.mikepenz:materialize:${latestVersion}" // at least 1.2.0 ``` -## v4.x.y -> Major release, migrates fully to Kotlin. Check out the changelog or the [MIGRATION GUIDE](https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md for more details - ## How to use -### 1. Implement your item (the easy way) +### 1. Implement your item +#### 1a. Implement your item as usual (the easy way) Just create a class which extends the `AbstractItem` as shown below. Implement the methods, and your item is ready. ```kotlin open class SimpleItem : AbstractItem() { @@ -92,7 +94,7 @@ open class SimpleItem : AbstractItem() { override val type: Int get() = R.id.fastadapter_sample_item_id - /** defines the layout which will be used for this item in the list */ + /** defines the layout which will be used for this item in the list */ override val layoutRes: Int get() = R.layout.sample_item @@ -104,7 +106,7 @@ open class SimpleItem : AbstractItem() { var name: TextView = view.findViewById(R.id.material_drawer_name) var description: TextView = view.findViewById(R.id.material_drawer_description) - override fun bindView(item: SimpleItem, payloads: MutableList) { + override fun bindView(item: SimpleItem, payloads: List) { name.text = item.name description.text = item.name } @@ -118,6 +120,26 @@ open class SimpleItem : AbstractItem() { ``` +#### 1b. Implement item with ViewBinding (the easiest way) + +```kotlin +class BindingIconItem : AbstractBindingItem() { + var name: String? = null + + override val type: Int + get() = R.id.fastadapter_icon_item_id + + override fun bindView(binding: IconItemBinding, payloads: List) { + binding.name.text = name + } + + override fun createBinding(inflater: LayoutInflater, parent: ViewGroup?): IconItemBinding { + return IconItemBinding.inflate(inflater, parent, false) + } +} +``` +Use the `binding` extension dependency in your application for this. + ### 2. Set the Adapter to the RecyclerView ```kotlin //create the ItemAdapter holding your Items @@ -226,7 +248,7 @@ override fun itemTouchOnMove(oldPosition: Int, newPosition: Int): Boolean { Start by initializing your adapters: ```kotlin -// Head is a model class for your header +// Header is a model class for your header val headerAdapter = ItemAdapter
() ``` @@ -295,9 +317,9 @@ open class SimpleSubExpandableItem : AbstractExpandableItem - + @@ -36,6 +34,9 @@ + diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/AdvancedSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/AdvancedSampleActivity.kt index ba0162e41..2f22a34cd 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/AdvancedSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/AdvancedSampleActivity.kt @@ -9,6 +9,7 @@ import androidx.appcompat.view.ActionMode import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.aboutlibraries.util.getThemeColor import com.mikepenz.fastadapter.* import com.mikepenz.fastadapter.adapters.GenericItemAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter @@ -20,8 +21,6 @@ import com.mikepenz.fastadapter.app.items.expandable.SimpleSubItem import com.mikepenz.fastadapter.expandable.getExpandableExtension import com.mikepenz.fastadapter.helpers.ActionModeHelper import com.mikepenz.fastadapter.select.getSelectExtension -import com.mikepenz.materialize.MaterializeBuilder -import com.mikepenz.materialize.util.UIUtils import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -41,7 +40,6 @@ class AdvancedSampleActivity : AppCompatActivity() { private var mActionModeHelper: ActionModeHelper? = null override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -49,9 +47,6 @@ class AdvancedSampleActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_advanced) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our adapters mHeaderAdapter = items() mItemAdapter = items() @@ -87,7 +82,7 @@ class AdvancedSampleActivity : AppCompatActivity() { val actionMode = mActionModeHelper?.onLongClick(this@AdvancedSampleActivity, position) if (actionMode != null) { //we want color our CAB - findViewById(R.id.action_mode_bar).setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(this@AdvancedSampleActivity, R.attr.colorPrimary, R.color.material_drawer_primary)) + findViewById(R.id.action_mode_bar).setBackgroundColor(this@AdvancedSampleActivity.getThemeColor(R.attr.colorPrimary, R.color.colorPrimary)) } //if we have no actionMode we do not consume the event actionMode != null diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/CheckBoxSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/CheckBoxSampleActivity.kt index cc70350a6..5c025ee67 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/CheckBoxSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/CheckBoxSampleActivity.kt @@ -12,7 +12,6 @@ import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.app.items.CheckBoxSampleItem import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension -import com.mikepenz.materialize.MaterializeBuilder import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -23,16 +22,12 @@ class CheckBoxSampleActivity : AppCompatActivity() { private lateinit var selectExtension: SelectExtension override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() selectExtension = fastItemAdapter.getSelectExtension() diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/DiffUtilActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/DiffUtilActivity.kt index 397cf48cc..9bc60e596 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/DiffUtilActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/DiffUtilActivity.kt @@ -4,25 +4,22 @@ import android.graphics.Color import android.os.Bundle import android.view.Menu import android.view.MenuItem -import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.app.items.SimpleItem import com.mikepenz.fastadapter.diff.FastAdapterDiffUtil -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt import com.mikepenz.itemanimators.AlphaInAnimator -import com.mikepenz.materialize.MaterializeBuilder import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.activity_sample.* -import java.util.* /** * Created by Aleksander Mielczarek on 07.08.2017. @@ -35,7 +32,6 @@ class DiffUtilActivity : AppCompatActivity() { private val disposables = CompositeDisposable() override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -43,9 +39,6 @@ class DiffUtilActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_diff_util) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() @@ -75,8 +68,8 @@ class DiffUtilActivity : AppCompatActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.refresh, menu) - menu.findItem(R.id.item_refresh).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_refresh).color(IconicsColor.colorInt(Color.BLACK)).actionBar() - menu.findItem(R.id.item_refresh_async).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_refresh_sync).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.item_refresh).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_refresh).apply { colorInt = Color.BLACK; actionBar() } + menu.findItem(R.id.item_refresh_async).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_refresh_sync).apply { colorInt = Color.BLACK; actionBar() } return true } @@ -113,24 +106,16 @@ class DiffUtilActivity : AppCompatActivity() { private fun setDataAsync() { disposables.add(Single.fromCallable { createData() } - .map { simpleItems -> FastAdapterDiffUtil.calculateDiff(fastItemAdapter.itemAdapter, simpleItems) }.subscribeOn(Schedulers.io()) + .map { simpleItems -> FastAdapterDiffUtil.calculateDiff(fastItemAdapter.itemAdapter, simpleItems) }.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { result -> FastAdapterDiffUtil[fastItemAdapter.itemAdapter] = result }) } private fun createData(): List { - val items = Arrays.asList( - SimpleItem().withName("Item 1").withIdentifier(1), - SimpleItem().withName("Item 2").withIdentifier(2), - SimpleItem().withName("Item 3").withIdentifier(3), - SimpleItem().withName("Item 4").withIdentifier(4), - SimpleItem().withName("Item 5").withIdentifier(5), - SimpleItem().withName("Item 6").withIdentifier(6), - SimpleItem().withName("Item 7").withIdentifier(7), - SimpleItem().withName("Item 8").withIdentifier(8), - SimpleItem().withName("Item 9").withIdentifier(9), - SimpleItem().withName("Item 10").withIdentifier(10) - ) + val items = mutableListOf() + repeat(100) { + items.add(SimpleItem().withName("Item ${it + 1}").withIdentifier((it + 1).toLong())) + } items.shuffle() return items } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/EndlessScrollListActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/EndlessScrollListActivity.kt index f4b559296..31dd4d11b 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/EndlessScrollListActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/EndlessScrollListActivity.kt @@ -6,7 +6,6 @@ import android.os.Handler import android.text.TextUtils import android.view.Menu import android.view.MenuItem -import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView @@ -26,13 +25,14 @@ import com.mikepenz.fastadapter.scroll.EndlessRecyclerOnScrollListener import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.fastadapter.ui.items.ProgressItem import com.mikepenz.fastadapter.utils.DragDropUtil -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic -import com.mikepenz.materialize.MaterializeBuilder +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt import kotlinx.android.synthetic.main.activity_sample.* import java.util.* + class EndlessScrollListActivity : AppCompatActivity(), ItemTouchCallback, ItemFilterListener { //save our FastAdapter @@ -47,16 +47,12 @@ class EndlessScrollListActivity : AppCompatActivity(), ItemTouchCallback, ItemFi lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() val selectExtension = fastItemAdapter.getSelectExtension() @@ -78,7 +74,7 @@ class EndlessScrollListActivity : AppCompatActivity(), ItemTouchCallback, ItemFi fastItemAdapter.itemFilter.filterPredicate = { item: GenericItem, constraint: CharSequence? -> if (item is SimpleItem) { //return true if we should filter it out - item.name?.text.toString().contains(constraint.toString(), ignoreCase = true) + item.name?.textString.toString().contains(constraint.toString(), ignoreCase = true) } else { //return false to keep it false @@ -154,7 +150,7 @@ class EndlessScrollListActivity : AppCompatActivity(), ItemTouchCallback, ItemFi inflater.inflate(R.menu.search, menu) //search icon - menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).apply { colorInt = Color.BLACK; actionBar() } val searchView = menu.findItem(R.id.search).actionView as SearchView searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { @@ -183,6 +179,7 @@ class EndlessScrollListActivity : AppCompatActivity(), ItemTouchCallback, ItemFi override fun itemTouchDropped(oldPosition: Int, newPosition: Int) { // save the new item order, i.e. in your database + // remove visual highlight to dropped item } override fun itemsFiltered(constraint: CharSequence?, results: List?) { diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableMultiselectDeleteSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableMultiselectDeleteSampleActivity.kt index 7aa698e05..80e2ad323 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableMultiselectDeleteSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableMultiselectDeleteSampleActivity.kt @@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode import androidx.recyclerview.widget.LinearLayoutManager import com.michaelflisar.dragselectrecyclerview.DragSelectTouchListener +import com.mikepenz.aboutlibraries.util.getThemeColor import com.mikepenz.fastadapter.* import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.adapters.GenericFastItemAdapter @@ -22,8 +23,6 @@ import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.fastadapter.utils.SubItemUtil import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialize.MaterializeBuilder -import com.mikepenz.materialize.util.UIUtils import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -37,16 +36,12 @@ class ExpandableMultiselectDeleteSampleActivity : AppCompatActivity() { private var mActionModeHelper: ActionModeHelper? = null override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_collapsible) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter fastItemAdapter = FastItemAdapter() mExpandableExtension = fastItemAdapter.getExpandableExtension() @@ -79,7 +74,7 @@ class ExpandableMultiselectDeleteSampleActivity : AppCompatActivity() { mRangeSelectorHelper.onLongClick(position) if (actionMode != null) { //we want color our CAB - this@ExpandableMultiselectDeleteSampleActivity.findViewById(R.id.action_mode_bar).setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(this@ExpandableMultiselectDeleteSampleActivity, R.attr.colorPrimary, R.color.material_drawer_primary)) + this@ExpandableMultiselectDeleteSampleActivity.findViewById(R.id.action_mode_bar).setBackgroundColor(this@ExpandableMultiselectDeleteSampleActivity.getThemeColor(R.attr.colorPrimary, R.color.colorPrimary)) // start the drag selection mDragSelectTouchListener.startDragSelection(position) diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableSampleActivity.kt index 579f6614d..677effaf4 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/ExpandableSampleActivity.kt @@ -2,7 +2,6 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.view.MenuItem -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import com.mikepenz.fastadapter.GenericItem @@ -13,7 +12,6 @@ import com.mikepenz.fastadapter.app.items.expandable.SimpleSubItem import com.mikepenz.fastadapter.expandable.getExpandableExtension import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialize.MaterializeBuilder import kotlinx.android.synthetic.main.activity_sample.* import java.util.* import java.util.concurrent.atomic.AtomicLong @@ -23,7 +21,6 @@ class ExpandableSampleActivity : AppCompatActivity() { private lateinit var fastItemAdapter: GenericFastItemAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -31,9 +28,6 @@ class ExpandableSampleActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_collapsible) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter fastItemAdapter = FastItemAdapter() @@ -47,6 +41,8 @@ class ExpandableSampleActivity : AppCompatActivity() { rv.itemAnimator = SlideDownAlphaAnimator() rv.adapter = fastItemAdapter + var itemToBeExpanded: SimpleSubExpandableItem? = null + //fill with some sample data val items = ArrayList() val identifier = AtomicLong(1) @@ -80,6 +76,11 @@ class ExpandableSampleActivity : AppCompatActivity() { val subSubSubItem = SimpleSubExpandableItem() subSubSubItem.withName("---- SubSubSubTest $iiii").identifier = identifier.getAndIncrement() subSubSubItems.add(subSubSubItem) + + //save 7th item just to demonstrate how expandAllOnPath works + if (identifier.get() == 7L) { + itemToBeExpanded = subSubSubItem + } } subSubItem.subItems.addAll(subSubSubItems) subSubItems.add(subSubItem) @@ -98,6 +99,9 @@ class ExpandableSampleActivity : AppCompatActivity() { //set the back arrow in the toolbar supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(false) + + //expand the whole path for the previously selected item + fastItemAdapter.getExpandableExtension().expandAllOnPath(itemToBeExpanded) } override fun onSaveInstanceState(_outState: Bundle) { diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/IconGridActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/IconGridActivity.kt index 2cc874c39..05ca2d532 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/IconGridActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/IconGridActivity.kt @@ -2,17 +2,15 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.view.MenuItem -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.adapters.GenericFastItemAdapter -import com.mikepenz.fastadapter.app.items.IconItem +import com.mikepenz.fastadapter.app.binding.BindingIconItem import com.mikepenz.fastadapter.app.items.expandable.SimpleSubExpandableItem import com.mikepenz.fastadapter.expandable.getExpandableExtension import com.mikepenz.iconics.Iconics import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialize.MaterializeBuilder import kotlinx.android.synthetic.main.activity_sample.* import java.util.ArrayList import kotlin.Comparator @@ -22,8 +20,6 @@ class IconGridActivity : AppCompatActivity() { private lateinit var fastItemAdapter: GenericFastItemAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -31,9 +27,6 @@ class IconGridActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_icon_grid) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() @@ -67,9 +60,9 @@ class IconGridActivity : AppCompatActivity() { val expandableItem = SimpleSubExpandableItem() expandableItem.withName(font.fontName).identifier = count.toLong() - val icons = ArrayList() + val icons = ArrayList() for (icon in font.icons) { - val iconItem = IconItem() + val iconItem = BindingIconItem() iconItem.withIcon(font.getIcon(icon)) icons.add(iconItem) } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/ImageListActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/ImageListActivity.kt index 6a3b0c6a8..c7be30995 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/ImageListActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/ImageListActivity.kt @@ -12,7 +12,6 @@ import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.app.dummy.ImageDummyData import com.mikepenz.fastadapter.app.items.ImageItem -import com.mikepenz.materialize.MaterializeBuilder import kotlinx.android.synthetic.main.activity_sample.* class ImageListActivity : AppCompatActivity() { @@ -20,7 +19,6 @@ class ImageListActivity : AppCompatActivity() { private lateinit var fastItemAdapter: FastItemAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -28,9 +26,6 @@ class ImageListActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_image_list) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/ModelItemActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/ModelItemActivity.kt index 08db80329..628b0d785 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/ModelItemActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/ModelItemActivity.kt @@ -14,11 +14,9 @@ import com.mikepenz.fastadapter.app.model.ModelIconItem import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.iconics.Iconics import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialize.MaterializeBuilder import com.turingtechnologies.materialscrollbar.CustomIndicator import com.turingtechnologies.materialscrollbar.DragScrollBar -import kotlinx.android.synthetic.main.activity_sample.rv -import kotlinx.android.synthetic.main.activity_sample.toolbar +import kotlinx.android.synthetic.main.activity_sample.* import java.util.ArrayList import kotlin.Comparator @@ -27,7 +25,6 @@ class ModelItemActivity : AppCompatActivity() { private lateinit var fastAdapter: FastAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -35,9 +32,6 @@ class ModelItemActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_model_item) - //style our ui - MaterializeBuilder().withActivity(this).build() - //adapters val fastScrollIndicatorAdapter = FastScrollIndicatorAdapter() val itemAdapter = ModelAdapter { model: IconModel -> diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/MopubAdsActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/MopubAdsActivity.kt index 9d6a5b803..c5e504172 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/MopubAdsActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/MopubAdsActivity.kt @@ -2,7 +2,6 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.view.MenuItem -import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager @@ -19,10 +18,9 @@ class MopubAdsActivity : AppCompatActivity() { private lateinit var adapter: MopubFastItemAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(R.layout.activity_sample) ButterKnife.bind(this) diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/MultiTypeModelItemActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/MultiTypeModelItemActivity.kt index 5fae6bf86..fac587580 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/MultiTypeModelItemActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/MultiTypeModelItemActivity.kt @@ -2,7 +2,6 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.view.MenuItem -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager import com.mikepenz.fastadapter.FastAdapter @@ -15,7 +14,6 @@ import com.mikepenz.fastadapter.app.model.RightModelIconItem import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.iconics.Iconics import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialize.MaterializeBuilder import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -24,7 +22,6 @@ class MultiTypeModelItemActivity : AppCompatActivity() { private lateinit var fastAdapter: GenericFastAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -32,9 +29,6 @@ class MultiTypeModelItemActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_multi_model_item) - //style our ui - MaterializeBuilder().withActivity(this).build() - //if you need multiple items for different models you can also do this be defining a Function which get's the model object and returns the item (extends IItem) val itemAdapter = ModelAdapter { element: IconModel -> if (element is RightIconModel) { diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt index 89b72644b..fe24dd6af 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/MultiselectSampleActivity.kt @@ -11,6 +11,7 @@ import androidx.appcompat.view.ActionMode import androidx.appcompat.widget.Toolbar import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar +import com.mikepenz.aboutlibraries.util.getThemeColor import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.ISelectionListener @@ -21,8 +22,6 @@ import com.mikepenz.fastadapter.helpers.UndoHelper import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialize.MaterializeBuilder -import com.mikepenz.materialize.util.UIUtils import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -34,7 +33,6 @@ class MultiselectSampleActivity : AppCompatActivity() { private lateinit var selectExtension: SelectExtension override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -43,9 +41,6 @@ class MultiselectSampleActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_multi_select) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our adapters val headerAdapter = ItemAdapter() val itemAdapter = ItemAdapter() @@ -85,7 +80,7 @@ class MultiselectSampleActivity : AppCompatActivity() { val actionMode = mActionModeHelper.onLongClick(this@MultiselectSampleActivity, position) if (actionMode != null) { //we want color our CAB - findViewById(R.id.action_mode_bar).setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(this@MultiselectSampleActivity, R.attr.colorPrimary, R.color.material_drawer_primary)) + findViewById(R.id.action_mode_bar).setBackgroundColor(this@MultiselectSampleActivity.getThemeColor(R.attr.colorPrimary, R.color.colorPrimary)) } //if we have no actionMode we do not consume the event actionMode != null diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/PagedActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/PagedActivity.kt index 07cc8349e..601fb41f4 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/PagedActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/PagedActivity.kt @@ -2,7 +2,6 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.os.Handler -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders @@ -27,11 +26,10 @@ class PagedActivity : AppCompatActivity() { private lateinit var mItemAdapter: PagedModelAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR //create the activity super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) @@ -63,8 +61,6 @@ class PagedActivity : AppCompatActivity() { val selectExtension = mFastAdapter.getSelectExtension() selectExtension.isSelectable = true - mFastAdapter.registerTypeInstance(SimpleImageItem()) - //configure our fastAdapter //rv.setLayoutManager(new GridLayoutManager(this, 3)); rv.layoutManager = LinearLayoutManager(this) diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/RadioButtonSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/RadioButtonSampleActivity.kt index 895c61402..ec4be5f54 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/RadioButtonSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/RadioButtonSampleActivity.kt @@ -12,7 +12,6 @@ import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.app.items.RadioButtonSampleItem import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension -import com.mikepenz.materialize.MaterializeBuilder import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -23,16 +22,12 @@ class RadioButtonSampleActivity : AppCompatActivity() { private lateinit var selectExtension: SelectExtension override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() selectExtension = fastItemAdapter.getSelectExtension() diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/RealmActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/RealmActivity.kt index a8a70d0d5..604edad03 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/RealmActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/RealmActivity.kt @@ -11,11 +11,11 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.fastadapter.app.items.RealmSampleUserItem -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt import com.mikepenz.itemanimators.AlphaInAnimator -import com.mikepenz.materialize.MaterializeBuilder import io.realm.Realm import io.realm.RealmChangeListener import io.realm.RealmResults @@ -29,17 +29,13 @@ class RealmActivity : AppCompatActivity() { private lateinit var mRealm: Realm override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_realm_list) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything mFastItemAdapter = FastItemAdapter() @@ -94,7 +90,7 @@ class RealmActivity : AppCompatActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.menu_add, menu) - menu.findItem(R.id.item_add).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_plus_square).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.item_add).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_plus_square).apply { colorInt = Color.BLACK; actionBar() } return true } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/SampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/SampleActivity.kt index afacca6c1..2a5a10739 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/SampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/SampleActivity.kt @@ -1,16 +1,17 @@ package com.mikepenz.fastadapter.app import android.content.Intent +import android.content.res.Configuration import android.graphics.Color import android.os.Bundle import android.os.Handler import android.view.Menu import android.view.MenuItem -import android.view.View +import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import com.mikepenz.aboutlibraries.Libs +import androidx.recyclerview.widget.RecyclerView import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter @@ -18,112 +19,117 @@ import com.mikepenz.fastadapter.app.dummy.ImageDummyData import com.mikepenz.fastadapter.app.items.SimpleImageItem import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt import com.mikepenz.itemanimators.SlideDownAlphaAnimator -import com.mikepenz.materialdrawer.Drawer -import com.mikepenz.materialdrawer.DrawerBuilder +import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.DividerDrawerItem import com.mikepenz.materialdrawer.model.PrimaryDrawerItem -import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem +import com.mikepenz.materialdrawer.model.interfaces.withDescription +import com.mikepenz.materialdrawer.model.interfaces.withIdentifier +import com.mikepenz.materialdrawer.model.interfaces.withName +import com.mikepenz.materialdrawer.model.interfaces.withSelectable +import com.mikepenz.materialdrawer.util.addItems import kotlinx.android.synthetic.main.activity_main.* class SampleActivity : AppCompatActivity() { - //save our header or result - private lateinit var mResult: Drawer + private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle + //save our FastAdapter private lateinit var mFastAdapter: FastAdapter + //save our FastAdapter private lateinit var mItemAdapter: ItemAdapter + //our `SelectExtension` private lateinit var selectExtension: SelectExtension + @Suppress("deprecation") override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - //create the activity super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Handle Toolbar setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setHomeButtonEnabled(true) supportActionBar?.title = "" + actionBarDrawerToggle = ActionBarDrawerToggle(this, root, toolbar, R.string.material_drawer_open, R.string.material_drawer_close) + //Create the drawer - mResult = DrawerBuilder() - .withActivity(this) - .withToolbar(toolbar) - .withHasStableIds(true) - .withSavedInstance(savedInstanceState) - .withShowDrawerOnFirstLaunch(true) - .addDrawerItems( - PrimaryDrawerItem().withName(R.string.sample_icon_grid).withDescription(R.string.sample_icon_grid_descr).withSelectable(false).withIdentifier(8).withIcon(MaterialDesignIconic.Icon.gmi_grid), - PrimaryDrawerItem().withName(R.string.sample_simple_item_list).withDescription(R.string.sample_simple_item_list_descr).withSelectable(false).withIdentifier(6).withIcon(MaterialDesignIconic.Icon.gmi_format_align_justify), - PrimaryDrawerItem().withName(R.string.sample_image_list).withDescription(R.string.sample_image_list_descr).withSelectable(false).withIdentifier(5).withIcon(MaterialDesignIconic.Icon.gmi_wallpaper), - PrimaryDrawerItem().withName(R.string.sample_multi_select).withDescription(R.string.sample_multi_select_descr).withSelectable(false).withIdentifier(1).withIcon(MaterialDesignIconic.Icon.gmi_select_all), - PrimaryDrawerItem().withName(R.string.sample_collapsible).withDescription(R.string.sample_collapsible_descr).withSelectable(false).withIdentifier(2).withIcon(MaterialDesignIconic.Icon.gmi_check_all), - PrimaryDrawerItem().withName(R.string.sample_sticky_header).withDescription(R.string.sample_sticky_header_descr).withSelectable(false).withIdentifier(3).withIcon(MaterialDesignIconic.Icon.gmi_format_align_left), - PrimaryDrawerItem().withName(R.string.sample_paged_list).withDescription(R.string.sample_paged_list_descr).withSelectable(false).withIdentifier(20).withIcon(MaterialDesignIconic.Icon.gmi_pages), - PrimaryDrawerItem().withName(R.string.sample_advanced).withDescription(R.string.sample_advanced_descr).withSelectable(false).withIdentifier(4).withIcon(MaterialDesignIconic.Icon.gmi_coffee), - PrimaryDrawerItem().withName(R.string.sample_model_item).withDescription(R.string.sample_model_item_descr).withSelectable(false).withIdentifier(7).withIcon(MaterialDesignIconic.Icon.gmi_font), - PrimaryDrawerItem().withName(R.string.sample_multi_model_item).withDescription(R.string.sample_multi_model_item_descr).withSelectable(false).withIdentifier(9).withIcon(MaterialDesignIconic.Icon.gmi_format_list_numbered), - PrimaryDrawerItem().withName(R.string.sample_checkbox_item).withDescription(R.string.sample_checkbox_item_descr).withSelectable(false).withIdentifier(10).withIcon(CommunityMaterial.Icon.cmd_checkbox_marked), - PrimaryDrawerItem().withName(R.string.sample_radiobutton_item).withDescription(R.string.sample_radiobutton_item_descr).withSelectable(false).withIdentifier(11).withIcon(CommunityMaterial.Icon2.cmd_radiobox_marked), - PrimaryDrawerItem().withName(R.string.sample_swipe_list).withDescription(R.string.sample_swipe_list_descr).withSelectable(false).withIdentifier(12).withIcon(MaterialDesignIconic.Icon.gmi_format_align_left), - PrimaryDrawerItem().withName(R.string.sample_endless_scroll_list).withDescription(R.string.sample_endless_scroll_list_descr).withSelectable(false).withIdentifier(13).withIcon(MaterialDesignIconic.Icon.gmi_long_arrow_down), - PrimaryDrawerItem().withName(R.string.sample_sort).withDescription(R.string.sample_sort_descr).withSelectable(false).withIdentifier(14).withIcon(MaterialDesignIconic.Icon.gmi_sort_by_alpha), - PrimaryDrawerItem().withName(R.string.sample_mopub).withDescription(R.string.sample_mopub_descr).withSelectable(false).withIdentifier(15).withIcon(MaterialDesignIconic.Icon.gmi_accounts_list), - PrimaryDrawerItem().withName(R.string.sample_realm_list).withDescription(R.string.sample_realm_list_descr).withSelectable(false).withIdentifier(16).withIcon(MaterialDesignIconic.Icon.gmi_format_color_text), - PrimaryDrawerItem().withName(R.string.sample_collapsible_multi_select_delete).withDescription(R.string.sample_collapsible_multi_select_delete_descr).withSelectable(false).withIdentifier(17).withIcon(MaterialDesignIconic.Icon.gmi_check_all), - PrimaryDrawerItem().withName(R.string.sample_sticky_header_mopub).withDescription(R.string.sample_sticky_header_mopub_descr).withSelectable(false).withIdentifier(18).withIcon(MaterialDesignIconic.Icon.gmi_accounts_list), - PrimaryDrawerItem().withName(R.string.sample_diff_util).withDescription(R.string.sample_diff_util_descr).withSelectable(false).withIdentifier(19).withIcon(MaterialDesignIconic.Icon.gmi_refresh), - DividerDrawerItem(), - PrimaryDrawerItem().withName(R.string.open_source).withSelectable(false).withIdentifier(100).withIcon(MaterialDesignIconic.Icon.gmi_github) - ) - .withOnDrawerItemClickListener(object : Drawer.OnDrawerItemClickListener { - override fun onItemClick(view: View?, position: Int, drawerItem: IDrawerItem<*>): Boolean { - var intent: Intent? = null - when { - drawerItem.identifier == 1L -> intent = Intent(this@SampleActivity, MultiselectSampleActivity::class.java) - drawerItem.identifier == 2L -> intent = Intent(this@SampleActivity, ExpandableSampleActivity::class.java) - drawerItem.identifier == 3L -> intent = Intent(this@SampleActivity, StickyHeaderSampleActivity::class.java) - drawerItem.identifier == 4L -> intent = Intent(this@SampleActivity, AdvancedSampleActivity::class.java) - drawerItem.identifier == 5L -> intent = Intent(this@SampleActivity, ImageListActivity::class.java) - drawerItem.identifier == 6L -> intent = Intent(this@SampleActivity, SimpleItemListActivity::class.java) - drawerItem.identifier == 7L -> intent = Intent(this@SampleActivity, ModelItemActivity::class.java) - drawerItem.identifier == 8L -> intent = Intent(this@SampleActivity, IconGridActivity::class.java) - drawerItem.identifier == 9L -> intent = Intent(this@SampleActivity, MultiTypeModelItemActivity::class.java) - drawerItem.identifier == 10L -> intent = Intent(this@SampleActivity, CheckBoxSampleActivity::class.java) - drawerItem.identifier == 11L -> intent = Intent(this@SampleActivity, RadioButtonSampleActivity::class.java) - drawerItem.identifier == 12L -> intent = Intent(this@SampleActivity, SwipeListActivity::class.java) - drawerItem.identifier == 13L -> intent = Intent(this@SampleActivity, EndlessScrollListActivity::class.java) - drawerItem.identifier == 14L -> intent = Intent(this@SampleActivity, SortActivity::class.java) - drawerItem.identifier == 15L -> intent = Intent(this@SampleActivity, MopubAdsActivity::class.java) - drawerItem.identifier == 16L -> intent = Intent(this@SampleActivity, RealmActivity::class.java) - drawerItem.identifier == 17L -> intent = Intent(this@SampleActivity, ExpandableMultiselectDeleteSampleActivity::class.java) - drawerItem.identifier == 18L -> intent = Intent(this@SampleActivity, StickyHeaderMopubAdsActivity::class.java) - drawerItem.identifier == 19L -> intent = Intent(this@SampleActivity, DiffUtilActivity::class.java) - drawerItem.identifier == 20L -> intent = Intent(this@SampleActivity, PagedActivity::class.java) - drawerItem.identifier == 100L -> intent = LibsBuilder() - .withFields(R.string::class.java.fields) - .withActivityTitle(getString(R.string.open_source)) - .withActivityStyle(Libs.ActivityStyle.LIGHT) - .withAboutIconShown(true) - .withVersionShown(true) - .withAboutVersionShown(true) - .intent(this@SampleActivity) - } - if (intent != null) { - this@SampleActivity.startActivity(intent) - } - return false - } - }) - .withSelectedItemByPosition(-1) - .build() + slider.apply { + addItems( + PrimaryDrawerItem().withName(R.string.sample_icon_grid).withDescription(R.string.sample_icon_grid_descr).withSelectable(false).withIdentifier(8).withIcon(MaterialDesignIconic.Icon.gmi_grid), + PrimaryDrawerItem().withName(R.string.sample_simple_item_list).withDescription(R.string.sample_simple_item_list_descr).withSelectable(false).withIdentifier(6).withIcon(MaterialDesignIconic.Icon.gmi_format_align_justify), + PrimaryDrawerItem().withName(R.string.sample_image_list).withDescription(R.string.sample_image_list_descr).withSelectable(false).withIdentifier(5).withIcon(MaterialDesignIconic.Icon.gmi_wallpaper), + PrimaryDrawerItem().withName(R.string.sample_multi_select).withDescription(R.string.sample_multi_select_descr).withSelectable(false).withIdentifier(1).withIcon(MaterialDesignIconic.Icon.gmi_select_all), + PrimaryDrawerItem().withName(R.string.sample_collapsible).withDescription(R.string.sample_collapsible_descr).withSelectable(false).withIdentifier(2).withIcon(MaterialDesignIconic.Icon.gmi_check_all), + PrimaryDrawerItem().withName(R.string.sample_sticky_header).withDescription(R.string.sample_sticky_header_descr).withSelectable(false).withIdentifier(3).withIcon(MaterialDesignIconic.Icon.gmi_format_align_left), + PrimaryDrawerItem().withName(R.string.sample_paged_list).withDescription(R.string.sample_paged_list_descr).withSelectable(false).withIdentifier(21).withIcon(MaterialDesignIconic.Icon.gmi_pages), + PrimaryDrawerItem().withName(R.string.sample_advanced).withDescription(R.string.sample_advanced_descr).withSelectable(false).withIdentifier(4).withIcon(MaterialDesignIconic.Icon.gmi_coffee), + PrimaryDrawerItem().withName(R.string.sample_model_item).withDescription(R.string.sample_model_item_descr).withSelectable(false).withIdentifier(7).withIcon(MaterialDesignIconic.Icon.gmi_font), + PrimaryDrawerItem().withName(R.string.sample_multi_model_item).withDescription(R.string.sample_multi_model_item_descr).withSelectable(false).withIdentifier(9).withIcon(MaterialDesignIconic.Icon.gmi_format_list_numbered), + PrimaryDrawerItem().withName(R.string.sample_checkbox_item).withDescription(R.string.sample_checkbox_item_descr).withSelectable(false).withIdentifier(10).withIcon(CommunityMaterial.Icon.cmd_checkbox_marked), + PrimaryDrawerItem().withName(R.string.sample_radiobutton_item).withDescription(R.string.sample_radiobutton_item_descr).withSelectable(false).withIdentifier(11).withIcon(CommunityMaterial.Icon2.cmd_radiobox_marked), + PrimaryDrawerItem().withName(R.string.sample_swipe_list).withDescription(R.string.sample_swipe_list_descr).withSelectable(false).withIdentifier(12).withIcon(MaterialDesignIconic.Icon.gmi_format_align_left), + PrimaryDrawerItem().withName(R.string.sample_swipe_drawer_list).withDescription(R.string.sample_swipe_drawer_list_descr).withSelectable(false).withIdentifier(13).withIcon(MaterialDesignIconic.Icon.gmi_format_align_left), + PrimaryDrawerItem().withName(R.string.sample_endless_scroll_list).withDescription(R.string.sample_endless_scroll_list_descr).withSelectable(false).withIdentifier(14).withIcon(MaterialDesignIconic.Icon.gmi_long_arrow_down), + PrimaryDrawerItem().withName(R.string.sample_sort).withDescription(R.string.sample_sort_descr).withSelectable(false).withIdentifier(15).withIcon(MaterialDesignIconic.Icon.gmi_sort_by_alpha), + PrimaryDrawerItem().withName(R.string.sample_mopub).withDescription(R.string.sample_mopub_descr).withSelectable(false).withIdentifier(16).withIcon(MaterialDesignIconic.Icon.gmi_accounts_list), + PrimaryDrawerItem().withName(R.string.sample_realm_list).withDescription(R.string.sample_realm_list_descr).withSelectable(false).withIdentifier(17).withIcon(MaterialDesignIconic.Icon.gmi_format_color_text), + PrimaryDrawerItem().withName(R.string.sample_collapsible_multi_select_delete).withDescription(R.string.sample_collapsible_multi_select_delete_descr).withSelectable(false).withIdentifier(18).withIcon(MaterialDesignIconic.Icon.gmi_check_all), + PrimaryDrawerItem().withName(R.string.sample_sticky_header_mopub).withDescription(R.string.sample_sticky_header_mopub_descr).withSelectable(false).withIdentifier(19).withIcon(MaterialDesignIconic.Icon.gmi_accounts_list), + PrimaryDrawerItem().withName(R.string.sample_diff_util).withDescription(R.string.sample_diff_util_descr).withSelectable(false).withIdentifier(20).withIcon(MaterialDesignIconic.Icon.gmi_refresh), + DividerDrawerItem(), + PrimaryDrawerItem().withName(R.string.open_source).withSelectable(false).withIdentifier(100).withIcon(MaterialDesignIconic.Icon.gmi_github) + ) + onDrawerItemClickListener = { v, drawerItem, position -> + val intent: Intent? = when (drawerItem.identifier) { + 1L -> Intent(this@SampleActivity, MultiselectSampleActivity::class.java) + 2L -> Intent(this@SampleActivity, ExpandableSampleActivity::class.java) + 3L -> Intent(this@SampleActivity, StickyHeaderSampleActivity::class.java) + 4L -> Intent(this@SampleActivity, AdvancedSampleActivity::class.java) + 5L -> Intent(this@SampleActivity, ImageListActivity::class.java) + 6L -> Intent(this@SampleActivity, SimpleItemListActivity::class.java) + 7L -> Intent(this@SampleActivity, ModelItemActivity::class.java) + 8L -> Intent(this@SampleActivity, IconGridActivity::class.java) + 9L -> Intent(this@SampleActivity, MultiTypeModelItemActivity::class.java) + 10L -> Intent(this@SampleActivity, CheckBoxSampleActivity::class.java) + 11L -> Intent(this@SampleActivity, RadioButtonSampleActivity::class.java) + 12L -> Intent(this@SampleActivity, SwipeListActivity::class.java) + 13L -> Intent(this@SampleActivity, SwipeDrawerListActivity::class.java) + 14L -> Intent(this@SampleActivity, EndlessScrollListActivity::class.java) + 15L -> Intent(this@SampleActivity, SortActivity::class.java) + 16L -> Intent(this@SampleActivity, MopubAdsActivity::class.java) + 17L -> Intent(this@SampleActivity, RealmActivity::class.java) + 18L -> Intent(this@SampleActivity, ExpandableMultiselectDeleteSampleActivity::class.java) + 19L -> Intent(this@SampleActivity, StickyHeaderMopubAdsActivity::class.java) + 20L -> Intent(this@SampleActivity, DiffUtilActivity::class.java) + 21L -> Intent(this@SampleActivity, PagedActivity::class.java) + 100L -> LibsBuilder() + .withFields(R.string::class.java.fields) + .withActivityTitle(getString(R.string.open_source)) + .withAboutIconShown(true) + .withVersionShown(true) + .withAboutVersionShown(true) + .withEdgeToEdge(true) + .intent(this@SampleActivity) + else -> throw UnsupportedOperationException() + } + if (intent != null) { + this@SampleActivity.startActivity(intent) + } + false + } + selectedItemPosition = RecyclerView.NO_POSITION + setSavedInstance(savedInstanceState) + } //create our ItemAdapter which will host our items mItemAdapter = ItemAdapter() @@ -156,18 +162,31 @@ class SampleActivity : AppCompatActivity() { }, 50) } + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + actionBarDrawerToggle.onConfigurationChanged(newConfig) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + actionBarDrawerToggle.syncState() + } override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.menu, menu) - menu.findItem(R.id.item_add).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_plus_square).color(IconicsColor.colorInt(Color.BLACK)).actionBar() - menu.findItem(R.id.item_delete).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_minus_square).color(IconicsColor.colorInt(Color.BLACK)).actionBar() - menu.findItem(R.id.item_change).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_settings_square).color(IconicsColor.colorInt(Color.BLACK)).actionBar() - menu.findItem(R.id.item_move).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_format_valign_bottom).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.item_add).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_plus_square).apply { colorInt = Color.BLACK; actionBar() } + menu.findItem(R.id.item_delete).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_minus_square).apply { colorInt = Color.BLACK; actionBar() } + menu.findItem(R.id.item_change).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_settings_square).apply { colorInt = Color.BLACK; actionBar() } + menu.findItem(R.id.item_move).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_format_valign_bottom).apply { colorInt = Color.BLACK; actionBar() } return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (actionBarDrawerToggle.onOptionsItemSelected(item)) { + return true + } + //find out the current visible position var firstVisiblePosition = 0 if (rv.layoutManager is LinearLayoutManager) { @@ -213,7 +232,7 @@ class SampleActivity : AppCompatActivity() { override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle - outState = mResult.saveInstanceState(outState) + outState = slider.saveInstanceState(outState) //add the values which need to be saved from the adapter to the bundle outState = mFastAdapter.saveInstanceState(outState) super.onSaveInstanceState(outState) @@ -221,8 +240,8 @@ class SampleActivity : AppCompatActivity() { override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity - if (mResult.isDrawerOpen) { - mResult.closeDrawer() + if (root.isDrawerOpen(slider)) { + root.closeDrawer(slider) } else { super.onBackPressed() } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/SimpleItemListActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/SimpleItemListActivity.kt index 47c52c68e..eef1bc00d 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/SimpleItemListActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/SimpleItemListActivity.kt @@ -12,6 +12,7 @@ import androidx.appcompat.widget.SearchView import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter @@ -23,10 +24,10 @@ import com.mikepenz.fastadapter.drag.SimpleDragCallback import com.mikepenz.fastadapter.listeners.ItemFilterListener import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.fastadapter.utils.DragDropUtil -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic -import com.mikepenz.materialize.MaterializeBuilder +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -41,16 +42,12 @@ class SimpleItemListActivity : AppCompatActivity(), ItemTouchCallback, ItemFilte private lateinit var touchHelper: ItemTouchHelper override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) - //style our ui - MaterializeBuilder().withActivity(this).build() - // val fastScrollIndicatorAdapter = FastScrollIndicatorAdapter() itemAdapter = items() @@ -70,7 +67,7 @@ class SimpleItemListActivity : AppCompatActivity(), ItemTouchCallback, ItemFilte //configure the itemAdapter itemAdapter.itemFilter.filterPredicate = { item: SimpleItem, constraint: CharSequence? -> - item.name?.text.toString().toLowerCase().contains(constraint.toString().toLowerCase()) + item.name?.textString.toString().toLowerCase(Locale.getDefault()).contains(constraint.toString().toLowerCase(Locale.getDefault())) } itemAdapter.itemFilter.itemFilterListener = this @@ -132,7 +129,7 @@ class SimpleItemListActivity : AppCompatActivity(), ItemTouchCallback, ItemFilte inflater.inflate(R.menu.search, menu) //search icon - menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).apply { colorInt = Color.BLACK; actionBar() } val searchView = menu.findItem(R.id.search).actionView as SearchView searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { @@ -159,6 +156,11 @@ class SimpleItemListActivity : AppCompatActivity(), ItemTouchCallback, ItemFilte override fun itemTouchDropped(oldPosition: Int, newPosition: Int) { // save the new item order, i.e. in your database + // remove visual highlight to dropped item + } + + override fun itemTouchStartDrag(viewHolder: RecyclerView.ViewHolder) { + // add visual highlight to dragged item } override fun itemsFiltered(constraint: CharSequence?, results: List?) { diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/SortActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/SortActivity.kt index 169470b56..05e12cd2b 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/SortActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/SortActivity.kt @@ -20,11 +20,11 @@ import com.mikepenz.fastadapter.app.items.SimpleItem import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension import com.mikepenz.fastadapter.utils.ComparableItemListImpl -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic -import com.mikepenz.materialize.MaterializeBuilder -import kotlinx.android.synthetic.main.activity_sort.toolbar +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt +import kotlinx.android.synthetic.main.activity_sample.* import java.io.Serializable import java.util.* @@ -62,18 +62,14 @@ class SortActivity : AppCompatActivity() { } override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) - setContentView(R.layout.activity_sort) + setContentView(R.layout.activity_sample) ButterKnife.bind(this) // Handle Toolbar setSupportActionBar(toolbar) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything itemListImpl = ComparableItemListImpl(comparator) itemAdapter = ItemAdapter(itemListImpl) @@ -129,9 +125,9 @@ class SortActivity : AppCompatActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.sort, menu) - menu.findItem(R.id.item_sort_random).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_wrap_text).color(IconicsColor.colorInt(Color.BLACK)).actionBar() - menu.findItem(R.id.item_sort_asc).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_sort_asc).color(IconicsColor.colorInt(Color.BLACK)).actionBar() - menu.findItem(R.id.item_sort_desc).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_sort_desc).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.item_sort_random).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_wrap_text).apply { colorInt = Color.BLACK; actionBar() } + menu.findItem(R.id.item_sort_asc).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_sort_asc).apply { colorInt = Color.BLACK; actionBar() } + menu.findItem(R.id.item_sort_desc).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_sort_desc).apply { colorInt = Color.BLACK; actionBar() } return true } @@ -222,7 +218,7 @@ class SortActivity : AppCompatActivity() { */ private inner class AlphabetComparatorAscending : Comparator, Serializable { override fun compare(lhs: SimpleItem, rhs: SimpleItem): Int { - return lhs.name?.text.toString().compareTo(rhs.name?.text.toString()) + return lhs.name?.textString.toString().compareTo(rhs.name?.textString.toString()) } } @@ -231,7 +227,7 @@ class SortActivity : AppCompatActivity() { */ private inner class AlphabetComparatorDescending : Comparator, Serializable { override fun compare(lhs: SimpleItem, rhs: SimpleItem): Int { - return rhs.name?.text.toString().compareTo(lhs.name?.text.toString()) + return rhs.name?.textString.toString().compareTo(lhs.name?.textString.toString()) } } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderMopubAdsActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderMopubAdsActivity.kt index 0b5ed8f86..1f4a696f2 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderMopubAdsActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderMopubAdsActivity.kt @@ -2,7 +2,6 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.view.MenuItem -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager @@ -28,10 +27,9 @@ class StickyHeaderMopubAdsActivity : AppCompatActivity() { private lateinit var mAdapter: MopubFastItemAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(R.layout.activity_sample) ButterKnife.bind(this) diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderSampleActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderSampleActivity.kt index 0aaa83979..280679791 100755 --- a/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderSampleActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/StickyHeaderSampleActivity.kt @@ -2,7 +2,6 @@ package com.mikepenz.fastadapter.app import android.os.Bundle import android.view.MenuItem -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager @@ -12,7 +11,6 @@ import com.mikepenz.fastadapter.adapters.ItemAdapter import com.mikepenz.fastadapter.app.adapters.StickyHeaderAdapter import com.mikepenz.fastadapter.app.items.SimpleItem import com.mikepenz.fastadapter.select.getSelectExtension -import com.mikepenz.materialize.MaterializeBuilder import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -27,7 +25,6 @@ class StickyHeaderSampleActivity : AppCompatActivity() { private lateinit var fastAdapter: FastAdapter override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) @@ -35,9 +32,6 @@ class StickyHeaderSampleActivity : AppCompatActivity() { setSupportActionBar(toolbar) supportActionBar?.setTitle(R.string.sample_sticky_header) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our adapters val stickyHeaderAdapter = StickyHeaderAdapter() val headerAdapter = ItemAdapter() diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/SwipeDrawerListActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/SwipeDrawerListActivity.kt new file mode 100644 index 000000000..6d0b52546 --- /dev/null +++ b/app/src/main/java/com/mikepenz/fastadapter/app/SwipeDrawerListActivity.kt @@ -0,0 +1,196 @@ +package com.mikepenz.fastadapter.app + +import android.graphics.Color +import android.os.Bundle +import android.text.TextUtils +import android.view.Menu +import android.view.MenuItem +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.SearchView +import androidx.recyclerview.widget.DefaultItemAnimator +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.fastadapter.adapters.FastItemAdapter +import com.mikepenz.fastadapter.app.adapters.IDraggableViewHolder +import com.mikepenz.fastadapter.app.items.SwipeableDrawerItem +import com.mikepenz.fastadapter.drag.ItemTouchCallback +import com.mikepenz.fastadapter.drag.SimpleDragCallback +import com.mikepenz.fastadapter.swipe_drag.SimpleSwipeDrawerDragCallback +import com.mikepenz.fastadapter.utils.DragDropUtil +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt +import io.reactivex.functions.Consumer +import kotlinx.android.synthetic.main.activity_sample.* +import java.util.* + +class SwipeDrawerListActivity : AppCompatActivity(), ItemTouchCallback { + + //save our FastAdapter + private lateinit var fastItemDrawerAdapter: FastItemAdapter + + //drag & drop + private lateinit var touchCallback: SimpleDragCallback + private lateinit var touchHelper: ItemTouchHelper + + + private fun delete(item: SwipeableDrawerItem) { + item.deleteAction = null + val position12 = fastItemDrawerAdapter.getAdapterPosition(item) + if (position12 != RecyclerView.NO_POSITION) { + //this sample uses a filter. If a filter is used we should use the methods provided by the filter (to make sure filter and normal state is updated) + fastItemDrawerAdapter.itemFilter.remove(position12) + Toast.makeText(this, "Deleted", Toast.LENGTH_SHORT).show() + } + } + + private fun archive(item: SwipeableDrawerItem) { + item.archiveAction = null + val position12 = fastItemDrawerAdapter.getAdapterPosition(item) + if (position12 != RecyclerView.NO_POSITION) { + // Do something intelligent here + Toast.makeText(this, "Archived", Toast.LENGTH_SHORT).show() + } + } + + private fun share(item: SwipeableDrawerItem) { + item.shareAction = null + val position12 = fastItemDrawerAdapter.getAdapterPosition(item) + if (position12 != RecyclerView.NO_POSITION) { + // Do something intelligent here + Toast.makeText(this, "Shared", Toast.LENGTH_SHORT).show() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_sample) + + // Handle Toolbar + setSupportActionBar(toolbar) + + //create our FastAdapter which will manage everything + fastItemDrawerAdapter = FastItemAdapter() + //configure the itemAdapter + fastItemDrawerAdapter.itemFilter.filterPredicate = { item: SwipeableDrawerItem, constraint: CharSequence? -> + item.name?.textString.toString().contains(constraint.toString(), ignoreCase = true) + } + + //get our recyclerView and do basic setup + rv.layoutManager = LinearLayoutManager(this) + rv.itemAnimator = DefaultItemAnimator() + rv.adapter = fastItemDrawerAdapter + + //fill with some sample data + var x = 0 + val items = ArrayList() + for (s in ALPHABET) { + val count = Random().nextInt(20) + for (i in 1..count) { + val swipeableItem = SwipeableDrawerItem().withName("$s Test $x") + swipeableItem.identifier = (100 + x).toLong() + swipeableItem.withIsSwipeable(i % 5 != 0) + swipeableItem.withIsDraggable(i % 5 != 0) + swipeableItem.deleteAction = Consumer { item -> delete(item) } + swipeableItem.archiveAction = Consumer { item -> archive(item) } + swipeableItem.shareAction = Consumer { item -> share(item) } + items.add(swipeableItem) + x++ + } + } + fastItemDrawerAdapter.add(items) + + + //add drag and drop for item + //and add swipe as well + touchCallback = SimpleSwipeDrawerDragCallback( + this, + ItemTouchHelper.LEFT) + .withNotifyAllDrops(true) + .withSwipeLeft(80) // Width of delete button + .withSwipeRight(160) // Width of archive and share buttons + .withSensitivity(10f) + + touchHelper = ItemTouchHelper(touchCallback) // Create ItemTouchHelper and pass with parameter the SimpleDragCallback + touchHelper.attachToRecyclerView(rv) // Attach ItemTouchHelper to RecyclerView + + //restore selections (this has to be done after the items were added) + fastItemDrawerAdapter.withSavedInstanceState(savedInstanceState) + + //set the back arrow in the toolbar + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setHomeButtonEnabled(false) + } + + override fun onSaveInstanceState(_outState: Bundle) { + var outState = _outState + //add the values which need to be saved from the adapter to the bundle + outState = fastItemDrawerAdapter.saveInstanceState(outState) + super.onSaveInstanceState(outState) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + //handle the click on the back arrow click + return when (item.itemId) { + android.R.id.home -> { + onBackPressed() + true + } + else -> super.onOptionsItemSelected(item) + } + } + + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + // Inflate the menu items for use in the action bar + val inflater = menuInflater + inflater.inflate(R.menu.search, menu) + + //search icon + menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).apply { colorInt = Color.BLACK; actionBar() } + + val searchView = menu.findItem(R.id.search).actionView as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(s: String): Boolean { + touchCallback.setIsDragEnabled(false) + fastItemDrawerAdapter.filter(s) + return true + } + + + override fun onQueryTextChange(s: String): Boolean { + fastItemDrawerAdapter.filter(s) + touchCallback.setIsDragEnabled(TextUtils.isEmpty(s)) + return true + } + }) + + return super.onCreateOptionsMenu(menu) + } + + override fun itemTouchOnMove(oldPosition: Int, newPosition: Int): Boolean { + DragDropUtil.onMove(fastItemDrawerAdapter.itemAdapter, oldPosition, newPosition) // change position + return true + } + + override fun itemTouchDropped(oldPosition: Int, newPosition: Int) { + val vh: RecyclerView.ViewHolder? = rv.findViewHolderForAdapterPosition(newPosition) + if (vh is IDraggableViewHolder) { + (vh as IDraggableViewHolder).onDropped() + } + // save the new item order, i.e. in your database + } + + override fun itemTouchStartDrag(viewHolder: RecyclerView.ViewHolder) { + if (viewHolder is IDraggableViewHolder) { + (viewHolder as IDraggableViewHolder).onDragged() + } + } + + companion object { + private val ALPHABET = arrayOf("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z") + } +} diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/SwipeListActivity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/SwipeListActivity.kt index 08da31e11..329bb98b3 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/SwipeListActivity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/SwipeListActivity.kt @@ -11,24 +11,24 @@ import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView -import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.adapters.FastItemAdapter +import com.mikepenz.fastadapter.app.adapters.IDraggableViewHolder import com.mikepenz.fastadapter.app.items.SwipeableItem import com.mikepenz.fastadapter.drag.ItemTouchCallback import com.mikepenz.fastadapter.drag.SimpleDragCallback import com.mikepenz.fastadapter.swipe.SimpleSwipeCallback import com.mikepenz.fastadapter.swipe_drag.SimpleSwipeDragCallback import com.mikepenz.fastadapter.utils.DragDropUtil -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.IconicsSize import com.mikepenz.iconics.typeface.library.materialdesigniconic.MaterialDesignIconic -import com.mikepenz.materialize.MaterializeBuilder +import com.mikepenz.iconics.utils.actionBar +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp import kotlinx.android.synthetic.main.activity_sample.* import java.util.* @@ -55,16 +55,12 @@ class SwipeListActivity : AppCompatActivity(), ItemTouchCallback, SimpleSwipeCal } override fun onCreate(savedInstanceState: Bundle?) { - findViewById(android.R.id.content).systemUiVisibility = findViewById(android.R.id.content).systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR super.onCreate(savedInstanceState) setContentView(R.layout.activity_sample) // Handle Toolbar setSupportActionBar(toolbar) - //style our ui - MaterializeBuilder().withActivity(this).build() - //create our FastAdapter which will manage everything fastItemAdapter = FastItemAdapter() @@ -76,7 +72,7 @@ class SwipeListActivity : AppCompatActivity(), ItemTouchCallback, SimpleSwipeCal //configure the itemAdapter fastItemAdapter.itemFilter.filterPredicate = { item: SwipeableItem, constraint: CharSequence? -> - item.name?.text.toString().contains(constraint.toString(), ignoreCase = true) + item.name?.textString.toString().contains(constraint.toString(), ignoreCase = true) } //get our recyclerView and do basic setup @@ -103,24 +99,21 @@ class SwipeListActivity : AppCompatActivity(), ItemTouchCallback, SimpleSwipeCal //add drag and drop for item //and add swipe as well - val leaveBehindDrawableLeft = IconicsDrawable(this) - .icon(MaterialDesignIconic.Icon.gmi_delete) - .color(IconicsColor.colorInt(Color.WHITE)) - .size(IconicsSize.dp(24)) - val leaveBehindDrawableRight = IconicsDrawable(this) - .icon(MaterialDesignIconic.Icon.gmi_archive) - .color(IconicsColor.colorInt(Color.WHITE)) - .size(IconicsSize.dp(24)) + val leaveBehindDrawableLeft = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_delete).apply { colorInt = Color.WHITE; sizeDp = 24 } + val leaveBehindDrawableRight = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_archive).apply { colorInt = Color.WHITE; sizeDp = 24 } touchCallback = SimpleSwipeDragCallback( this, this, leaveBehindDrawableLeft, ItemTouchHelper.LEFT, - ContextCompat.getColor(this, R.color.md_red_900) + Color.RED ) - .withBackgroundSwipeRight(ContextCompat.getColor(this, R.color.md_blue_900)) + .withBackgroundSwipeRight(Color.BLUE) .withLeaveBehindSwipeRight(leaveBehindDrawableRight) + .withNotifyAllDrops(true) + .withSensitivity(10f) + .withSurfaceThreshold(0.8f) touchHelper = ItemTouchHelper(touchCallback) // Create ItemTouchHelper and pass with parameter the SimpleDragCallback touchHelper.attachToRecyclerView(rv) // Attach ItemTouchHelper to RecyclerView @@ -158,7 +151,7 @@ class SwipeListActivity : AppCompatActivity(), ItemTouchCallback, SimpleSwipeCal inflater.inflate(R.menu.search, menu) //search icon - menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).color(IconicsColor.colorInt(Color.BLACK)).actionBar() + menu.findItem(R.id.search).icon = IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_search).apply { colorInt = Color.BLACK; actionBar() } val searchView = menu.findItem(R.id.search).actionView as SearchView searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { @@ -185,9 +178,19 @@ class SwipeListActivity : AppCompatActivity(), ItemTouchCallback, SimpleSwipeCal } override fun itemTouchDropped(oldPosition: Int, newPosition: Int) { + val vh: RecyclerView.ViewHolder? = rv.findViewHolderForAdapterPosition(newPosition) + if (vh is IDraggableViewHolder) { + (vh as IDraggableViewHolder).onDropped() + } // save the new item order, i.e. in your database } + override fun itemTouchStartDrag(viewHolder: RecyclerView.ViewHolder) { + if (viewHolder is IDraggableViewHolder) { + (viewHolder as IDraggableViewHolder).onDragged() + } + } + override fun itemSwiped(position: Int, direction: Int) { // -- Option 1: Direct action -- //do something when swiped such as: select, remove, update, ...: diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/adapters/FastScrollIndicatorAdapter.kt b/app/src/main/java/com/mikepenz/fastadapter/app/adapters/FastScrollIndicatorAdapter.kt index 20894411f..f98ef41a6 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/adapters/FastScrollIndicatorAdapter.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/adapters/FastScrollIndicatorAdapter.kt @@ -29,7 +29,7 @@ class FastScrollIndicatorAdapter : RecyclerView.Adapter : RecyclerView.Adapter) { + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List) { fastAdapter?.onBindViewHolder(holder, position, payloads) } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/adapters/IDraggableViewHolder.java b/app/src/main/java/com/mikepenz/fastadapter/app/adapters/IDraggableViewHolder.java new file mode 100644 index 000000000..1d1fe1d5e --- /dev/null +++ b/app/src/main/java/com/mikepenz/fastadapter/app/adapters/IDraggableViewHolder.java @@ -0,0 +1,16 @@ +package com.mikepenz.fastadapter.app.adapters; + +/** + * Helper interface to allow a viewHolder to react to drag events. + */ +public interface IDraggableViewHolder { + /** + * Called when an item enters drag state + */ + void onDragged(); + + /** + * Called when an item has been dropped + */ + void onDropped(); +} diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/adapters/StickyHeaderAdapter.kt b/app/src/main/java/com/mikepenz/fastadapter/app/adapters/StickyHeaderAdapter.kt index 2fb548e85..40460a386 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/adapters/StickyHeaderAdapter.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/adapters/StickyHeaderAdapter.kt @@ -171,7 +171,7 @@ class StickyHeaderAdapter : RecyclerView.Adapter) { + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List) { fastAdapter?.onBindViewHolder(holder, position, payloads) } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/binding/BindingIconItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/binding/BindingIconItem.kt new file mode 100644 index 000000000..a6d9bb5ca --- /dev/null +++ b/app/src/main/java/com/mikepenz/fastadapter/app/binding/BindingIconItem.kt @@ -0,0 +1,73 @@ +package com.mikepenz.fastadapter.app.binding + +import android.view.LayoutInflater +import android.view.ViewGroup +import com.mikepenz.aboutlibraries.util.getThemeColor +import com.mikepenz.fastadapter.IExpandable +import com.mikepenz.fastadapter.IParentItem +import com.mikepenz.fastadapter.ISubItem +import com.mikepenz.fastadapter.app.R +import com.mikepenz.fastadapter.app.databinding.IconItemBinding +import com.mikepenz.fastadapter.binding.AbstractBindingItem +import com.mikepenz.fastadapter.binding.BindingViewHolder +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.utils.colorInt + +/** + * Created by mikepenz on 28.12.15. + */ +class BindingIconItem : AbstractBindingItem(), IExpandable> { + var icon: IIcon? = null + + override var parent: IParentItem<*>? = null + override var isExpanded: Boolean = false + + override var subItems: MutableList> + get() = mutableListOf() + set(_) { + } + + override val isAutoExpanding: Boolean + get() = true + + /** + * defines the type defining this item. must be unique. preferably an id + * + * @return the type + */ + override val type: Int + get() = R.id.fastadapter_icon_item_id + + /** + * setter method for the Icon + * + * @param icon the icon + * @return this + */ + fun withIcon(icon: IIcon): BindingIconItem { + this.icon = icon + return this + } + + /** + * binds the data of this item onto the viewHolder + */ + override fun bindView(binding: IconItemBinding, payloads: List) { + //define our data for the view + icon?.let { + binding.icon.icon = IconicsDrawable(binding.icon.context, it).apply { + colorInt = binding.root.context.getThemeColor(R.attr.colorOnSurface) + } + } + binding.name.text = icon?.name + } + + override fun unbindView(binding: IconItemBinding) { + binding.icon.setImageDrawable(null) + } + + override fun createBinding(inflater: LayoutInflater, parent: ViewGroup?): IconItemBinding { + return IconItemBinding.inflate(inflater, parent, false) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/helpers/CustomStickyRecyclerHeadersDecoration.kt b/app/src/main/java/com/mikepenz/fastadapter/app/helpers/CustomStickyRecyclerHeadersDecoration.kt index ffe4253b3..aa870f790 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/helpers/CustomStickyRecyclerHeadersDecoration.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/helpers/CustomStickyRecyclerHeadersDecoration.kt @@ -99,7 +99,7 @@ class CustomStickyRecyclerHeadersDecoration private constructor(private val mAda * * @param x x-coordinate * @param y y-coordinate - * @return position of header, or -1 if not found + * @return position of header, or [androidx.recyclerview.widget.RecyclerView.NO_POSITION] (-1) if not found */ fun findHeaderPositionUnder(x: Int, y: Int): Int { for (i in 0 until mHeaderRects.size()) { @@ -108,7 +108,7 @@ class CustomStickyRecyclerHeadersDecoration private constructor(private val mAda return mHeaderRects.keyAt(i) } } - return -1 + return RecyclerView.NO_POSITION } /** diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/helpers/HeaderPositionCalculator.kt b/app/src/main/java/com/mikepenz/fastadapter/app/helpers/HeaderPositionCalculator.kt index ec7d63588..2769de7ed 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/helpers/HeaderPositionCalculator.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/helpers/HeaderPositionCalculator.kt @@ -81,7 +81,7 @@ class HeaderPositionCalculator(private val mAdapter: StickyRecyclerHeadersAdapte return false } - var nextItemHeaderId: Long = -1 + var nextItemHeaderId = -1L val nextItemPosition = originalPosition + if (isReverseLayout) 1 else -1 if (!indexOutOfBounds(nextItemPosition)) { nextItemHeaderId = mAdapter.getHeaderId(nextItemPosition) diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/CheckBoxSampleItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/CheckBoxSampleItem.kt index 0cead6ca9..c4bbb6958 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/CheckBoxSampleItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/CheckBoxSampleItem.kt @@ -67,7 +67,7 @@ class CheckBoxSampleItem : AbstractItem() { * * @param holder the viewHolder of this item */ - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) holder.checkBox.isChecked = isSelected diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/HeaderSelectionItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/HeaderSelectionItem.kt index 7ae5aae25..3573df1ff 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/HeaderSelectionItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/HeaderSelectionItem.kt @@ -18,7 +18,7 @@ open class HeaderSelectionItem : SimpleSubExpandableItem() { this.mSubSelectionProvider = subSelectionProvider } - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //get the context @@ -34,9 +34,7 @@ open class HeaderSelectionItem : SimpleSubExpandableItem() { var selectedSubItems = 0 if (mSubSelectionProvider != null) selectedSubItems = mSubSelectionProvider?.invoke() ?: 0 - val descr = StringHolder(description?.text) - if (selectedSubItems > 0) - descr.setText("Selected children: " + selectedSubItems + "/" + subItems.size) + val descr = StringHolder(if (selectedSubItems > 0) description?.textString else "Selected children: " + selectedSubItems + "/" + subItems.size) StringHolder.applyToOrHide(descr, holder.description) holder.description.setTextColor(if (selectedSubItems == 0) Color.BLACK else Color.RED) diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/IconItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/IconItem.kt index b81794503..414ad0969 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/IconItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/IconItem.kt @@ -3,6 +3,7 @@ package com.mikepenz.fastadapter.app.items import android.view.View import android.widget.TextView import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.aboutlibraries.util.getThemeColor import com.mikepenz.fastadapter.IExpandable import com.mikepenz.fastadapter.IParentItem import com.mikepenz.fastadapter.ISubItem @@ -10,6 +11,7 @@ import com.mikepenz.fastadapter.app.R import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.view.IconicsImageView /** @@ -61,12 +63,14 @@ class IconItem : AbstractItem(), IExpandable) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //define our data for the view mIcon?.let { - holder.image.icon = IconicsDrawable(holder.image.context, it) + holder.image.icon = IconicsDrawable(holder.image.context, it).apply { + colorInt = holder.view.context.getThemeColor(R.attr.colorOnSurface) + } } holder.name.text = mIcon?.name } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/ImageItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/ImageItem.kt index b221196f1..27f435014 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/ImageItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/ImageItem.kt @@ -69,7 +69,7 @@ class ImageItem : AbstractItem() { * * @param holder the viewHolder of this item */ - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //get the context diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/LetterItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/LetterItem.kt index d51200c59..c7172d1e3 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/LetterItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/LetterItem.kt @@ -14,7 +14,7 @@ class LetterItem(var letter: String) : AbstractItem() { override val layoutRes: Int get() = R.layout.letter_item - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) holder.text.text = letter } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/RadioButtonSampleItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/RadioButtonSampleItem.kt index e9726ab75..a7cc5e86c 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/RadioButtonSampleItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/RadioButtonSampleItem.kt @@ -67,7 +67,7 @@ class RadioButtonSampleItem : AbstractItem() { * * @param holder the viewHolder of this item */ - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) holder.radioButton.isChecked = isSelected diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/RealmSampleUserItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/RealmSampleUserItem.kt index 38842a7dd..46243f0b2 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/RealmSampleUserItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/RealmSampleUserItem.kt @@ -7,6 +7,8 @@ import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.IItem +import com.mikepenz.fastadapter.IItemVHFactory +import com.mikepenz.fastadapter.IItemViewGenerator import com.mikepenz.fastadapter.app.R import com.mikepenz.fastadapter.items.AbstractItem import io.realm.RealmObject @@ -15,18 +17,15 @@ import io.realm.annotations.PrimaryKey import io.realm.annotations.RealmClass @RealmClass -open class RealmSampleUserItem : RealmObject(), IItem { +open class RealmSampleUserItem : RealmObject(), IItem, IItemVHFactory, IItemViewGenerator { // Standard getters & setters generated by your IDE… var name: String? = null private set // the identifier for this item - /** - * @return the identifier of this item - */ @PrimaryKey - override var identifier: Long = -1 + override var identifier: Long = -1L // the tag for this item /** @@ -41,66 +40,35 @@ open class RealmSampleUserItem : RealmObject(), IItem? = null + // defines if this item is enabled - /** - * @return if this item is enabled - */ - /** - * set if this item is enabled - * - * @param enabled true if this item is enabled - * @return this - */ @Ignore override var isEnabled = true // defines if the item is selected - /** - * @return if this item is selected - */ - /** - * set if this item is selected - * - * @param selected true if this item is selected - * @return this - */ @Ignore override var isSelected = false // defines if this item is selectable - /** - * @return if this item is selectable - */ - /** - * set if this item is selectable - * - * @param selectable true if this item is selectable - * @return this - */ @Ignore override var isSelectable = true /** * returns the type of the Item. Can be a hardcoded INT, but preferred is a defined id - * - * @return */ override val type: Int get() = R.id.fastadapter_realm_sample_user_item_id /** * returns the layout for the given item - * - * @return */ - override val layoutRes: Int + val layoutRes: Int get() = R.layout.letter_item /** * set the name of this item - * - * @param name - * @return this */ fun withName(name: String): RealmSampleUserItem { this.name = name @@ -109,9 +77,6 @@ open class RealmSampleUserItem : RealmObject(), IItem) { + override fun bindView(holder: ViewHolder, payloads: List) { //set the selected state of this item. force this otherwise it may is missed when implementing an item holder.itemView.isSelected = isSelected diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleImageItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleImageItem.kt index 9af55fcc3..e9ce19013 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleImageItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleImageItem.kt @@ -7,15 +7,17 @@ import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import butterknife.ButterKnife import com.bumptech.glide.Glide +import com.mikepenz.aboutlibraries.util.getThemeColor +import com.mikepenz.fastadapter.IItemVHFactory import com.mikepenz.fastadapter.app.R -import com.mikepenz.fastadapter.items.AbstractItem +import com.mikepenz.fastadapter.items.BaseItem +import com.mikepenz.fastadapter.items.BaseItemFactory import com.mikepenz.fastadapter.ui.utils.FastAdapterUIUtils -import com.mikepenz.materialize.util.UIUtils /** * Created by mikepenz on 28.12.15. */ -class SimpleImageItem : AbstractItem() { +class SimpleImageItem : BaseItem() { private var mImageUrl: String? = null private var mName: String? = null @@ -31,12 +33,9 @@ class SimpleImageItem : AbstractItem() { get() = R.id.fastadapter_simple_image_item_id /** - * defines the layout which will be used for this item in the list - * - * @return the layout for this item + * defines the factory to create this items VH */ - override val layoutRes: Int - get() = R.layout.simple_image_item + override val factory: IItemVHFactory = SimpleImageItemFactory fun withImage(imageUrl: String): SimpleImageItem { this.mImageUrl = imageUrl @@ -68,7 +67,7 @@ class SimpleImageItem : AbstractItem() { * * @param holder the viewHolder of this item */ - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //get the context @@ -85,7 +84,7 @@ class SimpleImageItem : AbstractItem() { holder.imageView.setImageBitmap(null) //set the background for the item - val color = UIUtils.getThemeColor(ctx, R.attr.colorPrimary) + val color = ctx.getThemeColor(R.attr.colorPrimary, R.color.colorPrimary) holder.view.clearAnimation() holder.view.foreground = FastAdapterUIUtils.getSelectablePressedBackground(ctx, FastAdapterUIUtils.adjustAlpha(color, 100), 50, true) @@ -102,9 +101,6 @@ class SimpleImageItem : AbstractItem() { holder.imageDescription.text = null } - override fun getViewHolder(v: View): ViewHolder { - return ViewHolder(v) - } /** * our ViewHolder @@ -132,3 +128,20 @@ class SimpleImageItem : AbstractItem() { } } } + +/** + * Created by mikepenz on 28.12.15. + */ +object SimpleImageItemFactory : BaseItemFactory() { + /** + * defines the layout which will be used for this item in the list + * + * @return the layout for this item + */ + override val layoutRes: Int + get() = R.layout.simple_image_item + + override fun getViewHolder(v: View): SimpleImageItem.ViewHolder { + return SimpleImageItem.ViewHolder(v) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleItem.kt index 87fa970f3..bef03a2a1 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/SimpleItem.kt @@ -10,7 +10,6 @@ import com.mikepenz.fastadapter.drag.IDraggable import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.ui.utils.FastAdapterUIUtils import com.mikepenz.materialdrawer.holder.StringHolder -import com.mikepenz.materialize.util.UIUtils /** * Created by mikepenz on 28.12.15. @@ -85,12 +84,12 @@ open class SimpleItem : AbstractItem(), IDraggable { var name: TextView = view.findViewById(R.id.material_drawer_name) var description: TextView = view.findViewById(R.id.material_drawer_description) - override fun bindView(item: SimpleItem, payloads: MutableList) { + override fun bindView(item: SimpleItem, payloads: List) { //get the context val ctx = itemView.context //set the background for the item - UIUtils.setBackground(view, FastAdapterUIUtils.getSelectableBackground(ctx, Color.RED, true)) + view.background = FastAdapterUIUtils.getSelectableBackground(ctx, Color.RED, true) //set the text for the name StringHolder.applyTo(item.name, name) //set the text for the description or hide diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableDrawerItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableDrawerItem.kt new file mode 100644 index 000000000..36a072209 --- /dev/null +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableDrawerItem.kt @@ -0,0 +1,148 @@ +package com.mikepenz.fastadapter.app.items + +import android.graphics.Color +import android.view.View +import android.widget.TextView +import androidx.annotation.StringRes +import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.fastadapter.app.R +import com.mikepenz.fastadapter.app.adapters.IDraggableViewHolder +import com.mikepenz.fastadapter.drag.IDraggable +import com.mikepenz.fastadapter.items.AbstractItem +import com.mikepenz.fastadapter.swipe.IDrawerSwipeableViewHolder +import com.mikepenz.fastadapter.swipe.ISwipeable +import com.mikepenz.materialdrawer.holder.StringHolder +import io.reactivex.functions.Consumer + + +/** + * Created by Robb on 2020-07-03 + */ +class SwipeableDrawerItem : AbstractItem(), ISwipeable, IDraggable { + + var name: StringHolder? = null + var description: StringHolder? = null + + var deleteAction: Consumer? = null + var archiveAction: Consumer? = null + var shareAction: Consumer? = null + override var isSwipeable = true + override var isDraggable = true + + /** + * defines the type defining this item. must be unique. preferably an id + * + * @return the type + */ + override val type: Int + get() = R.id.fastadapter_swipable_drawer_item_id + + /** + * defines the layout which will be used for this item in the list + * + * @return the layout for this item + */ + override val layoutRes: Int + get() = R.layout.swipeable_drawer_item + + fun withName(Name: String): SwipeableDrawerItem { + this.name = StringHolder(Name) + return this + } + + fun withName(@StringRes NameRes: Int): SwipeableDrawerItem { + this.name = StringHolder(NameRes) + return this + } + + fun withDescription(description: String): SwipeableDrawerItem { + this.description = StringHolder(description) + return this + } + + fun withDescription(@StringRes descriptionRes: Int): SwipeableDrawerItem { + this.description = StringHolder(descriptionRes) + return this + } + + fun withIsSwipeable(swipeable: Boolean): SwipeableDrawerItem { + this.isSwipeable = swipeable + return this + } + + fun withIsDraggable(draggable: Boolean): SwipeableDrawerItem { + this.isDraggable = draggable + return this + } + + /** + * binds the data of this item onto the viewHolder + * + * @param holder the viewHolder of this item + */ + override fun bindView(holder: ViewHolder, payloads: List) { + super.bindView(holder, payloads) + + //set the text for the name + StringHolder.applyTo(name, holder.name) + //set the text for the description or hide + StringHolder.applyToOrHide(description, holder.description) + + holder.deleteActionRunnable = Runnable { deleteAction?.accept(this) } + holder.archiveActionRunnable = Runnable { archiveAction?.accept(this) } + holder.shareActionRunnable = Runnable { shareAction?.accept(this) } + } + + override fun unbindView(holder: ViewHolder) { + super.unbindView(holder) + holder.name.text = null + holder.description.text = null + holder.deleteActionRunnable = null + holder.archiveActionRunnable = null + holder.shareActionRunnable = null + holder.itemContent.translationX = 0f + } + + override fun getViewHolder(v: View): ViewHolder { + return ViewHolder(v) + } + + /** + * our ViewHolder + */ + class ViewHolder(view: View) : RecyclerView.ViewHolder(view), IDraggableViewHolder, IDrawerSwipeableViewHolder { + var name: TextView = view.findViewById(R.id.material_drawer_name) + var description: TextView = view.findViewById(R.id.material_drawer_description) + var archiveBtn: View = view.findViewById(R.id.archive_btn) + var deleteBtn: View = view.findViewById(R.id.delete_btn) + var shareBtn: View = view.findViewById(R.id.share_btn) + var itemContent: View = view.findViewById(R.id.item_content) + + var deleteActionRunnable: Runnable? = null + var archiveActionRunnable: Runnable? = null + var shareActionRunnable: Runnable? = null + + init { + deleteBtn.setOnClickListener { + deleteActionRunnable?.run() + } + archiveBtn.setOnClickListener { + archiveActionRunnable?.run() + } + shareBtn.setOnClickListener { + shareActionRunnable?.run() + } + } + + override fun onDropped() { + itemContent.setBackgroundColor(Color.WHITE) + } + + override fun onDragged() { + itemContent.setBackgroundColor(Color.LTGRAY) + } + + override val swipeableView: View + get() = itemContent + } +} diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableItem.kt index 946ef1435..a6184cf48 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/SwipeableItem.kt @@ -1,12 +1,13 @@ package com.mikepenz.fastadapter.app.items +import android.graphics.Color import android.view.View import android.widget.TextView import androidx.annotation.StringRes -import androidx.core.content.ContextCompat import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.app.R +import com.mikepenz.fastadapter.app.adapters.IDraggableViewHolder import com.mikepenz.fastadapter.drag.IDraggable import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.swipe.ISwipeable @@ -81,7 +82,7 @@ class SwipeableItem : AbstractItem(), ISwipeable, IDra * * @param holder the viewHolder of this item */ - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //set the text for the name @@ -97,7 +98,7 @@ class SwipeableItem : AbstractItem(), ISwipeable, IDra if (swipedDirection != 0) { swipedAction = holder.itemView.context.getString(R.string.action_undo) swipedText = if (swipedDirection == ItemTouchHelper.LEFT) "Removed" else "Archived" - holder.swipeResultContent.setBackgroundColor(ContextCompat.getColor(holder.itemView.context, if (swipedDirection == ItemTouchHelper.LEFT) R.color.md_red_900 else R.color.md_blue_900)) + holder.swipeResultContent.setBackgroundColor(if (swipedDirection == ItemTouchHelper.LEFT) Color.RED else Color.BLUE) } holder.swipedAction.text = swipedAction ?: "" holder.swipedText.text = swipedText ?: "" @@ -120,7 +121,7 @@ class SwipeableItem : AbstractItem(), ISwipeable, IDra /** * our ViewHolder */ - class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + class ViewHolder(view: View) : RecyclerView.ViewHolder(view), IDraggableViewHolder { var name: TextView = view.findViewById(R.id.material_drawer_name) var description: TextView = view.findViewById(R.id.material_drawer_description) var swipeResultContent: View = view.findViewById(R.id.swipe_result_content) @@ -135,5 +136,13 @@ class SwipeableItem : AbstractItem(), ISwipeable, IDra swipedActionRunnable?.run() } } + + override fun onDropped() { + itemContent.setBackgroundColor(Color.TRANSPARENT) + } + + override fun onDragged() { + itemContent.setBackgroundColor(Color.LTGRAY) + } } } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubExpandableItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubExpandableItem.kt index 6618a2bae..95f4f2131 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubExpandableItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubExpandableItem.kt @@ -107,7 +107,7 @@ open class SimpleSubExpandableItem : AbstractExpandableItem) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //get the context diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubItem.kt index ab80680f4..6b7667fbd 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/items/expandable/SimpleSubItem.kt @@ -72,7 +72,7 @@ open class SimpleSubItem : AbstractExpandableItem(), I * * @param holder the viewHolder of this item */ - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //get the context diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/model/ModelIconItem.kt b/app/src/main/java/com/mikepenz/fastadapter/app/model/ModelIconItem.kt index 103a59902..982e61475 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/model/ModelIconItem.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/model/ModelIconItem.kt @@ -3,9 +3,11 @@ package com.mikepenz.fastadapter.app.model import android.view.View import android.widget.TextView import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.aboutlibraries.util.getThemeColor import com.mikepenz.fastadapter.app.R import com.mikepenz.fastadapter.items.ModelAbstractItem import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.view.IconicsImageView /** @@ -34,11 +36,13 @@ open class ModelIconItem(icon: IconModel) : ModelAbstractItem) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) //define our data for the view - holder.image.icon = IconicsDrawable(holder.image.context, model.icon) + holder.image.icon = IconicsDrawable(holder.image.context, model.icon).apply { + colorInt = holder.view.context.getThemeColor(R.attr.colorOnSurface) + } holder.name.text = model.icon.name } diff --git a/app/src/main/java/com/mikepenz/fastadapter/app/paged/DemoEntity.kt b/app/src/main/java/com/mikepenz/fastadapter/app/paged/DemoEntity.kt index c117fbc13..794953665 100644 --- a/app/src/main/java/com/mikepenz/fastadapter/app/paged/DemoEntity.kt +++ b/app/src/main/java/com/mikepenz/fastadapter/app/paged/DemoEntity.kt @@ -7,22 +7,17 @@ import androidx.room.PrimaryKey * https://www.zoftino.com/pagination-in-android-using-paging-library */ @Entity -class DemoEntity { +class DemoEntity() { @PrimaryKey(autoGenerate = true) var identifier: Int = 0 var data1: String? = null var data2: String? = null - constructor() { - // required - } - - constructor(data1: String, data2: String) { + constructor(data1: String, data2: String) : this() { this.data1 = data1 this.data2 = data2 } - override fun equals(other: Any?): Boolean { if (other === this) return true diff --git a/app/src/main/res/drawable-v21/button_rect_list_normal.xml b/app/src/main/res/drawable-v21/button_rect_list_normal.xml new file mode 100644 index 000000000..9c3b65cc9 --- /dev/null +++ b/app/src/main/res/drawable-v21/button_rect_list_normal.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_rect_list_normal.xml b/app/src/main/res/drawable/button_rect_list_normal.xml index 17e4d7e7b..61486bbdc 100644 --- a/app/src/main/res/drawable/button_rect_list_normal.xml +++ b/app/src/main/res/drawable/button_rect_list_normal.xml @@ -1,5 +1,5 @@ - - - + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2b78ac202..31d9c044f 100755 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,41 @@ - + android:fitsSystemWindows="true"> - - - + android:gravity="center"> + + - - \ No newline at end of file + android:padding="8dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbar" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_sample.xml b/app/src/main/res/layout/activity_sample.xml index c9d4217fe..87accf82d 100755 --- a/app/src/main/res/layout/activity_sample.xml +++ b/app/src/main/res/layout/activity_sample.xml @@ -1,21 +1,29 @@ - + style="?toolbarStyle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:elevation="4dp" + android:fitsSystemWindows="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbar"> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_sort.xml b/app/src/main/res/layout/activity_sort.xml deleted file mode 100644 index 2d8a21237..000000000 --- a/app/src/main/res/layout/activity_sort.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/expandable_item.xml b/app/src/main/res/layout/expandable_item.xml index b8e5a1638..41d728887 100755 --- a/app/src/main/res/layout/expandable_item.xml +++ b/app/src/main/res/layout/expandable_item.xml @@ -47,7 +47,7 @@ android:layout_width="16dp" android:layout_height="16dp" android:layout_marginTop="@dimen/material_drawer_vertical_padding" - app:iiv_color="@color/md_black_1000" + app:iiv_color="?colorOnSurface" app:iiv_icon="gmd-keyboard-arrow-up" app:iiv_size="16dp" /> diff --git a/app/src/main/res/layout/icon_item.xml b/app/src/main/res/layout/icon_item.xml index ae728b687..0a2a5aaad 100755 --- a/app/src/main/res/layout/icon_item.xml +++ b/app/src/main/res/layout/icon_item.xml @@ -13,33 +13,38 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> + - + - + + + android:layout_height="wrap_content" + android:layout_margin="5dp" + android:clickable="true" + android:orientation="horizontal"> + + - + - \ No newline at end of file + + \ No newline at end of file diff --git a/app/src/main/res/layout/right_icon_item.xml b/app/src/main/res/layout/right_icon_item.xml index c8de134e5..bbb4e5ba6 100755 --- a/app/src/main/res/layout/right_icon_item.xml +++ b/app/src/main/res/layout/right_icon_item.xml @@ -28,10 +28,9 @@ android:background="@drawable/button_rect_list_normal" android:clickable="false" android:gravity="center_vertical" + android:paddingStart="8dp" android:paddingLeft="8dp" android:paddingRight="56dp" - android:paddingStart="8dp" - android:textColor="@color/md_light_primary_text" android:textSize="14sp" /> + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/swipeable_item.xml b/app/src/main/res/layout/swipeable_item.xml index 3b4a4807d..d97dd72ea 100644 --- a/app/src/main/res/layout/swipeable_item.xml +++ b/app/src/main/res/layout/swipeable_item.xml @@ -5,28 +5,28 @@ android:layout_height="@dimen/material_drawer_item_primary"> + android:visibility="visible"> @@ -38,25 +38,25 @@ android:gravity="center_vertical|start" android:lines="1" android:singleLine="true" - android:textDirection="anyRtl" + android:text="@string/action_undo" android:textAllCaps="true" android:textColor="@android:color/primary_text_dark" - android:textStyle="bold" + android:textDirection="anyRtl" android:textSize="@dimen/material_drawer_item_primary_description" - android:text="@string/action_undo" /> + android:textStyle="bold" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4dfd26c76..5603e4086 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,8 +5,10 @@ PageListAdapter SimpleItemList Sample Filter, Drag&Drop - SwipeList Sample + SwipeList Sample (delayed) Swipe, leave-behinds and actions + SwipeList Sample (drawer) + Swipe, buttons and actions IconGrid Sample Grid, Expandable ImageList Sample diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 16d39bdf5..f958b7fa1 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,8 +1,17 @@ - + + + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..62009613f --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0275e605e..8bc658854 100644 --- a/build.gradle +++ b/build.gradle @@ -2,35 +2,35 @@ buildscript { ext { release = [ - versionName: "4.1.2", - versionCode: 4102 + versionName: "5.2.4", + versionCode: 5024 ] setup = [ - compileSdk: 29, - buildTools: "29.0.2", - minSdk : 14, - targetSdk : 28 + gradleTools: '4.0.2', + compileSdk : 30, + buildTools : "30.0.2", + minSdk : 16, + targetSdk : 30 ] versions = [ - androidX : '1.0.0', - recyclerView : '1.1.0-beta05', - material : '1.1.0-rc01', - appcompat : '1.1.0', - drawerlayout : '1.1.0-alpha03', - constraintLayout: '2.0.0-beta3', + androidX : '1.1.0', + recyclerView : '1.1.0', + material : '1.2.1', + appcompat : '1.2.0', + drawerlayout : '1.1.0', + constraintLayout: '2.0.0', cardview : '1.0.0', - kotlin : '1.3.61', - materialize : '1.2.1', - iconics : '4.0.1', - materialdrawer : '7.0.0-rc08', - aboutlib : '7.0.4', - roboelectric : '4.3', + kotlin : '1.4.10', + iconics : '5.0.0', + materialdrawer : '8.1.6', + aboutlib : '8.4.2', + roboelectric : '4.4', detekt : '1.0.1', - paging : "2.1.0", - room : "1.1.1", - lifecycle : "1.1.1" + paging : "2.1.2", + room : "2.2.5", + lifecycle : "2.2.0" ] } @@ -42,11 +42,12 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath "com.android.tools.build:gradle:${setup.gradleTools}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5' classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:${versions.detekt}" + classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${versions.aboutlib}" } } @@ -58,6 +59,7 @@ allprojects { jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url "https://jitpack.io" } + maven { url "https://dl.bintray.com/mikepenz/maven" } } } diff --git a/gradle.properties b/gradle.properties index 169f1071e..ff4c35d7c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,11 +14,9 @@ POM_GITHUB_README=README.md POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo - POM_DEVELOPER_ID=mikepenz POM_DEVELOPER_NAME=Mike Penz - android.useAndroidX=true android.enableJetifier=true - -android.jetifier.blacklist=butterknife-compiler \ No newline at end of file +android.jetifier.blacklist=butterknife-compiler +org.gradle.jvmargs=-Xmx4G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf01..e708b1c02 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e3df5d9cd..33682bbbf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sat Oct 05 10:31:00 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/gradlew b/gradlew index 83f2acfdc..4f906e0c8 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a141..ac1b06f93 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/library-core/build.gradle b/library-core/build.gradle index d3f492a6f..a10f08d95 100644 --- a/library-core/build.gradle +++ b/library-core/build.gradle @@ -39,16 +39,16 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" implementation "androidx.appcompat:appcompat:${versions.appcompat}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.androidX}" - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation "org.robolectric:robolectric:${versions.roboelectric}" - testImplementation 'com.squareup.assertj:assertj-android:1.1.1' - testImplementation 'com.squareup.assertj:assertj-android-design:1.1.1@aar' - testImplementation 'com.squareup.assertj:assertj-android-appcompat-v7:1.1.1@aar' - testImplementation("com.squareup.assertj:assertj-android-support-v4:1.1.1@aar") { + testImplementation 'com.squareup.assertj:assertj-android:1.2.0' + testImplementation 'com.squareup.assertj:assertj-android-design:1.2.0@aar' + testImplementation 'com.squareup.assertj:assertj-android-appcompat-v7:1.2.0@aar' + testImplementation("com.squareup.assertj:assertj-android-support-v4:1.2.0@aar") { exclude group: "com.android.support", module: "support-annotations" exclude group: "com.android.support", module: "support-v4" } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/AbstractAdapter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/AbstractAdapter.kt index 77a955af0..95265bea9 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/AbstractAdapter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/AbstractAdapter.kt @@ -5,29 +5,7 @@ package com.mikepenz.fastadapter */ abstract class AbstractAdapter : IAdapter { override var fastAdapter: FastAdapter? = null - /** - * returs the position of this Adapter in the FastAdapter - * - * @return the position of this Adapter in the FastAdapter - */ - /** - * sets the position of this Adapter in the FastAdapter - * @param order the position of this Adapter in the FastAdapter - */ - override var order = -1 - /** - * internal mapper to remember and add possible types for the RecyclerView - * - * @param items - */ - override fun mapPossibleTypes(items: Iterable?) { - fastAdapter?.let { fastAdapter -> - if (items != null) { - for (item in items) { - fastAdapter.registerTypeInstance(item) - } - } - } - } + /** The position of this Adapter in the FastAdapter */ + override var order: Int = -1 } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/FastAdapter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/FastAdapter.kt index 44dc70af3..12f28bcaa 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/FastAdapter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/FastAdapter.kt @@ -13,7 +13,7 @@ import com.mikepenz.fastadapter.dsl.FastAdapterDsl import com.mikepenz.fastadapter.extensions.ExtensionsFactories import com.mikepenz.fastadapter.listeners.* import com.mikepenz.fastadapter.utils.AdapterPredicate -import com.mikepenz.fastadapter.utils.DefaultTypeInstanceCache +import com.mikepenz.fastadapter.utils.DefaultItemVHFactoryCache import com.mikepenz.fastadapter.utils.Triple import com.mikepenz.fastadapter.utils.attachToView import java.util.* @@ -45,13 +45,13 @@ open class FastAdapter : RecyclerView.Adapter>() /** - * Sets an type instance cache to this fast adapter instance. - * The cache will manage the type instances to create new views more efficient. - * Normally an shared cache is used over all adapter instances. + * Sets an item factory cache to this fast adapter instance. + * The cache will manage the item factories to create new views more efficient. + * Normally a shared cache is used over all adapter instances. * - * typeInstanceCache a custom `TypeInstanceCache` implementation + * DefaultItemFactoryCache a custom `IItemFactoryCache` implementation */ - open var typeInstanceCache: ITypeInstanceCache = DefaultTypeInstanceCache() + open var itemVHFactoryCache: IItemVHFactoryCache> = DefaultItemVHFactoryCache() // cache the sizes of the different adapters so we can access the items more performant private val adapterSizes = SparseArray>() // the total size @@ -59,9 +59,7 @@ open class FastAdapter : RecyclerView.Adapter>? = null - /** - * The eventHooks handled by this FastAdapter - */ + /** The eventHooks handled by this FastAdapter */ val eventHooks: MutableList> get() = _eventHooks ?: LinkedList>().also { _eventHooks = it } @@ -82,12 +80,12 @@ open class FastAdapter : RecyclerView.Adapter? = null @@ -106,9 +104,7 @@ open class FastAdapter : RecyclerView.Adapter> get() = extensionsCache.values - /** - * the ClickEventHook to hook onto the itemView of a viewholder - */ + /** The ClickEventHook to hook onto the itemView of a viewholder */ @Suppress("UNCHECKED_CAST") open val viewClickListener: ClickEventHook = object : ClickEventHook() { override fun onClick(v: View, position: Int, fastAdapter: FastAdapter, item: Item) { @@ -124,9 +120,7 @@ open class FastAdapter : RecyclerView.Adapter = object : LongClickEventHook() { override fun onLongClick(v: View, position: Int, fastAdapter: FastAdapter, item: Item): Boolean { if (!item.isEnabled) return false @@ -140,9 +134,7 @@ open class FastAdapter : RecyclerView.Adapter = object : TouchEventHook() { override fun onTouch(v: View, event: MotionEvent, position: Int, fastAdapter: FastAdapter, item: Item): Boolean { for (ext in fastAdapter.extensionsCache.values) { @@ -159,14 +151,14 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter) { adapter.fastAdapter = this - adapter.mapPossibleTypes(adapter.adapterItems) adapters.forEachIndexed { i, item -> item.order = i } cacheSizes() } @@ -213,10 +204,6 @@ open class FastAdapter : RecyclerView.Adapter> addExtension(extension: E): FastAdapter { if (extensionsCache.containsKey(extension.javaClass)) { throw IllegalStateException("The given extension was already registered with this FastAdapter instance") @@ -254,7 +241,7 @@ open class FastAdapter : RecyclerView.Adapter> requireOrCreateExtension(): T = getOrCreateExtension(T::class.java)!! /** - * adds a new event hook for an item + * Adds a new event hook for an item * NOTE: this has to be called before adding the first items, as this won't be called anymore after the ViewHolders were created * * @param eventHook the event hook to be added for an item @@ -266,7 +253,7 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter) { + registerItemFactory(item.type, item) + } else { + item.factory?.let { + registerItemFactory(item.type, it) + } + } + // note if the item does not implement `IItemFactory<*>`, and thus requires you to register the factory for the type. + } + + /** + * Register a new type factory into the TypeInstances to be able to efficiently create thew ViewHolders + * + * @param item an IItem which will be shown in the list + */ + fun registerItemFactory(type: Int, item: IItemVHFactory<*>) { + itemVHFactoryCache.register(type, item) } /** - * gets the TypeInstance remembered within the FastAdapter for an item + * Gets the TypeInstance remembered within the FastAdapter for an item * * @param type the int type of the item * @return the Item typeInstance */ - fun getTypeInstance(type: Int): Item { - return typeInstanceCache[type] + fun getTypeInstance(type: Int): IItemVHFactory<*> { + return itemVHFactoryCache[type] } /** - * clears the internal mapper - be sure, to remap everything before going on + * Clears the internal mapper - be sure, to remap everything before going on */ fun clearTypeInstance() { - typeInstanceCache.clear() + itemVHFactoryCache.clear() } /** - * helper method to get the position from a holder + * Helper method to get the position from a holder * overwrite this if you have an adapter adding additional items inbetwean * * @param holder the viewHolder of the item @@ -343,9 +346,8 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter) { + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List) { //we do not want the binding to happen twice (the legacyBindViewMode if (!legacyBindViewMode) { if (verboseLoggingEnabled) @@ -409,7 +411,7 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter (the found item, and it's global position if it is currently displayed) or null */ open fun getItemById(identifier: Long): Pair? { if (identifier == -1L) { @@ -525,11 +527,7 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter() val index = floorIndex(adapterSizes, position) if (index != -1) { - relativeInfo.item = adapterSizes.valueAt(index) - .getAdapterItem(position - adapterSizes.keyAt(index)) - relativeInfo.adapter = adapterSizes.valueAt(index) - relativeInfo.position = position + val peeked = adapterSizes.valueAt(index).peekAdapterItem(position - adapterSizes.keyAt(index)) + if (peeked != null) { + relativeInfo.item = peeked + relativeInfo.adapter = adapterSizes.valueAt(index) + relativeInfo.position = position + } } return relativeInfo } @@ -572,17 +572,22 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter The first value is true (it is always not null), the second contains the item and the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) */ fun recursive(predicate: AdapterPredicate, stopOnMatch: Boolean): Triple { return recursive(predicate, 0, stopOnMatch) } /** - * util function which recursively iterates over all items and subItems of the given adapter. + * Util function which recursively iterates over all items and subItems of the given adapter. * It executes the given `predicate` on every item and will either stop if that function returns true, or continue (if stopOnMatch is false) * * @param predicate the predicate to run on every item, to check for a match or do some changes (e.g. select) * @param globalStartPosition the start position at which we star tto recursively iterate over the items. (This will not stop at the end of a sub hierarchy!) * @param stopOnMatch defines if we should stop iterating after the first match - * @return Triple<Boolean, IItem, Integer> The first value is true (it is always not null), the second contains the item and the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) + * @return Triple The first value is true (it is always not null), the second contains the item and the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) */ fun recursive(predicate: AdapterPredicate, globalStartPosition: Int, stopOnMatch: Boolean): Triple { for (i in globalStartPosition until itemCount) { @@ -836,12 +838,12 @@ open class FastAdapter : RecyclerView.Adapter { var adapter: IAdapter? = null var item: Item? = null - var position = -1 + var position = RecyclerView.NO_POSITION } /** @@ -852,32 +854,24 @@ open class FastAdapter : RecyclerView.Adapter(itemView: View) : RecyclerView.ViewHolder(itemView) { - /** - * binds the data of this item onto the viewHolder - */ - abstract fun bindView(item: Item, payloads: MutableList) + /** Binds the data of this item onto the viewHolder */ + abstract fun bindView(item: Item, payloads: List) - /** - * View needs to release resources when its recycled - */ + /** View needs to release resources when its recycled */ abstract fun unbindView(item: Item) - /** - * View got attached to the window - */ - fun attachToWindow(item: Item) {} + /** View got attached to the window */ + open fun attachToWindow(item: Item) {} - /** - * View got detached from the window - */ - fun detachFromWindow(item: Item) {} + /** View got detached from the window */ + open fun detachFromWindow(item: Item) {} /** * View is in a transient state and could not be recycled * * @return return true if you want to recycle anyways (after clearing animations or so) */ - fun failedToRecycle(item: Item): Boolean { + open fun failedToRecycle(item: Item): Boolean { return false } } @@ -894,40 +888,40 @@ open class FastAdapter : RecyclerView.Adapter> with(adapter: A): FastAdapter { + fun with(adapter: IAdapter): FastAdapter { val fastAdapter = FastAdapter() fastAdapter.addAdapter(0, adapter) return fastAdapter } /** - * creates a new FastAdapter with the provided adapters + * Creates a new FastAdapter with the provided adapters * if adapters is null, a default ItemAdapter is defined * * @param adapters the adapters which this FastAdapter should use * @return a new FastAdapter */ @JvmStatic - fun > with(adapters: Collection?): FastAdapter { + fun with(adapters: Collection>?): FastAdapter { return with(adapters, null) } /** - * creates a new FastAdapter with the provided adapters + * Creates a new FastAdapter with the provided adapters * if adapters is null, a default ItemAdapter is defined * * @param adapters the adapters which this FastAdapter should use * @return a new FastAdapter */ @JvmStatic - fun > with(adapters: Collection?, extensions: Collection>?): FastAdapter { + fun with(adapters: Collection>?, extensions: Collection>? = null): FastAdapter { val fastAdapter = FastAdapter() if (adapters == null) { fastAdapter.adapters.add(items() as IAdapter) @@ -954,7 +948,7 @@ open class FastAdapter : RecyclerView.Adapter /** - * convenient helper method to get the Item from a holder + * Convenient helper method to get the Item from a holder * * @param holder the ViewHolder for which we want to retrieve the item * @return the Item found for this ViewHolder @@ -969,7 +963,7 @@ open class FastAdapter : RecyclerView.Adapter : RecyclerView.Adapter(holder)?.getItem(position) /** - * convenient helper method to get the Item from a holder via the defined tag + * Convenient helper method to get the Item from a holder via the defined tag * * @param holder the ViewHolder for which we want to retrieve the item * @return the Item found for the given position and that ViewHolder @@ -998,9 +992,9 @@ open class FastAdapter : RecyclerView.Adapter the type of the `Item` - * @return Triple<Boolean, IItem, Integer> The first value is true (it is always not null), the second contains the item and the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) - */ + * @param Item the type of the `Item` + * @return The first value is true (it is always not null), the second contains the item and the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) + */ @JvmStatic fun recursiveSub( lastParentAdapter: IAdapter, @@ -1013,7 +1007,7 @@ open class FastAdapter : RecyclerView.Adapter (sub as Item).let { subItem -> - if (predicate.apply(lastParentAdapter, lastParentPosition, subItem, -1) && stopOnMatch) { + if (predicate.apply(lastParentAdapter, lastParentPosition, subItem, RecyclerView.NO_POSITION) && stopOnMatch) { return Triple(true, sub, null) } } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IAdapter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IAdapter.kt index a5017f954..aca96e03e 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IAdapter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IAdapter.kt @@ -9,47 +9,32 @@ typealias GenericAdapter = IAdapter * Created by mikepenz on 27.12.15. */ interface IAdapter { - /** - * defines the FastAdapter which manages all the core logic - * - * @return the FastAdapter specified for this IAdapter - */ + + /** Defines the FastAdapter which manages all the core logic */ var fastAdapter: FastAdapter? - /** - * returs the position of this Adapter in the FastAdapter - * - * @return the position of this Adapter in the FastAdapter - */ - /** - * sets the position of this Adapter in the FastAdapter - */ + /** Defines the position of this Adapter in the FastAdapter */ var order: Int - /** - * defines the count of items of THIS adapter - * - * @return the count of items of THIS adapter - */ + /** Defines the count of items of THIS adapter */ val adapterItemCount: Int - /** - * @return the list of defined items within THIS adapter - */ + /** Defines the list of defined items within THIS adapter */ val adapterItems: List /** - * internal mapper to remember and add possible types for the RecyclerView - * - * @param items + * @param position the relative position + * @return the item at the given relative position within this adapter */ - fun mapPossibleTypes(items: Iterable?) + fun getAdapterItem(position: Int): Item /** * @param position the relative position - * @return the item at the given relative position within this adapter + * @return the item at the given relative position within this adapter if it has been loaded */ - fun getAdapterItem(position: Int): Item + fun peekAdapterItem(position: Int): Item? { + return getAdapterItem(position) + } /** * Searches for the given item and calculates its relative position diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IAdapterNotifier.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IAdapterNotifier.kt index 95cec9421..cf2cfcb30 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IAdapterNotifier.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IAdapterNotifier.kt @@ -27,8 +27,8 @@ interface IAdapterNotifier { } } newItemsCount == 0 -> fastAdapter.notifyAdapterItemRangeRemoved(itemsBeforeThisAdapter, previousItemsCount) - else -> //this condition should practically never happen - fastAdapter.notifyAdapterDataSetChanged() + //this condition practically should never happen + else -> fastAdapter.notifyAdapterDataSetChanged() } return false } @@ -50,8 +50,8 @@ interface IAdapterNotifier { fastAdapter.notifyAdapterItemRangeRemoved(itemsBeforeThisAdapter + newItemsCount, previousItemsCount - newItemsCount) } newItemsCount == 0 -> fastAdapter.notifyAdapterItemRangeRemoved(itemsBeforeThisAdapter, previousItemsCount) - else -> //this condition should practically never happen - fastAdapter.notifyAdapterDataSetChanged() + //this condition practically should never happen + else -> fastAdapter.notifyAdapterDataSetChanged() } return false } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IItem.kt index 985167c91..fa31b079b 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IItem.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IItem.kt @@ -1,10 +1,6 @@ package com.mikepenz.fastadapter -import android.content.Context -import android.view.View -import android.view.ViewGroup import androidx.annotation.IdRes -import androidx.annotation.LayoutRes import androidx.recyclerview.widget.RecyclerView /** @@ -17,90 +13,35 @@ typealias GenericItem = IItem */ interface IItem : IIdentifyable { - /** - * a Tag of the Item - */ + /** A Tag of the Item */ var tag: Any? - /** - * If the item is enabled - */ + /** If the item is enabled */ var isEnabled: Boolean - /** - * If the item is selected - */ + /** If the item is selected */ var isSelected: Boolean - /** - * If the item is selectable - */ + /** If the item is selectable */ var isSelectable: Boolean - /** - * The type of the Item. Can be a hardcoded INT, but preferred is a defined id - */ + /** The type of the Item. Can be a hardcoded INT, but preferred is a defined id */ @get:IdRes val type: Int - /** - * The layout for the given item - */ - @get:LayoutRes - val layoutRes: Int - - /** - * generates a view by the defined LayoutRes - * - * @param ctx - * @return - */ - fun generateView(ctx: Context): View + /** The factory to use for creating this item, this does not have to be provided if the IItemFactory is implemented by this item too */ + val factory: IItemVHFactory? - /** - * generates a view by the defined LayoutRes and pass the LayoutParams from the parent - * - * @param ctx - * @param parent - * @return - */ - fun generateView(ctx: Context, parent: ViewGroup): View + /** Binds the data of this item to the given holder */ + fun bindView(holder: VH, payloads: List) - /** - * Generates a ViewHolder from this Item with the given parent - * - * @param parent - * @return - */ - fun getViewHolder(parent: ViewGroup): VH - - /** - * Binds the data of this item to the given holder - * - * @param holder - * @param payloads - */ - fun bindView(holder: VH, payloads: MutableList) - - /** - * View needs to release resources when its recycled - * - * @param holder - */ + /** View needs to release resources when its recycled */ fun unbindView(holder: VH) - /** - * View got attached to the window - * - * @param holder - */ + /** View got attached to the window */ fun attachToWindow(holder: VH) - /** - * View got detached from the window - * - * @param holder - */ + /** View got detached from the window */ fun detachFromWindow(holder: VH) /** @@ -111,11 +52,6 @@ interface IItem : IIdentifyable { */ fun failedToRecycle(holder: VH): Boolean - /** - * If this item equals to the given identifier - * - * @param id - * @return - */ + /** If this item equals to the given identifier */ fun equals(id: Int): Boolean } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IItemAdapter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IItemAdapter.kt index d5c7bb613..78e009e12 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IItemAdapter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IItemAdapter.kt @@ -5,100 +5,73 @@ package com.mikepenz.fastadapter */ interface IItemAdapter : IAdapter { - /** - * The [IIdDistributor] used to provide identifiers to added items (if no identifier was specified prior) - */ + /** The [IIdDistributor] used to provide identifiers to added items (if no identifier was specified prior) */ var idDistributor: IIdDistributor - /** - * set a new list of items and apply it to the existing list (clear - add) for this adapter - * - * @param items - */ + /** Set a new list of items and apply it to the existing list (clear β€” add) for this adapter */ fun set(items: List): IItemAdapter - /** - * sets a complete new list of items onto this adapter, using the new list. Calls notifyDataSetChanged - * - * @param items - */ + /** Sets a complete new list of items onto this adapter, using the new list. Calls notifyDataSetChanged */ fun setNewList(items: List, retainFilter: Boolean = false): IItemAdapter - /** - * add an array of items to the end of the existing items - * - * @param items - */ + /** Add an array of items to the end of the existing items */ fun add(vararg items: Model): IItemAdapter - /** - * add a list of items to the end of the existing items - * - * @param items - */ + /** Add a list of items to the end of the existing items */ fun add(items: List): IItemAdapter - /** - * add a list of items to the end of the existing items - * - * @param items - */ + /** Add a list of items to the end of the existing items */ fun addInternal(items: List): IItemAdapter /** - * add an array of items at the given position within the existing items + * Add an array of items at the given position within the existing items * * @param position the global position - * @param items */ fun add(position: Int, vararg items: Model): IItemAdapter /** - * add a list of items at the given position within the existing items + * Add a list of items at the given position within the existing items * * @param position the global position - * @param items */ fun add(position: Int, items: List): IItemAdapter /** - * add a list of items at the given position within the existing items + * Add a list of items at the given position within the existing items * * @param position the global position - * @param items */ fun addInternal(position: Int, items: List): IItemAdapter /** - * sets an item at the given position, overwriting the previous item + * Sets an item at the given position, overwriting the previous item * * @param position the global position - * @param item */ operator fun set(position: Int, item: Model): IItemAdapter /** - * sets an item at the given position, overwriting the previous item + * Sets an item at the given position, overwriting the previous item * * @param position the global position - * @param item */ fun setInternal(position: Int, item: Item): IItemAdapter /** - * moves the item at the [fromPosition] to the [toPosition] + * Moves the item at the [fromPosition] to the [toPosition] */ fun move(fromPosition: Int, toPosition: Int): IItemAdapter /** - * removes an item at the given position within the existing icons + * Removes an item at the given position within the existing icons * * @param position the global position */ fun remove(position: Int): IItemAdapter /** - * removes a range of items starting with the given position within the existing icons + * Removes a range of items starting with the given position within the existing icons * * @param position the global position * @param itemCount @@ -106,12 +79,12 @@ interface IItemAdapter : IAdapter { fun removeRange(position: Int, itemCount: Int): IItemAdapter /** - * removes all items of this adapter + * Removes all items of this adapter */ fun clear(): IItemAdapter /** - * filters the items with the constraint using the provided Predicate + * Filters the items with the constraint using the provided Predicate * * @param constraint the string used to filter the list */ diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IItemList.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IItemList.kt index 7bf1fcf1a..405a06c23 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IItemList.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IItemList.kt @@ -6,6 +6,8 @@ package com.mikepenz.fastadapter interface IItemList { + var active: Boolean + val isEmpty: Boolean val items: MutableList @@ -33,4 +35,8 @@ interface IItemList { fun addAll(position: Int, items: List, preItemCount: Int) operator fun get(position: Int): Item? + + fun peek(position: Int): Item? { + return get(position) + } } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IItemVHFactory.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IItemVHFactory.kt new file mode 100644 index 000000000..bb936364d --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IItemVHFactory.kt @@ -0,0 +1,17 @@ +package com.mikepenz.fastadapter + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView + +/** + * Kotlin type alias to simplify usage for an all accepting item + */ +typealias GenericItemVHFactory = IItemVHFactory + +/** + * Defines the factory which is capable of creating the ViewHolder for a given Item + */ +interface IItemVHFactory { + /** Generates a ViewHolder from this Item with the given parent */ + fun getViewHolder(parent: ViewGroup): VH +} \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IItemVHFactoryCache.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IItemVHFactoryCache.kt new file mode 100644 index 000000000..f073e1b1a --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IItemVHFactoryCache.kt @@ -0,0 +1,15 @@ +package com.mikepenz.fastadapter + +/** + * Defines the factory logic to generate ViewHolders for an item + */ +interface IItemVHFactoryCache { + + fun register(type: Int, item: ItemVHFactory): Boolean + + operator fun get(type: Int): ItemVHFactory + + fun contains(type: Int): Boolean + + fun clear() +} diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IItemViewGenerator.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IItemViewGenerator.kt new file mode 100644 index 000000000..ce52f5aa4 --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IItemViewGenerator.kt @@ -0,0 +1,41 @@ +package com.mikepenz.fastadapter + +import android.content.Context +import android.view.View +import android.view.ViewGroup + +/** + * Defines an additional interface to more conveniently generate the view of an item if not used in a RV + */ +interface IItemViewGenerator { + /** Generates a view by the defined LayoutRes */ + fun generateView(ctx: Context): View + + /** Generates a view by the defined LayoutRes and pass the LayoutParams from the parent */ + fun generateView(ctx: Context, parent: ViewGroup): View +} + +/** +NOTE This may be implemented as the following code showcases: + +/** Generates a view by the defined LayoutRes */ +override fun generateView(ctx: Context): View { +val viewHolder = getViewHolder(createView(ctx, null)) + +//as we already know the type of our ViewHolder cast it to our type +bindView(viewHolder, Collections.emptyList()) + +//return the bound view +return viewHolder.itemView +} + +/** Generates a view by the defined LayoutRes and pass the LayoutParams from the parent */ +override fun generateView(ctx: Context, parent: ViewGroup): View { +val viewHolder = getViewHolder(createView(ctx, parent)) + +//as we already know the type of our ViewHolder cast it to our type +bindView(viewHolder, Collections.emptyList()) +//return the bound and generatedView +return viewHolder.itemView +} + */ \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IModelItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IModelItem.kt index 80e51cb50..c8036ece6 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IModelItem.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IModelItem.kt @@ -7,8 +7,6 @@ import androidx.recyclerview.widget.RecyclerView */ interface IModelItem : IItem { - /** - * The model of the item - */ + /** The model of the item */ var model: Model } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/IParentItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/IParentItem.kt index 117168bf9..3c9774082 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/IParentItem.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/IParentItem.kt @@ -4,8 +4,6 @@ import androidx.recyclerview.widget.RecyclerView interface IParentItem : IItem { - /** - * The list of subItems - */ + /** The list of subItems */ var subItems: MutableList> } \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/ISelectionListener.kt b/library-core/src/main/java/com/mikepenz/fastadapter/ISelectionListener.kt index 1f05532b4..adad545d1 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/ISelectionListener.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/ISelectionListener.kt @@ -6,10 +6,10 @@ package com.mikepenz.fastadapter interface ISelectionListener { /** - * is called, whenever the provided item is selected or deselected + * Is called, whenever the provided item is selected or deselected * * @param item the item who's selection state changed - * param selected the new selection state of the item + * @param selected the new selection state of the item */ fun onSelectionChanged(item: Item, selected: Boolean) } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/ITypeInstanceCache.kt b/library-core/src/main/java/com/mikepenz/fastadapter/ITypeInstanceCache.kt deleted file mode 100644 index 92f9d15df..000000000 --- a/library-core/src/main/java/com/mikepenz/fastadapter/ITypeInstanceCache.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.mikepenz.fastadapter - -/** - * Created by fabianterhorst on 24.08.17. - */ - -interface ITypeInstanceCache { - - fun register(item: Item): Boolean - - operator fun get(type: Int): Item - - fun clear() -} diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/MutableSubItemList.kt b/library-core/src/main/java/com/mikepenz/fastadapter/MutableSubItemList.kt index 66cd57f9b..7f47789fa 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/MutableSubItemList.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/MutableSubItemList.kt @@ -43,4 +43,14 @@ class MutableSubItemList>(val parent: IParentItem<*>, val list: element.parent = parent return list.set(index, element).also { oldElement -> oldElement.parent = null } } + + override fun clear() { + list.forEach { it.parent = null } + list.clear() + } + + fun setNewList(newList: List) { + clear() + addAll(newList) + } } \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemAdapter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemAdapter.kt index 010225472..469eb9202 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemAdapter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemAdapter.kt @@ -24,7 +24,7 @@ open class ItemAdapter : ModelAdapter { companion object { /** - * static method to retrieve a new `ItemAdapter` + * Static method to retrieve a new `ItemAdapter` * * @return a new ItemAdapter */ diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemFilter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemFilter.kt index 9fbb74afa..1b784d30c 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemFilter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ItemFilter.kt @@ -1,6 +1,7 @@ package com.mikepenz.fastadapter.adapters import android.widget.Filter +import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.GenericItem import com.mikepenz.fastadapter.listeners.ItemFilterListener import com.mikepenz.fastadapter.select.SelectExtension @@ -11,7 +12,7 @@ import kotlin.math.min * ItemFilter which extends the Filter api provided by Android * This calls automatically all required methods, just overwrite the filterItems method */ -open class ItemFilter(private val mItemAdapter: ModelAdapter) : +open class ItemFilter(private val itemAdapter: ModelAdapter) : Filter() { private var originalItems: MutableList? = null var constraint: CharSequence? = null @@ -25,30 +26,30 @@ open class ItemFilter(private val mItemAdapter: Model var filterPredicate: ((item: Item, constraint: CharSequence?) -> Boolean)? = null /** - * helper method to get all selections from the ItemAdapter's original item list + * Helper method to get all selections from the ItemAdapter's original item list * * @return a Set with the global positions of all selected Items */ open val selections: Set get() { - val fastAdapter = mItemAdapter.fastAdapter ?: return emptySet() - val adapterOffset = fastAdapter.getPreItemCountByOrder(mItemAdapter.order) + val fastAdapter = itemAdapter.fastAdapter ?: return emptySet() + val adapterOffset = fastAdapter.getPreItemCountByOrder(itemAdapter.order) return originalItems?.mapIndexedNotNullTo(HashSet()) { index, item -> if (item.isSelected) index + adapterOffset else null } ?: fastAdapter.getExtension>(SelectExtension::class.java)?.selections ?: emptySet() } /** - * helper method to get all selections from the ItemAdapter's original item list + * Helper method to get all selections from the ItemAdapter's original item list * * @return a Set with the selected items out of all items in this itemAdapter (not the listed ones) */ open val selectedItems: Set - get() { - return originalItems?.filterTo(HashSet()) { it.isSelected } - ?: mItemAdapter.fastAdapter?.getExtension>(SelectExtension::class.java)?.selectedItems + get() = originalItems?.filterTo(HashSet()) { it.isSelected } + ?: itemAdapter.fastAdapter + ?.getExtension>(SelectExtension::class.java) + ?.selectedItems ?: emptySet() - } override fun performFiltering(constraint: CharSequence?): FilterResults { val results = FilterResults() @@ -59,7 +60,7 @@ open class ItemFilter(private val mItemAdapter: Model } //call extensions - mItemAdapter.fastAdapter?.extensions?.forEach { adapterExtension -> + itemAdapter.fastAdapter?.extensions?.forEach { adapterExtension -> adapterExtension.performFiltering(constraint) } @@ -67,7 +68,7 @@ open class ItemFilter(private val mItemAdapter: Model // Gets original items or adapter items (set to original items) // Result is always nonnull - val items: List = originalItems ?: ArrayList(mItemAdapter.adapterItems).also { + val items: List = originalItems ?: ArrayList(itemAdapter.adapterItems).also { originalItems = it } @@ -84,7 +85,7 @@ open class ItemFilter(private val mItemAdapter: Model // We perform filtering operation val filteredItems = filterPredicate?.let { filterPredicate -> items.filter { filterPredicate(it, constraint) } - } ?: mItemAdapter.adapterItems + } ?: itemAdapter.adapterItems results.values = filteredItems results.count = filteredItems.size @@ -95,7 +96,7 @@ open class ItemFilter(private val mItemAdapter: Model override fun publishResults(constraint: CharSequence?, results: FilterResults) { // Now we have to inform the adapter about the new list filtered if (results.values != null) { - mItemAdapter.setInternal(results.values as List, false, null) + itemAdapter.setInternal(results.values as List, false, null) } //only fire when we are filtered, not in onreset @@ -130,41 +131,41 @@ open class ItemFilter(private val mItemAdapter: Model * @return the relative position */ fun getAdapterPosition(identifier: Long): Int { - return originalItems?.indexOfFirst { it.identifier == identifier } ?: -1 + return originalItems?.indexOfFirst { it.identifier == identifier } ?: RecyclerView.NO_POSITION } /** - * add an array of items to the end of the existing items + * Add an array of items to the end of the existing items * * @param items the items to add */ @SafeVarargs fun add(vararg items: Item): ModelAdapter<*, Item> { - return add(asList(*items)) + return add(listOf(*items)) } /** - * add a list of items to the end of the existing items + * Add a list of items to the end of the existing items * will prior check if we are currently filtering * * @param items the items to add */ fun add(items: List): ModelAdapter<*, Item> { if (items.isEmpty()) { - return mItemAdapter + return itemAdapter } return originalItems?.let { originalItems -> - if (mItemAdapter.isUseIdDistributor) { - mItemAdapter.idDistributor.checkIds(items) + if (itemAdapter.isUseIdDistributor) { + itemAdapter.idDistributor.checkIds(items) } originalItems.addAll(items) publishResults(constraint, performFiltering(constraint)) - mItemAdapter - } ?: mItemAdapter.addInternal(items) + itemAdapter + } ?: itemAdapter.addInternal(items) } /** - * add an array of items at the given position within the existing items + * Add an array of items at the given position within the existing items * * @param position the global position * @param items the items to add @@ -175,50 +176,50 @@ open class ItemFilter(private val mItemAdapter: Model } /** - * add a list of items at the given position within the existing items + * Add a list of items at the given position within the existing items * * @param position the global position * @param items the items to add */ fun add(position: Int, items: List): ModelAdapter<*, Item> { if (items.isEmpty()) { - return mItemAdapter + return itemAdapter } return originalItems?.let { originalItems -> - if (mItemAdapter.isUseIdDistributor) { - mItemAdapter.idDistributor.checkIds(items) + if (itemAdapter.isUseIdDistributor) { + itemAdapter.idDistributor.checkIds(items) } - mItemAdapter.fastAdapter?.let { fastAdapter -> - val origPosition = getAdapterPosition(mItemAdapter.adapterItems[position]) - fastAdapter.getPreItemCount(position) + itemAdapter.fastAdapter?.let { fastAdapter -> + val origPosition = getAdapterPosition(itemAdapter.adapterItems[position]) - fastAdapter.getPreItemCount(position) originalItems.addAll(origPosition, items) } publishResults(constraint, performFiltering(constraint)) - mItemAdapter - } ?: mItemAdapter.addInternal(position, items) + itemAdapter + } ?: itemAdapter.addInternal(position, items) } /** - * sets an item at the given position, overwriting the previous item + * Sets an item at the given position, overwriting the previous item * * @param position the global position * @param item the item to set */ operator fun set(position: Int, item: Item): ModelAdapter<*, Item> { return originalItems?.let { originalItems -> - if (mItemAdapter.isUseIdDistributor) { - mItemAdapter.idDistributor.checkId(item) + if (itemAdapter.isUseIdDistributor) { + itemAdapter.idDistributor.checkId(item) } - mItemAdapter.fastAdapter?.let { fastAdapter -> - val origPosition = getAdapterPosition(mItemAdapter.adapterItems[position]) - fastAdapter.getPreItemCount(position) + itemAdapter.fastAdapter?.let { fastAdapter -> + val origPosition = getAdapterPosition(itemAdapter.adapterItems[position]) - fastAdapter.getPreItemCount(position) originalItems[origPosition] = item } publishResults(constraint, performFiltering(constraint)) - mItemAdapter - } ?: mItemAdapter.setInternal(position, item) + itemAdapter + } ?: itemAdapter.setInternal(position, item) } /** - * moves an item within the list from a position to a position + * Moves an item within the list from a position to a position * * @param fromPosition the position global from which we want to move * @param toPosition the global position to which to move @@ -226,36 +227,36 @@ open class ItemFilter(private val mItemAdapter: Model */ fun move(fromPosition: Int, toPosition: Int): ModelAdapter<*, Item> { return originalItems?.let { originalItems -> - mItemAdapter.fastAdapter?.getPreItemCount(fromPosition)?.let { preItemCount -> - val adjustedFrom = getAdapterPosition(mItemAdapter.adapterItems[fromPosition]) - val adjustedTo = getAdapterPosition(mItemAdapter.adapterItems[toPosition]) + itemAdapter.fastAdapter?.getPreItemCount(fromPosition)?.let { preItemCount -> + val adjustedFrom = getAdapterPosition(itemAdapter.adapterItems[fromPosition]) + val adjustedTo = getAdapterPosition(itemAdapter.adapterItems[toPosition]) val item = originalItems[adjustedFrom - preItemCount] originalItems.removeAt(adjustedFrom - preItemCount) originalItems.add(adjustedTo - preItemCount, item) performFiltering(constraint) } - mItemAdapter - } ?: mItemAdapter.move(fromPosition, toPosition) + itemAdapter + } ?: itemAdapter.move(fromPosition, toPosition) } /** - * removes an item at the given position within the existing icons + * Removes an item at the given position within the existing icons * * @param position the global position */ fun remove(position: Int): ModelAdapter<*, Item> { return originalItems?.let { originalItems -> - mItemAdapter.fastAdapter?.let { fastAdapter -> - val origPosition = getAdapterPosition(mItemAdapter.adapterItems[position]) - fastAdapter.getPreItemCount(position) + itemAdapter.fastAdapter?.let { fastAdapter -> + val origPosition = getAdapterPosition(itemAdapter.adapterItems[position]) - fastAdapter.getPreItemCount(position) originalItems.removeAt(origPosition) } publishResults(constraint, performFiltering(constraint)) - mItemAdapter - } ?: mItemAdapter.remove(position) + itemAdapter + } ?: itemAdapter.remove(position) } /** - * removes a range of items starting with the given position within the existing icons + * Removes a range of items starting with the given position within the existing icons * * @param position the global position * @param itemCount the count of items which were removed @@ -264,7 +265,7 @@ open class ItemFilter(private val mItemAdapter: Model return originalItems?.let { originalItems -> //global position to relative val length = originalItems.size - mItemAdapter.fastAdapter?.getPreItemCount(position)?.let { preItemCount -> + itemAdapter.fastAdapter?.getPreItemCount(position)?.let { preItemCount -> //make sure we do not delete to many items val saveItemCount = min(itemCount, length - position + preItemCount) for (i in 0 until saveItemCount) { @@ -272,18 +273,18 @@ open class ItemFilter(private val mItemAdapter: Model } publishResults(constraint, performFiltering(constraint)) } - mItemAdapter - } ?: mItemAdapter.removeRange(position, itemCount) + itemAdapter + } ?: itemAdapter.removeRange(position, itemCount) } /** - * removes all items of this adapter + * Removes all items of this adapter */ fun clear(): ModelAdapter<*, Item> { return originalItems?.let { originalItems -> originalItems.clear() publishResults(constraint, performFiltering(constraint)) - mItemAdapter - } ?: mItemAdapter.clear() + itemAdapter + } ?: itemAdapter.clear() } } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ModelAdapter.kt b/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ModelAdapter.kt index 5c16f6779..0c348a6e1 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ModelAdapter.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/adapters/ModelAdapter.kt @@ -1,5 +1,6 @@ package com.mikepenz.fastadapter.adapters +import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.* import com.mikepenz.fastadapter.dsl.FastAdapterDsl import com.mikepenz.fastadapter.utils.AdapterPredicate @@ -7,7 +8,6 @@ import com.mikepenz.fastadapter.utils.DefaultItemList import com.mikepenz.fastadapter.utils.DefaultItemListImpl import com.mikepenz.fastadapter.utils.Triple import java.util.* -import java.util.Arrays.asList /** * Kotlin type alias to simplify usage for an all accepting ModelAdapter @@ -23,6 +23,11 @@ open class ModelAdapter( val itemList: IItemList, var interceptor: (element: Model) -> Item? ) : AbstractAdapter(), IItemAdapter { + + constructor(interceptor: (element: Model) -> Item?) : this( + DefaultItemListImpl(), interceptor + ) + override var fastAdapter: FastAdapter? get() = super.fastAdapter set(fastAdapter) { @@ -32,6 +37,16 @@ open class ModelAdapter( super.fastAdapter = fastAdapter } + /** + * defines if this adapter is currently activly shown in the list + */ + var active: Boolean = true + set(value) { + field = value + itemList.active = value + fastAdapter?.notifyAdapterDataSetChanged() // items are gone + } + open var reverseInterceptor: ((element: Item) -> Model?)? = null override var idDistributor: IIdDistributor = IIdDistributor.DEFAULT as IIdDistributor @@ -43,12 +58,12 @@ open class ModelAdapter( //filters the items /** - * allows you to define your own Filter implementation instead of the default `ItemFilter` + * Allows you to define your own Filter implementation instead of the default `ItemFilter` */ open var itemFilter = ItemFilter(this) /** - * the ModelAdapter does not keep a list of input model's to get retrieve them a `reverseInterceptor` is required + * The ModelAdapter does not keep a list of input model's to get retrieve them a `reverseInterceptor` is required * usually it is used to get the `Model` from a `IModelItem` * * @return a List of initial Model's @@ -68,7 +83,9 @@ open class ModelAdapter( list.add(interceptedItem) } } - else -> throw RuntimeException("to get the list of models, the item either needs to implement `IModelItem` or you have to provide a `reverseInterceptor`") + else -> throw RuntimeException( + "to get the list of models, the item either needs to implement `IModelItem` or you have to provide a `reverseInterceptor`" + ) } } return list @@ -78,7 +95,7 @@ open class ModelAdapter( * @return the count of items within this adapter */ override val adapterItemCount: Int - get() = itemList.size() + get() = if (active) itemList.size() else 0 /** * @return the items within this adapter @@ -86,11 +103,6 @@ open class ModelAdapter( override val adapterItems: MutableList get() = itemList.items - constructor(interceptor: (element: Model) -> Item?) : this( - DefaultItemListImpl(), - interceptor - ) - /** * Generates a `Item` based on it's `Model` using the interceptor * @@ -107,11 +119,10 @@ open class ModelAdapter( * @param models the List of Model which will be used to create the List of Item * @return the generated List of Item */ - open fun intercept(models: List): List = - models.mapNotNull { intercept(it) } + open fun intercept(models: List): List = models.mapNotNull { intercept(it) } /** - * filters the items with the constraint using the provided Predicate + * Filters the items with the constraint using the provided Predicate * * @param constraint the string used to filter the list */ @@ -140,7 +151,7 @@ open class ModelAdapter( } /** - * returns the global position if the relative position within this adapter was given + * Returns the global position if the relative position within this adapter was given * * @param position the relative position * @return the global position @@ -158,7 +169,7 @@ open class ModelAdapter( } /** - * set a new list of items and apply it to the existing list (clear - add) for this adapter + * Set a new list of items and apply it to the existing list (clear - add) for this adapter * NOTE may consider using setNewList if the items list is a reference to the list which is used inside the adapter * * @param items the items to set @@ -173,7 +184,7 @@ open class ModelAdapter( } /** - * set a new list of model items and apply it to the existing list (clear - add) for this adapter + * Set a new list of model items and apply it to the existing list (clear - add) for this adapter * NOTE may consider using setNewList if the items list is a reference to the list which is used inside the adapter * * @param list the items to set @@ -191,7 +202,7 @@ open class ModelAdapter( } /** - * set a new list of model and apply it to the existing list (clear - add) for this adapter + * Set a new list of model and apply it to the existing list (clear - add) for this adapter * NOTE may consider using setNewList if the items list is a reference to the list which is used inside the adapter * * @param items the items to set @@ -217,9 +228,6 @@ open class ModelAdapter( extension[items] = resetFilter } - //map the types - mapPossibleTypes(items) - //forward set val itemsBeforeThisAdapter = fastAdapter?.getPreItemCountByOrder(order) ?: 0 itemList[items, itemsBeforeThisAdapter] = adapterNotifier @@ -228,9 +236,9 @@ open class ModelAdapter( } /** - * sets a complete new list of items onto this adapter, using the new list. Calls notifyDataSetChanged + * Sets a complete new list of items onto this adapter, using the new list. Calls notifyDataSetChanged * - * @param items the new items to set + * @param items the new items to set * @param retainFilter set to true if you want to keep the filter applied * @return this */ @@ -248,8 +256,6 @@ open class ModelAdapter( itemFilter.resetFilter() } - mapPossibleTypes(newItems) - val publishResults = filter != null && retainFilter if (retainFilter) { filter?.let { filterText -> @@ -262,25 +268,24 @@ open class ModelAdapter( } /** - * forces to remap all possible types for the RecyclerView + * Forces to remap all possible types for the RecyclerView */ open fun remapMappedTypes() { fastAdapter?.clearTypeInstance() - mapPossibleTypes(itemList.items) } /** - * add an array of items to the end of the existing items + * Add an array of items to the end of the existing items * * @param items the items to add */ @SafeVarargs override fun add(vararg items: Model): ModelAdapter { - return add(asList(*items)) + return add(listOf(*items)) } /** - * add a list of items to the end of the existing items + * Add a list of items to the end of the existing items * * @param items the items to add */ @@ -298,23 +303,22 @@ open class ModelAdapter( } else { itemList.addAll(items, 0) } - mapPossibleTypes(items) return this } /** - * add an array of items at the given position within the existing items + * Add an array of items at the given position within the existing items * * @param position the global position * @param items the items to add */ @SafeVarargs override fun add(position: Int, vararg items: Model): ModelAdapter { - return add(position, asList(*items)) + return add(position, listOf(*items)) } /** - * add a list of items at the given position within the existing items + * Add a list of items at the given position within the existing items * * @param position the global position * @param items the items to add @@ -330,13 +334,12 @@ open class ModelAdapter( } if (items.isNotEmpty()) { itemList.addAll(position, items, fastAdapter?.getPreItemCountByOrder(order) ?: 0) - mapPossibleTypes(items) } return this } /** - * sets an item at the given position, overwriting the previous item + * Sets an item at the given position, overwriting the previous item * * @param position the global position * @param item the item to set @@ -351,12 +354,11 @@ open class ModelAdapter( idDistributor.checkId(item) } itemList[position, item] = fastAdapter?.getPreItemCount(position) ?: 0 - fastAdapter?.registerTypeInstance(item) return this } /** - * moves an item within the list from a position to a position + * Moves an item within the list from a position to a position * * @param fromPosition the position global from which we want to move * @param toPosition the global position to which to move @@ -368,7 +370,7 @@ open class ModelAdapter( } /** - * removes an item at the given position within the existing icons + * Removes an item at the given position within the existing icons * * @param position the global position */ @@ -378,7 +380,7 @@ open class ModelAdapter( } /** - * removes a range of items starting with the given position within the existing icons + * Removes a range of items starting with the given position within the existing icons * * @param position the global position * @param itemCount the count of items which were removed @@ -389,7 +391,7 @@ open class ModelAdapter( } /** - * removes all items of this adapter + * Removes all items of this adapter */ override fun clear(): ModelAdapter { itemList.clear(fastAdapter?.getPreItemCountByOrder(order) ?: 0) @@ -397,7 +399,7 @@ open class ModelAdapter( } /** - * remvoes an item by it's identifier + * Removes an item by it's identifier * * @param identifier the identifier to search for * @return this @@ -416,7 +418,7 @@ open class ModelAdapter( //a sub item which is not in the list can be instantly deleted expandable.parent?.subItems?.remove(item) } - if (position != -1) { + if (position != RecyclerView.NO_POSITION) { //a normal displayed item can only be deleted afterwards remove(position) } @@ -429,12 +431,15 @@ open class ModelAdapter( } /** - * util function which recursively iterates over all items and subItems of the given adapter. + * Util function which recursively iterates over all items and subItems of the given adapter. * It executes the given `predicate` on every item and will either stop if that function returns true, or continue (if stopOnMatch is false) * * @param predicate the predicate to run on every item, to check for a match or do some changes (e.g. select) * @param stopOnMatch defines if we should stop iterating after the first match - * @return Triple<Boolean, IItem, Integer> The first value is true (it is always not null), the second contains the item and the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) + * @return Triple + * The first value is true (it is always not null), + * the second contains the item, + * the third the position (if the item is visible) if we had a match, (always false and null and null in case of stopOnMatch == false) */ open fun recursive( predicate: AdapterPredicate, @@ -484,7 +489,7 @@ open class ModelAdapter( companion object { /** - * static method to retrieve a new `ItemAdapter` + * Static method to retrieve a new `ItemAdapter` * * @return a new ItemAdapter */ diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/items/AbstractItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/items/AbstractItem.kt index 3477b1a14..acf7556f8 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/items/AbstractItem.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/items/AbstractItem.kt @@ -4,107 +4,30 @@ import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.annotation.CallSuper +import androidx.annotation.LayoutRes import androidx.recyclerview.widget.RecyclerView -import com.mikepenz.fastadapter.IItem +import com.mikepenz.fastadapter.IItemVHFactory +import com.mikepenz.fastadapter.IItemViewGenerator import java.util.* /** - * Created by mikepenz on 14.07.15. * Implements the general methods of the IItem interface to speed up development. */ -abstract class AbstractItem : IItem { +abstract class AbstractItem : BaseItem(), IItemVHFactory, IItemViewGenerator { - /** - * The identifier of this item - */ - override var identifier: Long = -1 - - /** - * The tag of this item - */ - override var tag: Any? = null - - /** - * If this item is enabled - */ - override var isEnabled = true - - /** - * If this item is selected - */ - override var isSelected = false - - /** - * If this item is selectable - */ - override var isSelectable = true - - /** - * Binds the data of this item to the given holder - * - * @param holder - * @param payloads - */ - @CallSuper - override fun bindView(holder: VH, payloads: MutableList) { - //set the selected state of this item. force this otherwise it may is missed when implementing an item - holder.itemView.isSelected = isSelected - } - - /** - * View needs to release resources when its recycled - * - * @param holder - */ - override fun unbindView(holder: VH) { - } + /** The layout for the given item */ + @get:LayoutRes + abstract val layoutRes: Int /** - * View got attached to the window - * - * @param holder - */ - override fun attachToWindow(holder: VH) { - } - - /** - * View got detached from the window - * - * @param holder - */ - override fun detachFromWindow(holder: VH) { - } - - /** - * RecyclerView was not able to recycle that viewHolder because it's in a transient state - * Implement this and clear any animations, to allow recycling. Return true in that case - * - * @param holder - * @return true if you want it to get recycled - */ - override fun failedToRecycle(holder: VH): Boolean { - return false - } - - /** - * this method is called by generateView(Context ctx), generateView(Context ctx, ViewGroup parent) and getViewHolder(ViewGroup parent) + * This method is called by generateView(Context ctx), generateView(Context ctx, ViewGroup parent) and getViewHolder(ViewGroup parent) * it will generate the View from the layout, overwrite this if you want to implement your view creation programatically - * - * @param ctx - * @param parent - * @return */ open fun createView(ctx: Context, parent: ViewGroup?): View { return LayoutInflater.from(ctx).inflate(layoutRes, parent, false) } - /** - * generates a view by the defined LayoutRes - * - * @param ctx - * @return - */ + /** Generates a view by the defined LayoutRes */ override fun generateView(ctx: Context): View { val viewHolder = getViewHolder(createView(ctx, null)) @@ -115,13 +38,7 @@ abstract class AbstractItem : IItem { return viewHolder.itemView } - /** - * generates a view by the defined LayoutRes and pass the LayoutParams from the parent - * - * @param ctx - * @param parent - * @return - */ + /** Generates a view by the defined LayoutRes and pass the LayoutParams from the parent */ override fun generateView(ctx: Context, parent: ViewGroup): View { val viewHolder = getViewHolder(createView(ctx, parent)) @@ -131,50 +48,15 @@ abstract class AbstractItem : IItem { return viewHolder.itemView } - /** - * Generates a ViewHolder from this Item with the given parent - * - * @param parent - * @return - */ + /** Generates a ViewHolder from this Item with the given parent */ override fun getViewHolder(parent: ViewGroup): VH { return getViewHolder(createView(parent.context, parent)) } - /** * This method returns the ViewHolder for our item, using the provided View. * - * @param v * @return the ViewHolder for this Item */ abstract fun getViewHolder(v: View): VH - - /** - * If this item equals to the given identifier - * - * @param id identifier - * @return true if identifier equals id, false otherwise - */ - override fun equals(id: Int): Boolean = id.toLong() == identifier - - /** - * If this item equals to the given object - * - * @param o - * @return - */ - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || javaClass != other.javaClass) return false - val that = other as? AbstractItem<*>? - return identifier == that?.identifier - } - - /** - * the hashCode implementation - * - * @return - */ - override fun hashCode(): Int = identifier.hashCode() -} +} \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/items/BaseItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/items/BaseItem.kt new file mode 100644 index 000000000..0797d1b62 --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/items/BaseItem.kt @@ -0,0 +1,113 @@ +package com.mikepenz.fastadapter.items + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.CallSuper +import androidx.annotation.LayoutRes +import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.fastadapter.IItem +import com.mikepenz.fastadapter.IItemVHFactory + +/** + * Implements the general methods of the IItem interface to speed up development. + */ +abstract class BaseItem : IItem { + + /** The identifier of this item */ + override var identifier: Long = -1L + + /** The tag of this item */ + override var tag: Any? = null + + /** The factory to use for creating this item, this does not have to be provided if the IItemFactory is implemented by this item too */ + override val factory: IItemVHFactory? = null + + /** If this item is enabled */ + override var isEnabled: Boolean = true + + /** If this item is selected */ + override var isSelected: Boolean = false + + /** If this item is selectable */ + override var isSelectable: Boolean = true + + /** Binds the data of this item to the given holder */ + @CallSuper + override fun bindView(holder: VH, payloads: List) { + //set the selected state of this item. force this otherwise it may is missed when implementing an item + holder.itemView.isSelected = isSelected + } + + /** View needs to release resources when its recycled */ + override fun unbindView(holder: VH) { + } + + /** View got attached to the window */ + override fun attachToWindow(holder: VH) { + } + + /** View got detached from the window */ + override fun detachFromWindow(holder: VH) { + } + + /** + * RecyclerView was not able to recycle that viewHolder because it's in a transient state + * Implement this and clear any animations, to allow recycling. Return true in that case + * + * @return true if you want it to get recycled + */ + override fun failedToRecycle(holder: VH): Boolean { + return false + } + + /** + * If this item equals to the given identifier + * + * @param id identifier + * @return true if identifier equals id, false otherwise + */ + override fun equals(id: Int): Boolean = id.toLong() == identifier + + /** If this item equals to the given object */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || javaClass != other.javaClass) return false + val that = other as? BaseItem<*>? + return identifier == that?.identifier + } + + /** The hashCode implementation */ + override fun hashCode(): Int = identifier.hashCode() +} + +/** + * Implements an abstract item factory simplifying splitting the code into more meaningful parts + */ +abstract class BaseItemFactory : IItemVHFactory { + + /** The layout for the given item */ + @get:LayoutRes + abstract val layoutRes: Int + + /** Generates a ViewHolder from this Item with the given parent */ + override fun getViewHolder(parent: ViewGroup): VH { + return getViewHolder(createView(parent.context, parent)) + } + + /** + * This method returns the ViewHolder for our item, using the provided View. + * + * @return the ViewHolder for this Item + */ + abstract fun getViewHolder(v: View): VH + + /** + * This method is called by generateView(Context ctx), generateView(Context ctx, ViewGroup parent) and getViewHolder(ViewGroup parent) + * it will generate the View from the layout, overwrite this if you want to implement your view creation programatically + */ + open fun createView(ctx: Context, parent: ViewGroup?): View { + return LayoutInflater.from(ctx).inflate(layoutRes, parent, false) + } +} \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelAbstractItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelAbstractItem.kt index 444f39a61..b31234dbb 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelAbstractItem.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelAbstractItem.kt @@ -5,7 +5,6 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.IModelItem /** - * Created by mikepenz on 14.07.15. * Implements the general methods of the IItem interface to speed up development. */ abstract class ModelAbstractItem(override var model: Model) : diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelBaseItem.kt b/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelBaseItem.kt new file mode 100644 index 000000000..6251a0452 --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/items/ModelBaseItem.kt @@ -0,0 +1,11 @@ +package com.mikepenz.fastadapter.items + +import androidx.recyclerview.widget.RecyclerView + +import com.mikepenz.fastadapter.IModelItem + +/** + * Implements the general methods of the IItem interface to speed up development. + */ +abstract class ModelBaseItem(override var model: Model) : + BaseItem(), IModelItem diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ClickEventHook.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ClickEventHook.kt index 886fcf1fb..eea80b74c 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ClickEventHook.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ClickEventHook.kt @@ -13,9 +13,11 @@ abstract class ClickEventHook : EventHook { * Convenient extension function to simplify adding a [ClickEventHook] to the [FastAdapter] * * A sample implementation may look like: - * mFastAdapter.addClickListener({ vh: SimpleImageItem.ViewHolder -> vh.imageView }) { _, _, _, _ -> + * ``` + * fastAdapter.addClickListener({ vh: SimpleImageItem.ViewHolder -> vh.imageView }) { _, _, _, _ -> * // do something * } + * ``` */ inline fun FastAdapter.addClickListener(crossinline resolveView: (VH) -> View?, crossinline resolveViews: ((VH) -> List?) = { null }, crossinline onClick: (v: View, position: Int, fastAdapter: FastAdapter, item: Item) -> Unit) { addEventHook(object : ClickEventHook() { diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/CustomEventHook.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/CustomEventHook.kt index e6848b725..86bd76be1 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/CustomEventHook.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/CustomEventHook.kt @@ -7,28 +7,19 @@ import com.mikepenz.fastadapter.GenericItem abstract class CustomEventHook : EventHook { /** - * this method is called by the `FastAdapter` during ViewHolder creation ONCE. - * - * @param view - * @param viewHolder + * This method is called by the `FastAdapter` during ViewHolder creation ONCE. */ abstract fun attachEvent(view: View, viewHolder: RecyclerView.ViewHolder) /** * Helper method to get the FastAdapter from this ViewHolder - * - * @param viewHolder - * @return */ @Deprecated("Replaced with the new helper inside the FastAdapter class", ReplaceWith("FastAdapter.getFromHolderTag(viewHolder)", "com.mikepenz.fastadapter.FastAdapter")) fun getFastAdapter(viewHolder: RecyclerView.ViewHolder): FastAdapter? = FastAdapter.getFromHolderTag(viewHolder) /** - * helper method to get the item for this ViewHolder - * - * @param viewHolder - * @return + * Helper method to get the item for this ViewHolder */ @Deprecated("Replaced with the new helper inside the FastAdapter class", ReplaceWith("FastAdapter.getHolderAdapterItem(viewHolder)", "com.mikepenz.fastadapter.FastAdapter")) fun getItem(viewHolder: RecyclerView.ViewHolder): Item? = diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/EventHook.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/EventHook.kt index 75487e1d7..a9abed0ff 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/EventHook.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/EventHook.kt @@ -6,17 +6,17 @@ import com.mikepenz.fastadapter.GenericItem interface EventHook { - /* - * Return the view for this hook that the listener should be bound to - * - * @return null, if the provided ViewHolder should not be bound to the event hook; return the view responsible for the event otherwise - */ + /** + * Return the view for this hook that the listener should be bound to + * + * @return null, if the provided ViewHolder should not be bound to the event hook; return the view responsible for the event otherwise + */ fun onBind(viewHolder: RecyclerView.ViewHolder): View? = null - /* - * Return the views for this hook that the listener should be bound to - * - * @return null, if the provided ViewHolder should not be bound to the event hook; return the views responsible for the event otherwise - */ + /** + * Return the views for this hook that the listener should be bound to + * + * @return null, if the provided ViewHolder should not be bound to the event hook; return the views responsible for the event otherwise + */ fun onBindMany(viewHolder: RecyclerView.ViewHolder): List? = null } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ItemFilterListener.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ItemFilterListener.kt index adb1b40ca..a0f33eaf2 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ItemFilterListener.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/ItemFilterListener.kt @@ -3,7 +3,7 @@ package com.mikepenz.fastadapter.listeners import com.mikepenz.fastadapter.GenericItem /** - * interface for the ItemFilterListener + * Interface for the ItemFilterListener */ interface ItemFilterListener { fun itemsFiltered(constraint: CharSequence?, results: List?) diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/LongClickEventHook.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/LongClickEventHook.kt index bec6cfae9..2720be98a 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/LongClickEventHook.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/LongClickEventHook.kt @@ -13,10 +13,12 @@ abstract class LongClickEventHook : EventHook { * Convenient extension function to simplify adding a [LongClickEventHook] to the [FastAdapter] * * A sample implementation may look like: - * mFastAdapter.addLongClickListener({ vh: SimpleImageItem.ViewHolder -> vh.imageView }) { _, _, _, _ -> + * ``` + * fastAdapter.addLongClickListener({ vh: SimpleImageItem.ViewHolder -> vh.imageView }) { _, _, _, _ -> * // do something * true * } + * ``` */ inline fun FastAdapter.addLongClickListener(crossinline resolveView: (VH) -> View?, crossinline resolveViews: ((VH) -> List?) = { null }, crossinline onLongClick: (v: View, position: Int, fastAdapter: FastAdapter, item: Item) -> Boolean) { addEventHook(object : LongClickEventHook() { diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListener.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListener.kt index 5c0b3b436..ebc29af8c 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListener.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListener.kt @@ -4,16 +4,16 @@ import androidx.recyclerview.widget.RecyclerView interface OnBindViewHolderListener { /** - * is called in onBindViewHolder to bind the data on the ViewHolder + * Is called in onBindViewHolder to bind the data on the ViewHolder * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder * @param payloads the payloads provided by the adapter */ - fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int, payloads: MutableList) + fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int, payloads: List) /** - * is called in onViewRecycled to unbind the data on the ViewHolder + * Is called in onViewRecycled to unbind the data on the ViewHolder * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder @@ -21,7 +21,7 @@ interface OnBindViewHolderListener { fun unBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) /** - * is called in onViewAttachedToWindow when the view is detached from the window + * Is called in onViewAttachedToWindow when the view is detached from the window * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder @@ -29,7 +29,7 @@ interface OnBindViewHolderListener { fun onViewAttachedToWindow(viewHolder: RecyclerView.ViewHolder, position: Int) /** - * is called in onViewDetachedFromWindow when the view is detached from the window + * Is called in onViewDetachedFromWindow when the view is detached from the window * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder @@ -37,7 +37,7 @@ interface OnBindViewHolderListener { fun onViewDetachedFromWindow(viewHolder: RecyclerView.ViewHolder, position: Int) /** - * is called when the ViewHolder is in a transient state. return true if you want to reuse + * Is called when the ViewHolder is in a transient state. return true if you want to reuse * that view anyways * * @param viewHolder the viewHolder for the view which failed to recycle diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListenerImpl.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListenerImpl.kt index dc8841ecf..dfecdd4be 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListenerImpl.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnBindViewHolderListenerImpl.kt @@ -9,13 +9,13 @@ import com.mikepenz.fastadapter.R open class OnBindViewHolderListenerImpl : OnBindViewHolderListener { /** - * is called in onBindViewHolder to bind the data on the ViewHolder + * Is called in onBindViewHolder to bind the data on the ViewHolder * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder * @param payloads the payloads provided by the adapter */ - override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int, payloads: MutableList) { + override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int, payloads: List) { val adapter = FastAdapter.getFromHolderTag(viewHolder) ?: return val item = adapter.getItem(position) ?: return (item as? IItem)?.bindView(viewHolder, payloads) @@ -25,7 +25,7 @@ open class OnBindViewHolderListenerImpl : OnBindViewHolderLi } /** - * is called in onViewRecycled to unbind the data on the ViewHolder + * Is called in onViewRecycled to unbind the data on the ViewHolder * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder @@ -41,13 +41,13 @@ open class OnBindViewHolderListenerImpl : OnBindViewHolderLi } else { Log.e( "FastAdapter", - "The bindView method of this item should set the `Tag` on its itemView (https://github.com/mikepenz/FastAdapter/blob/develop/library-core/src/main/java/com/mikepenz/fastadapter/items/AbstractItem.java#L189)" + "The bindView method of this item should set the `Tag` on its itemView (https://github.com/mikepenz/FastAdapter/blob/develop/library-core/src/main/java/com/mikepenz/fastadapter/items/AbstractItem.kt#L22)" ) } } /** - * is called in onViewAttachedToWindow when the view is detached from the window + * Is called in onViewAttachedToWindow when the view is detached from the window * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder @@ -65,7 +65,7 @@ open class OnBindViewHolderListenerImpl : OnBindViewHolderLi } /** - * is called in onViewDetachedFromWindow when the view is detached from the window + * Is called in onViewDetachedFromWindow when the view is detached from the window * * @param viewHolder the viewHolder for the type at this position * @param position the position of this viewHolder @@ -78,7 +78,7 @@ open class OnBindViewHolderListenerImpl : OnBindViewHolderLi } /** - * is called when the ViewHolder is in a transient state. return true if you want to reuse + * Is called when the ViewHolder is in a transient state. return true if you want to reuse * that view anyways * * @param viewHolder the viewHolder for the view which failed to recycle diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListener.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListener.kt index 422315abb..f9ba27662 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListener.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListener.kt @@ -4,24 +4,25 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem +import com.mikepenz.fastadapter.IItemVHFactory interface OnCreateViewHolderListener { /** - * is called inside the onCreateViewHolder method and creates the viewHolder based on the provided viewTyp + * Is called inside the onCreateViewHolder method and creates the viewHolder based on the provided viewTyp * * @param fastAdapter the fastAdapter which handles the creation of this viewHolder * @param parent the parent which will host the View * @param viewType the type of the ViewHolder we want to create * @return the generated ViewHolder based on the given viewType */ - fun onPreCreateViewHolder(fastAdapter: FastAdapter, parent: ViewGroup, viewType: Int, typeInstance: Item): RecyclerView.ViewHolder + fun onPreCreateViewHolder(fastAdapter: FastAdapter, parent: ViewGroup, viewType: Int, itemVHFactory: IItemVHFactory<*>): RecyclerView.ViewHolder /** - * is called after the viewHolder was created and the default listeners were added + * Is called after the viewHolder was created and the default listeners were added * * @param fastAdapter the fastAdapter which handles the creation of this viewHolder * @param viewHolder the created viewHolder after all listeners were set * @return the viewHolder given as param */ - fun onPostCreateViewHolder(fastAdapter: FastAdapter, viewHolder: RecyclerView.ViewHolder, typeInstance: Item): RecyclerView.ViewHolder + fun onPostCreateViewHolder(fastAdapter: FastAdapter, viewHolder: RecyclerView.ViewHolder, itemVHFactory: IItemVHFactory<*>): RecyclerView.ViewHolder } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListenerImpl.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListenerImpl.kt index c094fd4eb..a9e4d2143 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListenerImpl.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/OnCreateViewHolderListenerImpl.kt @@ -5,33 +5,34 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem import com.mikepenz.fastadapter.IHookable +import com.mikepenz.fastadapter.IItemVHFactory import com.mikepenz.fastadapter.utils.bind /** - * default implementation of the OnCreateViewHolderListener + * Default implementation of the OnCreateViewHolderListener */ open class OnCreateViewHolderListenerImpl : OnCreateViewHolderListener { /** - * is called inside the onCreateViewHolder method and creates the viewHolder based on the provided viewTyp + * Is called inside the onCreateViewHolder method and creates the viewHolder based on the provided viewTyp * * @param parent the parent which will host the View * @param viewType the type of the ViewHolder we want to create * @return the generated ViewHolder based on the given viewType */ - override fun onPreCreateViewHolder(fastAdapter: FastAdapter, parent: ViewGroup, viewType: Int, typeInstance: Item): RecyclerView.ViewHolder { - return typeInstance.getViewHolder(parent) + override fun onPreCreateViewHolder(fastAdapter: FastAdapter, parent: ViewGroup, viewType: Int, itemVHFactory: IItemVHFactory<*>): RecyclerView.ViewHolder { + return itemVHFactory.getViewHolder(parent) } /** - * is called after the viewHolder was created and the default listeners were added + * Is called after the viewHolder was created and the default listeners were added * * @param viewHolder the created viewHolder after all listeners were set * @return the viewHolder given as param */ - override fun onPostCreateViewHolder(fastAdapter: FastAdapter, viewHolder: RecyclerView.ViewHolder, typeInstance: Item): RecyclerView.ViewHolder { + override fun onPostCreateViewHolder(fastAdapter: FastAdapter, viewHolder: RecyclerView.ViewHolder, itemVHFactory: IItemVHFactory<*>): RecyclerView.ViewHolder { fastAdapter.eventHooks.bind(viewHolder) //check if the item implements hookable and contains event hooks - (typeInstance as? IHookable<*>)?.eventHooks?.bind(viewHolder) + (itemVHFactory as? IHookable<*>)?.eventHooks?.bind(viewHolder) return viewHolder } } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/TouchEventHook.kt b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/TouchEventHook.kt index a0c14ef16..28d78a831 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/listeners/TouchEventHook.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/listeners/TouchEventHook.kt @@ -17,10 +17,12 @@ abstract class TouchEventHook : EventHook { * Convenient extension function to simplify adding a [TouchEventHook] to the [FastAdapter] * * A sample implementation may look like: - * mFastAdapter.addTouchListener({ vh: SimpleImageItem.ViewHolder -> vh.imageView }) { _, _, _, _ -> + * ``` + * fastAdapter.addTouchListener({ vh: SimpleImageItem.ViewHolder -> vh.imageView }) { _, _, _, _ -> * // do something * true * } + * ``` */ inline fun FastAdapter.addTouchListener(crossinline resolveView: (VH) -> View?, crossinline resolveViews: ((VH) -> List?) = { null }, crossinline onTouch: (v: View, event: MotionEvent, position: Int, fastAdapter: FastAdapter, item: Item) -> Boolean) { addEventHook(object : TouchEventHook() { diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/select/SelectExtension.kt b/library-core/src/main/java/com/mikepenz/fastadapter/select/SelectExtension.kt index 55122b1fb..62cd7d769 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/select/SelectExtension.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/select/SelectExtension.kt @@ -4,11 +4,18 @@ import android.os.Bundle import android.view.MotionEvent import android.view.View import androidx.collection.ArraySet -import com.mikepenz.fastadapter.* +import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.fastadapter.FastAdapter +import com.mikepenz.fastadapter.GenericItem +import com.mikepenz.fastadapter.IAdapter +import com.mikepenz.fastadapter.IAdapterExtension +import com.mikepenz.fastadapter.IExpandable +import com.mikepenz.fastadapter.IItemAdapter +import com.mikepenz.fastadapter.ISelectionListener import com.mikepenz.fastadapter.dsl.FastAdapterDsl import com.mikepenz.fastadapter.extensions.ExtensionsFactories import com.mikepenz.fastadapter.utils.AdapterPredicate -import java.util.* +import java.util.ArrayList /** * Extension method to retrieve or create the SelectExtension from the current FastAdapter. @@ -37,7 +44,7 @@ class SelectExtension(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter { @@ -358,7 +363,7 @@ class SelectExtension(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter? = null) { + fun deselect(item: Item, position: Int = RecyclerView.NO_POSITION, entries: MutableIterator? = null) { item.isSelected = false entries?.remove() if (position >= 0) { @@ -403,7 +408,7 @@ class SelectExtension(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter(private val fastAdapter: FastAdapter { * @param lastParentAdapter the last `IAdapter` managing the last (visible) parent item (that might also be a parent of a parent, ..) * @param lastParentPosition the global position of the last (visible) parent item, holding this sub item (that might also be a parent of a parent, ..) * @param item the item to check - * @param position the global position of the item, or "-1" if it is a non displayed sub item + * @param position the global position of the item, or [androidx.recyclerview.widget.RecyclerView.NO_POSITION] (-1) if it is a non displayed sub item * @return true if we matched and no longer want to continue (will be ignored if `stopOnMatch` of the recursive function is false) */ fun apply(lastParentAdapter: IAdapter, lastParentPosition: Int, item: Item, position: Int): Boolean diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/ComparableItemListImpl.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/ComparableItemListImpl.kt index d48b5c4a0..ff2ecc74f 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/ComparableItemListImpl.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/ComparableItemListImpl.kt @@ -1,32 +1,24 @@ package com.mikepenz.fastadapter.utils import com.mikepenz.fastadapter.GenericItem -import java.util.* +import java.util.ArrayList +import java.util.Collections +import java.util.Comparator /** * The default item list implementation */ +class ComparableItemListImpl @JvmOverloads constructor( + comparator: Comparator?, + items: MutableList = ArrayList() +) : DefaultItemListImpl(items) { -class ComparableItemListImpl : DefaultItemListImpl { - - /** - * @return the defined Comparator used for this ItemAdaper - */ - var comparator: Comparator? = null + /** @return the defined Comparator used for this ItemAdaper */ + var comparator: Comparator? = comparator private set - constructor(comparator: Comparator?) { - this.mItems = ArrayList() - this.comparator = comparator - } - - constructor(comparator: Comparator?, items: MutableList) { - this.mItems = items - this.comparator = comparator - } - /** - * define a comparator which will be used to sort the list "everytime" it is altered + * Define a comparator which will be used to sort the list "everytime" it is altered * NOTE this will only sort if you "set" a new list or "add" new items (not if you provide a position for the add function) * * @param comparator used to sort the list @@ -42,7 +34,7 @@ class ComparableItemListImpl : DefaultItemListImpl { //we directly sort the list with the defined comparator if (this.comparator != null && sortNow) { - Collections.sort(mItems, this.comparator) + Collections.sort(_items, this.comparator) fastAdapter?.notifyAdapterDataSetChanged() } @@ -50,36 +42,28 @@ class ComparableItemListImpl : DefaultItemListImpl { } override fun move(fromPosition: Int, toPosition: Int, preItemCount: Int) { - val item = mItems[fromPosition - preItemCount] - mItems.removeAt(fromPosition - preItemCount) - mItems.add(toPosition - preItemCount, item) - if (comparator != null) { - Collections.sort(mItems, comparator) - } + val item = _items[fromPosition - preItemCount] + _items.removeAt(fromPosition - preItemCount) + _items.add(toPosition - preItemCount, item) + _items.trySortWith(comparator) fastAdapter?.notifyAdapterDataSetChanged() } override fun addAll(items: List, preItemCount: Int) { - mItems.addAll(items) - if (comparator != null) { - Collections.sort(mItems, comparator) - } + _items.addAll(items) + _items.trySortWith(comparator) fastAdapter?.notifyAdapterDataSetChanged() } override fun addAll(position: Int, items: List, preItemCount: Int) { - mItems.addAll(position - preItemCount, items) - if (comparator != null) { - Collections.sort(mItems, comparator) - } + _items.addAll(position - preItemCount, items) + _items.trySortWith(comparator) fastAdapter?.notifyAdapterDataSetChanged() } override fun setNewList(items: List, notify: Boolean) { - mItems = ArrayList(items) - if (comparator != null) { - Collections.sort(mItems, comparator) - } + _items = ArrayList(items) + _items.trySortWith(comparator) if (notify) { fastAdapter?.notifyAdapterDataSetChanged() } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributor.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributor.kt index af3352b8e..baa458bcf 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributor.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributor.kt @@ -9,10 +9,7 @@ import com.mikepenz.fastadapter.IIdentifyable abstract class DefaultIdDistributor : IIdDistributor { /** - * set an unique identifier for all identifiables which do not have one set already - * - * @param identifiables - * @return + * Set an unique identifier for all identifiables which do not have one set already */ override fun checkIds(identifiables: List): List { var i = 0 @@ -25,10 +22,7 @@ abstract class DefaultIdDistributor : IIdDistribut } /** - * set an unique identifier for all items which do not have one set already - * - * @param identifiables - * @return + * Set an unique identifier for all items which do not have one set already */ override fun checkIds(vararg identifiables: Identifiable): Array { for (identifiable in identifiables) { @@ -38,10 +32,7 @@ abstract class DefaultIdDistributor : IIdDistribut } /** - * set an unique identifier for the identifiable which do not have one set already - * - * @param identifiable - * @return + * Set an unique identifier for the identifiable which do not have one set already */ override fun checkId(identifiable: Identifiable): Identifiable { if (identifiable.identifier == -1L) { diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributorImpl.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributorImpl.kt index cb3d0afc3..d816de5fd 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributorImpl.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultIdDistributorImpl.kt @@ -8,7 +8,6 @@ import java.util.concurrent.atomic.AtomicLong */ class DefaultIdDistributorImpl : DefaultIdDistributor() { - private val idDistributor = AtomicLong(-2L) override fun nextId(identifiable: Identifiable): Long { diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemList.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemList.kt index ff3884700..a1a05ce14 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemList.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemList.kt @@ -10,5 +10,13 @@ import com.mikepenz.fastadapter.IItemList abstract class DefaultItemList : IItemList { - var fastAdapter: FastAdapter? = null + private var _fastAdapter: FastAdapter? = null + + var fastAdapter: FastAdapter? + get() = if (active) _fastAdapter else null + set(value) { + _fastAdapter = value + } + + override var active: Boolean = true } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemListImpl.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemListImpl.kt index cf7953a91..d6ebf3a8c 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemListImpl.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemListImpl.kt @@ -8,87 +8,87 @@ import kotlin.math.min /** * The default item list implementation */ - open class DefaultItemListImpl @JvmOverloads constructor( - protected var mItems: MutableList = ArrayList() + @Suppress("ConstructorParameterNaming") + protected var _items: MutableList = ArrayList() ) : DefaultItemList() { override val items: MutableList - get() = mItems + get() = _items override val isEmpty: Boolean - get() = mItems.isEmpty() + get() = _items.isEmpty() override fun get(position: Int): Item { - return mItems[position] + return _items[position] } override fun getAdapterPosition(identifier: Long): Int = - mItems.indexOfFirst { it.identifier == identifier } + _items.indexOfFirst { it.identifier == identifier } override fun remove(position: Int, preItemCount: Int) { - mItems.removeAt(position - preItemCount) + _items.removeAt(position - preItemCount) fastAdapter?.notifyAdapterItemRemoved(position) } override fun removeRange(position: Int, itemCount: Int, preItemCount: Int) { //global position to relative - val length = mItems.size + val length = _items.size //make sure we do not delete too many items val saveItemCount = min(itemCount, length - position + preItemCount) for (i in 0 until saveItemCount) { - mItems.removeAt(position - preItemCount) + _items.removeAt(position - preItemCount) } fastAdapter?.notifyAdapterItemRangeRemoved(position, saveItemCount) } override fun move(fromPosition: Int, toPosition: Int, preItemCount: Int) { - val item = mItems[fromPosition - preItemCount] - mItems.removeAt(fromPosition - preItemCount) - mItems.add(toPosition - preItemCount, item) + val item = _items[fromPosition - preItemCount] + _items.removeAt(fromPosition - preItemCount) + _items.add(toPosition - preItemCount, item) fastAdapter?.notifyAdapterItemMoved(fromPosition, toPosition) } override fun size(): Int { - return mItems.size + return _items.size } override fun clear(preItemCount: Int) { - val size = mItems.size - mItems.clear() + val size = _items.size + _items.clear() fastAdapter?.notifyAdapterItemRangeRemoved(preItemCount, size) } override fun set(position: Int, item: Item, preItemCount: Int) { - mItems[position - preItemCount] = item + _items[position - preItemCount] = item fastAdapter?.notifyAdapterItemChanged(position) } override fun addAll(items: List, preItemCount: Int) { - val countBefore = mItems.size - mItems.addAll(items) + val countBefore = _items.size + _items.addAll(items) fastAdapter?.notifyAdapterItemRangeInserted(preItemCount + countBefore, items.size) } override fun addAll(position: Int, items: List, preItemCount: Int) { - mItems.addAll(position - preItemCount, items) + _items.addAll(position - preItemCount, items) fastAdapter?.notifyAdapterItemRangeInserted(position, items.size) } override fun set(items: List, preItemCount: Int, adapterNotifier: IAdapterNotifier?) { //get sizes val newItemsCount = items.size - val previousItemsCount = mItems.size + val previousItemsCount = _items.size //make sure the new items list is not a reference of the already mItems list - if (items !== mItems) { + if (items !== _items) { //remove all previous items - if (mItems.isNotEmpty()) { - mItems.clear() + if (_items.isNotEmpty()) { + _items.clear() } //add all new items to the list - mItems.addAll(items) + _items.addAll(items) } fastAdapter?.let { fastAdapter -> //now properly notify the adapter about the changes @@ -102,7 +102,7 @@ open class DefaultItemListImpl @JvmOverloads constructor( } override fun setNewList(items: List, notify: Boolean) { - mItems = ArrayList(items) + _items = ArrayList(items) if (notify) { fastAdapter?.notifyAdapterDataSetChanged() } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemVHFactoryCache.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemVHFactoryCache.kt new file mode 100644 index 000000000..708e26164 --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultItemVHFactoryCache.kt @@ -0,0 +1,32 @@ +package com.mikepenz.fastadapter.utils + +import android.util.SparseArray +import com.mikepenz.fastadapter.GenericItemVHFactory +import com.mikepenz.fastadapter.IItemVHFactoryCache + +/** + * The default implementation to cache the viewholder factories. + */ +class DefaultItemVHFactoryCache : IItemVHFactoryCache { + + // we remember all possible types so we can create a new view efficiently + private val typeInstances = SparseArray() + + override fun register(type: Int, item: ItemVHFactory): Boolean { + if (typeInstances.indexOfKey(type) < 0) { + typeInstances.put(type, item) + return true + } + return false + } + + override fun get(type: Int): ItemVHFactory { + return typeInstances.get(type) + } + + override fun contains(type: Int): Boolean = typeInstances.indexOfKey(type) >= 0 + + override fun clear() { + typeInstances.clear() + } +} diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultTypeInstanceCache.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultTypeInstanceCache.kt deleted file mode 100644 index bc55f24c9..000000000 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/DefaultTypeInstanceCache.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.mikepenz.fastadapter.utils - -import android.util.SparseArray -import com.mikepenz.fastadapter.GenericItem -import com.mikepenz.fastadapter.ITypeInstanceCache - -/** - * Created by fabianterhorst on 24.08.17. - */ - -class DefaultTypeInstanceCache : - ITypeInstanceCache { - - // we remember all possible types so we can create a new view efficiently - private val mTypeInstances = SparseArray() - - override fun register(item: Item): Boolean { - if (mTypeInstances.indexOfKey(item.type) < 0) { - mTypeInstances.put(item.type, item) - return true - } - return false - } - - override fun get(type: Int): Item { - return mTypeInstances.get(type) - } - - override fun clear() { - mTypeInstances.clear() - } -} diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/EventHookUtil.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/EventHookUtil.kt index a4b06142f..50207e7d5 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/EventHookUtil.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/EventHookUtil.kt @@ -5,10 +5,14 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem import com.mikepenz.fastadapter.R -import com.mikepenz.fastadapter.listeners.* +import com.mikepenz.fastadapter.listeners.ClickEventHook +import com.mikepenz.fastadapter.listeners.CustomEventHook +import com.mikepenz.fastadapter.listeners.EventHook +import com.mikepenz.fastadapter.listeners.LongClickEventHook +import com.mikepenz.fastadapter.listeners.TouchEventHook /** - * binds the hooks to the viewHolder + * Binds the hooks to the viewHolder * * @param viewHolder the viewHolder of the item */ @@ -28,7 +32,7 @@ internal fun List>.bind(viewHolder: RecyclerView.View } /** - * attaches the specific event to a view + * Attaches the specific event to a view * * @param viewHolder the viewHolder containing this view * @param view the view to attach to @@ -82,7 +86,7 @@ internal fun EventHook.attachToView(viewHolder: Recyc } false }) - is CustomEventHook<*> -> //we trigger the event binding - (this as CustomEventHook).attachEvent(view, viewHolder) + //we trigger the event binding + is CustomEventHook<*> -> (this as CustomEventHook).attachEvent(view, viewHolder) } } diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/Sort.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/Sort.kt new file mode 100644 index 000000000..5d32ad64f --- /dev/null +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/Sort.kt @@ -0,0 +1,8 @@ +package com.mikepenz.fastadapter.utils + +/** + * @author pa.gulko zTrap (14.12.2019) + */ +internal fun MutableList.trySortWith(comparator: Comparator?) { + comparator?.let { sortWith(it) } +} \ No newline at end of file diff --git a/library-core/src/main/java/com/mikepenz/fastadapter/utils/Triple.kt b/library-core/src/main/java/com/mikepenz/fastadapter/utils/Triple.kt index 25e8ad35e..d49305fb1 100644 --- a/library-core/src/main/java/com/mikepenz/fastadapter/utils/Triple.kt +++ b/library-core/src/main/java/com/mikepenz/fastadapter/utils/Triple.kt @@ -1,10 +1,6 @@ package com.mikepenz.fastadapter.utils /** - * a helper class to provide a triple class, to store 3 values and return them from a method - * - * @param - * @param - * @param - */ + * A helper class to provide a triple class, to store 3 values and return them from a method + */ data class Triple(val first: T, val second: U?, val third: V?) \ No newline at end of file diff --git a/library-core/src/test/java/com/mikepenz/fastadapter/FastAdapterTest.java b/library-core/src/test/java/com/mikepenz/fastadapter/FastAdapterTest.java index 0ad04c17f..6789e2f80 100644 --- a/library-core/src/test/java/com/mikepenz/fastadapter/FastAdapterTest.java +++ b/library-core/src/test/java/com/mikepenz/fastadapter/FastAdapterTest.java @@ -124,7 +124,7 @@ public void getItemViewType() throws Exception { List items = TestDataGenerator.genTestItemList(100); itemAdapter.set(items); - assertThat(adapter.getItemViewType(40)).isEqualTo(-1); + assertThat(adapter.getItemViewType(40)).isEqualTo(RecyclerView.NO_POSITION); } @Test @@ -209,6 +209,7 @@ public void testAddPreviouslyFilledAdapterPropagatesPossibleTypesToParentFastAda itemAdapter.add(testItem); FastAdapter adapter = new FastAdapter<>(); adapter.addAdapter(0, itemAdapter); + adapter.registerItemFactory(testItem.getType(), testItem); // registering the factory happens only during usage of the adapter now final ViewGroup dummyParent = new FrameLayout(RuntimeEnvironment.application); adapter.onCreateViewHolder(dummyParent, testItem.getType()); } diff --git a/library-extensions-binding/.gitignore b/library-extensions-binding/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/library-extensions-binding/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library-extensions-binding/build.gradle b/library-extensions-binding/build.gradle new file mode 100644 index 000000000..a572394b2 --- /dev/null +++ b/library-extensions-binding/build.gradle @@ -0,0 +1,48 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion setup.compileSdk + buildToolsVersion setup.buildTools + + defaultConfig { + minSdkVersion setup.minSdk + targetSdkVersion setup.targetSdk + versionCode release.versionCode + versionName release.versionName + + consumerProguardFiles 'consumer-proguard-rules.pro' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + productFlavors { + } + lintOptions { + abortOnError false + } + testOptions { + unitTests { + includeAndroidResources = true + } + } + // specify the artifactId as module-name for kotlin + kotlinOptions.freeCompilerArgs += ["-module-name", POM_ARTIFACT_ID] +} + +dependencies { + implementation project(':library-core') + + implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" + + implementation "androidx.annotation:annotation:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" + compileOnly "androidx.databinding:viewbinding:${setup.gradleTools}" +} + +if (project.hasProperty('pushall') || project.hasProperty('library_extensions_binding_only')) { + apply from: '../gradle-release.gradle' +} \ No newline at end of file diff --git a/library-extensions-binding/consumer-proguard-rules.pro b/library-extensions-binding/consumer-proguard-rules.pro new file mode 100644 index 000000000..37aa54db0 --- /dev/null +++ b/library-extensions-binding/consumer-proguard-rules.pro @@ -0,0 +1 @@ +-dontwarn com.mikepenz.fastadapter.binding.** diff --git a/library-extensions-binding/gradle.properties b/library-extensions-binding/gradle.properties new file mode 100755 index 000000000..9ec44e9e4 --- /dev/null +++ b/library-extensions-binding/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=FastAdapter Library-Extensions-Binding +POM_DESCRIPTION=Binding extension for the FastAdapter library. The bullet proof, fast and easy to use adapter library. +POM_ARTIFACT_ID=fastadapter-extensions-binding +POM_PACKAGING=aar diff --git a/library-extensions-binding/proguard-rules.pro b/library-extensions-binding/proguard-rules.pro new file mode 100644 index 000000000..da6f30276 --- /dev/null +++ b/library-extensions-binding/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 /Development/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/library-extensions-binding/src/main/AndroidManifest.xml b/library-extensions-binding/src/main/AndroidManifest.xml new file mode 100644 index 000000000..767a68415 --- /dev/null +++ b/library-extensions-binding/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/AbstractBindingItem.kt b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/AbstractBindingItem.kt new file mode 100644 index 000000000..a9c88ff16 --- /dev/null +++ b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/AbstractBindingItem.kt @@ -0,0 +1,59 @@ +package com.mikepenz.fastadapter.binding + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.CallSuper +import androidx.viewbinding.ViewBinding +import com.mikepenz.fastadapter.IItemVHFactory +import com.mikepenz.fastadapter.items.BaseItem + +/** + * Implements an abstract item simplifying usage with ViewBinding as much as possible. + */ +abstract class AbstractBindingItem : BaseItem>(), IItemVHFactory> { + + @CallSuper + override fun bindView(holder: BindingViewHolder, payloads: List) { + super.bindView(holder, payloads) + bindView(holder.binding, payloads) + } + + open fun bindView(binding: Binding, payloads: List) {} + + override fun unbindView(holder: BindingViewHolder) { + super.unbindView(holder) + unbindView(holder.binding) + } + + open fun unbindView(binding: Binding) {} + + override fun attachToWindow(holder: BindingViewHolder) { + super.attachToWindow(holder) + attachToWindow(holder.binding) + } + + open fun attachToWindow(binding: Binding) {} + + override fun detachFromWindow(holder: BindingViewHolder) { + super.detachFromWindow(holder) + detachFromWindow(holder.binding) + } + + open fun detachFromWindow(binding: Binding) {} + + /** + * This method is called by generateView(Context ctx), generateView(Context ctx, ViewGroup parent) and getViewHolder(ViewGroup parent) + * it will generate the ViewBinding. You have to provide the correct binding class. + */ + abstract fun createBinding(inflater: LayoutInflater, parent: ViewGroup? = null): Binding + + /** Generates a ViewHolder from this Item with the given parent */ + override fun getViewHolder(parent: ViewGroup): BindingViewHolder { + return getViewHolder(createBinding(LayoutInflater.from(parent.context), parent)) + } + + /** Generates a ViewHolder from this Item with the given ViewBinding */ + open fun getViewHolder(viewBinding: Binding): BindingViewHolder { + return BindingViewHolder(viewBinding) + } +} \ No newline at end of file diff --git a/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/BaseBindingItemVHFactory.kt b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/BaseBindingItemVHFactory.kt new file mode 100644 index 000000000..e22b37354 --- /dev/null +++ b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/BaseBindingItemVHFactory.kt @@ -0,0 +1,25 @@ +package com.mikepenz.fastadapter.binding + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.mikepenz.fastadapter.IItemVHFactory + +/** + * Implements an abstract item simplifying usage with ViewBinding. + */ +abstract class BaseBindingItemVHFactory> : IItemVHFactory { + /** + * This method is called by generateView(Context ctx), generateView(Context ctx, ViewGroup parent) and getViewHolder(ViewGroup parent) + * it will generate the ViewBinding. You have to provide the correct binding class. + */ + abstract fun createBinding(inflater: LayoutInflater, parent: ViewGroup? = null): VB + + /** Generates a ViewHolder from this Item with the given parent */ + override fun getViewHolder(parent: ViewGroup): VH { + return getViewHolder(createBinding(LayoutInflater.from(parent.context), parent)) + } + + /** Generates a ViewHolder from this Item with the given ViewBinding */ + abstract fun getViewHolder(viewBinding: VB): VH +} \ No newline at end of file diff --git a/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/BindingViewHolder.kt b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/BindingViewHolder.kt new file mode 100644 index 000000000..9830ef110 --- /dev/null +++ b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/BindingViewHolder.kt @@ -0,0 +1,9 @@ +package com.mikepenz.fastadapter.binding + +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding + +/** + * A Simple [ViewHolder] providing easier support for ViewBinding + */ +open class BindingViewHolder(val binding: VB) : RecyclerView.ViewHolder(binding.root) \ No newline at end of file diff --git a/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/ModelAbstractBindingItem.kt b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/ModelAbstractBindingItem.kt new file mode 100644 index 000000000..27233c1fe --- /dev/null +++ b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/ModelAbstractBindingItem.kt @@ -0,0 +1,10 @@ +package com.mikepenz.fastadapter.binding + +import androidx.viewbinding.ViewBinding +import com.mikepenz.fastadapter.IModelItem + +/** + * Provides a convenient abstract class for having a split model and item (with binding) + */ +abstract class ModelAbstractBindingItem(override var model: Model) : + AbstractBindingItem(), IModelItem> diff --git a/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/listeners/BindingEventHookExtensions.kt b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/listeners/BindingEventHookExtensions.kt new file mode 100644 index 000000000..86b302768 --- /dev/null +++ b/library-extensions-binding/src/main/java/com/mikepenz/fastadapter/binding/listeners/BindingEventHookExtensions.kt @@ -0,0 +1,93 @@ +package com.mikepenz.fastadapter.binding.listeners + +import android.view.MotionEvent +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import com.mikepenz.fastadapter.FastAdapter +import com.mikepenz.fastadapter.GenericItem +import com.mikepenz.fastadapter.binding.BindingViewHolder +import com.mikepenz.fastadapter.listeners.ClickEventHook +import com.mikepenz.fastadapter.listeners.LongClickEventHook +import com.mikepenz.fastadapter.listeners.TouchEventHook + +/** + * Convenient extension function to simplify adding a [ClickEventHook] to the [FastAdapter] + * + * A sample implementation may look like: + * ``` + * fastAdapter.addClickListener({ binding -> binding.view }) { v, position, fastAdapter, item -> + * // do something + * } + * ``` + */ +inline fun FastAdapter.addClickListener(crossinline resolveView: (Binding) -> View?, crossinline resolveViews: ((Binding) -> List?) = { null }, crossinline onClick: (v: View, position: Int, fastAdapter: FastAdapter, item: Item) -> Unit) { + addEventHook(object : ClickEventHook() { + override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { + return if (viewHolder is BindingViewHolder<*> && viewHolder.binding is Binding) resolveView.invoke(viewHolder.binding) else super.onBind(viewHolder) + } + + override fun onBindMany(viewHolder: RecyclerView.ViewHolder): List? { + return if (viewHolder is BindingViewHolder<*> && viewHolder.binding is Binding) resolveViews.invoke(viewHolder.binding) else super.onBindMany(viewHolder) + } + + override fun onClick(v: View, position: Int, fastAdapter: FastAdapter, item: Item) { + onClick.invoke(v, position, fastAdapter, item) + } + }) +} + + +/** + * Convenient extension function to simplify adding a [LongClickEventHook] to the [FastAdapter] + * + * A sample implementation may look like: + * ``` + * fastAdapter.addLongClickListener({ binding -> binding.view }) { v, position, fastAdapter, item -> + * // do something + * true + * } + * ``` + */ +inline fun FastAdapter.addLongClickListener(crossinline resolveView: (Binding) -> View?, crossinline resolveViews: ((Binding) -> List?) = { null }, crossinline onLongClick: (v: View, position: Int, fastAdapter: FastAdapter, item: Item) -> Boolean) { + addEventHook(object : LongClickEventHook() { + override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { + return if (viewHolder is BindingViewHolder<*> && viewHolder.binding is Binding) resolveView.invoke(viewHolder.binding) else super.onBind(viewHolder) + } + + override fun onBindMany(viewHolder: RecyclerView.ViewHolder): List? { + return if (viewHolder is BindingViewHolder<*> && viewHolder.binding is Binding) resolveViews.invoke(viewHolder.binding) else super.onBindMany(viewHolder) + } + + override fun onLongClick(v: View, position: Int, fastAdapter: FastAdapter, item: Item): Boolean { + return onLongClick.invoke(v, position, fastAdapter, item) + } + }) +} + +/** + * Convenient extension function to simplify adding a [TouchEventHook] to the [FastAdapter] + * + * A sample implementation may look like: + * ``` + * fastAdapter.addTouchListener({ binding -> binding.view }) { v, position, fastAdapter, item -> + * // do something + * true + * } + * ``` + */ +inline fun FastAdapter.addTouchListener(crossinline resolveView: (Binding) -> View?, crossinline resolveViews: ((Binding) -> List?) = { null }, crossinline onTouch: (v: View, event: MotionEvent, position: Int, fastAdapter: FastAdapter, item: Item) -> Boolean) { + addEventHook(object : TouchEventHook() { + override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { + return if (viewHolder is BindingViewHolder<*> && viewHolder.binding is Binding) resolveView.invoke(viewHolder.binding) else super.onBind(viewHolder) + } + + override fun onBindMany(viewHolder: RecyclerView.ViewHolder): List? { + return if (viewHolder is BindingViewHolder<*> && viewHolder.binding is Binding) resolveViews.invoke(viewHolder.binding) else super.onBindMany(viewHolder) + } + + override fun onTouch(v: View, event: MotionEvent, position: Int, fastAdapter: FastAdapter, item: Item): Boolean { + return onTouch.invoke(v, event, position, fastAdapter, item) + } + }) +} \ No newline at end of file diff --git a/library-extensions-diff/build.gradle b/library-extensions-diff/build.gradle index 65f640cb2..069ee571f 100644 --- a/library-extensions-diff/build.gradle +++ b/library-extensions-diff/build.gradle @@ -38,16 +38,16 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.androidX}" - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation "org.robolectric:robolectric:${versions.roboelectric}" - testImplementation 'com.squareup.assertj:assertj-android:1.1.1' - testImplementation 'com.squareup.assertj:assertj-android-design:1.1.1@aar' - testImplementation 'com.squareup.assertj:assertj-android-appcompat-v7:1.1.1@aar' - testImplementation("com.squareup.assertj:assertj-android-support-v4:1.1.1@aar") { + testImplementation 'com.squareup.assertj:assertj-android:1.2.0' + testImplementation 'com.squareup.assertj:assertj-android-design:1.2.0@aar' + testImplementation 'com.squareup.assertj:assertj-android-appcompat-v7:1.2.0@aar' + testImplementation("com.squareup.assertj:assertj-android-support-v4:1.2.0@aar") { exclude group: "com.android.support", module: "support-annotations" exclude group: "com.android.support", module: "support-v4" } diff --git a/library-extensions-diff/src/main/java/com/mikepenz/fastadapter/diff/FastAdapterDiffUtil.kt b/library-extensions-diff/src/main/java/com/mikepenz/fastadapter/diff/FastAdapterDiffUtil.kt index 4da6f7226..96306c01a 100644 --- a/library-extensions-diff/src/main/java/com/mikepenz/fastadapter/diff/FastAdapterDiffUtil.kt +++ b/library-extensions-diff/src/main/java/com/mikepenz/fastadapter/diff/FastAdapterDiffUtil.kt @@ -16,26 +16,21 @@ import java.util.* object FastAdapterDiffUtil { /** - * This method will compute a [androidx.recyclerview.widget.DiffUtil.DiffResult] based on the given adapter, and the list of new items. - * + * This method will prepare the adapter and the previous set of of items for the diffing. * * It automatically collapses all expandables (if enabled) as they are not supported by the diff util, - * pre sort the items based on the comparator if available, - * map the new item types for the FastAdapter then calculates the [androidx.recyclerview.widget.DiffUtil.DiffResult] using the [DiffUtil]. - * + * pre sort the items based on the comparator if available. * - * As the last step it will replace the items inside the adapter with the new set of items provided. + * Note this is not needed in simple usecases. See [set] instead (set without [DiffUtil.DiffResult]). * * @param adapter the adapter containing the current items. * @param items the new set of items we want to put into the adapter - * @param callback the callback used to implement the required checks to identify changes of items. - * @param detectMoves configuration for the [DiffUtil.calculateDiff] method - * @param The adapter type, whereas A extends [ModelAdapter] - * @param The model type we work with - * @param The item type kept in the adapter - * @return the [androidx.recyclerview.widget.DiffUtil.DiffResult] computed. - */ - fun , Model, Item : GenericItem> calculateDiff(adapter: A, items: List, callback: DiffCallback = DiffCallbackImpl(), detectMoves: Boolean = true): DiffUtil.DiffResult { + * @param A The adapter type, whereas A extends [ModelAdapter] + * @param Model The model type we work with + * @param Item The item type kept in the adapter + * @return the list of original items as a copy, to calculate the diff on + */ + fun , Model, Item : GenericItem> prepare(adapter: A, items: List): List { if (adapter.isUseIdDistributor) { adapter.idDistributor.checkIds(items) } @@ -48,35 +43,68 @@ object FastAdapterDiffUtil { Collections.sort(items, (adapter.itemList as ComparableItemListImpl).comparator) } - //map the types - adapter.mapPossibleTypes(items) + //remember the old items + return adapter.adapterItems.toList() + } + /** + * This method will compute a [DiffUtil.DiffResult] based on the given adapter, and the list of new items. + * + * It automatically collapses all expandables (if enabled) as they are not supported by the diff util, + * pre sort the items based on the comparator if available, + * map the new item types for the FastAdapter then calculates the [DiffUtil.DiffResult] using the [DiffUtil]. + * + * As the last step it will replace the items inside the adapter with the new set of items provided. + * + * @param adapter the adapter containing the current items. + * @param items the new set of items we want to put into the adapter + * @param callback the callback used to implement the required checks to identify changes of items. + * @param detectMoves configuration for the [DiffUtil.calculateDiff] method + * @param A The adapter type, whereas A extends [ModelAdapter] + * @param Model The model type we work with + * @param Item The item type kept in the adapter + * @return the [DiffUtil.DiffResult] computed. + */ + fun , Model, Item : GenericItem> calculateDiff(adapter: A, items: List, callback: DiffCallback = DiffCallbackImpl(), detectMoves: Boolean = true): DiffUtil.DiffResult { //remember the old items + val oldItems = prepare(adapter, items) val adapterItems = adapter.adapterItems - val oldItems = adapterItems.toList() //pass in the oldItem list copy as we will update the one in the adapter itself val result = DiffUtil.calculateDiff(FastAdapterCallback(oldItems, items, callback), detectMoves) //make sure the new items list is not a reference of the already mItems list - if (items !== adapterItems) { + postCalculate(adapter, items) + + return result + } + + + /** + * This method will ensure to update the maintained list of elements in the adapter. *After* the diff util updated the UI. + * This is required to ensure the adapter contains the new elements! those are required for the diff util to update the RV with the notify methods. + * + * Note this is not needed in simple usecases. See [set] instead (set without [DiffUtil.DiffResult]). + * + * @param oldItems the original list of items before the diff was calculated + * @param Item the list of *new* items we used to calculate the diff + * @return the [DiffUtil.DiffResult] computed. + */ + fun , Model, Item : GenericItem> postCalculate(adapter: A, newItems: List) { + //make sure the new items list is not a reference of the already mItems list + val adapterItems = adapter.adapterItems + if (newItems !== adapterItems) { //remove all previous items if (adapterItems.isNotEmpty()) { adapterItems.clear() } //add all new items to the list - adapterItems.addAll(items) + adapterItems.addAll(newItems) } - - return result } - /** - * Uses Reflection to collapse all items if this adapter uses expandable items - * - * @param fastAdapter - */ + /** Uses Reflection to collapse all items if this adapter uses expandable items */ private fun collapseIfPossible(fastAdapter: FastAdapter?) { fastAdapter ?: return try { @@ -92,10 +120,10 @@ object FastAdapterDiffUtil { } /** - * Dispatches a [androidx.recyclerview.widget.DiffUtil.DiffResult] to the given Adapter. + * Dispatches a [DiffUtil.DiffResult] to the given Adapter. * * @param adapter the adapter to dispatch the updates to - * @param result the computed [androidx.recyclerview.widget.DiffUtil.DiffResult] + * @param result the computed [DiffUtil.DiffResult] * @return the adapter to allow chaining */ operator fun , Model, Item : GenericItem> set(adapter: A, result: DiffUtil.DiffResult): A { @@ -104,51 +132,51 @@ object FastAdapterDiffUtil { } /** - * convenient function for [calculateDiff] + * Convenient function for [calculateDiff] * - * @return the [androidx.recyclerview.widget.DiffUtil.DiffResult] computed. + * @return the [DiffUtil.DiffResult] computed. */ fun , Model, Item : GenericItem> calculateDiff(adapter: A, items: List, callback: DiffCallback): DiffUtil.DiffResult { return calculateDiff(adapter, items, callback, true) } /** - * convenient function for [calculateDiff] + * Convenient function for [calculateDiff] * - * @return the [androidx.recyclerview.widget.DiffUtil.DiffResult] computed. + * @return the [DiffUtil.DiffResult] computed. */ fun , Model, Item : GenericItem> calculateDiff(adapter: A, items: List, detectMoves: Boolean): DiffUtil.DiffResult { return calculateDiff(adapter, items, DiffCallbackImpl(), detectMoves) } /** - * convenient function for [calculateDiff] + * Convenient function for [calculateDiff] * - * @return the [androidx.recyclerview.widget.DiffUtil.DiffResult] computed. + * @return the [DiffUtil.DiffResult] computed. */ fun , Model, Item : GenericItem> calculateDiff(adapter: A, items: List): DiffUtil.DiffResult { return calculateDiff(adapter, items, DiffCallbackImpl(), true) } /** - * Calculates a [androidx.recyclerview.widget.DiffUtil.DiffResult] given the adapter and the items, and will directly dispatch them to the adapter. + * Calculates a [DiffUtil.DiffResult] given the adapter and the items, and will directly dispatch them to the adapter. * * @param adapter the adapter containing the current items. * @param items the new set of items we want to put into the adapter * @param callback the callback used to implement the required checks to identify changes of items. * @param detectMoves configuration for the [DiffUtil.calculateDiff] method - * @param The adapter type, whereas A extends [ModelAdapter] - * @param The model type we work with - * @param The item type kept in the adapter + * @param A The adapter type, whereas A extends [ModelAdapter] + * @param Model The model type we work with + * @param Item The item type kept in the adapter * @return the adapter to allow chaining - */ + */ fun , Model, Item : GenericItem> set(adapter: A, items: List, callback: DiffCallback, detectMoves: Boolean): A { val result = calculateDiff(adapter, items, callback, detectMoves) return set(adapter, result) } /** - * convenient function for [.set] + * Convenient function for [set] * * @return the adapter to allow chaining */ @@ -157,7 +185,7 @@ object FastAdapterDiffUtil { } /** - * convenient function for [.set] + * Convenient function for [set] * * @return the adapter to allow chaining */ @@ -166,7 +194,7 @@ object FastAdapterDiffUtil { } /** - * convenient function for [.set] + * Convenient function for [set] * * @return the adapter to allow chaining */ @@ -175,10 +203,10 @@ object FastAdapterDiffUtil { } /** - * Convenient implementation for the [androidx.recyclerview.widget.DiffUtil.Callback] to simplify difference calculation using [FastAdapter] items. + * Convenient implementation for the [DiffUtil.Callback] to simplify difference calculation using [FastAdapter] items. * - * @param the item type in the adapter - */ + * @param Item the item type in the adapter + */ private class FastAdapterCallback internal constructor(private val oldItems: List, private val newItems: List, private val callback: DiffCallback) : DiffUtil.Callback() { override fun getOldListSize(): Int { diff --git a/library-extensions-drag/build.gradle b/library-extensions-drag/build.gradle index 7554129f8..f0c23ec2c 100644 --- a/library-extensions-drag/build.gradle +++ b/library-extensions-drag/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.androidX}" } diff --git a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IDraggable.kt b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IDraggable.kt index 1596b9243..067ca6732 100644 --- a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IDraggable.kt +++ b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IDraggable.kt @@ -4,8 +4,6 @@ package com.mikepenz.fastadapter.drag * Created by mikepenz on 30.12.15. */ interface IDraggable { - /** - * @return true if draggable - */ + /** @return true if draggable */ val isDraggable: Boolean } diff --git a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IExtendedDraggable.kt b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IExtendedDraggable.kt index dc21582ef..dfa7fabb4 100644 --- a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IExtendedDraggable.kt +++ b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/IExtendedDraggable.kt @@ -10,14 +10,14 @@ import androidx.recyclerview.widget.RecyclerView interface IExtendedDraggable : IDraggable { /** - * this returns the ItemTouchHelper + * This returns the ItemTouchHelper * * @return the ItemTouchHelper if item has one or null */ val touchHelper: ItemTouchHelper? /** - * this method returns the drag view inside the item + * This method returns the drag view inside the item * use this with (@withTouchHelper) to start dragging when this view is touched * * @param viewHolder the ViewHolder diff --git a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/ItemTouchCallback.kt b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/ItemTouchCallback.kt index 4ea5a8ca4..ab231f220 100644 --- a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/ItemTouchCallback.kt +++ b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/ItemTouchCallback.kt @@ -1,7 +1,16 @@ package com.mikepenz.fastadapter.drag +import androidx.recyclerview.widget.RecyclerView + interface ItemTouchCallback { + /** + * Called when an item enters drag state + * + * @param viewHolder dragged ViewHolder + */ + fun itemTouchStartDrag(viewHolder: RecyclerView.ViewHolder) {} + /** * Called when an item has been dragged * This event is called on every item in a dragging chain @@ -14,10 +23,12 @@ interface ItemTouchCallback { /** * Called when an item has been dropped - * This event is only called once when the user stopped dragging the item + * This event is only called : + * - Once when the user stopped dragging the item + * - If the corresponding AbstractItem implements {@link IDraggable} * * @param oldPosition start position * @param newPosition end position */ - fun itemTouchDropped(oldPosition: Int, newPosition: Int) + fun itemTouchDropped(oldPosition: Int, newPosition: Int) {} } \ No newline at end of file diff --git a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/SimpleDragCallback.kt b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/SimpleDragCallback.kt index f700d14b1..b9efb5bfb 100644 --- a/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/SimpleDragCallback.kt +++ b/library-extensions-drag/src/main/java/com/mikepenz/fastadapter/drag/SimpleDragCallback.kt @@ -8,44 +8,50 @@ import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter.adapters.ItemAdapter /** - * based on the sample from - * https://github.com/AleBarreto/DragRecyclerView + * Based on the [sample](https://github.com/AleBarreto/DragRecyclerView) */ open class SimpleDragCallback : ItemTouchHelper.SimpleCallback { //our callback - private var mCallbackItemTouch: ItemTouchCallback? = null // interface - private var mIsDragEnabled = true + private var callbackItemTouch: ItemTouchCallback? = null // interface - private var mFrom = RecyclerView.NO_POSITION - private var mTo = RecyclerView.NO_POSITION + /** enable to drag around via long press */ + var isDragEnabled = true - private var mDirections = UP_DOWN + private var from = RecyclerView.NO_POSITION + private var to = RecyclerView.NO_POSITION + + private var directions = UP_DOWN + + /** enable notification for all drops, even if location did not change */ + var notifyAllDrops = false // Default behaviour of v5.0.1- @Suppress("EmptyDefaultConstructor") @IntDef(ALL, UP_DOWN, LEFT_RIGHT) @Retention(AnnotationRetention.SOURCE) - annotation class Directions() + annotation class Directions { + // empty on purpose + } constructor(@Directions directions: Int = UP_DOWN) : super(directions, 0) { - this.mDirections = directions + this.directions = directions } constructor(@Directions directions: Int, itemTouchCallback: ItemTouchCallback) : super(directions, 0) { - this.mDirections = directions - this.mCallbackItemTouch = itemTouchCallback + this.directions = directions + this.callbackItemTouch = itemTouchCallback } constructor(itemTouchCallback: ItemTouchCallback) : super(UP_DOWN, 0) { - this.mCallbackItemTouch = itemTouchCallback + this.callbackItemTouch = itemTouchCallback } fun setIsDragEnabled(mIsDragEnabled: Boolean) { - this.mIsDragEnabled = mIsDragEnabled + this.isDragEnabled = mIsDragEnabled } override fun isLongPressDragEnabled(): Boolean { - return mIsDragEnabled + return isDragEnabled } override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { @@ -53,13 +59,13 @@ open class SimpleDragCallback : ItemTouchHelper.SimpleCallback { val item = FastAdapter.getHolderAdapterItem>(viewHolder) if (item is IDraggable) { if ((item as IDraggable).isDraggable) { - if (mFrom == RecyclerView.NO_POSITION) { - mFrom = viewHolder.adapterPosition + if (from == RecyclerView.NO_POSITION) { + from = viewHolder.adapterPosition } - mTo = target.adapterPosition + to = target.adapterPosition } } - if (mCallbackItemTouch == null) { + if (callbackItemTouch == null) { val adapter = recyclerView.adapter var itemAdapter: ItemAdapter<*>? = null if (adapter is FastAdapter<*>) { @@ -74,7 +80,7 @@ open class SimpleDragCallback : ItemTouchHelper.SimpleCallback { } throw RuntimeException("SimpleDragCallback without an callback is only allowed when using the ItemAdapter or the FastItemAdapter") } - return mCallbackItemTouch?.itemTouchOnMove(viewHolder.adapterPosition, target.adapterPosition) + return callbackItemTouch?.itemTouchOnMove(viewHolder.adapterPosition, target.adapterPosition) ?: false // information to the interface } @@ -87,7 +93,7 @@ open class SimpleDragCallback : ItemTouchHelper.SimpleCallback { 0 } } else { - mDirections + directions } } @@ -97,12 +103,22 @@ open class SimpleDragCallback : ItemTouchHelper.SimpleCallback { override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { super.clearView(recyclerView, viewHolder) - if (mFrom != RecyclerView.NO_POSITION && mTo != RecyclerView.NO_POSITION) { - mCallbackItemTouch?.itemTouchDropped(mFrom, mTo) + if (notifyAllDrops || (from != RecyclerView.NO_POSITION && to != RecyclerView.NO_POSITION)) { + // If 'to' is not set, then we can assume the item hasn't moved at all + if (from != RecyclerView.NO_POSITION && to == RecyclerView.NO_POSITION) to = from + callbackItemTouch?.itemTouchDropped(from, to) } // reset the from/to positions - mTo = RecyclerView.NO_POSITION - mFrom = mTo + to = RecyclerView.NO_POSITION + from = to + } + + override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { + super.onSelectedChanged(viewHolder, actionState) + if (ItemTouchHelper.ACTION_STATE_DRAG == actionState && viewHolder != null) { + from = viewHolder.adapterPosition + callbackItemTouch?.itemTouchStartDrag(viewHolder) + } } companion object { diff --git a/library-extensions-expandable/build.gradle b/library-extensions-expandable/build.gradle index e3bf85280..e22fa116a 100644 --- a/library-extensions-expandable/build.gradle +++ b/library-extensions-expandable/build.gradle @@ -37,22 +37,22 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" implementation "androidx.appcompat:appcompat:${versions.appcompat}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.androidX}" - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation "org.robolectric:robolectric:${versions.roboelectric}" - testImplementation 'androidx.test:rules:1.2.0' - testImplementation 'androidx.test:runner:1.2.0' - testImplementation 'androidx.test.ext:junit:1.1.1' - testImplementation 'androidx.test.espresso:espresso-core:3.2.0' + testImplementation 'androidx.test:rules:1.3.0' + testImplementation 'androidx.test:runner:1.3.0' + testImplementation 'androidx.test.ext:junit:1.1.2' + testImplementation 'androidx.test.espresso:espresso-core:3.3.0' - testImplementation 'com.squareup.assertj:assertj-android:1.1.1' - testImplementation 'com.squareup.assertj:assertj-android-design:1.1.1@aar' - testImplementation 'com.squareup.assertj:assertj-android-appcompat-v7:1.1.1@aar' - testImplementation("com.squareup.assertj:assertj-android-support-v4:1.1.1@aar") { + testImplementation 'com.squareup.assertj:assertj-android:1.2.0' + testImplementation 'com.squareup.assertj:assertj-android-design:1.2.0@aar' + testImplementation 'com.squareup.assertj:assertj-android-appcompat-v7:1.2.0@aar' + testImplementation("com.squareup.assertj:assertj-android-support-v4:1.2.0@aar") { exclude group: "com.android.support", module: "support-annotations" exclude group: "com.android.support", module: "support-v4" } diff --git a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtension.kt b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtension.kt index 0d625ce85..f6fdfa5c8 100644 --- a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtension.kt +++ b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtension.kt @@ -28,22 +28,16 @@ inline fun FastAdapter.expandableExtension(block: Exp getExpandableExtension().apply(block) } -/** - * internal helper function to check if an item is expanded. - */ +/** Internal helper function to check if an item is expanded. */ internal val IItem?.isExpanded: Boolean get() = (this as? IExpandable<*>)?.isExpanded == true -/** - * internal helper function to execute the block if the item is expandable - */ +/** Internal helper function to execute the block if the item is expandable */ internal fun IItem?.ifExpandable(block: (IExpandable<*>) -> R): R? { return (this as? IExpandable<*>)?.let(block) } -/** - * internal helper function to execute the block if the item is expandable - */ +/** Internal helper function to execute the block if the item is expandable */ internal fun IItem?.ifExpandableParent(block: (IExpandable<*>, IParentItem<*>) -> R): R? { return (this as? IExpandable<*>)?.parent?.let { block.invoke(this, it) @@ -69,12 +63,12 @@ class ExpandableExtension(private val fastAdapter: FastAdapt position: Int ): Boolean { //we do not care about non visible items - if (position == -1) { + if (position == RecyclerView.NO_POSITION) { return false } //this is the entrance parent - if (allowedParents.size > 0) { + if (allowedParents.isNotEmpty()) { // Go on until we hit an item with a parent which was not in our expandable hierarchy val parent = (item as? ISubItem<*>)?.parent if (parent == null || !allowedParents.contains(parent)) { @@ -102,11 +96,12 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } // only one expanded section - /** - * If there should be only one expanded, expandable item in the list - */ + /** If there should be only one expanded, expandable item in the list */ var isOnlyOneExpandedItem = false + /** Defines if the library will notify item changed on auto toggling */ + var notifyOnAutoToggleExpandable = true + //------------------------- //------------------------- //Expandable stuff @@ -114,7 +109,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt //------------------------- /** - * returns the expanded items this contains position and the count of items + * Returns the expanded items this contains position and the count of items * which are expanded by this position * * @return the expanded items @@ -122,15 +117,12 @@ class ExpandableExtension(private val fastAdapter: FastAdapt val expanded: SparseIntArray get() { val expandedItems = SparseIntArray() - var i = 0 - val size = fastAdapter.itemCount - while (i < size) { + for (i in 0 until fastAdapter.itemCount) { fastAdapter.getItem(i).ifExpandable { expandableItem -> if (expandableItem.isExpanded) { expandedItems.put(i, expandableItem.subItems.size) } } - i++ } return expandedItems } @@ -139,11 +131,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt * @return a set with the global positions of all expanded items */ val expandedItems: IntArray - get() { - return (0 until fastAdapter.itemCount).filter { - fastAdapter.getItem(it).isExpanded - }.toIntArray() - } + get() = (0 until fastAdapter.itemCount).filter { fastAdapter.getItem(it).isExpanded }.toIntArray() override fun withSavedInstanceState(savedInstanceState: Bundle?, prefix: String) { val expandedItems = savedInstanceState?.getLongArray(BUNDLE_EXPANDED + prefix) ?: return @@ -177,7 +165,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt //if this is a expandable item :D (this has to happen after we handled the selection as we refer to the position) item.ifExpandable { expandableItem -> if (expandableItem.isAutoExpanding) { - toggleExpandable(pos) + toggleExpandable(pos, notifyOnAutoToggleExpandable) } //if there should be only one expanded item we want to collapse all the others but the current one (this has to happen after we handled the selection as we refer to the position) if (isOnlyOneExpandedItem) { @@ -243,7 +231,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * notifies the fastAdapter about new / removed items within a sub hierarchy + * Notifies the fastAdapter about new / removed items within a sub hierarchy * NOTE this currently only works for sub items with only 1 level * * @param position the global position of the parent item @@ -307,13 +295,13 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * toggles the expanded state of the given expandable item at the given position + * Toggles the expanded state of the given expandable item at the given position * * @param position the global position * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false */ @JvmOverloads - fun toggleExpandable(position: Int, notifyItemChanged: Boolean = true) { + fun toggleExpandable(position: Int, notifyItemChanged: Boolean = false) { val item = fastAdapter.getItem(position) as? IExpandable<*> ?: return if (item.isExpanded) { collapse(position, notifyItemChanged) @@ -323,12 +311,12 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * collapses all expanded items + * Collapses all expanded items * * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false */ @JvmOverloads - fun collapse(notifyItemChanged: Boolean = true) { + fun collapse(notifyItemChanged: Boolean = false) { val expandedItems = expandedItems for (i in expandedItems.indices.reversed()) { collapse(expandedItems[i], notifyItemChanged) @@ -336,7 +324,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * collapses (closes) the given collapsible item at the given position + * Collapses (closes) the given collapsible item at the given position * * @param position the global position * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false @@ -355,7 +343,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * collapses (closes) the given collapsible item at the given position with parents who contains this item + * Collapses (closes) the given collapsible item at the given position with parents who contains this item * * @param position the global position * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false @@ -373,7 +361,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * expands all expandable items + * Expands all expandable items * * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false */ @@ -387,7 +375,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt /** - * opens the expandable item at the given position + * Opens the expandable item at the given position * * @param position the global position * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false @@ -418,7 +406,26 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * opens the expandable item at the given position with parents who contains this item + * Expand all items on a path from the root to a certain item + * + * @param item item to be expanded + * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false + */ + @JvmOverloads + fun expandAllOnPath(item: IExpandable<*>?, notifyItemChanged: Boolean = false) { + val parents = getExpandableParents(item ?: return) + + parents.forEach { expand(fastAdapter.getPosition(it.identifier)) } + + //we need to notify to get the correct drawable if there is one showing the current state + if (notifyItemChanged) { + val position = fastAdapter.getPosition(item.identifier) + fastAdapter.notifyItemChanged(position) + } + } + + /** + * Opens the expandable item at the given position with parents who contains this item * * @param position the global position * @param notifyItemChanged true if we need to call notifyItemChanged. DEFAULT: false @@ -436,7 +443,7 @@ class ExpandableExtension(private val fastAdapter: FastAdapt } /** - * calculates the count of expanded items before a given position + * Calculates the count of expanded items before a given position * * @param from the global start position you should pass here the count of items of the previous adapters (or 0 if you want to start from the beginning) * @param position the global position @@ -451,12 +458,16 @@ class ExpandableExtension(private val fastAdapter: FastAdapt .sum() } - /** - * Walks through the parents tree while parents are non-null and parents are IExpandable - */ + /** Walks through the parents tree while parents are non-null and parents are IExpandable */ private fun getExpandableParents(position: Int): List> { val expandable = fastAdapter.getItem(position) as? IExpandable<*> ?: return emptyList() + return getExpandableParents(expandable) + } + + /** Walks through the parents tree while parents are non-null and parents are IExpandable */ + private fun getExpandableParents(expandable: IExpandable<*>): List> { + // walk through the parents tree val parents = mutableListOf>() diff --git a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtensionFactory.kt b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtensionFactory.kt index 8c7160a95..763d40d6c 100644 --- a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtensionFactory.kt +++ b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/ExpandableExtensionFactory.kt @@ -8,9 +8,7 @@ class ExpandableExtensionFactory : ExtensionFactory> { override val clazz = ExpandableExtension::class.java - override fun create( - fastAdapter: FastAdapter - ): ExpandableExtension<*>? { + override fun create(fastAdapter: FastAdapter): ExpandableExtension<*>? { return ExpandableExtension(fastAdapter) } } diff --git a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/AbstractExpandableItem.kt b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/AbstractExpandableItem.kt index 8b6ba05f0..bea8cd533 100644 --- a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/AbstractExpandableItem.kt +++ b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/AbstractExpandableItem.kt @@ -1,26 +1,27 @@ package com.mikepenz.fastadapter.expandable.items import androidx.recyclerview.widget.RecyclerView -import com.mikepenz.fastadapter.* +import com.mikepenz.fastadapter.IExpandable +import com.mikepenz.fastadapter.IItem +import com.mikepenz.fastadapter.IParentItem +import com.mikepenz.fastadapter.ISubItem +import com.mikepenz.fastadapter.MutableSubItemList import com.mikepenz.fastadapter.items.AbstractItem abstract class AbstractExpandableItem : AbstractItem(), IItem, IExpandable { + private val _subItems = MutableSubItemList>(this) + override var isExpanded: Boolean = false override var parent: IParentItem<*>? = null - - override var subItems: MutableList> = MutableSubItemList(this) - set(value) { - field = value - for (item in value) { - item.parent = this - } - } + override var subItems: MutableList> + set(value) = _subItems.setNewList(value) + get() = _subItems override val isAutoExpanding: Boolean = true override var isSelectable: Boolean - get() = subItems.isNullOrEmpty() + get() = subItems.isEmpty() set(_) {} } diff --git a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/ModelAbstractExpandableItem.kt b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/ModelAbstractExpandableItem.kt index d0471b7bf..5c33d6a21 100644 --- a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/ModelAbstractExpandableItem.kt +++ b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/expandable/items/ModelAbstractExpandableItem.kt @@ -7,25 +7,19 @@ import com.mikepenz.fastadapter.ISubItem import com.mikepenz.fastadapter.MutableSubItemList import com.mikepenz.fastadapter.items.ModelAbstractItem -abstract class ModelAbstractExpandableItem(model: Model) : ModelAbstractItem(model), - IExpandable where Parent : IExpandable, SubItem : IExpandable { +abstract class ModelAbstractExpandableItem(model: Model) : + ModelAbstractItem(model), + IExpandable { + private val _subItems = MutableSubItemList>(this) + override var isExpanded: Boolean = false override var parent: IParentItem<*>? = null - private var _subItems: MutableList> = MutableSubItemList(this) override var subItems: MutableList> - set(value) { - _subItems = value - _subItems.let { subItems -> - for (item in subItems) { - item.parent = this - } - } - } - get() { - return _subItems - } + set(value) = _subItems.setNewList(value) + get() = _subItems + override val isAutoExpanding: Boolean = true override var isSelectable: Boolean - get() = _subItems.isNotEmpty() + get() = _subItems.isEmpty() set(_) {} } diff --git a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/AdapterUtil.kt b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/AdapterUtil.kt index d0c53c29d..a2d2da675 100644 --- a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/AdapterUtil.kt +++ b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/AdapterUtil.kt @@ -3,54 +3,48 @@ package com.mikepenz.fastadapter.utils import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem import com.mikepenz.fastadapter.IExpandable -import java.util.* +import java.util.ArrayList /** * Created by mikepenz on 31.12.15. */ object AdapterUtil { /** - * internal method to restore the selection state of subItems + * Internal method to restore the selection state of subItems * * @param item the parent item * @param selectedItems the list of selectedItems from the savedInstanceState */ - fun restoreSubItemSelectionStatesForAlternativeStateManagement(item: Item, selectedItems: List?) where Item : GenericItem, Item : IExpandable<*> { + @JvmStatic fun restoreSubItemSelectionStatesForAlternativeStateManagement(item: Item, selectedItems: List?) where Item : GenericItem, Item : IExpandable<*> { if (!item.isExpanded) { val subItems = (item as IExpandable<*>).subItems - var i = 0 - val size = subItems.size - while (i < size) { + for (i in subItems.indices) { val subItem = subItems[i] as Item val id = subItem.identifier.toString() if (selectedItems != null && selectedItems.contains(id)) { subItem.isSelected = true } restoreSubItemSelectionStatesForAlternativeStateManagement(subItem, selectedItems) - i++ } } } /** - * internal method to find all selections from subItems and sub sub items so we can save those inside our savedInstanceState + * Internal method to find all selections from subItems and sub sub items so we can save those inside our savedInstanceState * * @param item the parent item * @param selections the ArrayList which will be stored in the savedInstanceState */ - fun findSubItemSelections(item: Item, selections: MutableList) where Item : GenericItem, Item : IExpandable<*> { + @JvmStatic fun findSubItemSelections(item: Item, selections: MutableList) where Item : GenericItem, Item : IExpandable<*> { if (!item.isExpanded) { val subItems = (item as IExpandable<*>).subItems - var i = 0 - val size = subItems.size - while (i < size) { + for (i in subItems.indices) { val subItem = subItems[i] as Item val id = subItem.identifier.toString() if (subItem.isSelected) { selections.add(id) } findSubItemSelections(subItem, selections) - i++ } } } @@ -61,7 +55,7 @@ object AdapterUtil { * @param fastAdapter the FastAdapter * @return a list of all items including the whole subItem hirachy */ - fun getAllItems(fastAdapter: FastAdapter): List where Item : GenericItem, Item : IExpandable<*> { + @JvmStatic fun getAllItems(fastAdapter: FastAdapter): List where Item : GenericItem, Item : IExpandable<*> { val size = fastAdapter.itemCount val items = ArrayList(size) for (i in 0 until size) { @@ -79,17 +73,14 @@ object AdapterUtil { * @param item the parent from which we add all items * @param items the list in which we add the subItems */ - fun addAllSubItems(item: Item?, items: MutableList) where Item : GenericItem, Item : IExpandable<*> { + @JvmStatic fun addAllSubItems(item: Item?, items: MutableList) where Item : GenericItem, Item : IExpandable<*> { if (item is IExpandable<*> && !item.isExpanded) { val subItems = (item as IExpandable<*>).subItems var subItem: Item - var i = 0 - val size = subItems.size - while (i < size) { + for (i in subItems.indices) { subItem = subItems[i] as Item items.add(subItem) addAllSubItems(subItem, items) - i++ } } } diff --git a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/SubItemUtil.kt b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/SubItemUtil.kt index 3eda65d17..a630ac0ae 100644 --- a/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/SubItemUtil.kt +++ b/library-extensions-expandable/src/main/java/com/mikepenz/fastadapter/utils/SubItemUtil.kt @@ -1,5 +1,6 @@ package com.mikepenz.fastadapter.utils +import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.IExpandable import com.mikepenz.fastadapter.IItem @@ -7,7 +8,8 @@ import com.mikepenz.fastadapter.IItemAdapter import com.mikepenz.fastadapter.expandable.ExpandableExtension import com.mikepenz.fastadapter.select.SelectExtension import com.mikepenz.fastadapter.select.getSelectExtension -import java.util.* +import java.util.ArrayList +import java.util.LinkedList /** @@ -15,77 +17,85 @@ import java.util.* */ object SubItemUtil { /** - * counts the items in the adapter, respecting subitems regardless of there current visibility + * Counts the items in the adapter, respecting subitems regardless of there current visibility * * @param adapter the adapter instance * @param predicate predicate against which each item will be checked before counting it * @return number of items in the adapter that apply to the predicate */ - fun countItems(adapter: IItemAdapter<*, *>, predicate: IPredicate>): Int { - return countItems(adapter.adapterItems, true, false, predicate) + @JvmStatic fun countItems(adapter: IItemAdapter<*, *>, predicate: IPredicate>): Int { + return countItems( + items = adapter.adapterItems, + countHeaders = true, + subItemsOnly = false, + predicate = predicate + ) } /** - * counts the items in the adapter, respecting subitems regardless of there current visibility + * Counts the items in the adapter, respecting subitems regardless of there current visibility * * @param adapter the adapter instance * @param countHeaders if true, headers will be counted as well * @return number of items in the adapter */ - fun countItems(adapter: IItemAdapter<*, *>, countHeaders: Boolean): Int { + @JvmStatic fun countItems(adapter: IItemAdapter<*, *>, countHeaders: Boolean): Int { return countItems(adapter.adapterItems, countHeaders, false, null) } - private fun countItems(items: List>, countHeaders: Boolean, subItemsOnly: Boolean, predicate: IPredicate>?): Int { + @JvmStatic private fun countItems(items: List>, countHeaders: Boolean, subItemsOnly: Boolean, predicate: IPredicate>?): Int { return getAllItems(items, countHeaders, subItemsOnly, predicate).size } /** - * retrieves a flat list of the items in the adapter, respecting subitems regardless of there current visibility + * Retrieves a flat list of the items in the adapter, respecting subitems regardless of there current visibility * * @param adapter the adapter instance * @param predicate predicate against which each item will be checked before adding it to the result * @return list of items in the adapter that apply to the predicate */ - fun getAllItems(adapter: IItemAdapter<*, *>, predicate: IPredicate>): List> { - return getAllItems(adapter.adapterItems, true, false, predicate) + @JvmStatic fun getAllItems(adapter: IItemAdapter<*, *>, predicate: IPredicate>): List> { + return getAllItems( + items = adapter.adapterItems, + countHeaders = true, + subItemsOnly = false, + predicate = predicate + ) } /** - * retrieves a flat list of the items in the adapter, respecting subitems regardless of there current visibility + * Retrieves a flat list of the items in the adapter, respecting subitems regardless of there current visibility * * @param adapter the adapter instance * @param countHeaders if true, headers will be counted as well * @return list of items in the adapter */ - fun getAllItems(adapter: IItemAdapter<*, *>, countHeaders: Boolean): List> { + @JvmStatic fun getAllItems(adapter: IItemAdapter<*, *>, countHeaders: Boolean): List> { return getAllItems(adapter.adapterItems, countHeaders, false, null) } /** - * retrieves a flat list of the items in the provided list, respecting subitems regardless of there current visibility + * Retrieves a flat list of the items in the provided list, respecting subitems regardless of there current visibility * * @param items the list of items to process * @param countHeaders if true, headers will be counted as well * @return list of items in the adapter */ - fun getAllItems(items: List>, countHeaders: Boolean, predicate: IPredicate>): List> { + @JvmStatic fun getAllItems(items: List>, countHeaders: Boolean, predicate: IPredicate>): List> { return getAllItems(items, countHeaders, false, predicate) } /** - * internal function! - * + * Internal function! * * Why countHeaders and subItems => because the subItemsOnly is an internal flag for the recursive call to optimise it! */ - private fun getAllItems(items: List>?, countHeaders: Boolean, subItemsOnly: Boolean, predicate: IPredicate>?): List> { + @JvmStatic private fun getAllItems(items: List>?, countHeaders: Boolean, subItemsOnly: Boolean, predicate: IPredicate>?): List> { val res = ArrayList>() if (items == null || items.isEmpty()) { return res } - var temp: Int val itemCount = items.size var item: IItem<*> var subItems: List>? @@ -106,8 +116,7 @@ object SubItemUtil { if (countHeaders && predicate.apply(item)) { res.add(item) } - temp = subItems.size - for (j in 0 until temp) { + for (j in subItems.indices) { subItems[j].let { if (predicate.apply(it)) { res.add(it) @@ -127,13 +136,13 @@ object SubItemUtil { } /** - * counts the selected items in the adapter underneath an expandable item, recursively + * Counts the selected items in the adapter underneath an expandable item, recursively * * @param adapter the adapter instance * @param header the header who's selected children should be counted * @return number of selected items underneath the header */ - fun countSelectedSubItems(adapter: FastAdapter<*>, header: T): Int where T : IItem<*>, T : IExpandable<*> { + @JvmStatic fun countSelectedSubItems(adapter: FastAdapter<*>, header: T): Int where T : IItem<*>, T : IExpandable<*> { val extension = adapter.getExtension(SelectExtension::class.java) as SelectExtension<*>? if (extension != null) { val selections = extension.selectedItems @@ -142,11 +151,10 @@ object SubItemUtil { return 0 } - fun countSelectedSubItems(selections: Set>, header: T): Int where T : IItem<*>, T : IExpandable<*> { + @JvmStatic fun countSelectedSubItems(selections: Set>, header: T): Int where T : IItem<*>, T : IExpandable<*> { var count = 0 val subItems = header.subItems - val items = subItems.size - for (i in 0 until items) { + for (i in subItems.indices) { if (selections.contains(subItems[i])) { count++ } @@ -158,18 +166,18 @@ object SubItemUtil { } /** - * select or unselect all sub itmes underneath an expandable item + * Select or unselect all sub itmes underneath an expandable item * * @param adapter the adapter instance * @param header the header who's children should be selected or deselected * @param select the new selected state of the sub items */ - fun selectAllSubItems(adapter: Adapter, header: T, select: Boolean) where T : IItem<*>, T : IExpandable<*>, Adapter : FastAdapter { + @JvmStatic fun selectAllSubItems(adapter: Adapter, header: T, select: Boolean) where T : IItem<*>, T : IExpandable<*>, Adapter : FastAdapter { selectAllSubItems(adapter, header, select, false, null) } /** - * select or unselect all sub itmes underneath an expandable item + * Select or unselect all sub itmes underneath an expandable item * * @param adapter the adapter instance * @param header the header who's children should be selected or deselected @@ -177,13 +185,12 @@ object SubItemUtil { * @param notifyParent true, if the parent should be notified about the changes of its children selection state * @param payload payload for the notifying function */ - fun selectAllSubItems(adapter: Adapter, header: T, select: Boolean, notifyParent: Boolean, payload: Any?) where T : IItem<*>, Adapter : FastAdapter { + @JvmStatic fun selectAllSubItems(adapter: Adapter, header: T, select: Boolean, notifyParent: Boolean, payload: Any?) where T : IItem<*>, Adapter : FastAdapter { if (header is IExpandable<*>) { val subItems = header.subItems - val subItemsCount = subItems.size val position = adapter.getPosition(header) if (header.isExpanded) { - for (i in 0 until subItemsCount) { + for (i in subItems.indices) { if ((subItems[i] as IItem<*>).isSelectable) { val extension: SelectExtension? = adapter.getSelectExtension() if (extension != null) { @@ -199,7 +206,7 @@ object SubItemUtil { } } } else { - for (i in 0 until subItemsCount) { + for (i in subItems.indices) { if ((subItems[i] as IItem<*>).isSelectable) { (subItems[i] as IItem<*>).isSelected = select } @@ -215,14 +222,12 @@ object SubItemUtil { } } - private fun getParent(item: IItem<*>?): T? where T : IExpandable<*>, T : IItem<*> { - return if (item is IExpandable<*>) { - item.parent as T? - } else null + @JvmStatic private fun getParent(item: IItem<*>?): T? where T : IExpandable<*>, T : IItem<*> { + return (item as? IExpandable)?.parent as? T? } /** - * deletes all selected items from the adapter respecting if the are sub items or not + * Deletes all selected items from the adapter respecting if the are sub items or not * subitems are removed from their parents sublists, main items are directly removed * * Alternatively you might consider also looking at: [SelectExtension.deleteAllSelectedItems] @@ -230,7 +235,7 @@ object SubItemUtil { * @param deleteEmptyHeaders if true, empty headers will be removed from the adapter * @return List of items that have been removed from the adapter */ - fun deleteSelected(fastAdapter: FastAdapter>, selectExtension: SelectExtension<*>, expandableExtension: ExpandableExtension<*>, notifyParent: Boolean, deleteEmptyHeaders: Boolean): List> { + @JvmStatic fun deleteSelected(fastAdapter: FastAdapter>, selectExtension: SelectExtension<*>, expandableExtension: ExpandableExtension<*>, notifyParent: Boolean, deleteEmptyHeaders: Boolean): List> { val deleted = ArrayList>() // we use a LinkedList, because this has performance advantages when modifying the listIterator during iteration! @@ -256,12 +261,12 @@ object SubItemUtil { val subItems = parent.subItems subItems.remove(item) // check if parent is expanded and notify the adapter about the removed item, if necessary (only if parent is visible) - if (parentPos != -1 && parent.isExpanded) { + if (parentPos != RecyclerView.NO_POSITION && parent.isExpanded) { expandableExtension.notifyAdapterSubItemsChanged(parentPos, subItems.size + 1) } // if desired, notify the parent about its changed items (only if parent is visible!) - if (parentPos != -1 && notifyParent) { + if (parentPos != RecyclerView.NO_POSITION && notifyParent) { expanded = parent.isExpanded fastAdapter.notifyAdapterItemChanged(parentPos) // expand the item again if it was expanded before calling notifyAdapterItemChanged @@ -272,11 +277,11 @@ object SubItemUtil { deleted.add(item) - if (deleteEmptyHeaders && subItems.size == 0) { + if (deleteEmptyHeaders && subItems.isEmpty()) { it.add(parent) it.previous() } - } else if (pos != -1) { + } else if (pos != RecyclerView.NO_POSITION) { // if we did not find a parent, we remove the item from the adapter val adapter = fastAdapter.getAdapter(pos) if (adapter is IItemAdapter<*, *>) { @@ -289,7 +294,7 @@ object SubItemUtil { } /** - * deletes all items in identifiersToDelete collection from the adapter respecting if there are sub items or not + * Deletes all items in identifiersToDelete collection from the adapter respecting if there are sub items or not * subitems are removed from their parents sublists, main items are directly removed * * @param fastAdapter the adapter to remove the items from @@ -298,7 +303,7 @@ object SubItemUtil { * @param deleteEmptyHeaders if true, empty headers will be removed from the adapter * @return List of items that have been removed from the adapter */ - fun delete(fastAdapter: FastAdapter>, expandableExtension: ExpandableExtension<*>, identifiersToDelete: Collection?, notifyParent: Boolean, deleteEmptyHeaders: Boolean): List> { + @JvmStatic fun delete(fastAdapter: FastAdapter>, expandableExtension: ExpandableExtension<*>, identifiersToDelete: Collection?, notifyParent: Boolean, deleteEmptyHeaders: Boolean): List> { val deleted = ArrayList>() if (identifiersToDelete == null || identifiersToDelete.isEmpty()) { return deleted @@ -329,12 +334,12 @@ object SubItemUtil { parentPos = fastAdapter.getPosition(parent) val subItems = parent.subItems // check if parent is expanded and notify the adapter about the removed item, if necessary (only if parent is visible) - if (parentPos != -1 && parent.isExpanded) { + if (parentPos != RecyclerView.NO_POSITION && parent.isExpanded) { expandableExtension.notifyAdapterSubItemsChanged(parentPos, subItems.size + 1) } // if desired, notify the parent about it's changed items (only if parent is visible!) - if (parentPos != -1 && notifyParent) { + if (parentPos != RecyclerView.NO_POSITION && notifyParent) { expanded = parent.isExpanded fastAdapter.notifyAdapterItemChanged(parentPos) // expand the item again if it was expanded before calling notifyAdapterItemChanged @@ -349,7 +354,7 @@ object SubItemUtil { it.add(parent.identifier) it.previous() } - } else if (pos != -1) { + } else if (pos != RecyclerView.NO_POSITION) { // if we did not find a parent, we remove the item from the adapter val adapter = fastAdapter.getAdapter(pos) var success: Boolean @@ -366,29 +371,28 @@ object SubItemUtil { } /** - * notifies items (incl. sub items if they are currently extended) + * Notifies items (incl. sub items if they are currently extended) * * @param adapter the adapter * @param identifiers set of identifiers that should be notified * @param restoreExpandedState true, if expanded headers should stay expanded */ + @JvmStatic @JvmOverloads fun notifyItemsChanged(adapter: FastAdapter>, expandableExtension: ExpandableExtension<*>, identifiers: Set, restoreExpandedState: Boolean = false) where Item : IItem<*>, Item : IExpandable<*> { - var i = 0 var item: IItem<*>? - while (i < adapter.itemCount) { + for (i in 0 until adapter.itemCount) { item = adapter.getItem(i) if (item is IExpandable<*>) { notifyItemsChanged(adapter, expandableExtension, item, identifiers, true, restoreExpandedState) } else if (identifiers.contains(item?.identifier)) { adapter.notifyAdapterItemChanged(i) } - i++ } } /** - * notifies items (incl. sub items if they are currently extended) + * Notifies items (incl. sub items if they are currently extended) * * @param adapter the adapter * @param header the expandable header that should be checked (incl. sub items) @@ -396,7 +400,7 @@ object SubItemUtil { * @param checkSubItems true, if sub items of headers items should be checked recursively * @param restoreExpandedState true, if expanded headers should stay expanded */ - fun notifyItemsChanged(adapter: FastAdapter>, expandableExtension: ExpandableExtension<*>, header: Item, identifiers: Set, checkSubItems: Boolean, restoreExpandedState: Boolean) where Item : IItem<*>, Item : IExpandable<*> { + @JvmStatic fun notifyItemsChanged(adapter: FastAdapter>, expandableExtension: ExpandableExtension<*>, header: Item, identifiers: Set, checkSubItems: Boolean, restoreExpandedState: Boolean) where Item : IItem<*>, Item : IExpandable<*> { val subItems = header.subItems val subItemsCount = subItems.size val position = adapter.getPosition(header) diff --git a/library-extensions-expandable/src/test/java/com/mikepenz/fastadapter/ExpandableFastAdapterTest.kt b/library-extensions-expandable/src/test/java/com/mikepenz/fastadapter/ExpandableFastAdapterTest.kt index 7c9e62e80..b3471512c 100644 --- a/library-extensions-expandable/src/test/java/com/mikepenz/fastadapter/ExpandableFastAdapterTest.kt +++ b/library-extensions-expandable/src/test/java/com/mikepenz/fastadapter/ExpandableFastAdapterTest.kt @@ -1,5 +1,6 @@ package com.mikepenz.fastadapter +import android.os.Build import android.os.Bundle import androidx.test.ext.junit.runners.AndroidJUnit4 import com.mikepenz.fastadapter.adapters.ItemAdapter @@ -11,9 +12,11 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.robolectric.annotation.Config import java.util.* @RunWith(AndroidJUnit4::class) +@Config(sdk = [Build.VERSION_CODES.P]) class ExpandableFastAdapterTest { private lateinit var adapter: FastAdapter private lateinit var itemAdapter: ItemAdapter @@ -24,7 +27,7 @@ class ExpandableFastAdapterTest { @Throws(Exception::class) fun setUp() { itemAdapter = ItemAdapter() - adapter = FastAdapter.with>(itemAdapter) + adapter = FastAdapter.with(itemAdapter) expandableExtension = adapter.getExpandableExtension() selectExtension = adapter.getSelectExtension() } @@ -140,7 +143,7 @@ class ExpandableFastAdapterTest { @Throws(Exception::class) fun toggleNoneExpandable() { val itemAdapter = ItemAdapter() - val fastAdapter = FastAdapter.with>(itemAdapter) + val fastAdapter = FastAdapter.with(itemAdapter) val expandableExtension = fastAdapter.getExpandableExtension() val noneExpandableTestItems = ArrayList() val item = NoneExpandableTestItem() diff --git a/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedItemListImpl.kt b/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedItemListImpl.kt index 5c962b7a3..b3552010f 100644 --- a/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedItemListImpl.kt +++ b/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedItemListImpl.kt @@ -14,7 +14,7 @@ import com.mikepenz.fastadapter.utils.DefaultItemList * A item list implementation to support the PagedList from the `androidx.paging:paging-runtime` jetpack library */ @ExperimentalPagedSupport -open class PagedItemListImpl @JvmOverloads constructor( +open class PagedItemListImpl( listUpdateCallback: ListUpdateCallback, differConfig: AsyncDifferConfig, var placeholderInterceptor: (position: Int) -> Item = getDefaultPlaceholderInterceptor(), @@ -44,6 +44,14 @@ open class PagedItemListImpl @JvmOverloads constructo } } + override fun peek(position: Int): Item? { + return if (differ.itemCount > position) { + differ.currentList?.subList(position, position + 1)?.first()?.let { cache[it] } + } else { + null + } + } + private fun getItem(model: Model): Item? { return cache[model] ?: run { return interceptor.invoke(model)?.let { @@ -59,23 +67,17 @@ open class PagedItemListImpl @JvmOverloads constructo override fun getAdapterPosition(identifier: Long): Int = differ.currentList?.indexOfFirst { getItem(it)?.identifier == identifier } ?: throw RuntimeException("No item found at position") - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun remove(position: Int, preItemCount: Int) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun removeRange(position: Int, itemCount: Int, preItemCount: Int) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun move(fromPosition: Int, toPosition: Int, preItemCount: Int) { throw UnsupportedOperationException("Not supported") } @@ -84,44 +86,32 @@ open class PagedItemListImpl @JvmOverloads constructo return differ.currentList?.size ?: 0 } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun clear(preItemCount: Int) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun set(position: Int, item: Item, preItemCount: Int) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun addAll(items: List, preItemCount: Int) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun addAll(position: Int, items: List, preItemCount: Int) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun set(items: List, preItemCount: Int, adapterNotifier: IAdapterNotifier?) { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun setNewList(items: List, notify: Boolean) { throw UnsupportedOperationException("Not supported") } @@ -129,7 +119,6 @@ open class PagedItemListImpl @JvmOverloads constructo /** * Set the new list to be displayed. * - * * If a list is already being displayed, a diff will be computed on a background thread, which * will dispatch Adapter.notifyItem events on the main thread. * @@ -142,11 +131,9 @@ open class PagedItemListImpl @JvmOverloads constructo /** * Set the new list to be displayed. * - * * If a list is already being displayed, a diff will be computed on a background thread, which * will dispatch Adapter.notifyItem events on the main thread. * - * * The commit callback can be used to know when the PagedList is committed, but note that it * may not be executed. If PagedList B is submitted immediately after PagedList A, and is * committed directly, the callback associated with PagedList A will not be run. @@ -161,10 +148,10 @@ open class PagedItemListImpl @JvmOverloads constructo /** * Get the item from the current PagedList at the specified index. - *

+ * * Note that this operates on both loaded items and null padding within the PagedList. * - * @param position Index of item to get, must be >= 0, and < {@link #getItemCount()}. + * @param position Index of item to get, must be >= 0, and < {@link #getItemCount()}. * @return The item, or null, if a null placeholder is at the specified position. */ fun getItem(position: Int): Model? { @@ -174,14 +161,13 @@ open class PagedItemListImpl @JvmOverloads constructo /** * Returns the PagedList currently being displayed by the Adapter. * - * * This is not necessarily the most recent list passed to [.submitList], * because a diff is computed asynchronously between the new list and the current list before * updating the currentList value. May be null if no PagedList is being presented. * * @return The list currently being displayed. * - * @see .onCurrentListChanged + * @see AsyncPagedListDiffer.onCurrentListChanged */ fun getCurrentList(): PagedList? { return differ.currentList @@ -192,13 +178,25 @@ open class PagedItemListImpl @JvmOverloads constructo * * @param listener Listener to receive updates. * - * @see #getCurrentList() - * @see #removePagedListListener(PagedListListener) + * @see getCurrentList + * @see removePagedListListener */ fun addPagedListListener(listener: AsyncPagedListDiffer.PagedListListener) { differ.addPagedListListener(listener) } + /** + * Removes a PagedListListener to receive updates when the current PagedList changes. + * + * @param listener Listener to receive updates. + * + * @see getCurrentList + * @see addPagedListListener + */ + fun removePagedListListener(listener: AsyncPagedListDiffer.PagedListListener) { + differ.removePagedListListener(listener) + } + companion object { private const val TAG = "PagedItemListImpl" diff --git a/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedModelAdapter.kt b/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedModelAdapter.kt index 8333b0b14..220287843 100644 --- a/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedModelAdapter.kt +++ b/library-extensions-paged/src/main/java/com/mikepenz/fastadapter/paged/PagedModelAdapter.kt @@ -59,7 +59,7 @@ open class PagedModelAdapter( } /** - * the ModelAdapter does not keep a list of input model's to get retrieve them a `reverseInterceptor` is required + * The ModelAdapter does not keep a list of input model's to get retrieve them a `reverseInterceptor` is required * usually it is used to get the `Model` from a `IModelItem` * * @return a List of initial Model's @@ -82,25 +82,25 @@ open class PagedModelAdapter( get() = itemList.items /** - * Generates a `Item` based on it's `Model` using the interceptor + * Generates a [Item] based on it's [Model] using the interceptor * - * @param model the `Model` which will be used to create the `Item` - * @return the generated `Item` + * @param model the [Model] which will be used to create the [Item] + * @return the generated [Item] */ open fun intercept(model: Model): Item? { return interceptor.invoke(model) } /** - * Generates a List of Item based on it's List of Model using the interceptor + * Generates a [List] of [Item] based on it's [List] of [Model] using the interceptor * - * @param models the List of Model which will be used to create the List of Item - * @return the generated List of Item + * @param models the [List] of [Model] which will be used to create the [List] of [Item] + * @return the generated [List] of [Item] */ open fun intercept(models: List): List = models.mapNotNull { intercept(it) } /** - * filters the items with the constraint using the provided Predicate + * Filters the items with the constraint using the provided Predicate * * @param constraint the string used to filter the list */ @@ -129,7 +129,7 @@ open class PagedModelAdapter( } /** - * returns the global position if the relative position within this adapter was given + * Returns the global position if the relative position within this adapter was given * * @param position the relative position * @return the global position @@ -147,108 +147,86 @@ open class PagedModelAdapter( } /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter + * @param position the relative position + * @return the item at the given relative position within this adapter if it has been loaded */ + override fun peekAdapterItem(position: Int): Item? { + return itemList.peek(position) + } + + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun set(items: List): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ open operator fun set(list: List, resetFilter: Boolean, adapterNotifier: IAdapterNotifier?): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun setNewList(items: List, retainFilter: Boolean): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ @SafeVarargs override fun add(vararg items: Model): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun add(items: List): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ @SafeVarargs override fun add(position: Int, vararg items: Model): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun add(position: Int, items: List): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun set(position: Int, item: Model): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun move(fromPosition: Int, toPosition: Int): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun remove(position: Int): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun removeRange(position: Int, itemCount: Int): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun addInternal(items: List): IItemAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun addInternal(position: Int, items: List): IItemAdapter { throw UnsupportedOperationException("Not supported") } - /** - * Managed by the PagedList not supported to be managed via the PagedModelAdapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun setInternal(position: Int, item: Item): IItemAdapter { throw UnsupportedOperationException("Not supported") } - /** - * removes all items of this adapter - */ + /** Managed by the [PagedList] not supported to be managed via the [PagedModelAdapter] */ override fun clear(): PagedModelAdapter { throw UnsupportedOperationException("Not supported") } @@ -272,21 +250,19 @@ open class PagedModelAdapter( /** * Called when the current PagedList is updated. * - * - * This may be dispatched as part of [.submitList] if a background diff isn't + * This may be dispatched as part of [submitList] if a background diff isn't * needed (such as when the first list is passed, or the list is cleared). In either case, * PagedListAdapter will simply call - * [notifyItemRangeInserted/Removed(0, mPreviousSize)][.notifyItemRangeInserted]. + * [notifyItemRangeInserted/Removed(0, previousSize)][FastAdapter.notifyItemRangeInserted]. * - * - * This method will *not*be called when the Adapter switches from presenting a PagedList - * to a snapshot version of the PagedList during a diff. This means you cannot observe each - * PagedList via this method. + * This method will *not* be called when the Adapter switches from presenting a [PagedList] + * to a snapshot version of the [PagedList] during a diff. This means you cannot observe each + * [PagedList] via this method. * * @param previousList PagedList that was previously displayed, may be null. * @param currentList new PagedList being displayed, may be null. * - * @see .getCurrentList + * @see getCurrentList */ open fun onCurrentListChanged(previousList: PagedList?, currentList: PagedList?) { } @@ -294,7 +270,6 @@ open class PagedModelAdapter( /** * Set the new list to be displayed. * - * * If a list is already being displayed, a diff will be computed on a background thread, which * will dispatch Adapter.notifyItem events on the main thread. * @@ -307,17 +282,15 @@ open class PagedModelAdapter( /** * Set the new list to be displayed. * - * * If a list is already being displayed, a diff will be computed on a background thread, which * will dispatch Adapter.notifyItem events on the main thread. * - * - * The commit callback can be used to know when the PagedList is committed, but note that it - * may not be executed. If PagedList B is submitted immediately after PagedList A, and is - * committed directly, the callback associated with PagedList A will not be run. + * The commit callback can be used to know when the [PagedList] is committed, but note that it + * may not be executed. If [PagedList] B is submitted immediately after [PagedList] A, and is + * committed directly, the callback associated with [PagedList] A will not be run. * * @param pagedList The new list to be displayed. - * @param commitCallback Optional runnable that is executed when the PagedList is committed, if + * @param commitCallback Optional runnable that is executed when the [PagedList] is committed, if * it is committed. */ fun submitList(pagedList: PagedList?, commitCallback: Runnable?) { @@ -326,10 +299,10 @@ open class PagedModelAdapter( /** * Get the item from the current PagedList at the specified index. - *

- * Note that this operates on both loaded items and null padding within the PagedList. * - * @param position Index of item to get, must be >= 0, and < {@link #getItemCount()}. + * Note that this operates on both loaded items and null padding within the [PagedList]. + * + * @param position Index of item to get, must be >= 0, and < [adapterItemCount]. * @return The item, or null, if a null placeholder is at the specified position. */ protected fun getItem(position: Int): Model? { @@ -337,16 +310,15 @@ open class PagedModelAdapter( } /** - * Returns the PagedList currently being displayed by the Adapter. - * + * Returns the [PagedList] currently being displayed by the Adapter. * - * This is not necessarily the most recent list passed to [.submitList], + * This is not necessarily the most recent list passed to [submitList], * because a diff is computed asynchronously between the new list and the current list before * updating the currentList value. May be null if no PagedList is being presented. * * @return The list currently being displayed. * - * @see .onCurrentListChanged + * @see onCurrentListChanged */ fun getCurrentList(): PagedList? { return itemList.getCurrentList() @@ -355,7 +327,7 @@ open class PagedModelAdapter( companion object { /** - * static method to retrieve a new `ItemAdapter` + * Static method to retrieve a new `ItemAdapter` * * @return a new ItemAdapter */ diff --git a/library-extensions-scroll/build.gradle b/library-extensions-scroll/build.gradle index 92bdb79be..190746442 100644 --- a/library-extensions-scroll/build.gradle +++ b/library-extensions-scroll/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.androidX}" } diff --git a/library-extensions-scroll/src/main/java/androidx/recyclerview/widget/com_mikepenz_fastadapter_extensions_scroll.kt b/library-extensions-scroll/src/main/java/androidx/recyclerview/widget/com_mikepenz_fastadapter_extensions_scroll.kt index b4826eef8..746a484c8 100644 --- a/library-extensions-scroll/src/main/java/androidx/recyclerview/widget/com_mikepenz_fastadapter_extensions_scroll.kt +++ b/library-extensions-scroll/src/main/java/androidx/recyclerview/widget/com_mikepenz_fastadapter_extensions_scroll.kt @@ -5,16 +5,14 @@ import androidx.recyclerview.widget.RecyclerView.LayoutManager /** * Why the class name? Because it guarantees zero naming conflicts! * - * * With this really long name, I recommend `import static *.*` ! * - * * Created by jayson on 3/27/2016. */ @Suppress("all") object com_mikepenz_fastadapter_extensions_scroll { - fun postOnRecyclerView(layoutManager: LayoutManager, action: Runnable): Boolean { + @JvmStatic fun postOnRecyclerView(layoutManager: LayoutManager, action: Runnable): Boolean { if (layoutManager.mRecyclerView != null) { layoutManager.mRecyclerView.post(action) return true diff --git a/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnScrollListener.kt b/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnScrollListener.kt index 5d781d769..09ca70ec3 100644 --- a/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnScrollListener.kt +++ b/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnScrollListener.kt @@ -8,9 +8,9 @@ import com.mikepenz.fastadapter.adapters.ItemAdapter abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { private var enabled = true - private var mPreviousTotal = 0 - private var mLoading = true - private var mVisibleThreshold = -1 + private var previousTotal = 0 + private var isLoading = true + private var visibleThreshold = RecyclerView.NO_POSITION var firstVisibleItem: Int = 0 private set var visibleItemCount: Int = 0 @@ -18,13 +18,13 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { var totalItemCount: Int = 0 private set - private var mIsOrientationHelperVertical: Boolean = false - private var mOrientationHelper: OrientationHelper? = null + private var isOrientationHelperVertical: Boolean = false + private var orientationHelper: OrientationHelper? = null var currentPage = 0 private set - private var mFooterAdapter: ItemAdapter<*>? = null + private var footerAdapter: ItemAdapter<*>? = null lateinit var layoutManager: RecyclerView.LayoutManager private set @@ -35,7 +35,7 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { * @param adapter the ItemAdapter used to host footer items */ constructor(adapter: ItemAdapter<*>) { - this.mFooterAdapter = adapter + this.footerAdapter = adapter } constructor(layoutManager: RecyclerView.LayoutManager) { @@ -43,12 +43,12 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { } constructor(visibleThreshold: Int) { - this.mVisibleThreshold = visibleThreshold + this.visibleThreshold = visibleThreshold } constructor(layoutManager: RecyclerView.LayoutManager, visibleThreshold: Int) { this.layoutManager = layoutManager - this.mVisibleThreshold = visibleThreshold + this.visibleThreshold = visibleThreshold } /** @@ -58,8 +58,8 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { */ constructor(layoutManager: RecyclerView.LayoutManager, visibleThreshold: Int, footerAdapter: ItemAdapter<*>) { this.layoutManager = layoutManager - this.mVisibleThreshold = visibleThreshold - this.mFooterAdapter = footerAdapter + this.visibleThreshold = visibleThreshold + this.footerAdapter = footerAdapter } private fun findFirstVisibleItemPosition(recyclerView: RecyclerView): Int { @@ -74,15 +74,15 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { private fun findOneVisibleChild(fromIndex: Int, toIndex: Int, completelyVisible: Boolean, acceptPartiallyVisible: Boolean): View? { - if (layoutManager.canScrollVertically() != mIsOrientationHelperVertical || mOrientationHelper == null) { - mIsOrientationHelperVertical = layoutManager.canScrollVertically() - mOrientationHelper = if (mIsOrientationHelperVertical) + if (layoutManager.canScrollVertically() != isOrientationHelperVertical || orientationHelper == null) { + isOrientationHelperVertical = layoutManager.canScrollVertically() + orientationHelper = if (isOrientationHelperVertical) OrientationHelper.createVerticalHelper(layoutManager) else OrientationHelper.createHorizontalHelper(layoutManager) } - val mOrientationHelper = this.mOrientationHelper ?: return null + val mOrientationHelper = this.orientationHelper ?: return null val start = mOrientationHelper.startAfterPadding val end = mOrientationHelper.endAfterPadding @@ -115,32 +115,34 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { super.onScrolled(recyclerView, dx, dy) if (enabled) { - if (!::layoutManager.isInitialized) + if (!::layoutManager.isInitialized) { layoutManager = recyclerView.layoutManager ?: throw RuntimeException("A LayoutManager is required") + } - val footerItemCount = mFooterAdapter?.adapterItemCount ?: 0 + val footerItemCount = footerAdapter?.adapterItemCount ?: 0 - if (mVisibleThreshold == -1) - mVisibleThreshold = findLastVisibleItemPosition(recyclerView) - findFirstVisibleItemPosition(recyclerView) - footerItemCount + if (visibleThreshold == RecyclerView.NO_POSITION) { + visibleThreshold = findLastVisibleItemPosition(recyclerView) - findFirstVisibleItemPosition(recyclerView) - footerItemCount + } visibleItemCount = recyclerView.childCount - footerItemCount totalItemCount = layoutManager.itemCount - footerItemCount firstVisibleItem = findFirstVisibleItemPosition(recyclerView) - if (mLoading) { - if (totalItemCount > mPreviousTotal) { - mLoading = false - mPreviousTotal = totalItemCount + if (isLoading) { + if (totalItemCount > previousTotal) { + isLoading = false + previousTotal = totalItemCount } } - if (!mLoading && totalItemCount - visibleItemCount <= firstVisibleItem + mVisibleThreshold) { + if (!isLoading && totalItemCount - visibleItemCount <= firstVisibleItem + visibleThreshold) { currentPage++ onLoadMore(currentPage) - mLoading = true + isLoading = true } } } @@ -157,8 +159,8 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { @JvmOverloads fun resetPageCount(page: Int = 0) { - mPreviousTotal = 0 - mLoading = true + previousTotal = 0 + isLoading = true currentPage = page onLoadMore(currentPage) } diff --git a/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnTopScrollListener.kt b/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnTopScrollListener.kt index 419f7e1ec..80e93dedc 100644 --- a/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnTopScrollListener.kt +++ b/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessRecyclerOnTopScrollListener.kt @@ -7,22 +7,24 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter abstract class EndlessRecyclerOnTopScrollListener : RecyclerView.OnScrollListener { - private var mPreviousTotal = 0 - private var mLoading = true + private var previousTotal = 0 + private var isLoading = true + private var adapter: FastAdapter<*>? = null + private var orientationHelper: OrientationHelper? = null + private var isOrientationHelperVertical: Boolean = false + private var alreadyCalledOnNoMore: Boolean = false + + private lateinit var _layoutManager: LinearLayoutManager + var currentPage = 0 private set - private var mAdapter: FastAdapter<*>? = null - private lateinit var mLayoutManager: LinearLayoutManager - var visibleThreshold = -1 - private var mOrientationHelper: OrientationHelper? = null - private var mIsOrientationHelperVertical: Boolean = false var firstVisibleItem: Int = 0 private set var visibleItemCount: Int = 0 private set var totalItemCount: Int = 0 private set - private var mAlreadyCalledOnNoMore: Boolean = false + var visibleThreshold = RecyclerView.NO_POSITION // how many items your adapter must have at the end? // leave it -1 as its by default to disable onNothingToLoad() feature if you have only local data var totalLoadedItems = -1 @@ -31,54 +33,54 @@ abstract class EndlessRecyclerOnTopScrollListener : RecyclerView.OnScrollListene get() = totalLoadedItems != -1 private val isNothingToLoadNeeded: Boolean - get() = mAdapter?.itemCount == totalLoadedItems && !mAlreadyCalledOnNoMore + get() = adapter?.itemCount == totalLoadedItems && !alreadyCalledOnNoMore val layoutManager: RecyclerView.LayoutManager? - get() = mLayoutManager + get() = _layoutManager constructor(adapter: FastAdapter<*>, totalItems: Int) { - this.mAdapter = adapter + this.adapter = adapter totalLoadedItems = totalItems } constructor(adapter: FastAdapter<*>) { - this.mAdapter = adapter + this.adapter = adapter } override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) - if (!::mLayoutManager.isInitialized) { - this.mLayoutManager = recyclerView.layoutManager as LinearLayoutManager? + if (!::_layoutManager.isInitialized) { + this._layoutManager = recyclerView.layoutManager as LinearLayoutManager? ?: throw RuntimeException("A layoutmanager is required") } - if (visibleThreshold == -1) { + if (visibleThreshold == RecyclerView.NO_POSITION) { visibleThreshold = findLastVisibleItemPosition(recyclerView) - findFirstVisibleItemPosition(recyclerView) } visibleItemCount = recyclerView.childCount - totalItemCount = mLayoutManager.itemCount + totalItemCount = _layoutManager.itemCount firstVisibleItem = findFirstVisibleItemPosition(recyclerView) - totalItemCount = mAdapter?.itemCount ?: 0 + totalItemCount = adapter?.itemCount ?: 0 - if (mLoading) { - if (totalItemCount > mPreviousTotal) { - mLoading = false - mPreviousTotal = totalItemCount + if (isLoading) { + if (totalItemCount > previousTotal) { + isLoading = false + previousTotal = totalItemCount } } - if (!mLoading && mLayoutManager.findFirstVisibleItemPosition() - visibleThreshold <= 0) { + if (!isLoading && _layoutManager.findFirstVisibleItemPosition() - visibleThreshold <= 0) { currentPage++ onLoadMore(currentPage) - mLoading = true + isLoading = true } else { if (isNothingToLoadFeatureEnabled && isNothingToLoadNeeded) { onNothingToLoad() - mAlreadyCalledOnNoMore = true + alreadyCalledOnNoMore = true } } } @@ -89,41 +91,41 @@ abstract class EndlessRecyclerOnTopScrollListener : RecyclerView.OnScrollListene } private fun findFirstVisibleItemPosition(recyclerView: RecyclerView): Int { - val child = findOneVisibleChild(0, mLayoutManager.childCount, false, true) + val child = findOneVisibleChild(0, _layoutManager.childCount, false, true) return if (child == null) RecyclerView.NO_POSITION else recyclerView.getChildAdapterPosition(child) } /** - * load more data + * Load more data * * @param page page number, starts from 0 */ abstract fun onLoadMore(page: Int) /** - * there's no more data to be loaded, you may want + * There's no more data to be loaded, you may want * to send a request to server for asking more data */ abstract fun onNothingToLoad() private fun findOneVisibleChild(fromIndex: Int, toIndex: Int, completelyVisible: Boolean, acceptPartiallyVisible: Boolean): View? { - if (mLayoutManager.canScrollVertically() != mIsOrientationHelperVertical || mOrientationHelper == null) { - mIsOrientationHelperVertical = mLayoutManager.canScrollVertically() - mOrientationHelper = if (mIsOrientationHelperVertical) - OrientationHelper.createVerticalHelper(mLayoutManager) + if (_layoutManager.canScrollVertically() != isOrientationHelperVertical || orientationHelper == null) { + isOrientationHelperVertical = _layoutManager.canScrollVertically() + orientationHelper = if (isOrientationHelperVertical) + OrientationHelper.createVerticalHelper(_layoutManager) else - OrientationHelper.createHorizontalHelper(mLayoutManager) + OrientationHelper.createHorizontalHelper(_layoutManager) } - val mOrientationHelper = this.mOrientationHelper ?: return null + val mOrientationHelper = this.orientationHelper ?: return null val start = mOrientationHelper.startAfterPadding val end = mOrientationHelper.endAfterPadding val next = if (toIndex > fromIndex) 1 else -1 var partiallyVisible: View? = null var i = fromIndex while (i != toIndex) { - val child = mLayoutManager.getChildAt(i) + val child = _layoutManager.getChildAt(i) if (child != null) { val childStart = mOrientationHelper.getDecoratedStart(child) val childEnd = mOrientationHelper.getDecoratedEnd(child) @@ -145,20 +147,20 @@ abstract class EndlessRecyclerOnTopScrollListener : RecyclerView.OnScrollListene } /** - * reset page count + * Reset page count */ fun resetPageCount() { this.resetPageCount(0) } /** - * reset page count to specified page + * Reset page count to specified page * * @param page page number, starts from 0 */ fun resetPageCount(page: Int) { - this.mPreviousTotal = 0 - this.mLoading = true + this.previousTotal = 0 + this.isLoading = true this.currentPage = page this.onLoadMore(this.currentPage) } diff --git a/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessScrollHelper.kt b/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessScrollHelper.kt index 2a4939239..1f5614d5f 100644 --- a/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessScrollHelper.kt +++ b/library-extensions-scroll/src/main/java/com/mikepenz/fastadapter/scroll/EndlessScrollHelper.kt @@ -12,8 +12,6 @@ import com.mikepenz.fastadapter.adapters.ModelAdapter import com.mikepenz.fastadapter.scroll.EndlessScrollHelper.OnLoadMoreHandler import com.mikepenz.fastadapter.scroll.EndlessScrollHelper.OnNewItemsListener import java.lang.ref.WeakReference -import java.util.* - /** * This is an extension of [EndlessRecyclerOnScrollListener], providing a more powerful API @@ -26,15 +24,15 @@ import java.util.* * This class also takes care of other various stuffs like: * * * Ensuring the results are delivered on the RecyclerView's handler which also ensures - * that the results are delivered only when the RecyclerView is attached to the window, see [ ][View.post]. - * * Prevention of memory leaks when implemented properly (i.e. [ OnLoadMoreHandler][OnLoadMoreHandler] should be implemented via static classes or lambda expressions). - * * An easier way to deliver results to an [IItemAdapter][.withNewItemsDeliveredTo] or [ ModelAdapter][.withNewItemsDeliveredTo]. + * that the results are delivered only when the RecyclerView is attached to the window, see [View.post]. + * * Prevention of memory leaks when implemented properly (i.e. [OnLoadMoreHandler] should be implemented via static classes or lambda expressions). + * * An easier way to deliver results to an [IItemAdapter][withNewItemsDeliveredTo] or [ModelAdapter][withNewItemsDeliveredTo]. * * Created by jayson on 3/26/2016. */ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { - private var mOnLoadMoreHandler: OnLoadMoreHandler? = null - private var mOnNewItemsListener: OnNewItemsListener? = null + private var onLoadMoreHandler: OnLoadMoreHandler? = null + private var onNewItemsListener: OnNewItemsListener? = null constructor() @@ -55,26 +53,22 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { } /** - * A callback interface provided by the [EndlessScrollHelper] where - * [onLoadMore()][.onLoadMore] results are to be delivered. + * A callback interface provided by the [EndlessScrollHelper] where [onLoadMore] + * results are to be delivered. * The underlying implementation is safe to use by any background-thread, as long as only 1 - * thread is using it. Results delivered via [.deliverNewItems] are automatically + * thread is using it. Results delivered via [deliverNewItems] are automatically * dispatched to the RecyclerView's message queue (i.e. to be delivered in the ui thread). - * - * @param - */ + */ interface ResultReceiver { - /** - * @return the current page where the results will be delivered. - */ + /** @return the current page where the results will be delivered. */ val receiverPage: Int /** - * Delivers the result of an [onLoadMore()][.onLoadMore] for the - * current [page][.getReceiverPage]. This method must be called only once. + * Delivers the result of an [onLoadMore] for the current [page][receiverPage]. + * This method must be called only once. * - * @param result the result of an [onLoadMore()][.onLoadMore] + * @param result the result of an [onLoadMore()][onLoadMore] * @return whether results where delivered successfully or not, possibly because the * RecyclerView is no longer attached or the [EndlessScrollHelper] is no longer * in use (and it has been garbage collected). @@ -85,108 +79,60 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { interface OnLoadMoreHandler { - /** - * Handles loading of the specified page and delivers the results to the specified - * [ResultReceiver]. - * - * @param out - * @param currentPage - */ + /** Handles loading of the specified page and delivers the results to the specified [ResultReceiver] */ fun onLoadMore(out: ResultReceiver, currentPage: Int) } interface OnNewItemsListener { - /** - * Called on the RecyclerView's message queue to receive the results of a previous - * [onLoadMore()][.onLoadMore]. - * - * @param newItems - * @param page - */ + /** Called on the RecyclerView's message queue to receive the results of a previous [onLoadMore] */ fun onNewItems(newItems: List, page: Int) } - /** - * Define the [OnLoadMoreHandler] which will be used for loading new - * items. - * - * @param onLoadMoreHandler - * @return - */ + /** Define the [OnLoadMoreHandler] which will be used for loading new items. */ fun withOnLoadMoreHandler(onLoadMoreHandler: OnLoadMoreHandler): EndlessScrollHelper { - mOnLoadMoreHandler = onLoadMoreHandler + this.onLoadMoreHandler = onLoadMoreHandler return this } - /** - * Define the [OnNewItemsListener] which will receive the new items - * loaded by [onLoadMore()][.onLoadMore]. - * - * @param onNewItemsListener - * @return - * @see .withNewItemsDeliveredTo - * @see .withNewItemsDeliveredTo - */ + /** Define the [OnNewItemsListener] which will receive the new items loaded by [onLoadMore] */ fun withOnNewItemsListener(onNewItemsListener: OnNewItemsListener): EndlessScrollHelper { - mOnNewItemsListener = onNewItemsListener + this.onNewItemsListener = onNewItemsListener return this } /** * Registers an [OnNewItemsListener] that delivers results to the - * specified [IItemAdapter]. Converting each result to an [IItem] using the given - * `itemFactory`. - * - * @param itemAdapter - * @param itemFactory - * @param - * @return - * @see .withNewItemsDeliveredTo - */ + * specified [IItemAdapter]. Converting each result to an [IItem] using the given [itemFactory]. + */ fun withNewItemsDeliveredTo(itemAdapter: IItemAdapter<*, Item>, itemFactory: (element: Model) -> Item?): EndlessScrollHelper { - mOnNewItemsListener = DeliverToIItemAdapter(itemAdapter, itemFactory) + onNewItemsListener = DeliverToIItemAdapter(itemAdapter, itemFactory) return this } /** * Registers an [OnNewItemsListener] that delivers results to the * specified [ModelAdapter] through its [ModelAdapter.add] method. - * - * @param modelItemAdapter - * @return - * @see .withNewItemsDeliveredTo */ fun withNewItemsDeliveredTo(modelItemAdapter: ModelAdapter): EndlessScrollHelper { - mOnNewItemsListener = DeliverToModelAdapter(modelItemAdapter) + onNewItemsListener = DeliverToModelAdapter(modelItemAdapter) return this } /** - * An overload of [withNewItemsDeliveredTo()][.withNewItemsDeliveredTo] + * An overload of [withNewItemsDeliveredTo()][withNewItemsDeliveredTo] * that allows additional callbacks. - * - * @param itemAdapter - * @param itemFactory - * @param extraOnNewItemsListener - * @param - * @return - */ + */ fun withNewItemsDeliveredTo(itemAdapter: IItemAdapter<*, Item>, itemFactory: (element: Model) -> Item?, extraOnNewItemsListener: OnNewItemsListener): EndlessScrollHelper { - mOnNewItemsListener = DeliverToIItemAdapter2(itemAdapter, itemFactory, extraOnNewItemsListener) + onNewItemsListener = DeliverToIItemAdapter2(itemAdapter, itemFactory, extraOnNewItemsListener) return this } /** - * An overload of [withNewItemsDeliveredTo()][.withNewItemsDeliveredTo] - * that allows additional callbacks. - * - * @param modelItemAdapter - * @param extraOnNewItemsListener - * @return + * An overload of [withNewItemsDeliveredTo()][withNewItemsDeliveredTo] that allows additional callbacks. */ fun withNewItemsDeliveredTo(modelItemAdapter: ModelAdapter, extraOnNewItemsListener: OnNewItemsListener): EndlessScrollHelper { - mOnNewItemsListener = DeliverToModelAdapter2(modelItemAdapter, extraOnNewItemsListener) + onNewItemsListener = DeliverToModelAdapter2(modelItemAdapter, extraOnNewItemsListener) return this } @@ -196,16 +142,9 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { //------------------------- //------------------------- - /** - * The default implementation takes care of calling the previously set - * [OnLoadMoreHandler]. - * - * @param out - * @param currentPage - * @see .withOnLoadMoreHandler - */ + /** The default implementation takes care of calling the previously set [OnLoadMoreHandler] */ protected fun onLoadMore(out: ResultReceiver, currentPage: Int) { - val loadMoreHandler = this.mOnLoadMoreHandler + val loadMoreHandler = this.onLoadMoreHandler try { loadMoreHandler?.onLoadMore(out, currentPage) } catch (npe: NullPointerException) { @@ -217,16 +156,9 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { } } - /** - * The default implementation takes care of calling the previously set - * [OnNewItemsListener]. - * - * @param newItems - * @param page - * @see .withOnNewItemsListener - */ + /** The default implementation takes care of calling the previously set [OnNewItemsListener] */ protected fun onNewItems(newItems: List, page: Int) { - val onNewItemsListener = this.mOnNewItemsListener + val onNewItemsListener = this.onNewItemsListener try { onNewItemsListener?.onNewItems(newItems, page) } catch (npe: NullPointerException) { @@ -248,18 +180,20 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { onLoadMore(ResultReceiverImpl(this, currentPage), currentPage) } - private class ResultReceiverImpl internal constructor(helper: EndlessScrollHelper, override val receiverPage: Int)// We use WeakReferences to outer class to avoid memory leaks. + private class ResultReceiverImpl internal constructor(helper: EndlessScrollHelper, override val receiverPage: Int) + // We use WeakReferences to outer class to avoid memory leaks. : WeakReference>(helper), ResultReceiver, Runnable { - private var mHelperStrongRef: EndlessScrollHelper? = null - private var mResult: List? = null + private var helperStrongRef: EndlessScrollHelper? = null + private var result: List? = null override fun deliverNewItems(result: List): Boolean { - if (mResult != null) - // We might also see `null` here if more than 1 thread is modifying this. + if (this.result != null) { + // We might also see `null` here if more than 1 thread is modifying this. throw IllegalStateException("`result` already provided!") - mResult = result - mHelperStrongRef = super.get() - mHelperStrongRef?.let { + } + this.result = result + helperStrongRef = super.get() + helperStrongRef?.let { return postOnRecyclerView(it.layoutManager, this) } return false @@ -268,22 +202,20 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { override fun run() { // At this point, mHelperStrongRef != null try { - if (mHelperStrongRef?.currentPage != receiverPage) { + if (helperStrongRef?.currentPage != receiverPage) { // throw new IllegalStateException("Inconsistent state! " // + "Page might have already been loaded! " // + "Or `loadMore(result)` might have been used by more than 1 thread!"); return // Let it fail and possibly load correctly } } catch (npe: NullPointerException) { - if (mHelperStrongRef == null) { + if (helperStrongRef == null) { throw AssertionError(npe) } throw npe } - mResult?.let { - mHelperStrongRef?.onNewItems(it, receiverPage) - } + result?.let { helperStrongRef?.onNewItems(it, receiverPage) } } } @@ -293,30 +225,30 @@ open class EndlessScrollHelper : EndlessRecyclerOnScrollListener { //----------------------------------------- //----------------------------------------- - private open class DeliverToIItemAdapter internal constructor(private val mItemAdapter: IItemAdapter<*, Item>, private val mItemFactory: (element: Model) -> Item?) : OnNewItemsListener { + private open class DeliverToIItemAdapter internal constructor(private val itemAdapter: IItemAdapter<*, Item>, private val itemFactory: (element: Model) -> Item?) : OnNewItemsListener { override fun onNewItems(newItems: List, page: Int) { - val items = newItems.mapNotNull(mItemFactory) - mItemAdapter.addInternal(items) + val items = newItems.mapNotNull(itemFactory) + itemAdapter.addInternal(items) } } - private open class DeliverToModelAdapter internal constructor(private val mModelAdapter: ModelAdapter) : OnNewItemsListener { + private open class DeliverToModelAdapter internal constructor(private val modelAdapter: ModelAdapter) : OnNewItemsListener { override fun onNewItems(newItems: List, page: Int) { - mModelAdapter.add(newItems) + modelAdapter.add(newItems) } } - private class DeliverToIItemAdapter2 internal constructor(itemAdapter: IItemAdapter<*, Item>, itemFactory: (element: Model) -> Item?, private val mExtraOnNewItemsListener: OnNewItemsListener) : DeliverToIItemAdapter(itemAdapter, itemFactory) { + private class DeliverToIItemAdapter2 internal constructor(itemAdapter: IItemAdapter<*, Item>, itemFactory: (element: Model) -> Item?, private val extraOnNewItemsListener: OnNewItemsListener) : DeliverToIItemAdapter(itemAdapter, itemFactory) { override fun onNewItems(newItems: List, page: Int) { - mExtraOnNewItemsListener.onNewItems(newItems, page) + extraOnNewItemsListener.onNewItems(newItems, page) super.onNewItems(newItems, page) } } - private class DeliverToModelAdapter2 internal constructor(modelItemAdapter: ModelAdapter, private val mExtraOnNewItemsListener: OnNewItemsListener) : DeliverToModelAdapter(modelItemAdapter) { + private class DeliverToModelAdapter2 internal constructor(modelItemAdapter: ModelAdapter, private val extraOnNewItemsListener: OnNewItemsListener) : DeliverToModelAdapter(modelItemAdapter) { override fun onNewItems(newItems: List, page: Int) { - mExtraOnNewItemsListener.onNewItems(newItems, page) + extraOnNewItemsListener.onNewItems(newItems, page) super.onNewItems(newItems, page) } } diff --git a/library-extensions-swipe/build.gradle b/library-extensions-swipe/build.gradle index 5fbd0566b..1e4741972 100644 --- a/library-extensions-swipe/build.gradle +++ b/library-extensions-swipe/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.androidX}" } diff --git a/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/IDrawerSwipeableViewHolder.kt b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/IDrawerSwipeableViewHolder.kt new file mode 100644 index 000000000..f15ce1f64 --- /dev/null +++ b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/IDrawerSwipeableViewHolder.kt @@ -0,0 +1,11 @@ +package com.mikepenz.fastadapter.swipe + +import android.view.View + +/** + * Created by Robb on 03.07.20. + */ +interface IDrawerSwipeableViewHolder { + /** @return View that will move with the swipe gesture inside the ViewHolder */ + val swipeableView: View +} diff --git a/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/ISwipeable.kt b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/ISwipeable.kt index 0f1fad011..8bf95691f 100644 --- a/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/ISwipeable.kt +++ b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/ISwipeable.kt @@ -4,8 +4,6 @@ package com.mikepenz.fastadapter.swipe * Created by mikepenz on 30.12.15. */ interface ISwipeable { - /** - * @return true if swipeable - */ + /** @return true if swipeable */ val isSwipeable: Boolean } diff --git a/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeCallback.kt b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeCallback.kt index 889260fcc..d2f74e249 100644 --- a/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeCallback.kt +++ b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeCallback.kt @@ -23,6 +23,10 @@ class SimpleSwipeCallback @JvmOverloads constructor(private val itemSwipeCallbac private var bgPaint: Paint? = null private var horizontalMargin = Integer.MAX_VALUE + // Swipe movement control + private var sensitivityFactor = 1f + private var surfaceThreshold = 0.5f + interface ItemSwipeCallback { /** @@ -57,11 +61,33 @@ class SimpleSwipeCallback @JvmOverloads constructor(private val itemSwipeCallbac fun withBackgroundSwipeLeft(@ColorInt bgColor: Int): SimpleSwipeCallback { bgColorLeft = bgColor + setDefaultSwipeDirs(swipeDirs or ItemTouchHelper.LEFT) return this } fun withBackgroundSwipeRight(@ColorInt bgColor: Int): SimpleSwipeCallback { bgColorRight = bgColor + setDefaultSwipeDirs(swipeDirs or ItemTouchHelper.RIGHT) + return this + } + + /** + * Control the sensitivity of the swipe gesture + * 0.5 : very sensitive + * 1 : Android default + * 10 : almost insensitive + */ + fun withSensitivity(f: Float): SimpleSwipeCallback { + sensitivityFactor = f + return this + } + + /** + * % of the item's width or height needed to confirm the swipe action + * Android default : 0.5 + */ + fun withSurfaceThreshold(f: Float): SimpleSwipeCallback { + surfaceThreshold = f return this } @@ -92,6 +118,14 @@ class SimpleSwipeCallback @JvmOverloads constructor(private val itemSwipeCallbac return false } + override fun getSwipeEscapeVelocity(defaultValue: Float): Float { + return defaultValue * sensitivityFactor + } + + override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float { + return surfaceThreshold + } + //Inspired/modified from: https://github.com/nemanja-kovacevic/recycler-view-swipe-to-delete/blob/master/app/src/main/java/net/nemanjakovacevic/recyclerviewswipetodelete/MainActivity.java override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { val itemView = viewHolder.itemView @@ -120,7 +154,7 @@ class SimpleSwipeCallback @JvmOverloads constructor(private val itemSwipeCallbac if (drawable != null) { val itemHeight = itemView.bottom - itemView.top val intrinsicWidth = drawable.intrinsicWidth - val intrinsicHeight = drawable.intrinsicWidth + val intrinsicHeight = drawable.intrinsicHeight val left: Int val right: Int diff --git a/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeDrawerCallback.kt b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeDrawerCallback.kt new file mode 100644 index 000000000..499d25e55 --- /dev/null +++ b/library-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeDrawerCallback.kt @@ -0,0 +1,153 @@ +package com.mikepenz.fastadapter.swipe + +import android.graphics.Canvas +import android.graphics.Rect +import android.view.MotionEvent +import android.view.View +import android.view.View.VISIBLE +import android.view.ViewGroup +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.fastadapter.FastAdapter +import com.mikepenz.fastadapter.IItem + + +/** + * Created by Robb on 2020-07-04. + */ +class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs: Int = ItemTouchHelper.LEFT) : ItemTouchHelper.SimpleCallback(0, swipeDirs) { + + // Swipe movement control + private var sensitivityFactor = 1f + + // "Drawer width" swipe gesture is allowed to reach before blocking + private var swipeWidthLeftDp = 20 + private var swipeWidthRightDp = 20 + + // Indicates whether the touchTransmitter has been set on the RecyclerView + private var touchTransmitterSet = false + + + /** + * Enable swipe to the left until the given width has been reached + */ + fun withSwipeLeft(widthDp: Int): SimpleSwipeDrawerCallback { + swipeWidthLeftDp = widthDp + setDefaultSwipeDirs(swipeDirs or ItemTouchHelper.LEFT) + return this + } + + /** + * Enable swipe to the right until the given width has been reached + */ + fun withSwipeRight(widthDp: Int): SimpleSwipeDrawerCallback { + swipeWidthRightDp = widthDp + setDefaultSwipeDirs(swipeDirs or ItemTouchHelper.RIGHT) + return this + } + + /** + * Control the sensitivity of the swipe gesture + * 0.5 : very sensitive + * 1 : Android default + * 10 : almost insensitive + */ + fun withSensitivity(f: Float): SimpleSwipeDrawerCallback { + sensitivityFactor = f + return this + } + + override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + val item = FastAdapter.getHolderAdapterItem>(viewHolder) + return if (item is ISwipeable) { + if ((item as ISwipeable).isSwipeable) { + super.getSwipeDirs(recyclerView, viewHolder) + } else { + 0 + } + } else { + super.getSwipeDirs(recyclerView, viewHolder) + } + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + // Not used + } + + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { + // Not enabled + return false + } + + override fun getSwipeEscapeVelocity(defaultValue: Float): Float { + return defaultValue * sensitivityFactor + } + + override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { + val itemView = viewHolder.itemView + + if (!touchTransmitterSet) { + recyclerView.setOnTouchListener(RecyclerTouchTransmitter()) + touchTransmitterSet = true + } + + if (viewHolder.adapterPosition == RecyclerView.NO_POSITION) { + return + } + + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + val isLeft = dX < 0 + var swipeWidthPc = recyclerView.context.resources.displayMetrics.density / itemView.width + swipeWidthPc *= if (isLeft) swipeWidthLeftDp else swipeWidthRightDp + + var swipeableView = itemView + if (viewHolder is IDrawerSwipeableViewHolder) swipeableView = viewHolder.swipeableView + + swipeableView.translationX = dX * swipeWidthPc + } else super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) + } + + /** + * Hack to force-transmit click events to the first visible View at the clicked coordinates + * [< swiped area ] exposed sublayer ] + * Android default touch event mechanisms don't transmit these events to the sublayer : + * any click on the exposed surface just swipe the item back to where it came + */ + class RecyclerTouchTransmitter : View.OnTouchListener { + + override fun onTouch(v: View?, event: MotionEvent): Boolean { + if (null == v || v !is ViewGroup) return false + + // Get the first visible View under the clicked coordinates + val childView = v.getFirstVisibleViewByCoordinates(event.x, event.y) + // Transmit the ACTION_DOWN and ACTION_UP events to this View + if (childView != null) + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + childView.onTouchEvent(event) + } + MotionEvent.ACTION_UP -> { + childView.onTouchEvent(event) + } + } + return false + } + + /** + * Return the first visible non-ViewGroup View within the given ViewGroup, at the given coordinates + */ + private fun ViewGroup.getFirstVisibleViewByCoordinates(x: Float, y: Float): View? { + (childCount - 1 downTo 0) + .map { this.getChildAt(it) } + .forEach { + val bounds = Rect() + it.getHitRect(bounds) + if (bounds.contains(x.toInt(), y.toInt()) && VISIBLE == it.visibility) { + return if (it is ViewGroup) it.getFirstVisibleViewByCoordinates(x - bounds.left, y - bounds.top) + else it + } + } + return null + } + } +} diff --git a/library-extensions-ui/build.gradle b/library-extensions-ui/build.gradle index 66fd9eb16..8c335ab47 100644 --- a/library-extensions-ui/build.gradle +++ b/library-extensions-ui/build.gradle @@ -29,15 +29,13 @@ android { } dependencies { - implementation project(':library-core') + implementation project(':library-core') implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "com.google.android.material:material:${versions.androidX}" implementation "androidx.annotation:annotation:${versions.androidX}" - - implementation "com.mikepenz:materialize:${versions.materialize}" } if (project.hasProperty('pushall') || project.hasProperty('library_extensions_ui_only')) { diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterBottomSheetDialog.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterBottomSheetDialog.kt index 212a16897..d248f23cf 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterBottomSheetDialog.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterBottomSheetDialog.kt @@ -7,7 +7,6 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.bottomsheet.BottomSheetDialog import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem -import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter /** @@ -20,6 +19,7 @@ class FastAdapterBottomSheetDialog : BottomSheetDialog { private set var fastAdapter: FastAdapter? = null + lateinit var itemAdapter: ItemAdapter constructor(context: Context) : super(context) { @@ -59,7 +59,7 @@ class FastAdapterBottomSheetDialog : BottomSheetDialog { private fun initAdapterIfNeeded() { if (fastAdapter == null || recyclerView?.adapter == null) { itemAdapter = ItemAdapter.items() - fastAdapter = FastAdapter.with>(itemAdapter) + fastAdapter = FastAdapter.with(itemAdapter) recyclerView?.adapter = fastAdapter } } @@ -106,7 +106,7 @@ class FastAdapterBottomSheetDialog : BottomSheetDialog { * Start the dialog and display it on screen. The window is placed in the * application layer and opaque. Note that you should not override this * method to do initialization when the dialog is shown, instead implement - * that in [.onStart]. + * that in [onStart]. */ override fun show() { if (recyclerView?.layoutManager == null) { diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterDialog.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterDialog.kt index 6c24839a4..0f2132372 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterDialog.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/dialog/FastAdapterDialog.kt @@ -9,7 +9,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem -import com.mikepenz.fastadapter.IAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter class FastAdapterDialog : AlertDialog { @@ -77,7 +76,7 @@ class FastAdapterDialog : AlertDialog { private fun initAdapterIfNeeded() { if (fastAdapter == null || recyclerView!!.adapter == null) { itemAdapter = ItemAdapter.items() - fastAdapter = FastAdapter.with>(itemAdapter!!) + fastAdapter = FastAdapter.with(itemAdapter!!) recyclerView!!.adapter = fastAdapter } } @@ -258,7 +257,7 @@ class FastAdapterDialog : AlertDialog { * Start the dialog and display it on screen. The window is placed in the * application layer and opaque. Note that you should not override this * method to do initialization when the dialog is shown, instead implement - * that in [.onStart]. + * that in [onStart]. */ override fun show() { if (recyclerView!!.layoutManager == null) { diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ProgressItem.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ProgressItem.kt index 2d2938c9e..437526dc2 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ProgressItem.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ProgressItem.kt @@ -15,19 +15,14 @@ class ProgressItem : AbstractItem() { override val layoutRes: Int get() = R.layout.progress_item - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) if (isEnabled) { holder.itemView.setBackgroundResource(FastAdapterUIUtils.getSelectableBackground(holder.itemView.context)) } } - override fun unbindView(holder: ViewHolder) { - } - - override fun getViewHolder(v: View): ViewHolder { - return ViewHolder(v) - } + override fun getViewHolder(v: View): ViewHolder = ViewHolder(v) class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { private var progressBar: ProgressBar = view.findViewById(R.id.progress_bar) diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/SingleLineItem.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/SingleLineItem.kt index e90373257..67ee5f548 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/SingleLineItem.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/SingleLineItem.kt @@ -11,8 +11,8 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.ui.R import com.mikepenz.fastadapter.ui.utils.FastAdapterUIUtils -import com.mikepenz.materialize.holder.ImageHolder -import com.mikepenz.materialize.holder.StringHolder +import com.mikepenz.fastadapter.ui.utils.ImageHolder +import com.mikepenz.fastadapter.ui.utils.StringHolder /** * Created by fabianterhorst on 30.03.16. @@ -24,6 +24,7 @@ class SingleLineItem : AbstractItem() { var avatar: ImageHolder? = null private set + var icon: ImageHolder? = null private set @@ -88,7 +89,7 @@ class SingleLineItem : AbstractItem() { return this } - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) if (isEnabled) { holder.itemView.setBackgroundResource(FastAdapterUIUtils.getSelectableBackground(holder.itemView.context)) @@ -106,9 +107,7 @@ class SingleLineItem : AbstractItem() { holder.icon.visibility = View.VISIBLE } - override fun getViewHolder(v: View): ViewHolder { - return ViewHolder(v) - } + override fun getViewHolder(v: View): ViewHolder = ViewHolder(v) class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.name) as TextView diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ThreeLineItem.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ThreeLineItem.kt index 9dfe7793b..6d0ee01ca 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ThreeLineItem.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/ThreeLineItem.kt @@ -11,8 +11,8 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.ui.R import com.mikepenz.fastadapter.ui.utils.FastAdapterUIUtils -import com.mikepenz.materialize.holder.ImageHolder -import com.mikepenz.materialize.holder.StringHolder +import com.mikepenz.fastadapter.ui.utils.ImageHolder +import com.mikepenz.fastadapter.ui.utils.StringHolder /** * Created by fabianterhorst on 30.03.16. @@ -21,11 +21,13 @@ class ThreeLineItem : AbstractItem() { var name: StringHolder? = null private set + var description: StringHolder? = null private set var avatar: ImageHolder? = null private set + var icon: ImageHolder? = null private set @@ -90,8 +92,7 @@ class ThreeLineItem : AbstractItem() { return this } - - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) if (isEnabled) { holder.itemView.setBackgroundResource(FastAdapterUIUtils.getSelectableBackground(holder.itemView.context)) @@ -111,9 +112,7 @@ class ThreeLineItem : AbstractItem() { holder.icon.visibility = View.VISIBLE } - override fun getViewHolder(v: View): ViewHolder { - return ViewHolder(v) - } + override fun getViewHolder(v: View): ViewHolder = ViewHolder(v) class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.name) as TextView diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/TwoLineItem.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/TwoLineItem.kt index 55d554189..c5dc7c337 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/TwoLineItem.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/items/TwoLineItem.kt @@ -11,8 +11,8 @@ import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.items.AbstractItem import com.mikepenz.fastadapter.ui.R import com.mikepenz.fastadapter.ui.utils.FastAdapterUIUtils -import com.mikepenz.materialize.holder.ImageHolder -import com.mikepenz.materialize.holder.StringHolder +import com.mikepenz.fastadapter.ui.utils.ImageHolder +import com.mikepenz.fastadapter.ui.utils.StringHolder /** * Created by fabianterhorst on 30.03.16. @@ -21,11 +21,13 @@ class TwoLineItem : AbstractItem() { var name: StringHolder? = null private set + var description: StringHolder? = null private set var avatar: ImageHolder? = null private set + var icon: ImageHolder? = null private set @@ -95,7 +97,7 @@ class TwoLineItem : AbstractItem() { return this } - override fun bindView(holder: ViewHolder, payloads: MutableList) { + override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) if (isEnabled) { holder.itemView.setBackgroundResource(FastAdapterUIUtils.getSelectableBackground(holder.itemView.context)) @@ -115,9 +117,7 @@ class TwoLineItem : AbstractItem() { holder.icon.visibility = View.VISIBLE } - override fun getViewHolder(v: View): ViewHolder { - return ViewHolder(v) - } + override fun getViewHolder(v: View): ViewHolder = ViewHolder(v) class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.name) as TextView diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FastAdapterUIUtils.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FastAdapterUIUtils.kt index cf7156229..4c97800f7 100644 --- a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FastAdapterUIUtils.kt +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FastAdapterUIUtils.kt @@ -17,14 +17,19 @@ import java.util.* object FastAdapterUIUtils { /** - * helper to get the system default selectable background inclusive an active state + * Helper to get the system default selectable background inclusive an active state * * @param ctx the context * @param selected_color the selected color - * @param animate true if you want to fade over the states (only animates if API newer than Build.VERSION_CODES.HONEYCOMB) - * @return the StateListDrawable + * @param animate true if you want to fade over the states (only animates if API newer than [Build.VERSION_CODES.HONEYCOMB]) + * @return the [StateListDrawable] */ - fun getSelectableBackground(ctx: Context, @ColorInt selected_color: Int, animate: Boolean): StateListDrawable { + @JvmStatic + fun getSelectableBackground( + ctx: Context, + @ColorInt selected_color: Int, + animate: Boolean + ): StateListDrawable { val states = StateListDrawable() val clrActive = ColorDrawable(selected_color) @@ -43,15 +48,21 @@ object FastAdapterUIUtils { } /** - * helper to get the system default selectable background inclusive an active and pressed state + * Helper to get the system default selectable background inclusive an active and pressed state * * @param ctx the context * @param selected_color the selected color * @param pressed_alpha 0-255 - * @param animate true if you want to fade over the states (only animates if API newer than Build.VERSION_CODES.HONEYCOMB) - * @return the StateListDrawable + * @param animate true if you want to fade over the states (only animates if API newer than [Build.VERSION_CODES.HONEYCOMB]) + * @return the [StateListDrawable] */ - fun getSelectablePressedBackground(ctx: Context, @ColorInt selected_color: Int, pressed_alpha: Int, animate: Boolean): StateListDrawable { + @JvmStatic + fun getSelectablePressedBackground( + ctx: Context, + @ColorInt selected_color: Int, + pressed_alpha: Int, + animate: Boolean + ): StateListDrawable { val states = getSelectableBackground(ctx, selected_color, animate) val clrPressed = ColorDrawable(adjustAlpha(selected_color, pressed_alpha)) states.addState(intArrayOf(android.R.attr.state_pressed), clrPressed) @@ -59,22 +70,19 @@ object FastAdapterUIUtils { } /** - * adjusts the alpha of a color + * Adjusts the alpha of a color * * @param color the color * @param alpha the alpha value we want to set 0-255 * @return the adjusted color */ + @JvmStatic fun adjustAlpha(@ColorInt color: Int, alpha: Int): Int { return alpha shl 24 or (color and 0x00ffffff) } - /** - * helper to get the system default selectable background - * - * @param ctx - * @return - */ + /** Helper to get the system default selectable background */ + @JvmStatic fun getSelectableBackground(ctx: Context): Int { // If we're running on Honeycomb or newer, then we can use the Theme's // selectableItemBackground to ensure that the View has a pressed state @@ -85,14 +93,19 @@ object FastAdapterUIUtils { } /** - * helper to create an ripple drawable with the given normal and pressed color + * Helper to create an ripple drawable with the given normal and pressed color * * @param normalColor the normal color * @param pressedColor the pressed color * @param radius the button radius * @return the ripple drawable */ - fun getRippleDrawable(@ColorInt normalColor: Int, @ColorInt pressedColor: Int, radius: Int): Drawable { + @JvmStatic + fun getRippleDrawable( + @ColorInt normalColor: Int, + @ColorInt pressedColor: Int, + radius: Int + ): Drawable { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { RippleDrawable(ColorStateList.valueOf(pressedColor), ColorDrawable(normalColor), getRippleMask(normalColor, radius)) @@ -102,12 +115,13 @@ object FastAdapterUIUtils { } /** - * helper to create an ripple mask with the given color and radius + * Helper to create an ripple mask with the given color and radius * * @param color the color * @param radius the radius * @return the mask drawable */ + @JvmStatic private fun getRippleMask(color: Int, radius: Int): Drawable { val outerRadius = FloatArray(8) Arrays.fill(outerRadius, radius.toFloat()) @@ -118,12 +132,13 @@ object FastAdapterUIUtils { } /** - * helper to create an StateListDrawable for the given normal and pressed color + * Helper to create an [StateListDrawable] for the given normal and pressed color * * @param normalColor the normal color * @param pressedColor the pressed color - * @return the StateListDrawable + * @return the [StateListDrawable] */ + @JvmStatic private fun getStateListDrawable( normalColor: Int, pressedColor: Int): StateListDrawable { val states = StateListDrawable() @@ -137,4 +152,18 @@ object FastAdapterUIUtils { ColorDrawable(normalColor)) return states } + + /** + * helper to create a stateListDrawable for the icon + * + * @param icon + * @param selectedIcon + * @return + */ + fun getIconStateList(icon: Drawable, selectedIcon: Drawable): StateListDrawable { + val iconStateListDrawable = StateListDrawable() + iconStateListDrawable.addState(intArrayOf(android.R.attr.state_selected), selectedIcon) + iconStateListDrawable.addState(intArrayOf(), icon) + return iconStateListDrawable + } } diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FixStateListDrawable.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FixStateListDrawable.kt new file mode 100644 index 000000000..f34f28c3d --- /dev/null +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/FixStateListDrawable.kt @@ -0,0 +1,47 @@ +package com.mikepenz.fastadapter.ui.utils + +import android.R +import android.annotation.SuppressLint +import android.content.res.ColorStateList +import android.graphics.PorterDuff +import android.graphics.drawable.Drawable +import android.graphics.drawable.StateListDrawable + +/** + * http://stackoverflow.com/questions/7979440/android-cloning-a-drawable-in-order-to-make-a-statelistdrawable-with-filters + * http://stackoverflow.com/users/2075875/malachiasz + */ +@SuppressLint("InlinedApi") +class FixStateListDrawable : StateListDrawable { + var color: ColorStateList? + + constructor(drawable: Drawable, color: ColorStateList?) : super() { + var drawable = drawable + drawable = drawable.mutate() + addState(intArrayOf(R.attr.state_selected), drawable) + addState(intArrayOf(), drawable) + this.color = color + } + + constructor(drawable: Drawable, selectedDrawable: Drawable, color: ColorStateList?) : super() { + var drawable = drawable + var selectedDrawable = selectedDrawable + drawable = drawable.mutate() + selectedDrawable = selectedDrawable.mutate() + addState(intArrayOf(R.attr.state_selected), selectedDrawable) + addState(intArrayOf(), drawable) + this.color = color + } + + override fun onStateChange(states: IntArray): Boolean { + val color = color + if (color != null) { + super.setColorFilter(color.getColorForState(states, color.defaultColor), PorterDuff.Mode.SRC_IN) + } + return super.onStateChange(states) + } + + override fun isStateful(): Boolean { + return true + } +} \ No newline at end of file diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/ImageHolder.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/ImageHolder.kt new file mode 100644 index 000000000..da9322514 --- /dev/null +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/ImageHolder.kt @@ -0,0 +1,193 @@ +package com.mikepenz.fastadapter.ui.utils + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Bitmap +import android.graphics.PorterDuff +import android.graphics.drawable.Drawable +import android.net.Uri +import android.view.View +import android.widget.ImageView +import androidx.annotation.DrawableRes +import androidx.core.content.ContextCompat +import com.mikepenz.fastadapter.ui.utils.FastAdapterUIUtils.getIconStateList +import java.io.FileNotFoundException + +/** + * Defines a custom holder class to support providing images either as uri, drawable, bitmap, or resource. Does not require a [Context] and will resolve the value when applying. + */ +open class ImageHolder { + /** Defines the uri image */ + var uri: Uri? = null + internal set + /** Defines the drawable image */ + var icon: Drawable? = null + internal set + /** Defines the bitmap image */ + var bitmap: Bitmap? = null + internal set + /** Defines the resource image */ + var iconRes = -1 + internal set + + protected constructor() + + constructor(url: String) { + this.uri = Uri.parse(url) + } + + constructor(uri: Uri) { + this.uri = uri + } + + constructor(icon: Drawable?) { + this.icon = icon + } + + constructor(bitmap: Bitmap) { + this.bitmap = bitmap + } + + constructor(@DrawableRes iconRes: Int) { + this.iconRes = iconRes + } + + /** + * sets an existing image to the imageView + */ + @JvmOverloads + open fun applyTo(imageView: ImageView, tag: String? = null): Boolean { + when { + uri != null -> imageView.setImageURI(uri) + icon != null -> imageView.setImageDrawable(icon) + bitmap != null -> imageView.setImageBitmap(bitmap) + iconRes != -1 -> imageView.setImageResource(iconRes) + else -> { + imageView.setImageBitmap(null) + return false + } + } + return true + } + + /** + * this only handles Drawables + */ + open fun decideIcon(ctx: Context, iconColor: ColorStateList, tint: Boolean, paddingDp: Int = 1): Drawable? { + var icon = this.icon + when { + iconRes != -1 -> icon = ContextCompat.getDrawable(ctx, iconRes) + uri != null -> try { + val inputStream = ctx.contentResolver.openInputStream(uri!!) + icon = Drawable.createFromStream(inputStream, uri!!.toString()) + } catch (e: FileNotFoundException) { + //no need to handle this + } + } + //if we got an icon AND we have auto tinting enabled AND it is no IIcon, tint it ;) + if (icon != null && tint) { + icon = icon.mutate() + icon.setColorFilter(iconColor.defaultColor, PorterDuff.Mode.SRC_IN) + } + + return icon + } + + companion object { + + /** + * a small static helper to set the image from the imageHolder nullSave to the imageView + */ + @JvmOverloads + fun applyTo(imageHolder: ImageHolder?, imageView: ImageView?, tag: String? = null): Boolean { + return if (imageHolder != null && imageView != null) { + imageHolder.applyTo(imageView, tag) + } else false + } + + /** + * a small static helper to set the image from the imageHolder nullSave to the imageView and hide the view if no image was set + */ + @JvmOverloads + fun applyToOrSetInvisible(imageHolder: ImageHolder?, imageView: ImageView?, tag: String? = null) { + val imageSet = applyTo(imageHolder, imageView, tag) + if (imageView != null) { + if (imageSet) { + imageView.visibility = View.VISIBLE + } else { + imageView.visibility = View.INVISIBLE + } + } + } + + /** + * a small static helper to set the image from the imageHolder nullSave to the imageView and hide the view if no image was set + */ + @JvmOverloads + fun applyToOrSetGone(imageHolder: ImageHolder?, imageView: ImageView?, tag: String? = null) { + val imageSet = applyTo(imageHolder, imageView, tag) + if (imageView != null) { + if (imageSet) { + imageView.visibility = View.VISIBLE + } else { + imageView.visibility = View.GONE + } + } + } + + /** + * a small static helper which catches nulls for us + */ + fun decideIcon(imageHolder: ImageHolder?, ctx: Context, iconColor: ColorStateList, tint: Boolean, paddingDp: Int = 1): Drawable? { + return imageHolder?.decideIcon(ctx, iconColor, tint, paddingDp) + } + + /** + * decides which icon to apply or hide this view + */ + fun applyDecidedIconOrSetGone(imageHolder: ImageHolder?, imageView: ImageView?, iconColor: ColorStateList, tint: Boolean, paddingDp: Int = 1) { + if (imageHolder != null && imageView != null) { + val drawable = decideIcon(imageHolder, imageView.context, iconColor, tint, paddingDp) + when { + drawable != null -> { + imageView.setImageDrawable(drawable) + imageView.visibility = View.VISIBLE + } + imageHolder.bitmap != null -> { + imageView.setImageBitmap(imageHolder.bitmap) + imageView.visibility = View.VISIBLE + } + else -> imageView.visibility = View.GONE + } + } else if (imageView != null) { + imageView.visibility = View.GONE + } + } + + /** + * a small static helper to set a multi state drawable on a view + */ + fun applyMultiIconTo(icon: Drawable?, selectedIcon: Drawable?, iconColor: ColorStateList, tinted: Boolean, imageView: ImageView) { + //if we have an icon then we want to set it + if (icon != null) { + //if we got a different color for the selectedIcon we need a StateList + if (selectedIcon != null) { + if (tinted) { + imageView.setImageDrawable(FixStateListDrawable(icon, selectedIcon, iconColor)) + } else { + imageView.setImageDrawable(getIconStateList(icon, selectedIcon)) + } + } else if (tinted) { + imageView.setImageDrawable(FixStateListDrawable(icon, iconColor)) + } else { + imageView.setImageDrawable(icon) + } + //make sure we display the icon + imageView.visibility = View.VISIBLE + } else { + //hide the icon + imageView.visibility = View.GONE + } + } + } +} \ No newline at end of file diff --git a/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/StringHolder.kt b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/StringHolder.kt new file mode 100644 index 000000000..4fd865fb7 --- /dev/null +++ b/library-extensions-ui/src/main/java/com/mikepenz/fastadapter/ui/utils/StringHolder.kt @@ -0,0 +1,93 @@ +package com.mikepenz.fastadapter.ui.utils + +import android.content.Context +import android.view.View +import android.widget.TextView +import androidx.annotation.StringRes + +/** + * Defines a custom holder class to support providing strings either as string or resource. Does not require a [Context] and will resolve the value when applying. + */ +open class StringHolder { + /** Defines the string text */ + var textString: CharSequence? = null + internal set + /** Defines the string resource */ + var textRes = -1 + internal set + + constructor(text: CharSequence?) { + this.textString = text + } + + constructor(@StringRes textRes: Int) { + this.textRes = textRes + } + + /** + * Applies the text to a [TextView] + */ + open fun applyTo(textView: TextView?) { + when { + textString != null -> textView?.text = textString + textRes != -1 -> textView?.setText(textRes) + else -> textView?.text = "" + } + } + + /** + * Applies the [TextView] if no text given, hide the textView + */ + open fun applyToOrHide(textView: TextView?): Boolean { + textView ?: return false + return when { + textString != null -> { + textView.text = textString + textView.visibility = View.VISIBLE + true + } + textRes != -1 -> { + textView.setText(textRes) + textView.visibility = View.VISIBLE + true + } + else -> { + textView.visibility = View.GONE + false + } + } + } + + /** + * Returns the text as [String] + */ + open fun getText(ctx: Context): String? { + if (textString != null) { + return textString.toString() + } else if (textRes != -1) { + return ctx.getString(textRes) + } + return null + } + + companion object { + /** + * Helper to apply the text to a [TextView] + */ + fun applyTo(text: StringHolder?, textView: TextView?) { + text?.applyTo(textView) + } + + /** + * Helper to apply the text to a [TextView] or hide if null + */ + fun applyToOrHide(text: StringHolder?, textView: TextView?): Boolean { + return if (text != null) { + text.applyToOrHide(textView) + } else { + textView?.visibility = View.GONE + false + } + } + } +} \ No newline at end of file diff --git a/library-extensions-utils/build.gradle b/library-extensions-utils/build.gradle index 635396517..49f4453a2 100644 --- a/library-extensions-utils/build.gradle +++ b/library-extensions-utils/build.gradle @@ -36,7 +36,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation "androidx.recyclerview:recyclerview:${versions.androidX}" + implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "com.google.android.material:material:${versions.androidX}" implementation "androidx.annotation:annotation:${versions.androidX}" } diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/AbstractWrapAdapter.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/AbstractWrapAdapter.kt index 945c515c4..51c7e0145 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/AbstractWrapAdapter.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/AbstractWrapAdapter.kt @@ -3,6 +3,7 @@ package com.mikepenz.fastadapter.adapters import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.mikepenz.fastadapter.IItem +import com.mikepenz.fastadapter.IItemVHFactory /** * Created by mikepenz on 03.03.16. @@ -29,49 +30,26 @@ abstract class AbstractWrapAdapter, VH : RecyclerView.ViewHolde return this } - /** - * this method states if we should insert a custom element at the vien position - * - * @param position - * @return - */ + /** This method states if we should insert a custom element at the given position */ abstract fun shouldInsertItemAtPosition(position: Int): Boolean - /** - * this method calculates how many elements were already inserted before this position; - * - * @param position - * @return - */ + /** This method calculates how many elements were already inserted before this position */ abstract fun itemInsertedBeforeCount(position: Int): Int - /** - * overwrite the registerAdapterDataObserver to correctly forward all events to the FastAdapter - * - * @param observer - */ + /** Overwrite the [RecyclerView.Adapter.registerAdapterDataObserver] to correctly forward all events to the FastAdapter */ override fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) { super.registerAdapterDataObserver(observer) adapter?.registerAdapterDataObserver(observer) } - /** - * overwrite the unregisterAdapterDataObserver to correctly forward all events to the FastAdapter - * - * @param observer - */ + /** Overwrite the [RecyclerView.Adapter.unregisterAdapterDataObserver] to correctly forward all events to the FastAdapter */ override fun unregisterAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) { super.unregisterAdapterDataObserver(observer) adapter?.unregisterAdapterDataObserver(observer) } - /** - * overwrite the getItemViewType to correctly return the value from the FastAdapter - * - * @param position - * @return - */ + /** Overwrite the [RecyclerView.Adapter.getItemViewType] to correctly return the value from the FastAdapter */ override fun getItemViewType(position: Int): Int { return if (shouldInsertItemAtPosition(position)) { getItem(position)?.type ?: 0 @@ -80,12 +58,7 @@ abstract class AbstractWrapAdapter, VH : RecyclerView.ViewHolde } } - /** - * overwrite the getItemId to correctly return the value from the FastAdapter - * - * @param position - * @return - */ + /** Overwrite the [RecyclerView.Adapter.getItemId] to correctly return the value from the FastAdapter */ override fun getItemId(position: Int): Long { return if (shouldInsertItemAtPosition(position)) { getItem(position)?.identifier ?: 0 @@ -94,38 +67,25 @@ abstract class AbstractWrapAdapter, VH : RecyclerView.ViewHolde } } - /** - * make sure we return the Item from the FastAdapter so we retrieve the item from all adapters - * - * @param position - * @return - */ + /** Make sure we return the Item from the FastAdapter so we retrieve the item from all adapters */ fun getItem(position: Int): Item? { return if (shouldInsertItemAtPosition(position)) { items[itemInsertedBeforeCount(position - 1)] - } else null + } else { + null + } } - /** - * make sure we return the count from the FastAdapter so we retrieve the count from all adapters - * - * @return - */ + /** Make sure we return the count from the FastAdapter so we retrieve the count from all adapters */ override fun getItemCount(): Int { val itemCount = adapter?.itemCount ?: 0 return itemCount + itemInsertedBeforeCount(itemCount) } - /** - * the onCreateViewHolder is managed by the FastAdapter so forward this correctly - * - * @param parent - * @param viewType - * @return - */ + /** The [RecyclerView.Adapter.onCreateViewHolder] is managed by the FastAdapter so forward this correctly */ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { //TODO OPTIMIZE - val vh = items.firstOrNull { it.type == viewType }?.getViewHolder(parent) + val vh = items.asSequence().mapNotNull { it to it as? IItemVHFactory }.firstOrNull { (item, factory) -> item.type == viewType }?.second?.getViewHolder(parent) if (vh != null) { return vh } @@ -138,13 +98,8 @@ abstract class AbstractWrapAdapter, VH : RecyclerView.ViewHolde //empty implementation as the one with the List payloads is already called } - /** - * the onBindViewHolder is managed by the FastAdapter so forward this correctly - * - * @param holder - * @param position - */ - override fun onBindViewHolder(holder: VH, position: Int, payloads: MutableList) { + /** The [RecyclerView.Adapter.onBindViewHolder] is managed by the FastAdapter so forward this correctly */ + override fun onBindViewHolder(holder: VH, position: Int, payloads: List) { if (shouldInsertItemAtPosition(position)) { getItem(position)?.bindView(holder, payloads) } else { @@ -152,66 +107,37 @@ abstract class AbstractWrapAdapter, VH : RecyclerView.ViewHolde } } - /** - * the setHasStableIds is managed by the FastAdapter so forward this correctly - * - * @param hasStableIds - */ + /** The [RecyclerView.Adapter.setHasStableIds] is managed by the FastAdapter so forward this correctly */ override fun setHasStableIds(hasStableIds: Boolean) { adapter?.setHasStableIds(hasStableIds) } - /** - * the onViewRecycled is managed by the FastAdapter so forward this correctly - * - * @param holder - */ + /** The [RecyclerView.Adapter.onViewRecycled] is managed by the FastAdapter so forward this correctly */ override fun onViewRecycled(holder: VH) { adapter?.onViewRecycled(holder) } - /** - * the onFailedToRecycleView is managed by the FastAdapter so forward this correctly - * - * @param holder - * @return - */ + /** The [RecyclerView.Adapter.onFailedToRecycleView] is managed by the FastAdapter so forward this correctly */ override fun onFailedToRecycleView(holder: VH): Boolean { return adapter?.onFailedToRecycleView(holder) ?: false } - /** - * the onViewDetachedFromWindow is managed by the FastAdapter so forward this correctly - * - * @param holder - */ + /** The [RecyclerView.Adapter.onViewDetachedFromWindow] is managed by the FastAdapter so forward this correctly */ override fun onViewDetachedFromWindow(holder: VH) { adapter?.onViewDetachedFromWindow(holder) } - /** - * the onViewAttachedToWindow is managed by the FastAdapter so forward this correctly - * - * @param holder - */ + /** The [RecyclerView.Adapter.onViewAttachedToWindow] is managed by the FastAdapter so forward this correctly */ override fun onViewAttachedToWindow(holder: VH) { adapter?.onViewAttachedToWindow(holder) } - /** - * the onAttachedToRecyclerView is managed by the FastAdapter so forward this correctly - * - * @param recyclerView - */ + /** The [RecyclerView.Adapter.onAttachedToRecyclerView] is managed by the FastAdapter so forward this correctly */ override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { adapter?.onAttachedToRecyclerView(recyclerView) } - /** - * the onDetachedFromRecyclerView is managed by the FastAdapter so forward this correctly - * - * @param recyclerView - */ + /** The [RecyclerView.Adapter.onDetachedFromRecyclerView] is managed by the FastAdapter so forward this correctly */ override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { adapter?.onDetachedFromRecyclerView(recyclerView) } diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/FastItemAdapter.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/FastItemAdapter.kt index 376806c1f..1448baa03 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/FastItemAdapter.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/adapters/FastItemAdapter.kt @@ -15,27 +15,22 @@ typealias GenericFastItemAdapter = FastItemAdapter * Created by mikepenz on 18.01.16. */ open class FastItemAdapter( - /** - * returns the internal created [ItemAdapter] - */ + /** @return the internal created [ItemAdapter] */ val itemAdapter: ItemAdapter = items() ) : IItemAdapter by itemAdapter, FastAdapter() { - /** - * @return the filter used to filter items - */ + + /** @return the filter used to filter items */ val itemFilter: ItemFilter<*, Item> get() = itemAdapter.itemFilter - /** - * ctor - */ + /** ctor */ init { addAdapter>(0, itemAdapter) cacheSizes() } /** - * defines if the IdDistributor is used to provide an ID to all added items which do not yet define an id + * Defines if the IdDistributor is used to provide an ID to all added items which do not yet define an id * * @param useIdDistributor false if the IdDistributor shouldn't be used * @return this @@ -47,20 +42,18 @@ open class FastItemAdapter( } /** - * removes a range of items starting with the given position within the existing icons + * Removes a range of items starting with the given position within the existing icons * * @param position the global position * @param itemCount the count of items removed */ @Deprecated(message = "removeItemRange is deprecated", replaceWith = ReplaceWith("removeRange"), level = DeprecationLevel.WARNING) open fun removeItemRange(position: Int, itemCount: Int): FastItemAdapter { - itemAdapter.removeRange(position, itemCount) + removeRange(position, itemCount) return this } - /** - * convenient open functions, to force to remap all possible types for the RecyclerView - */ + /** Convenient open functions, to force to remap all possible types for the RecyclerView */ open fun remapMappedTypes() { itemAdapter.remapMappedTypes() } diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/ActionModeHelper.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/ActionModeHelper.kt index 3fbef9f05..aacdaa47d 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/ActionModeHelper.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/ActionModeHelper.kt @@ -34,7 +34,7 @@ class ActionModeHelper { private var actionItemClickedListener: ActionItemClickedListener? = null /** - * convenient method to check if action mode is active or nor + * Convenient method to check if action mode is active or nor * * @return true, if ActionMode is active, false otherwise */ @@ -76,7 +76,7 @@ class ActionModeHelper { } /** - * no longer needed, the FastAdapter can handle sub items now on its own + * No longer needed, the FastAdapter can handle sub items now on its own * * @param expandableExtension * @return @@ -87,7 +87,7 @@ class ActionModeHelper { } /** - * implements the basic behavior of a CAB and multi select behavior, + * Implements the basic behavior of a CAB and multi select behavior, * including logics if the clicked item is collapsible * * @param item the current item @@ -98,7 +98,7 @@ class ActionModeHelper { } /** - * implements the basic behavior of a CAB and multi select behavior, + * Implements the basic behavior of a CAB and multi select behavior, * including logics if the clicked item is collapsible * * @param act the current Activity @@ -128,7 +128,7 @@ class ActionModeHelper { } /** - * implements the basic behavior of a CAB and multi select behavior onLongClick + * Implements the basic behavior of a CAB and multi select behavior onLongClick * * @param act the current Activity * @param position the position of the clicked item @@ -149,7 +149,7 @@ class ActionModeHelper { } /** - * check if the ActionMode should be shown or not depending on the currently selected items + * Check if the ActionMode should be shown or not depending on the currently selected items * Additionally, it will also update the title in the CAB for you * * @param act the current Activity @@ -161,7 +161,7 @@ class ActionModeHelper { } /** - * reset any active action mode if it is active, useful, to avoid leaking the activity if this helper class is retained + * Reset any active action mode if it is active, useful, to avoid leaking the activity if this helper class is retained */ fun reset() { if (actionMode != null) { @@ -186,7 +186,7 @@ class ActionModeHelper { } /** - * updates the title to reflect the current selected items or to show a user defined title + * Updates the title to reflect the current selected items or to show a user defined title * * @param selected number of selected items */ diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/HeaderHelper.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/HeaderHelper.kt index 515e7dab7..885a412ca 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/HeaderHelper.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/HeaderHelper.kt @@ -1,53 +1,38 @@ package com.mikepenz.fastadapter.helpers import com.mikepenz.fastadapter.adapters.ModelAdapter -import java.util.* +import java.util.Collections +import java.util.Comparator /** * Created by mikepenz on 17.08.16. */ class HeaderHelper { - /** - * @return the ModelAdapter - */ - /** - * @param modelAdapter the ModelAdapter - */ + + /** The ModelAdapter */ var modelAdapter: ModelAdapter? = null - /** - * @return the function used to determine headers - */ - /** - * @param groupingFunction the function used to determine headers - */ + + /** The function used to determine headers */ var groupingFunction: GroupingFunction - /** - * @return the comparator to use before adding the headers - */ - /** - * @param comparator the comparator to use before adding the headers - */ + + /** The comparator to use before adding the headers */ var comparator: Comparator? = null - /** - * @param groupingFunction - */ constructor(groupingFunction: GroupingFunction) { this.groupingFunction = groupingFunction } - /** - * @param modelAdapter - * @param groupingFunction - */ - constructor(modelAdapter: ModelAdapter, groupingFunction: GroupingFunction) { + constructor( + modelAdapter: ModelAdapter, + groupingFunction: GroupingFunction + ) { this.modelAdapter = modelAdapter this.groupingFunction = groupingFunction } /** - * call this when your list order has changed or was updated, and you have to readd the headres + * Call this when your list order has changed or was updated, and you have to readd the headres * * @param items the list which will get the headers added inbetween */ @@ -71,20 +56,17 @@ class HeaderHelper { if (headerItem != null) { items.add(i + 1, headerItem) - i += 1 - size += 1 + i++ + size++ } i++ } } - /** - * set the sorted list to the modelAdapter if provided - */ + // Set the sorted list to the modelAdapter if provided modelAdapter?.set(items) } - interface GroupingFunction { /** * @param currentItem the current item we check diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/RangeSelectorHelper.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/RangeSelectorHelper.kt index 9db1e10f4..de7516bff 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/RangeSelectorHelper.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/RangeSelectorHelper.kt @@ -11,63 +11,63 @@ import com.mikepenz.fastadapter.utils.SubItemUtil /** * Created by Michael on 15.09.2016. */ -open class RangeSelectorHelper(private val mFastAdapter: FastItemAdapter) { - private var mActionModeHelper: ActionModeHelper<*>? = null - private var mSupportSubItems = false - private var mPayload: Any? = null +open class RangeSelectorHelper(private val fastAdapter: FastItemAdapter) { + private var actionModeHelper: ActionModeHelper<*>? = null + private var supportSubItems = false + private var payload: Any? = null - private var mLastLongPressIndex: Int? = null + private var lastLongPressIndex: Int? = null /** - * set the ActionModeHelper, if you want to notify it after a range was selected + * Set the ActionModeHelper, if you want to notify it after a range was selected * so that it can update the ActionMode title * * @param actionModeHelper the action mode helper that should be used * @return this, for supporting function call chaining */ fun withActionModeHelper(actionModeHelper: ActionModeHelper<*>?): RangeSelectorHelper<*> { - mActionModeHelper = actionModeHelper + this.actionModeHelper = actionModeHelper return this } /** - * enable this, if you want the range selector to correclty handle sub items as well + * Enable this, if you want the range selector to correclty handle sub items as well * * @param supportSubItems true, if sub items are supported, false otherwise * @return this, for supporting function call chaining */ fun withSupportSubItems(supportSubItems: Boolean): RangeSelectorHelper<*> { - this.mSupportSubItems = supportSubItems + this.supportSubItems = supportSubItems return this } /** - * the provided payload will be passed to the adapters notify function, if one is provided + * The provided payload will be passed to the adapters notify function, if one is provided * * @param payload the paylaod that should be passed to the adapter on selection state change * @return this, for supporting function call chaining */ fun withPayload(payload: Any): RangeSelectorHelper<*> { - mPayload = payload + this.payload = payload return this } /** - * resets the last long pressed index, we only want to respect two consecutive long clicks for selecting a range of items + * Resets the last long pressed index, we only want to respect two consecutive long clicks for selecting a range of items */ fun onClick() { reset() } /** - * resets the last long pressed index, we only want to respect two consecutive long presses for selecting a range of items + * Resets the last long pressed index, we only want to respect two consecutive long presses for selecting a range of items */ fun reset() { - mLastLongPressIndex = null + lastLongPressIndex = null } /** - * will take care to save the long pressed index + * Will take care to save the long pressed index * or to select all items in the range between the current long pressed item and the last long pressed item * * @param index the index of the long pressed item @@ -76,31 +76,31 @@ open class RangeSelectorHelper(private val mFastAdapter: Fas */ @JvmOverloads fun onLongClick(index: Int, selectItem: Boolean = true): Boolean { - if (mLastLongPressIndex == null) { + if (lastLongPressIndex == null) { // we only consider long presses on not selected items - if (mFastAdapter.getAdapterItem(index).isSelectable) { - mLastLongPressIndex = index + if (fastAdapter.getAdapterItem(index).isSelectable) { + lastLongPressIndex = index // we select this item as well if (selectItem) { - val selectExtension: SelectExtension? = mFastAdapter.getExtension(SelectExtension::class.java) + val selectExtension: SelectExtension? = fastAdapter.getExtension(SelectExtension::class.java) selectExtension?.select(index) } - mActionModeHelper?.checkActionMode(null) // works with null as well, as the ActionMode is active for sure! + actionModeHelper?.checkActionMode(null) // works with null as well, as the ActionMode is active for sure! return true } - } else if (mLastLongPressIndex != index) { - mLastLongPressIndex?.let { + } else if (lastLongPressIndex != index) { + lastLongPressIndex?.let { // select all items in the range between the two long clicks selectRange(it, index, true) } // reset the index - mLastLongPressIndex = null + lastLongPressIndex = null } return false } /** - * selects all items in a range, from and to indizes are inclusive + * Selects all items in a range, from and to indizes are inclusive * * @param from the from index * @param to the to index @@ -119,9 +119,9 @@ open class RangeSelectorHelper(private val mFastAdapter: Fas var item: IItem<*> for (i in from..to) { - item = mFastAdapter.getAdapterItem(i) + item = fastAdapter.getAdapterItem(i) if (item.isSelectable) { - val selectExtension: SelectExtension? = mFastAdapter.getExtension(SelectExtension::class.java) + val selectExtension: SelectExtension? = fastAdapter.getExtension(SelectExtension::class.java) if (selectExtension != null) { if (select) { selectExtension.select(i) @@ -130,19 +130,19 @@ open class RangeSelectorHelper(private val mFastAdapter: Fas } } } - if (mSupportSubItems && !skipHeaders) { + if (supportSubItems && !skipHeaders) { // if a group is collapsed, select all sub items if (item is IExpandable<*> && !(item as IExpandable<*>).isExpanded) { - SubItemUtil.selectAllSubItems(mFastAdapter, mFastAdapter.getAdapterItem(i), select, true, mPayload) + SubItemUtil.selectAllSubItems(fastAdapter, fastAdapter.getAdapterItem(i), select, true, payload) } } } - mActionModeHelper?.checkActionMode(null) // works with null as well, as the ActionMode is active for sure! + actionModeHelper?.checkActionMode(null) // works with null as well, as the ActionMode is active for sure! } /** - * add the values to the bundle for saveInstanceState + * Add the values to the bundle for saveInstanceState * * @param savedInstanceState If the activity is being re-initialized after * previously being shut down then this Bundle contains the data it most @@ -152,14 +152,14 @@ open class RangeSelectorHelper(private val mFastAdapter: Fas */ @JvmOverloads fun saveInstanceState(savedInstanceState: Bundle, prefix: String = ""): Bundle { - mLastLongPressIndex?.let { + lastLongPressIndex?.let { savedInstanceState.putInt(BUNDLE_LAST_LONG_PRESS, it) } return savedInstanceState } /** - * restore the index of the last long pressed index + * Restore the index of the last long pressed index * IMPORTANT! Call this method only after all items where added to the adapters again. Otherwise it may select wrong items! * * @param savedInstanceState If the activity is being re-initialized after @@ -171,7 +171,7 @@ open class RangeSelectorHelper(private val mFastAdapter: Fas @JvmOverloads fun withSavedInstanceState(savedInstanceState: Bundle?, prefix: String = ""): RangeSelectorHelper<*> { if (savedInstanceState != null && savedInstanceState.containsKey(BUNDLE_LAST_LONG_PRESS + prefix)) - mLastLongPressIndex = savedInstanceState.getInt(BUNDLE_LAST_LONG_PRESS + prefix) + lastLongPressIndex = savedInstanceState.getInt(BUNDLE_LAST_LONG_PRESS + prefix) return this } diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/UndoHelper.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/UndoHelper.kt index dd12c7a94..b6dc97543 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/UndoHelper.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/helpers/UndoHelper.kt @@ -2,6 +2,7 @@ package com.mikepenz.fastadapter.helpers import android.view.View import android.widget.TextView +import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.GenericItem @@ -12,18 +13,17 @@ import java.util.Arrays.asList /** * Created by mikepenz on 04.01.16. - */ -class UndoHelper -/** + * * Constructor to create the UndoHelper * * @param adapter the root FastAdapter * @param undoListener the listener which gets called when an item was really removed */ -(private val mAdapter: FastAdapter, private val mUndoListener: UndoListener) { +class UndoHelper( + private val adapter: FastAdapter, + private val undoListener: UndoListener +) { private var history: History? = null - var snackBar: Snackbar? = null - private set private var snackBarActionText = "" private var alreadyCommitted: Boolean = false @@ -46,8 +46,11 @@ class UndoHelper } } + var snackBar: Snackbar? = null + private set + /** - * an optional method to add a [Snackbar] of your own with custom styling. + * An optional method to add a [Snackbar] of your own with custom styling. * note that using this method will override your custom action * * @param snackBar your own Snackbar @@ -60,10 +63,10 @@ class UndoHelper } /** - * convenience method to be used if you have previously set a [Snackbar] with [.withSnackBar] + * Convenience method to be used if you have previously set a [Snackbar] with [withSnackBar] * * @param positions the positions where the items were removed - * @return the snackbar or null if [.withSnackBar] was not previously called + * @return the snackbar or null if [withSnackBar] was not previously called */ fun remove(positions: Set): Snackbar? { val snackBar = this.snackBar ?: return null @@ -73,9 +76,9 @@ class UndoHelper } /** - * removes items from the ItemAdapter. + * Removes items from the ItemAdapter. * note that the values of "view", "text", "actionText", and "duration" - * will be ignored if [.withSnackBar] was used. + * will be ignored if [withSnackBar] was used. * if it was not used, a default snackbar will be generated * * @param view the view which will host the SnackBar @@ -84,7 +87,7 @@ class UndoHelper * @param positions the positions where the items were removed * @return the generated Snackbar */ - fun remove(view: View, text: String, actionText: String, @Snackbar.Duration duration: Int, positions: Set): Snackbar { + fun remove(view: View, text: String, actionText: String, @BaseTransientBottomBar.Duration duration: Int, positions: Set): Snackbar { if (history != null) { // Set a flag, if remove was called before the Snackbar // executed the commit -> Snackbar does not commit the new @@ -96,7 +99,7 @@ class UndoHelper val history = History() history.action = ACTION_REMOVE for (position in positions) { - history.items.add(mAdapter.getRelativeInfo(position)) + history.items.add(adapter.getRelativeInfo(position)) } history.items.sortWith(Comparator { lhs, rhs -> Integer.valueOf(lhs.position).compareTo(rhs.position) }) @@ -117,7 +120,7 @@ class UndoHelper for (relativeInfo in mHistory.items) { positions.add(relativeInfo.position) } - mUndoListener.commitRemove(positions, mHistory.items) + undoListener.commitRemove(positions, mHistory.items) this.history = null } } @@ -149,7 +152,7 @@ class UndoHelper relativeInfo.item?.let { adapter?.addInternal(relativeInfo.position, asList(it)) if (relativeInfo.item?.isSelected == true) { - val selectExtension = mAdapter.getExtension>(SelectExtension::class.java) + val selectExtension = this.adapter.getExtension>(SelectExtension::class.java) selectExtension?.select(relativeInfo.position) } } diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDragCallback.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDragCallback.kt index cc9cd48ad..175916169 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDragCallback.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDragCallback.kt @@ -16,7 +16,13 @@ import com.mikepenz.fastadapter.swipe.SimpleSwipeCallback /** * Created by Mattias on 2016-02-13. */ -class SimpleSwipeDragCallback @JvmOverloads constructor(itemTouchCallback: ItemTouchCallback, itemSwipeCallback: SimpleSwipeCallback.ItemSwipeCallback, leaveBehindDrawable: Drawable, swipeDirs: Int = ItemTouchHelper.LEFT, @ColorInt bgColor: Int = Color.RED) : SimpleDragCallback(itemTouchCallback) { +class SimpleSwipeDragCallback @JvmOverloads constructor( + itemTouchCallback: ItemTouchCallback, + itemSwipeCallback: SimpleSwipeCallback.ItemSwipeCallback, + leaveBehindDrawable: Drawable?, + swipeDirs: Int = ItemTouchHelper.LEFT, + @ColorInt bgColor: Int = Color.RED +) : SimpleDragCallback(itemTouchCallback) { private val simpleSwipeCallback: SimpleSwipeCallback private var defaultSwipeDirs: Int = 0 @@ -54,15 +60,32 @@ class SimpleSwipeDragCallback @JvmOverloads constructor(itemTouchCallback: ItemT } fun withBackgroundSwipeLeft(@ColorInt bgColor: Int): SimpleSwipeDragCallback { + setDefaultSwipeDirs(defaultSwipeDirs or ItemTouchHelper.LEFT) simpleSwipeCallback.withBackgroundSwipeLeft(bgColor) return this } fun withBackgroundSwipeRight(@ColorInt bgColor: Int): SimpleSwipeDragCallback { + setDefaultSwipeDirs(defaultSwipeDirs or ItemTouchHelper.RIGHT) simpleSwipeCallback.withBackgroundSwipeRight(bgColor) return this } + fun withNotifyAllDrops(notifyAllDrops: Boolean): SimpleSwipeDragCallback { + this.notifyAllDrops = notifyAllDrops + return this + } + + fun withSensitivity(f: Float): SimpleSwipeDragCallback { + simpleSwipeCallback.withSensitivity(f) + return this + } + + fun withSurfaceThreshold(f: Float): SimpleSwipeDragCallback { + simpleSwipeCallback.withSurfaceThreshold(f) + return this + } + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { simpleSwipeCallback.onSwiped(viewHolder, direction) } @@ -71,8 +94,23 @@ class SimpleSwipeDragCallback @JvmOverloads constructor(itemTouchCallback: ItemT return simpleSwipeCallback.getSwipeDirs(recyclerView, viewHolder) } + override fun getSwipeEscapeVelocity(defaultValue: Float): Float { + return simpleSwipeCallback.getSwipeEscapeVelocity(defaultValue) + } + + override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float { + return simpleSwipeCallback.getSwipeThreshold(viewHolder) + } - override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { simpleSwipeCallback.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) //Happen to know that our direct parent class doesn't (currently) draw anything... //super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDrawerDragCallback.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDrawerDragCallback.kt new file mode 100644 index 000000000..9815a8d3c --- /dev/null +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/swipe_drag/SimpleSwipeDrawerDragCallback.kt @@ -0,0 +1,81 @@ +@file:Suppress("PackageName", "PackageNaming") + +package com.mikepenz.fastadapter.swipe_drag + +import android.graphics.Canvas +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.mikepenz.fastadapter.drag.ItemTouchCallback +import com.mikepenz.fastadapter.drag.SimpleDragCallback +import com.mikepenz.fastadapter.swipe.SimpleSwipeDrawerCallback + +/** + * Created by Mattias on 2016-02-13. + */ +class SimpleSwipeDrawerDragCallback @JvmOverloads constructor( + itemTouchCallback: ItemTouchCallback, + swipeDirs: Int = ItemTouchHelper.LEFT) : SimpleDragCallback(itemTouchCallback) { + + private val simpleSwipeCallback: SimpleSwipeDrawerCallback + private var defaultSwipeDirs: Int = 0 + + init { + setDefaultSwipeDirs(swipeDirs) + simpleSwipeCallback = SimpleSwipeDrawerCallback(swipeDirs) + } + + override fun setDefaultSwipeDirs(defaultSwipeDirs: Int) { + this.defaultSwipeDirs = defaultSwipeDirs + super.setDefaultSwipeDirs(defaultSwipeDirs) + } + + fun withNotifyAllDrops(notifyAllDrops: Boolean): SimpleSwipeDrawerDragCallback { + this.notifyAllDrops = notifyAllDrops + return this + } + + fun withSwipeLeft(widthDp: Int): SimpleSwipeDrawerDragCallback { + simpleSwipeCallback.withSwipeLeft(widthDp) + return this + } + + fun withSwipeRight(widthDp: Int): SimpleSwipeDrawerDragCallback { + simpleSwipeCallback.withSwipeRight(widthDp) + return this + } + + fun withSensitivity(f: Float): SimpleSwipeDrawerDragCallback { + simpleSwipeCallback.withSensitivity(f) + return this + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + simpleSwipeCallback.onSwiped(viewHolder, direction) + } + + override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + return simpleSwipeCallback.getSwipeDirs(recyclerView, viewHolder) + } + + override fun getSwipeEscapeVelocity(defaultValue: Float): Float { + return simpleSwipeCallback.getSwipeEscapeVelocity(defaultValue) + } + + override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float { + return simpleSwipeCallback.getSwipeThreshold(viewHolder) + } + + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + simpleSwipeCallback.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) + //Happen to know that our direct parent class doesn't (currently) draw anything... + //super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } +} diff --git a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/utils/DragDropUtil.kt b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/utils/DragDropUtil.kt index fcda5ef53..96e08ae1c 100644 --- a/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/utils/DragDropUtil.kt +++ b/library-extensions-utils/src/main/java/com/mikepenz/fastadapter/utils/DragDropUtil.kt @@ -8,15 +8,14 @@ import com.mikepenz.fastadapter.drag.IExtendedDraggable /** * Created by flisar on 30.09.2016. */ - object DragDropUtil { /** - * this functions binds the view's touch listener to start the drag via the touch helper... + * This functions binds the view's touch listener to start the drag via the touch helper… * * @param holder the view holder * @param holder the item */ - fun bindDragHandle(holder: RecyclerView.ViewHolder, item: IExtendedDraggable) { + @JvmStatic fun bindDragHandle(holder: RecyclerView.ViewHolder, item: IExtendedDraggable) { // if necessary, init the drag handle, which will start the drag when touched if (item.touchHelper != null) { item.getDragView(holder)?.setOnTouchListener { _, event -> @@ -37,8 +36,9 @@ object DragDropUtil { * @param oldPosition the start position of the move * @param newPosition the end position of the move */ - fun onMove(itemAdapter: IItemAdapter<*, *>, oldPosition: Int, newPosition: Int) { - // necessary, because the positions passed to this function may be jumping in case of that the recycler view is scrolled while holding an item outside of the recycler view + @JvmStatic fun onMove(itemAdapter: IItemAdapter<*, *>, oldPosition: Int, newPosition: Int) { + // necessary, because the positions passed to this function may be jumping in case of + // that the recycler view is scrolled while holding an item outside of the recycler view if (oldPosition < newPosition) { for (i in oldPosition + 1..newPosition) { itemAdapter.move(i, i - 1) diff --git a/release.sh b/release.sh index 7527ffd68..80c8c78d5 100755 --- a/release.sh +++ b/release.sh @@ -5,6 +5,7 @@ if [ "$1" = "release" ]; then ./gradlew library-core:bintrayUpload -Plibrary_core_only + ./gradlew library-extensions-binding:bintrayUpload -x test -x lint -Plibrary_extensions_binding_only ./gradlew library-extensions-diff:bintrayUpload -x test -x lint -Plibrary_extensions_diff_only ./gradlew library-extensions-drag:bintrayUpload -x test -x lint -Plibrary_extensions_drag_only ./gradlew library-extensions-expandable:bintrayUpload -x test -x lint -Plibrary_extensions_expandable_only diff --git a/settings.gradle b/settings.gradle index e49ca9251..3a1ce8340 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ include ':app' include ':library-core' +include ':library-extensions-binding' include ':library-extensions-diff' include ':library-extensions-drag' include ':library-extensions-expandable'