瀏覽代碼

Update flexible adapter. Show fast scroller in chapters screen

inorichi 7 年之前
父節點
當前提交
5c4139be45
共有 36 個文件被更改,包括 157 次插入480 次删除
  1. 1 1
      app/build.gradle
  2. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueController.kt
  3. 15 14
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueItem.kt
  4. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt
  5. 3 1
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt
  6. 4 7
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/ProgressItem.kt
  7. 2 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt
  8. 6 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt
  9. 2 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt
  10. 2 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt
  11. 2 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt
  12. 7 6
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt
  13. 7 6
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt
  14. 2 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt
  15. 6 4
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt
  16. 3 6
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchCardItem.kt
  17. 3 6
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchItem.kt
  18. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/main/CatalogueMainController.kt
  19. 3 6
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/main/LangItem.kt
  20. 2 6
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/main/SourceItem.kt
  21. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt
  22. 25 24
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt
  23. 4 10
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt
  24. 9 8
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
  25. 12 11
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt
  26. 4 1
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
  27. 3 7
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt
  28. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt
  29. 6 7
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt
  30. 2 4
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt
  31. 2 7
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt
  32. 5 4
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt
  33. 3 11
      app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadController.kt
  34. 2 8
      app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadItem.kt
  35. 0 281
      app/src/main/java/eu/kanade/tachiyomi/widget/UndoHelper.java
  36. 1 1
      app/src/main/res/layout/chapters_controller.xml

+ 1 - 1
app/build.gradle

@@ -194,7 +194,7 @@ dependencies {
     // UI
     implementation 'com.dmitrymalkovich.android:material-design-dimens:1.4'
     implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
-    implementation 'eu.davidea:flexible-adapter:5.0.0-rc1'
+    implementation 'eu.davidea:flexible-adapter:5.0.0-rc3'
     implementation 'com.nononsenseapps:filepicker:2.5.2'
     implementation 'com.github.amulyakhare:TextDrawable:558677e'
     implementation('com.afollestad.material-dialogs:core:0.9.4.7') {

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueController.kt

@@ -44,7 +44,7 @@ open class CatalogueController(bundle: Bundle) :
         SecondaryDrawerController,
         FlexibleAdapter.OnItemClickListener,
         FlexibleAdapter.OnItemLongClickListener,
-        FlexibleAdapter.EndlessScrollListener<ProgressItem>,
+        FlexibleAdapter.EndlessScrollListener,
         ChangeMangaCategoriesDialog.Listener {
 
     constructor(source: CatalogueSource) : this(Bundle().apply {

+ 15 - 14
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueItem.kt

@@ -1,39 +1,40 @@
 package eu.kanade.tachiyomi.ui.catalogue
 
 import android.view.Gravity
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.widget.FrameLayout
+import com.f2prateek.rx.preferences.Preference
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.util.inflate
+import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.widget.AutofitRecyclerView
 import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
 
-class CatalogueItem(val manga: Manga) : AbstractFlexibleItem<CatalogueHolder>() {
+class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Boolean>) :
+        AbstractFlexibleItem<CatalogueHolder>() {
 
     override fun getLayoutRes(): Int {
-        return R.layout.catalogue_grid_item
+        return if (catalogueAsList.getOrDefault())
+            R.layout.catalogue_list_item
+        else
+            R.layout.catalogue_grid_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>,
-                                  inflater: LayoutInflater,
-                                  parent: ViewGroup): CatalogueHolder {
-
-        if (parent is AutofitRecyclerView) {
-            val view = parent.inflate(R.layout.catalogue_grid_item).apply {
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CatalogueHolder {
+        val parent = adapter.recyclerView
+        return if (parent is AutofitRecyclerView) {
+            view.apply {
                 card.layoutParams = FrameLayout.LayoutParams(
                         MATCH_PARENT, parent.itemWidth / 3 * 4)
                 gradient.layoutParams = FrameLayout.LayoutParams(
                         MATCH_PARENT, parent.itemWidth / 3 * 4 / 2, Gravity.BOTTOM)
             }
-            return CatalogueGridHolder(view, adapter)
+            CatalogueGridHolder(view, adapter)
         } else {
-            val view = parent.inflate(R.layout.catalogue_list_item)
-            return CatalogueListHolder(view, adapter)
+            CatalogueListHolder(view, adapter)
         }
     }
 

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt

@@ -34,7 +34,7 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
     }
 
     fun setFilters(items: List<IFlexible<*>>) {
-        adapter.updateDataSet(items.toMutableList())
+        adapter.updateDataSet(items)
     }
 
 }

+ 3 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt

@@ -131,13 +131,15 @@ open class CataloguePresenter(
 
         val sourceId = source.id
 
+        val catalogueAsList = prefs.catalogueAsList()
+
         // Prepare the pager.
         pagerSubscription?.let { remove(it) }
         pagerSubscription = pager.results()
                 .observeOn(Schedulers.io())
                 .map { it.first to it.second.map { networkToLocalManga(it, sourceId) } }
                 .doOnNext { initializeMangas(it.second) }
-                .map { it.first to it.second.map(::CatalogueItem) }
+                .map { it.first to it.second.map { CatalogueItem(it, catalogueAsList) } }
                 .observeOn(AndroidSchedulers.mainThread())
                 .subscribeReplay({ view, (page, mangas) ->
                     view.onAddPage(page, mangas)

+ 4 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/ProgressItem.kt

@@ -1,30 +1,27 @@
 package eu.kanade.tachiyomi.ui.catalogue
 
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.ProgressBar
 import android.widget.TextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
-import eu.davidea.flexibleadapter.items.IFlexible
 import eu.davidea.viewholders.FlexibleViewHolder
 import eu.kanade.tachiyomi.R
 
 
 class ProgressItem : AbstractFlexibleItem<ProgressItem.Holder>() {
 
-    var loadMore = true
+    private var loadMore = true
 
     override fun getLayoutRes(): Int {
         return R.layout.catalogue_progress_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
-    override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: Holder, position: Int, payloads: List<Any?>) {
+    override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>) {
         holder.progressBar.visibility = View.GONE
         holder.progressMessage.visibility = View.GONE
 

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt

@@ -1,8 +1,6 @@
 package eu.kanade.tachiyomi.ui.catalogue.filter
 
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.CheckBox
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
@@ -16,8 +14,8 @@ open class CheckboxItem(val filter: Filter.CheckBox) : AbstractFlexibleItem<Chec
         return R.layout.navigation_view_checkbox
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 6 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt

@@ -1,8 +1,6 @@
 package eu.kanade.tachiyomi.ui.catalogue.filter
 
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.TextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
@@ -19,8 +17,12 @@ class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<Grou
         return R.layout.navigation_view_group
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun getItemViewType(): Int {
+        return 101
+    }
+
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt

@@ -2,9 +2,7 @@ package eu.kanade.tachiyomi.ui.catalogue.filter
 
 import android.annotation.SuppressLint
 import android.support.design.R
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.TextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem
@@ -18,8 +16,8 @@ class HeaderItem(val filter: Filter.Header) : AbstractHeaderItem<HeaderItem.Hold
         return R.layout.design_navigation_item_subheader
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt

@@ -1,8 +1,6 @@
 package eu.kanade.tachiyomi.ui.catalogue.filter
 
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.ArrayAdapter
 import android.widget.Spinner
 import android.widget.TextView
@@ -19,8 +17,8 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<Selec
         return R.layout.navigation_view_spinner
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt

@@ -2,9 +2,7 @@ package eu.kanade.tachiyomi.ui.catalogue.filter
 
 import android.annotation.SuppressLint
 import android.support.design.R
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem
 import eu.davidea.viewholders.FlexibleViewHolder
@@ -17,8 +15,8 @@ class SeparatorItem(val filter: Filter.Separator) : AbstractHeaderItem<Separator
         return R.layout.design_navigation_item_separator
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 7 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt

@@ -1,8 +1,6 @@
 package eu.kanade.tachiyomi.ui.catalogue.filter
 
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
 import eu.davidea.flexibleadapter.items.ISectionable
@@ -12,13 +10,16 @@ import eu.kanade.tachiyomi.util.setVectorCompat
 
 class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem<SortGroup.Holder, ISectionable<*, *>>() {
 
-    // Use an id instead of the layout res to allow to reuse the layout.
     override fun getLayoutRes(): Int {
-        return R.id.catalogue_filter_sort_group
+        return R.layout.navigation_view_group
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(R.layout.navigation_view_group, parent, false), adapter)
+    override fun getItemViewType(): Int {
+        return 100
+    }
+
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 7 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt

@@ -2,9 +2,7 @@ package eu.kanade.tachiyomi.ui.catalogue.filter
 
 import android.support.graphics.drawable.VectorDrawableCompat
 import android.support.v4.content.ContextCompat
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.CheckedTextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractSectionableItem
@@ -15,13 +13,16 @@ import eu.kanade.tachiyomi.util.getResourceColor
 
 class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem<SortItem.Holder, SortGroup>(group) {
 
-    // Use an id instead of the layout res to allow to reuse the layout.
     override fun getLayoutRes(): Int {
-        return R.id.catalogue_filter_sort_item
+        return R.layout.navigation_view_checkedtext
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(R.layout.navigation_view_checkedtext, parent, false), adapter)
+    override fun getItemViewType(): Int {
+        return 102
+    }
+
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt

@@ -1,9 +1,7 @@
 package eu.kanade.tachiyomi.ui.catalogue.filter
 
 import android.support.design.widget.TextInputLayout
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.EditText
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
@@ -18,8 +16,8 @@ open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem<TextItem.Hol
         return R.layout.navigation_view_text
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 6 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt

@@ -2,9 +2,7 @@ package eu.kanade.tachiyomi.ui.catalogue.filter
 
 import android.support.design.R
 import android.support.graphics.drawable.VectorDrawableCompat
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.CheckedTextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
@@ -20,8 +18,12 @@ open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriS
         return TR.layout.navigation_view_checkedtext
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup?): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun getItemViewType(): Int {
+        return 103
+    }
+
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 3 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchCardItem.kt

@@ -1,12 +1,10 @@
 package eu.kanade.tachiyomi.ui.catalogue.global_search
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.util.inflate
 
 class CatalogueSearchCardItem(val manga: Manga) : AbstractFlexibleItem<CatalogueSearchCardHolder>() {
 
@@ -14,9 +12,8 @@ class CatalogueSearchCardItem(val manga: Manga) : AbstractFlexibleItem<Catalogue
         return R.layout.catalogue_global_search_controller_card_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater,
-                                  parent: ViewGroup): CatalogueSearchCardHolder {
-        return CatalogueSearchCardHolder(parent.inflate(layoutRes), adapter as CatalogueSearchCardAdapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CatalogueSearchCardHolder {
+        return CatalogueSearchCardHolder(view, adapter as CatalogueSearchCardAdapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: CatalogueSearchCardHolder,

+ 3 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchItem.kt

@@ -1,12 +1,10 @@
 package eu.kanade.tachiyomi.ui.catalogue.global_search
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.source.CatalogueSource
-import eu.kanade.tachiyomi.util.inflate
 
 /**
  * Item that contains search result information.
@@ -30,9 +28,8 @@ class CatalogueSearchItem(val source: CatalogueSource, val results: List<Catalog
      *
      * @return holder of view.
      */
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater,
-                                  parent: ViewGroup): CatalogueSearchHolder {
-        return CatalogueSearchHolder(parent.inflate(layoutRes), adapter as CatalogueSearchAdapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CatalogueSearchHolder {
+        return CatalogueSearchHolder(view, adapter as CatalogueSearchAdapter)
     }
 
     /**

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/main/CatalogueMainController.kt

@@ -221,7 +221,7 @@ class CatalogueMainController : NucleusController<CatalogueMainPresenter>(),
      * Called to update adapter containing sources.
      */
     fun setSources(sources: List<IFlexible<*>>) {
-        adapter?.updateDataSet(sources.toMutableList())
+        adapter?.updateDataSet(sources)
     }
 
     /**

+ 3 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/main/LangItem.kt

@@ -1,7 +1,6 @@
 package eu.kanade.tachiyomi.ui.catalogue.main
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem
 import eu.kanade.tachiyomi.R
@@ -23,10 +22,8 @@ data class LangItem(val code: String) : AbstractHeaderItem<LangHolder>() {
     /**
      * Creates a new view holder for this item.
      */
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater,
-                                  parent: ViewGroup): LangHolder {
-
-        return LangHolder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): LangHolder {
+        return LangHolder(view, adapter)
     }
 
     /**

+ 2 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/main/SourceItem.kt

@@ -1,7 +1,6 @@
 package eu.kanade.tachiyomi.ui.catalogue.main
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractSectionableItem
 import eu.kanade.tachiyomi.R
@@ -26,10 +25,7 @@ data class SourceItem(val source: CatalogueSource, val header: LangItem? = null)
     /**
      * Creates a new view holder for this item.
      */
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater,
-                                  parent: ViewGroup): SourceHolder {
-
-        val view = inflater.inflate(layoutRes, parent, false)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): SourceHolder {
         return SourceHolder(view, adapter as CatalogueMainAdapter)
     }
 

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt

@@ -20,14 +20,14 @@ class CategoryAdapter(controller: CategoryController) :
      */
     override fun clearSelection() {
         super.clearSelection()
-        (0 until itemCount).forEach { getItem(it).isSelected = false }
+        (0 until itemCount).forEach { getItem(it)?.isSelected = false }
     }
 
     /**
      * Clears the active selections from the model.
      */
     fun clearModelSelection() {
-        selectedPositions.forEach { getItem(it).isSelected = false }
+        selectedPositions.forEach { getItem(it)?.isSelected = false }
     }
 
     /**
@@ -37,7 +37,7 @@ class CategoryAdapter(controller: CategoryController) :
      */
     override fun toggleSelection(position: Int) {
         super.toggleSelection(position)
-        getItem(position).isSelected = isSelected(position)
+        getItem(position)?.isSelected = isSelected(position)
     }
 
     interface OnItemReleaseListener {

+ 25 - 24
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi.ui.category
 
 import android.os.Bundle
+import android.support.design.widget.Snackbar
 import android.support.v7.app.AppCompatActivity
 import android.support.v7.view.ActionMode
 import android.support.v7.widget.LinearLayoutManager
@@ -8,11 +9,12 @@ import android.support.v7.widget.RecyclerView
 import android.view.*
 import com.jakewharton.rxbinding.view.clicks
 import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.SelectableAdapter
+import eu.davidea.flexibleadapter.helpers.UndoHelper
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Category
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.util.toast
-import eu.kanade.tachiyomi.widget.UndoHelper
 import kotlinx.android.synthetic.main.categories_controller.view.*
 
 /**
@@ -38,7 +40,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
     private var adapter: CategoryAdapter? = null
 
     /**
-     * Undo helper for deleting categories.
+     * Undo helper used for restoring a deleted category.
      */
     private var undoHelper: UndoHelper? = null
 
@@ -79,6 +81,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
             recycler.setHasFixedSize(true)
             recycler.adapter = adapter
             adapter?.isHandleDragEnabled = true
+            adapter?.isPermanentDelete = false
 
             fab.clicks().subscribeUntilDestroy {
                 CategoryCreateDialog(this@CategoryController).showDialog(router, null)
@@ -93,7 +96,8 @@ class CategoryController : NucleusController<CategoryPresenter>(),
      */
     override fun onDestroyView(view: View) {
         super.onDestroyView(view)
-        undoHelper?.dismissNow() // confirm categories deletion if required
+        // Manually call callback to delete categories if required
+        undoHelper?.onDeleteConfirmed(Snackbar.Callback.DISMISS_EVENT_MANUAL)
         undoHelper = null
         actionMode = null
         adapter = null
@@ -106,7 +110,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
      */
     fun setCategories(categories: List<CategoryItem>) {
         actionMode?.finish()
-        adapter?.updateDataSet(categories.toMutableList())
+        adapter?.updateDataSet(categories)
         val selected = categories.filter { it.isSelected }
         if (selected.isNotEmpty()) {
             selected.forEach { onItemLongClick(categories.indexOf(it)) }
@@ -126,7 +130,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
         // Inflate menu.
         mode.menuInflater.inflate(R.menu.category_selection, menu)
         // Enable adapter multi selection.
-        adapter?.mode = FlexibleAdapter.MODE_MULTI
+        adapter?.mode = SelectableAdapter.Mode.MULTI
         return true
     }
 
@@ -161,26 +165,20 @@ class CategoryController : NucleusController<CategoryPresenter>(),
 
         when (item.itemId) {
             R.id.action_delete -> {
-                undoHelper = UndoHelper(adapter, this).apply {
-                    withAction(UndoHelper.ACTION_REMOVE, object : UndoHelper.OnActionListener {
-                        override fun onPreAction(): Boolean {
-                            adapter.clearModelSelection()
-                            return false
-                        }
-
-                        override fun onPostAction() {
-                            mode.finish()
-                        }
-                    })
-                    remove(adapter.selectedPositions, view!!,
-                            R.string.snack_categories_deleted, R.string.action_undo, 3000)
-                }
+                undoHelper = UndoHelper(adapter, this)
+                undoHelper?.start(adapter.selectedPositions, view!!,
+                                R.string.snack_categories_deleted, R.string.action_undo, 3000)
+
+                mode.finish()
             }
             R.id.action_edit -> {
                 // Edit selected category
                 if (adapter.selectedItemCount == 1) {
                     val position = adapter.selectedPositions.first()
-                    editCategory(adapter.getItem(position).category)
+                    val category = adapter.getItem(position)?.category
+                    if (category != null) {
+                        editCategory(category)
+                    }
                 }
             }
             else -> return false
@@ -195,7 +193,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
      */
     override fun onDestroyActionMode(mode: ActionMode) {
         // Reset adapter to single selection
-        adapter?.mode = FlexibleAdapter.MODE_IDLE
+        adapter?.mode = SelectableAdapter.Mode.IDLE
         adapter?.clearSelection()
         actionMode = null
     }
@@ -260,7 +258,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
      */
     override fun onItemReleased(position: Int) {
         val adapter = adapter ?: return
-        val categories = (0..adapter.itemCount-1).map { adapter.getItem(it).category }
+        val categories = (0 until adapter.itemCount).mapNotNull { adapter.getItem(it)?.category }
         presenter.reorderCategories(categories)
     }
 
@@ -269,18 +267,21 @@ class CategoryController : NucleusController<CategoryPresenter>(),
      *
      * @param action The action performed.
      */
-    override fun onUndoConfirmed(action: Int) {
+    override fun onActionCanceled(action: Int) {
         adapter?.restoreDeletedItems()
+        undoHelper = null
     }
 
     /**
      * Called when the time to restore the items expires.
      *
      * @param action The action performed.
+     * @param event The event that triggered the action
      */
-    override fun onDeleteConfirmed(action: Int) {
+    override fun onActionConfirmed(action: Int, event: Int) {
         val adapter = adapter ?: return
         presenter.deleteCategories(adapter.deletedItems.map { it.category })
+        undoHelper = null
     }
 
     /**

+ 4 - 10
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt

@@ -1,12 +1,10 @@
 package eu.kanade.tachiyomi.ui.category
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Category
-import eu.kanade.tachiyomi.util.inflate
 
 /**
  * Category item for a recycler view.
@@ -28,15 +26,11 @@ class CategoryItem(val category: Category) : AbstractFlexibleItem<CategoryHolder
     /**
      * Returns a new view holder for this item.
      *
+     * @param view The view of this item.
      * @param adapter The adapter of this item.
-     * @param inflater The layout inflater for XML inflation.
-     * @param parent The container view.
      */
-    override fun createViewHolder(adapter: FlexibleAdapter<*>,
-                                  inflater: LayoutInflater,
-                                  parent: ViewGroup): CategoryHolder {
-
-        return CategoryHolder(parent.inflate(layoutRes), adapter as CategoryAdapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CategoryHolder {
+        return CategoryHolder(view, adapter as CategoryAdapter)
     }
 
     /**

+ 9 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt

@@ -6,6 +6,7 @@ import android.support.v7.widget.RecyclerView
 import android.util.AttributeSet
 import android.widget.FrameLayout
 import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.SelectableAdapter
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Category
 import eu.kanade.tachiyomi.data.database.models.Manga
@@ -103,9 +104,9 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
         this.category = category
 
         adapter.mode = if (controller.selectedMangas.isNotEmpty()) {
-            FlexibleAdapter.MODE_MULTI
+            SelectableAdapter.Mode.MULTI
         } else {
-            FlexibleAdapter.MODE_SINGLE
+            SelectableAdapter.Mode.SINGLE
         }
 
         subscriptions += controller.searchRelay
@@ -144,7 +145,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
         // Update the category with its manga.
         adapter.setItems(mangaForCategory)
 
-        if (adapter.mode == FlexibleAdapter.MODE_MULTI) {
+        if (adapter.mode == SelectableAdapter.Mode.MULTI) {
             controller.selectedMangas.forEach { manga ->
                 val position = adapter.indexOf(manga)
                 if (position != -1 && !adapter.isSelected(position)) {
@@ -164,19 +165,19 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
     private fun onSelectionChanged(event: LibrarySelectionEvent) {
         when (event) {
             is LibrarySelectionEvent.Selected -> {
-                if (adapter.mode != FlexibleAdapter.MODE_MULTI) {
-                    adapter.mode = FlexibleAdapter.MODE_MULTI
+                if (adapter.mode != SelectableAdapter.Mode.MULTI) {
+                    adapter.mode = SelectableAdapter.Mode.MULTI
                 }
                 findAndToggleSelection(event.manga)
             }
             is LibrarySelectionEvent.Unselected -> {
                 findAndToggleSelection(event.manga)
                 if (controller.selectedMangas.isEmpty()) {
-                    adapter.mode = FlexibleAdapter.MODE_SINGLE
+                    adapter.mode = SelectableAdapter.Mode.SINGLE
                 }
             }
             is LibrarySelectionEvent.Cleared -> {
-                adapter.mode = FlexibleAdapter.MODE_SINGLE
+                adapter.mode = SelectableAdapter.Mode.SINGLE
                 adapter.clearSelection()
             }
         }
@@ -204,7 +205,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
     override fun onItemClick(position: Int): Boolean {
         // If the action mode is created and the position is valid, toggle the selection.
         val item = adapter.getItem(position) ?: return false
-        if (adapter.mode == FlexibleAdapter.MODE_MULTI) {
+        if (adapter.mode == SelectableAdapter.Mode.MULTI) {
             toggleSelection(position)
             return true
         } else {

+ 12 - 11
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt

@@ -1,33 +1,35 @@
 package eu.kanade.tachiyomi.ui.library
 
 import android.view.Gravity
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.widget.FrameLayout
+import com.f2prateek.rx.preferences.Preference
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.davidea.flexibleadapter.items.IFilterable
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.LibraryManga
-import eu.kanade.tachiyomi.util.inflate
+import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.widget.AutofitRecyclerView
 import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
 
-class LibraryItem(val manga: LibraryManga) : AbstractFlexibleItem<LibraryHolder>(), IFilterable {
+class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference<Boolean>) :
+        AbstractFlexibleItem<LibraryHolder>(), IFilterable {
 
     var downloadCount = -1
 
     override fun getLayoutRes(): Int {
-        return R.layout.catalogue_grid_item
+        return if (libraryAsList.getOrDefault())
+            R.layout.catalogue_list_item
+        else
+            R.layout.catalogue_grid_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>,
-                                  inflater: LayoutInflater,
-                                  parent: ViewGroup): LibraryHolder {
-
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): LibraryHolder {
+        val parent = adapter.recyclerView
         return if (parent is AutofitRecyclerView) {
-            val view = parent.inflate(R.layout.catalogue_grid_item).apply {
+            view.apply {
                 val coverHeight = parent.itemWidth / 3 * 4
                 card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
                 gradient.layoutParams = FrameLayout.LayoutParams(
@@ -35,7 +37,6 @@ class LibraryItem(val manga: LibraryManga) : AbstractFlexibleItem<LibraryHolder>
             }
             LibraryGridHolder(view, adapter)
         } else {
-            val view = parent.inflate(R.layout.catalogue_list_item)
             LibraryListHolder(view, adapter)
         }
     }

+ 4 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt

@@ -290,8 +290,11 @@ class LibraryPresenter(
      * value.
      */
     private fun getLibraryMangasObservable(): Observable<LibraryMap> {
+        val libraryAsList = preferences.libraryAsList()
         return db.getLibraryMangas().asRxObservable()
-                .map { list -> list.map(::LibraryItem).groupBy { it.manga.category } }
+                .map { list ->
+                    list.map { LibraryItem(it, libraryAsList) }.groupBy { it.manga.category }
+                }
     }
 
     /**

+ 3 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt

@@ -1,7 +1,6 @@
 package eu.kanade.tachiyomi.ui.manga.chapter
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.kanade.tachiyomi.R
@@ -27,11 +26,8 @@ class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem
         return R.layout.chapters_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>,
-                                  inflater: LayoutInflater,
-                                  parent: ViewGroup): ChapterHolder {
-
-        return ChapterHolder(inflater.inflate(layoutRes, parent, false), adapter as ChaptersAdapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): ChapterHolder {
+        return ChapterHolder(view, adapter as ChaptersAdapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>,

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt

@@ -29,9 +29,9 @@ class ChaptersAdapter(
 
     val dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT)
 
-    override fun updateDataSet(items: List<ChapterItem>) {
-        this.items = items
-        super.updateDataSet(items.toList())
+    override fun updateDataSet(items: List<ChapterItem>?) {
+        this.items = items ?: emptyList()
+        super.updateDataSet(items)
     }
 
     fun indexOf(item: ChapterItem): Int {

+ 6 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt

@@ -14,6 +14,7 @@ import android.view.*
 import com.jakewharton.rxbinding.support.v4.widget.refreshes
 import com.jakewharton.rxbinding.view.clicks
 import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.SelectableAdapter
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Chapter
 import eu.kanade.tachiyomi.data.database.models.Manga
@@ -79,9 +80,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
             recycler.layoutManager = LinearLayoutManager(context)
             recycler.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
             recycler.setHasFixedSize(true)
-            // TODO enable in a future commit
-//             adapter.setFastScroller(fast_scroller, context.getResourceColor(R.attr.colorAccent))
-//             adapter.toggleFastScroller()
+            adapter?.fastScroller = view.fast_scroller
 
             swipe_refresh.refreshes().subscribeUntilDestroy { fetchChaptersFromSource() }
 
@@ -247,7 +246,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
     override fun onItemClick(position: Int): Boolean {
         val adapter = adapter ?: return false
         val item = adapter.getItem(position) ?: return false
-        if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
+        if (actionMode != null && adapter.mode == SelectableAdapter.Mode.MULTI) {
             toggleSelection(position)
             return true
         } else {
@@ -277,7 +276,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
 
     fun getSelectedChapters(): List<ChapterItem> {
         val adapter = adapter ?: return emptyList()
-        return adapter.selectedPositions.map { adapter.getItem(it) }
+        return adapter.selectedPositions.mapNotNull { adapter.getItem(it) }
     }
 
     fun createActionModeIfNeeded() {
@@ -292,7 +291,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
 
     override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
         mode.menuInflater.inflate(R.menu.chapter_selection, menu)
-        adapter?.mode = FlexibleAdapter.MODE_MULTI
+        adapter?.mode = SelectableAdapter.Mode.MULTI
         return true
     }
 
@@ -320,7 +319,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
     }
 
     override fun onDestroyActionMode(mode: ActionMode) {
-        adapter?.mode = FlexibleAdapter.MODE_SINGLE
+        adapter?.mode = SelectableAdapter.Mode.SINGLE
         adapter?.clearSelection()
         selectedItems.clear()
         actionMode = null

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt

@@ -1,9 +1,7 @@
 package eu.kanade.tachiyomi.ui.recent_updates
 
 import android.text.format.DateUtils
-import android.view.LayoutInflater
 import android.view.View
-import android.view.ViewGroup
 import android.widget.TextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem
@@ -17,8 +15,8 @@ class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() {
         return R.layout.recent_chapters_section_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
-        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
+        return Holder(view, adapter)
     }
 
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 2 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt

@@ -1,7 +1,6 @@
 package eu.kanade.tachiyomi.ui.recent_updates
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractSectionableItem
 import eu.kanade.tachiyomi.R
@@ -27,11 +26,7 @@ class RecentChapterItem(val chapter: Chapter, val manga: Manga, header: DateItem
         return R.layout.recent_chapters_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>,
-                                  inflater: LayoutInflater,
-                                  parent: ViewGroup): RecentChapterHolder {
-
-        val view = inflater.inflate(layoutRes, parent, false)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): RecentChapterHolder {
         return RecentChapterHolder(view , adapter as RecentChaptersAdapter)
     }
 

+ 5 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt

@@ -11,6 +11,7 @@ import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
 import com.jakewharton.rxbinding.support.v4.widget.refreshes
 import com.jakewharton.rxbinding.support.v7.widget.scrollStateChanges
 import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.SelectableAdapter
 import eu.davidea.flexibleadapter.items.IFlexible
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.download.model.Download
@@ -120,7 +121,7 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
 
         // Get item from position
         val item = adapter.getItem(position) as? RecentChapterItem ?: return false
-        if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
+        if (actionMode != null && adapter.mode == SelectableAdapter.Mode.MULTI) {
             toggleSelection(position)
             return true
         } else {
@@ -175,7 +176,7 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
      */
     fun onNextRecentChapters(chapters: List<IFlexible<*>>) {
         destroyActionModeIfNeeded()
-        adapter?.updateDataSet(chapters.toMutableList())
+        adapter?.updateDataSet(chapters)
     }
 
     override fun onUpdateEmptyView(size: Int) {
@@ -295,7 +296,7 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
      */
     override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
         mode.menuInflater.inflate(R.menu.chapter_recent_selection, menu)
-        adapter?.mode = FlexibleAdapter.MODE_MULTI
+        adapter?.mode = SelectableAdapter.Mode.MULTI
         return true
     }
 
@@ -332,7 +333,7 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
      * @param mode the ActionMode object
      */
     override fun onDestroyActionMode(mode: ActionMode?) {
-        adapter?.mode = FlexibleAdapter.MODE_IDLE
+        adapter?.mode = SelectableAdapter.Mode.IDLE
         adapter?.clearSelection()
         actionMode = null
     }

+ 3 - 11
app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadController.kt

@@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.recently_read
 
 import android.os.Bundle
 import android.support.v7.widget.LinearLayoutManager
-import android.support.v7.widget.RecyclerView
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -77,7 +76,7 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
      * @param mangaHistory list of manga history
      */
     fun onNextManga(mangaHistory: List<RecentlyReadItem>) {
-        adapter?.updateDataSet(mangaHistory.toList())
+        adapter?.updateDataSet(mangaHistory)
     }
 
     override fun onUpdateEmptyView(size: Int) {
@@ -91,10 +90,7 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
 
     override fun onResumeClick(position: Int) {
         val activity = activity ?: return
-        val adapter = adapter ?: return
-        if (position == RecyclerView.NO_POSITION) return
-
-        val (manga, chapter, _) = adapter.getItem(position).mch
+        val (manga, chapter, _) = adapter?.getItem(position)?.mch ?: return
 
         val nextChapter = presenter.getNextChapter(chapter, manga)
         if (nextChapter != null) {
@@ -106,11 +102,7 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
     }
 
     override fun onRemoveClick(position: Int) {
-        val adapter = adapter ?: return
-        if (position == RecyclerView.NO_POSITION) return
-
-        val (manga, _, history) = adapter.getItem(position).mch
-
+        val (manga, _, history) = adapter?.getItem(position)?.mch ?: return
         RemoveHistoryDialog(this, manga, history).showDialog(router)
     }
 

+ 2 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadItem.kt

@@ -1,12 +1,10 @@
 package eu.kanade.tachiyomi.ui.recently_read
 
-import android.view.LayoutInflater
-import android.view.ViewGroup
+import android.view.View
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
-import eu.kanade.tachiyomi.util.inflate
 
 class RecentlyReadItem(val mch: MangaChapterHistory) : AbstractFlexibleItem<RecentlyReadHolder>() {
 
@@ -14,11 +12,7 @@ class RecentlyReadItem(val mch: MangaChapterHistory) : AbstractFlexibleItem<Rece
         return R.layout.recently_read_item
     }
 
-    override fun createViewHolder(adapter: FlexibleAdapter<*>,
-                                  inflater: LayoutInflater,
-                                  parent: ViewGroup): RecentlyReadHolder {
-
-        val view = parent.inflate(layoutRes)
+    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): RecentlyReadHolder {
         return RecentlyReadHolder(view, adapter as RecentlyReadAdapter)
     }
 

+ 0 - 281
app/src/main/java/eu/kanade/tachiyomi/widget/UndoHelper.java

@@ -1,281 +0,0 @@
-/*
- * Copyright 2016 Davide Steduto
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package eu.kanade.tachiyomi.widget;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
-import android.support.design.widget.Snackbar;
-import android.view.View;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-import eu.davidea.flexibleadapter.FlexibleAdapter;
-
-/**
- * Helper to simplify the Undo operation with FlexibleAdapter.
- *
- * @author Davide Steduto
- * @since 30/04/2016
- */
-@SuppressWarnings("WeakerAccess")
-public class UndoHelper extends Snackbar.Callback {
-
-    /**
-     * Default undo-timeout of 5''.
-     */
-    public static final int UNDO_TIMEOUT = 5000;
-    /**
-     * Indicates that the Confirmation Listener (Undo and Delete) will perform a deletion.
-     */
-    public static final int ACTION_REMOVE = 0;
-    /**
-     * Indicates that the Confirmation Listener (Undo and Delete) will perform an update.
-     */
-    public static final int ACTION_UPDATE = 1;
-
-    /**
-     * Annotation interface for Undo actions.
-     */
-    @IntDef({ACTION_REMOVE, ACTION_UPDATE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Action {
-    }
-
-    @Action
-    private int mAction = ACTION_REMOVE;
-    private List<Integer> mPositions = null;
-    private Object mPayload = null;
-    private FlexibleAdapter mAdapter;
-    private Snackbar mSnackbar = null;
-    private OnActionListener mActionListener;
-    private OnUndoListener mUndoListener;
-    private @ColorInt int mActionTextColor = Color.TRANSPARENT;
-
-
-    /**
-     * Default constructor.
-     * <p>By calling this constructor, {@link FlexibleAdapter#setPermanentDelete(boolean)}
-     * is set {@code false} automatically.
-     *
-     * @param adapter      the instance of {@code FlexibleAdapter}
-     * @param undoListener the callback for the Undo and Delete confirmation
-     */
-    public UndoHelper(FlexibleAdapter adapter, OnUndoListener undoListener) {
-        this.mAdapter = adapter;
-        this.mUndoListener = undoListener;
-        adapter.setPermanentDelete(false);
-    }
-
-    /**
-     * Sets the payload to inform other linked items about the change in action.
-     *
-     * @param payload any non-null user object to notify the parent (the payload will be
-     *                therefore passed to the bind method of the parent ViewHolder),
-     *                pass null to <u>not</u> notify the parent
-     * @return this object, so it can be chained
-     */
-    public UndoHelper withPayload(Object payload) {
-        this.mPayload = payload;
-        return this;
-    }
-
-    /**
-     * By default {@link UndoHelper#ACTION_REMOVE} is performed.
-     *
-     * @param action         the action, one of {@link UndoHelper#ACTION_REMOVE}, {@link UndoHelper#ACTION_UPDATE}
-     * @param actionListener the listener for the custom action to perform before the deletion
-     * @return this object, so it can be chained
-     */
-    public UndoHelper withAction(@Action int action, @NonNull OnActionListener actionListener) {
-        this.mAction = action;
-        this.mActionListener = actionListener;
-        return this;
-    }
-
-    /**
-     * Sets the text color of the action.
-     *
-     * @param color the color for the action button
-     * @return this object, so it can be chained
-     */
-    public UndoHelper withActionTextColor(@ColorInt int color) {
-        this.mActionTextColor = color;
-        return this;
-    }
-
-    /**
-     * As {@link #remove(List, View, CharSequence, CharSequence, int)} but with String
-     * resources instead of CharSequence.
-     */
-    public void remove(List<Integer> positions, @NonNull View mainView,
-                       @StringRes int messageStringResId, @StringRes int actionStringResId,
-                       @IntRange(from = -1) int undoTime) {
-        Context context = mainView.getContext();
-        remove(positions, mainView, context.getString(messageStringResId),
-                context.getString(actionStringResId), undoTime);
-    }
-
-    /**
-     * Performs the action on the specified positions and displays a SnackBar to Undo
-     * the operation. To customize the UPDATE event, please set a custom listener with
-     * {@link #withAction(int, OnActionListener)} method.
-     * <p>By default the DELETE action will be performed.</p>
-     *
-     * @param positions  the position to delete or update
-     * @param mainView   the view to find a parent from
-     * @param message    the text to show. Can be formatted text
-     * @param actionText the action text to display
-     * @param undoTime   How long to display the message. Either {@link Snackbar#LENGTH_SHORT} or
-     *                   {@link Snackbar#LENGTH_LONG} or any custom Integer.
-     * @see #remove(List, View, int, int, int)
-     */
-    @SuppressWarnings("WrongConstant")
-    public void remove(List<Integer> positions, @NonNull View mainView,
-                       CharSequence message, CharSequence actionText,
-                       @IntRange(from = -1) int undoTime) {
-        this.mPositions = positions;
-        Snackbar snackbar;
-        if (!mAdapter.isPermanentDelete()) {
-            snackbar = Snackbar.make(mainView, message, undoTime > 0 ? undoTime + 400 : undoTime)
-                    .setAction(actionText, new View.OnClickListener() {
-                        @Override
-                        public void onClick(View v) {
-                            if (mUndoListener != null)
-                                mUndoListener.onUndoConfirmed(mAction);
-                        }
-                    });
-        } else {
-            snackbar = Snackbar.make(mainView, message, undoTime);
-        }
-        if (mActionTextColor != Color.TRANSPARENT) {
-            snackbar.setActionTextColor(mActionTextColor);
-        }
-        mSnackbar = snackbar;
-        snackbar.addCallback(this);
-        snackbar.show();
-    }
-
-    public void dismissNow() {
-        if (mSnackbar != null) {
-            mSnackbar.removeCallback(this);
-            mSnackbar.dismiss();
-            onDismissed(mSnackbar, Snackbar.Callback.DISMISS_EVENT_MANUAL);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onDismissed(Snackbar snackbar, int event) {
-        if (mAdapter.isPermanentDelete()) return;
-        switch (event) {
-            case DISMISS_EVENT_SWIPE:
-            case DISMISS_EVENT_MANUAL:
-            case DISMISS_EVENT_TIMEOUT:
-                if (mUndoListener != null)
-                    mUndoListener.onDeleteConfirmed(mAction);
-                mAdapter.emptyBin();
-                mSnackbar = null;
-            case DISMISS_EVENT_CONSECUTIVE:
-            case DISMISS_EVENT_ACTION:
-            default:
-                break;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onShown(Snackbar snackbar) {
-        boolean consumed = false;
-        // Perform the action before deletion
-        if (mActionListener != null) consumed = mActionListener.onPreAction();
-        // Remove selected items from Adapter list after SnackBar is shown
-        if (!consumed) mAdapter.removeItems(mPositions, mPayload);
-        // Perform the action after the deletion
-        if (mActionListener != null) mActionListener.onPostAction();
-        // Here, we can notify the callback only in case of permanent deletion
-        if (mAdapter.isPermanentDelete() && mUndoListener != null)
-            mUndoListener.onDeleteConfirmed(mAction);
-    }
-
-    /**
-     * Basic implementation of {@link OnActionListener} interface.
-     * <p>Override the methods as your convenience.</p>
-     */
-    public static class SimpleActionListener implements OnActionListener {
-        @Override
-        public boolean onPreAction() {
-            return false;
-        }
-
-        @Override
-        public void onPostAction() {
-
-        }
-    }
-
-    public interface OnActionListener {
-        /**
-         * Performs the custom action before item deletion.
-         *
-         * @return true if action has been consumed and should stop the deletion, false to
-         * continue with the deletion
-         */
-        boolean onPreAction();
-
-        /**
-         * Performs custom action After items deletion. Useful to finish the action mode and perform
-         * secondary custom actions.
-         */
-        void onPostAction();
-    }
-
-    /**
-     * @since 30/04/2016
-     */
-    public interface OnUndoListener {
-        /**
-         * Called when Undo event is triggered. Perform custom action after restoration.
-         * <p>Usually for a delete restoration you should call
-         * {@link FlexibleAdapter#restoreDeletedItems()}.</p>
-         *
-         * @param action one of {@link UndoHelper#ACTION_REMOVE}, {@link UndoHelper#ACTION_UPDATE}
-         */
-        void onUndoConfirmed(int action);
-
-        /**
-         * Called when Undo timeout is over and action must be committed in the user Database.
-         * <p>Due to Java Generic, it's too complicated and not well manageable if we pass the
-         * List&lt;T&gt; object.<br/>
-         * So, to get deleted items, use {@link FlexibleAdapter#getDeletedItems()} from the
-         * implementation of this method.</p>
-         *
-         * @param action one of {@link UndoHelper#ACTION_REMOVE}, {@link UndoHelper#ACTION_UPDATE}
-         */
-        void onDeleteConfirmed(int action);
-    }
-
-}

+ 1 - 1
app/src/main/res/layout/chapters_controller.xml

@@ -43,7 +43,7 @@
         android:layout_height="match_parent"
         android:layout_centerHorizontal="true"
         android:layout_gravity="end"
-        android:visibility="gone"
+        app:fastScrollerBubbleEnabled="false"
         tools:visibility="visible"/>
 
     <android.support.design.widget.FloatingActionButton