Browse Source

Update recent chapters adapter

len 8 years ago
parent
commit
c6b89a826c

+ 15 - 11
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -57,18 +57,22 @@ class MainActivity : BaseActivity() {
             empty_view.hide()
 
             val id = item.itemId
-            when (id) {
-                R.id.nav_drawer_library -> setFragment(LibraryFragment.newInstance(), id)
-                R.id.nav_drawer_recent_updates -> setFragment(RecentChaptersFragment.newInstance(), id)
-                R.id.nav_drawer_recently_read -> setFragment(RecentlyReadFragment.newInstance(), id)
-                R.id.nav_drawer_catalogues -> setFragment(CatalogueFragment.newInstance(), id)
-                R.id.nav_drawer_latest_updates -> setFragment(LatestUpdatesFragment.newInstance(), id)
-                R.id.nav_drawer_downloads -> startActivity(Intent(this, DownloadActivity::class.java))
-                R.id.nav_drawer_settings -> {
-                    val intent = Intent(this, SettingsActivity::class.java)
-                    startActivityForResult(intent, REQUEST_OPEN_SETTINGS)
+
+            val oldFragment = supportFragmentManager.findFragmentById(R.id.frame_container)
+            if (oldFragment == null || oldFragment.tag.toInt() != id) {
+                when (id) {
+                    R.id.nav_drawer_library -> setFragment(LibraryFragment.newInstance(), id)
+                    R.id.nav_drawer_recent_updates -> setFragment(RecentChaptersFragment.newInstance(), id)
+                    R.id.nav_drawer_recently_read -> setFragment(RecentlyReadFragment.newInstance(), id)
+                    R.id.nav_drawer_catalogues -> setFragment(CatalogueFragment.newInstance(), id)
+                    R.id.nav_drawer_latest_updates -> setFragment(LatestUpdatesFragment.newInstance(), id)
+                    R.id.nav_drawer_downloads -> startActivity(Intent(this, DownloadActivity::class.java))
+                    R.id.nav_drawer_settings -> {
+                        val intent = Intent(this, SettingsActivity::class.java)
+                        startActivityForResult(intent, REQUEST_OPEN_SETTINGS)
+                    }
+                    R.id.nav_drawer_backup -> setFragment(BackupFragment.newInstance(), id)
                 }
-                R.id.nav_drawer_backup -> setFragment(BackupFragment.newInstance(), id)
             }
             drawer.closeDrawer(GravityCompat.START)
             true

+ 50 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt

@@ -0,0 +1,50 @@
+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
+import eu.davidea.viewholders.FlexibleViewHolder
+import eu.kanade.tachiyomi.R
+import java.util.*
+
+class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() {
+
+    override fun getLayoutRes(): Int {
+        return R.layout.item_recent_chapter_section
+    }
+
+    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
+        return Holder(inflater.inflate(layoutRes, parent, false), adapter)
+    }
+
+    override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
+        holder.bind(this)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other is DateItem) {
+            return date == other.date
+        }
+        return false
+    }
+
+    override fun hashCode(): Int {
+        return date.hashCode()
+    }
+
+    class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter, true) {
+
+        private val now = Date().time
+
+        val section_text = view.findViewById(R.id.section_text) as TextView
+
+        fun bind(item: DateItem) {
+            section_text.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
+        }
+    }
+}

+ 0 - 22
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapter.kt

@@ -1,22 +0,0 @@
-package eu.kanade.tachiyomi.ui.recent_updates
-
-import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.MangaChapter
-import eu.kanade.tachiyomi.data.download.model.Download
-
-class RecentChapter(mc: MangaChapter) : Chapter by mc.chapter {
-
-    val manga = mc.manga
-
-    private var _status: Int = 0
-
-    var status: Int
-        get() = download?.status ?: _status
-        set(value) { _status = value }
-
-    @Transient var download: Download? = null
-
-    val isDownloaded: Boolean
-        get() = status == Download.DOWNLOADED
-
-}

+ 22 - 24
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersHolder.kt → app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt

@@ -2,9 +2,9 @@ package eu.kanade.tachiyomi.ui.recent_updates
 
 import android.view.View
 import android.widget.PopupMenu
+import eu.davidea.viewholders.FlexibleViewHolder
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.download.model.Download
-import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
 import eu.kanade.tachiyomi.util.getResourceColor
 import kotlinx.android.synthetic.main.item_recent_chapters.view.*
 
@@ -18,11 +18,9 @@ import kotlinx.android.synthetic.main.item_recent_chapters.view.*
  * @param listener a listener to react to single tap and long tap events.
  * @constructor creates a new recent chapter holder.
  */
-class RecentChaptersHolder(
-        private val view: View,
-        private val adapter: RecentChaptersAdapter,
-        listener: OnListItemClickListener)
-: FlexibleViewHolder(view, adapter, listener) {
+class RecentChapterHolder(private val view: View, private val adapter: RecentChaptersAdapter) :
+        FlexibleViewHolder(view, adapter) {
+
     /**
      * Color of read chapter
      */
@@ -34,33 +32,33 @@ class RecentChaptersHolder(
     private var unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary)
 
     /**
-     * Object containing chapter information
+     * Currently bound item.
      */
-    private var chapter: RecentChapter? = null
+    private var item: RecentChapterItem? = null
 
     init {
         // We need to post a Runnable to show the popup to make sure that the PopupMenu is
         // correctly positioned. The reason being that the view may change position before the
         // PopupMenu is shown.
-        view.chapter_menu.setOnClickListener { it.post({ showPopupMenu(it) }) }
+        view.chapter_menu.setOnClickListener { it.post { showPopupMenu(it) } }
     }
 
     /**
      * Set values of view
      *
-     * @param chapter item containing chapter information
+     * @param item item containing chapter information
      */
-    fun onSetValues(chapter: RecentChapter) {
-        this.chapter = chapter
+    fun bind(item: RecentChapterItem) {
+        this.item = item
 
         // Set chapter title
-        view.chapter_title.text = chapter.name
+        view.chapter_title.text = item.chapter.name
 
         // Set manga title
-        view.manga_title.text = chapter.manga.title
+        view.manga_title.text = item.manga.title
 
         // Check if chapter is read and set correct color
-        if (chapter.read) {
+        if (item.chapter.read) {
             view.chapter_title.setTextColor(readColor)
             view.manga_title.setTextColor(readColor)
         } else {
@@ -69,7 +67,7 @@ class RecentChaptersHolder(
         }
 
         // Set chapter status
-        notifyStatus(chapter.status)
+        notifyStatus(item.status)
     }
 
     /**
@@ -92,7 +90,7 @@ class RecentChaptersHolder(
      *
      * @param view view containing popup menu.
      */
-    private fun showPopupMenu(view: View) = chapter?.let { chapter ->
+    private fun showPopupMenu(view: View) = item?.let { item ->
         // Create a PopupMenu, giving it the clicked view for an anchor
         val popup = PopupMenu(view.context, view)
 
@@ -100,18 +98,18 @@ class RecentChaptersHolder(
         popup.menuInflater.inflate(R.menu.chapter_recent, popup.menu)
 
         // Hide download and show delete if the chapter is downloaded and
-        if (chapter.isDownloaded) {
+        if (item.isDownloaded) {
             popup.menu.findItem(R.id.action_download).isVisible = false
             popup.menu.findItem(R.id.action_delete).isVisible = true
         }
 
         // Hide mark as unread when the chapter is unread
-        if (!chapter.read /*&& mangaChapter.chapter.last_page_read == 0*/) {
+        if (!item.chapter.read /*&& mangaChapter.chapter.last_page_read == 0*/) {
             popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
         }
 
         // Hide mark as read when the chapter is read
-        if (chapter.read) {
+        if (item.chapter.read) {
             popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
         }
 
@@ -119,10 +117,10 @@ class RecentChaptersHolder(
         popup.setOnMenuItemClickListener { menuItem ->
             with(adapter.fragment) {
                 when (menuItem.itemId) {
-                    R.id.action_download -> downloadChapter(chapter)
-                    R.id.action_delete -> deleteChapter(chapter)
-                    R.id.action_mark_as_read -> markAsRead(listOf(chapter))
-                    R.id.action_mark_as_unread -> markAsUnread(listOf(chapter))
+                    R.id.action_download -> downloadChapter(item)
+                    R.id.action_delete -> deleteChapter(item)
+                    R.id.action_mark_as_read -> markAsRead(listOf(item))
+                    R.id.action_mark_as_unread -> markAsUnread(listOf(item))
                 }
             }
 

+ 50 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt

@@ -0,0 +1,50 @@
+package eu.kanade.tachiyomi.ui.recent_updates
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.items.AbstractSectionableItem
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.database.models.Chapter
+import eu.kanade.tachiyomi.data.database.models.Manga
+import eu.kanade.tachiyomi.data.download.model.Download
+
+class RecentChapterItem(val chapter: Chapter, val manga: Manga, header: DateItem) :
+        AbstractSectionableItem<RecentChapterHolder, DateItem>(header) {
+
+    private var _status: Int = 0
+
+    var status: Int
+        get() = download?.status ?: _status
+        set(value) { _status = value }
+
+    @Transient var download: Download? = null
+
+    val isDownloaded: Boolean
+        get() = status == Download.DOWNLOADED
+
+    override fun getLayoutRes(): Int {
+        return R.layout.item_recent_chapters
+    }
+
+    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): RecentChapterHolder {
+        return RecentChapterHolder(inflater.inflate(layoutRes, parent, false), adapter as RecentChaptersAdapter)
+    }
+
+    override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: RecentChapterHolder, position: Int, payloads: List<Any?>?) {
+        holder.bind(this)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other is RecentChapterItem) {
+            return chapter.id!! == other.chapter.id!!
+        }
+        return false
+    }
+
+    override fun hashCode(): Int {
+        return chapter.id!!.hashCode()
+    }
+
+}

+ 5 - 121
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt

@@ -1,128 +1,12 @@
 package eu.kanade.tachiyomi.ui.recent_updates
 
-import android.support.v7.widget.RecyclerView
-import android.view.View
-import android.view.ViewGroup
-import eu.davidea.flexibleadapter4.FlexibleAdapter
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.util.inflate
-import java.util.*
+import eu.davidea.flexibleadapter.FlexibleAdapter
 
-/**
- * Adapter of RecentChaptersHolder.
- * Connection between Fragment and Holder
- * Holder updates should be called from here.
- *
- * @param fragment a RecentChaptersFragment object
- * @constructor creates an instance of the adapter.
- */
-
-class RecentChaptersAdapter(val fragment: RecentChaptersFragment)
-: FlexibleAdapter<RecyclerView.ViewHolder, Any>() {
-    /**
-     * The id of the view type
-     */
-    private val VIEW_TYPE_CHAPTER = 0
-
-    /**
-     * The id of the view type
-     */
-    private val VIEW_TYPE_SECTION = 1
+class RecentChaptersAdapter(val fragment: RecentChaptersFragment) :
+        FlexibleAdapter<RecentChapterItem>(null, fragment, true) {
 
     init {
-        // Let each each item in the data set be represented with a unique identifier.
-        setHasStableIds(true)
-    }
-
-    /**
-     * Called when ViewHolder is bind
-     *
-     * @param holder bind holder
-     * @param position position of holder
-     */
-    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
-        // Check which view type and set correct values.
-        val item = getItem(position)
-        when (holder.itemViewType) {
-            VIEW_TYPE_CHAPTER -> {
-                if (item is RecentChapter) {
-                    (holder as RecentChaptersHolder).onSetValues(item)
-                }
-            }
-            VIEW_TYPE_SECTION -> {
-                if (item is Date) {
-                    (holder as SectionViewHolder).onSetValues(item)
-                }
-            }
-        }
-
-        //When user scrolls this bind the correct selection status
-        holder.itemView.isActivated = isSelected(position)
-    }
-
-    /**
-     * Called when ViewHolder is created
-     *
-     * @param parent parent View
-     * @param viewType int containing viewType
-     */
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder? {
-        val view: View
-
-        // Check which view type and set correct values.
-        when (viewType) {
-            VIEW_TYPE_CHAPTER -> {
-                view = parent.inflate(R.layout.item_recent_chapters)
-                return RecentChaptersHolder(view, this, fragment)
-            }
-            VIEW_TYPE_SECTION -> {
-                view = parent.inflate(R.layout.item_recent_chapter_section)
-                return SectionViewHolder(view)
-            }
-        }
-        return null
-    }
-
-    /**
-     * Returns the correct ViewType
-     *
-     * @param position position of item
-     */
-    override fun getItemViewType(position: Int): Int {
-        return if (getItem(position) is RecentChapter) VIEW_TYPE_CHAPTER else VIEW_TYPE_SECTION
+        setDisplayHeadersAtStartUp(true)
+        setStickyHeaders(true)
     }
-
-
-    /**
-     * Update items
-
-     * @param items items
-     */
-    fun setItems(items: List<Any>) {
-        mItems = items
-        notifyDataSetChanged()
-    }
-
-    /**
-     * Needed to determine holder id
-     *
-     * @param position position of holder item
-     */
-    override fun getItemId(position: Int): Long {
-        val item = getItem(position)
-        if (item is RecentChapter)
-            return item.id!!
-        else
-            return item.hashCode().toLong()
-    }
-
-    /**
-     * Abstract function (not needed).
-     *
-     * @param p0 a string.
-     */
-    override fun updateDataSet(p0: String) {
-        // Empty function.
-    }
-
 }

+ 46 - 47
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersFragment.kt

@@ -8,11 +8,10 @@ import android.support.v7.widget.LinearLayoutManager
 import android.support.v7.widget.RecyclerView
 import android.view.*
 import com.afollestad.materialdialogs.MaterialDialog
-import eu.davidea.flexibleadapter4.FlexibleAdapter
+import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.data.library.LibraryUpdateService
-import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
 import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.reader.ReaderActivity
@@ -28,8 +27,11 @@ import timber.log.Timber
  * UI related actions should be called from here.
  */
 @RequiresPresenter(RecentChaptersPresenter::class)
-class RecentChaptersFragment
-: BaseRxFragment<RecentChaptersPresenter>(), ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
+class RecentChaptersFragment:
+        BaseRxFragment<RecentChaptersPresenter>(),
+        ActionMode.Callback,
+        FlexibleAdapter.OnItemClickListener,
+        FlexibleAdapter.OnItemLongClickListener{
 
     companion object {
         /**
@@ -97,40 +99,45 @@ class RecentChaptersFragment
 
         // Update toolbar text
         setToolbarTitle(R.string.label_recent_updates)
+
+        // Disable toolbar elevation, it looks better with sticky headers.
+//        ViewCompat.setElevation(activity.appbar, 0f)
     }
 
+//    override fun onDestroyView() {
+//        ViewCompat.setElevation(activity.appbar, 4.dpToPx.toFloat())
+//        super.onDestroyView()
+//    }
+
     /**
      * Returns selected chapters
      * @return list of selected chapters
      */
-    fun getSelectedChapters(): List<RecentChapter> {
-        return adapter.selectedItems.map { adapter.getItem(it) as? RecentChapter }.filterNotNull()
+    fun getSelectedChapters(): List<RecentChapterItem> {
+        return adapter.selectedPositions.mapNotNull { adapter.getItem(it) }
     }
 
     /**
      * Called when item in list is clicked
      * @param position position of clicked item
      */
-    override fun onListItemClick(position: Int): Boolean {
+    override fun onItemClick(position: Int): Boolean {
         // Get item from position
         val item = adapter.getItem(position)
-        if (item is RecentChapter) {
-            if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
-                toggleSelection(position)
-                return true
-            } else {
-                openChapter(item)
-                return false
-            }
+        if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
+            toggleSelection(position)
+            return true
+        } else {
+            openChapter(item)
+            return false
         }
-        return false
     }
 
     /**
      * Called when item in list is long clicked
      * @param position position of clicked item
      */
-    override fun onListItemLongClick(position: Int) {
+    override fun onItemLongClick(position: Int) {
         if (actionMode == null)
             actionMode = activity.startSupportActionMode(this)
 
@@ -142,31 +149,22 @@ class RecentChaptersFragment
      * @param position position of selected item
      */
     private fun toggleSelection(position: Int) {
-        adapter.toggleSelection(position, false)
+        adapter.toggleSelection(position)
 
         val count = adapter.selectedItemCount
         if (count == 0) {
             actionMode?.finish()
         } else {
-            setContextTitle(count)
-            actionMode?.invalidate()
+            actionMode?.title = getString(R.string.label_selected, count)
         }
     }
 
-    /**
-     * Set the context title
-     * @param count count of selected items
-     */
-    private fun setContextTitle(count: Int) {
-        actionMode?.title = getString(R.string.label_selected, count)
-    }
-
     /**
      * Open chapter in reader
      * @param chapter selected chapter
      */
-    private fun openChapter(chapter: RecentChapter) {
-        val intent = ReaderActivity.newIntent(activity, chapter.manga, chapter)
+    private fun openChapter(item: RecentChapterItem) {
+        val intent = ReaderActivity.newIntent(activity, item.manga, item.chapter)
         startActivity(intent)
     }
 
@@ -174,7 +172,7 @@ class RecentChaptersFragment
      * Download selected items
      * @param chapters list of selected [RecentChapter]s
      */
-    fun downloadChapters(chapters: List<RecentChapter>) {
+    fun downloadChapters(chapters: List<RecentChapterItem>) {
         destroyActionModeIfNeeded()
         presenter.downloadChapters(chapters)
     }
@@ -183,12 +181,12 @@ class RecentChaptersFragment
      * Populate adapter with chapters
      * @param chapters list of [Any]
      */
-    fun onNextRecentChapters(chapters: List<Any>) {
+    fun onNextRecentChapters(chapters: List<RecentChapterItem>) {
         (activity as MainActivity).updateEmptyView(chapters.isEmpty(),
                 R.string.information_no_recent, R.drawable.ic_update_black_128dp)
 
         destroyActionModeIfNeeded()
-        adapter.setItems(chapters)
+        adapter.updateDataSet(chapters.toMutableList(), true)
     }
 
     /**
@@ -203,15 +201,15 @@ class RecentChaptersFragment
      * Returns holder belonging to chapter
      * @param download [Download] object containing download progress.
      */
-    private fun getHolder(download: Download): RecentChaptersHolder? {
-        return recycler.findViewHolderForItemId(download.chapter.id!!) as? RecentChaptersHolder
+    private fun getHolder(download: Download): RecentChapterHolder? {
+        return recycler.findViewHolderForItemId(download.chapter.id!!) as? RecentChapterHolder
     }
 
     /**
      * Mark chapter as read
      * @param chapters list of chapters
      */
-    fun markAsRead(chapters: List<RecentChapter>) {
+    fun markAsRead(chapters: List<RecentChapterItem>) {
         presenter.markChapterRead(chapters, true)
         if (presenter.preferences.removeAfterMarkedAsRead()) {
             deleteChapters(chapters)
@@ -222,7 +220,7 @@ class RecentChaptersFragment
      * Delete selected chapters
      * @param chapters list of [RecentChapter] objects
      */
-    fun deleteChapters(chapters: List<RecentChapter>) {
+    fun deleteChapters(chapters: List<RecentChapterItem>) {
         destroyActionModeIfNeeded()
         DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
         presenter.deleteChapters(chapters)
@@ -239,7 +237,7 @@ class RecentChaptersFragment
      * Mark chapter as unread
      * @param chapters list of selected [RecentChapter]
      */
-    fun markAsUnread(chapters: List<RecentChapter>) {
+    fun markAsUnread(chapters: List<RecentChapterItem>) {
         presenter.markChapterRead(chapters, false)
     }
 
@@ -247,15 +245,15 @@ class RecentChaptersFragment
      * Start downloading chapter
      * @param chapter selected chapter with manga
      */
-    fun downloadChapter(chapter: RecentChapter) {
-        presenter.downloadChapter(chapter)
+    fun downloadChapter(chapter: RecentChapterItem) {
+        presenter.downloadChapters(listOf(chapter))
     }
 
     /**
      * Start deleting chapter
      * @param chapter selected chapter with manga
      */
-    fun deleteChapter(chapter: RecentChapter) {
+    fun deleteChapter(chapter: RecentChapterItem) {
         DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
         presenter.deleteChapters(listOf(chapter))
     }
@@ -281,11 +279,8 @@ class RecentChaptersFragment
      * Called to dismiss deleting dialog
      */
     fun dismissDeletingDialog() {
-        (childFragmentManager.findFragmentByTag(DeletingChaptersDialog.TAG) as? DialogFragment)?.dismiss()
-    }
-
-    override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
-        return false
+        (childFragmentManager.findFragmentByTag(DeletingChaptersDialog.TAG) as? DialogFragment)
+                ?.dismissAllowingStateLoss()
     }
 
     /**
@@ -322,12 +317,16 @@ class RecentChaptersFragment
         return true
     }
 
+    override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
+        return false
+    }
+
     /**
      * Called when ActionMode destroyed
      * @param mode the ActionMode object
      */
     override fun onDestroyActionMode(mode: ActionMode?) {
-        adapter.mode = FlexibleAdapter.MODE_SINGLE
+        adapter.mode = FlexibleAdapter.MODE_IDLE
         adapter.clearSelection()
         actionMode = null
     }

+ 72 - 99
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt

@@ -41,7 +41,7 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
     /**
      * List containing chapter and manga information
      */
-    private var chapters: List<RecentChapter>? = null
+    private var chapters: List<RecentChapterItem> = emptyList()
 
     override fun onCreate(savedState: Bundle?) {
         super.onCreate(savedState)
@@ -53,15 +53,15 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
         getChapterStatusObservable()
                 .subscribeLatestCache(RecentChaptersFragment::onChapterStatusChange,
                         { view, error -> Timber.e(error) })
-
     }
 
     /**
      * Get observable containing recent chapters and date
+     *
      * @return observable containing recent chapters and date
      */
-    fun getRecentChaptersObservable(): Observable<ArrayList<Any>> {
-        // Set date for recent chapters
+    fun getRecentChaptersObservable(): Observable<List<RecentChapterItem>> {
+        // Set date limit for recent chapters
         val cal = Calendar.getInstance().apply {
             time = Date()
             add(Calendar.MONTH, -1)
@@ -70,33 +70,48 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
         return db.getRecentChapters(cal.time).asRxObservable()
                 // Convert to a list of recent chapters.
                 .map { mangaChapters ->
-                    mangaChapters.map { it.toModel() }
+                    val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
+                    val byDay = mangaChapters.groupByTo(map, { getMapKey(it.chapter.date_fetch) })
+                    byDay.flatMap {
+                        val dateItem = DateItem(it.key)
+                        it.value.map { RecentChapterItem(it.chapter, it.manga, dateItem) }
+                    }
                 }
                 .doOnNext {
-                    setDownloadedChapters(it)
-                    chapters = it
-                }
-                // Group chapters by the date they were fetched on a ordered map.
-                .flatMap { recentItems ->
-                    Observable.from(recentItems)
-                            .toMultimap(
-                                    { getMapKey(it.date_fetch) },
-                                    { it },
-                                    { TreeMap { d1, d2 -> d2.compareTo(d1) } })
-                }
-                // Add every day and all its chapters to a single list.
-                .map { recentItems ->
-                    ArrayList<Any>().apply {
-                        for ((key, value) in recentItems) {
-                            add(key)
-                            addAll(value)
+                    it.forEach { item ->
+                        // Find an active download for this chapter.
+                        val download = downloadManager.queue.find { it.chapter.id == item.chapter.id }
+
+                        // If there's an active download, assign it, otherwise ask the manager if the chapter is
+                        // downloaded and assign it to the status.
+                        if (download != null) {
+                            item.download = download
                         }
                     }
+                    setDownloadedChapters(it)
+                    chapters = it
                 }
     }
 
+    /**
+     * Get date as time key
+     *
+     * @param date desired date
+     * @return date as time key
+     */
+    private fun getMapKey(date: Long): Date {
+        val cal = Calendar.getInstance()
+        cal.time = Date(date)
+        cal[Calendar.HOUR_OF_DAY] = 0
+        cal[Calendar.MINUTE] = 0
+        cal[Calendar.SECOND] = 0
+        cal[Calendar.MILLISECOND] = 0
+        return cal.time
+    }
+
     /**
      * Returns observable containing chapter status.
+     *
      * @return download object containing download progress.
      */
     private fun getChapterStatusObservable(): Observable<Download> {
@@ -105,38 +120,21 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
                 .doOnNext { download -> onDownloadStatusChange(download) }
     }
 
-    /**
-     * Converts a chapter from the database to an extended model, allowing to store new fields.
-     */
-    private fun MangaChapter.toModel(): RecentChapter {
-        // Create the model object.
-        val model = RecentChapter(this)
-
-        // Find an active download for this chapter.
-        val download = downloadManager.queue.find { it.chapter.id == chapter.id }
-
-        // If there's an active download, assign it, otherwise ask the manager if the chapter is
-        // downloaded and assign it to the status.
-        if (download != null) {
-            model.download = download
-        }
-        return model
-    }
-
     /**
      * Finds and assigns the list of downloaded chapters.
      *
-     * @param chapters the list of chapter from the database.
+     * @param items the list of chapter from the database.
      */
-    private fun setDownloadedChapters(chapters: List<RecentChapter>) {
+    private fun setDownloadedChapters(items: List<RecentChapterItem>) {
         // Cached list of downloaded manga directories.
         val mangaDirectories = mutableMapOf<Long, Array<UniFile>>()
 
         // Cached list of downloaded chapter directories for a manga.
         val chapterDirectories = mutableMapOf<Long, Array<UniFile>>()
 
-        for (chapter in chapters) {
-            val manga = chapter.manga
+        for (item in items) {
+            val manga = item.manga
+            val chapter = item.chapter
             val source = sourceManager.get(manga.source) ?: continue
 
             val mangaDirs = mangaDirectories.getOrPut(source.id) {
@@ -152,64 +150,52 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
 
             val chapterDirName = downloadManager.getChapterDirName(chapter)
             if (chapterDirs.any { it.name == chapterDirName }) {
-                chapter.status = Download.DOWNLOADED
+                item.status = Download.DOWNLOADED
             }
         }
     }
 
     /**
      * Update status of chapters.
+     *
      * @param download download object containing progress.
      */
     private fun onDownloadStatusChange(download: Download) {
         // Assign the download to the model object.
         if (download.status == Download.QUEUE) {
-            val chapter = chapters?.find { it.id == download.chapter.id }
+            val chapter = chapters.find { it.chapter.id == download.chapter.id }
             if (chapter != null && chapter.download == null) {
                 chapter.download = download
             }
         }
     }
 
-    /**
-     * Get date as time key
-     * @param date desired date
-     * @return date as time key
-     */
-    private fun getMapKey(date: Long): Date {
-        val cal = Calendar.getInstance()
-        cal.time = Date(date)
-        cal[Calendar.HOUR_OF_DAY] = 0
-        cal[Calendar.MINUTE] = 0
-        cal[Calendar.SECOND] = 0
-        cal[Calendar.MILLISECOND] = 0
-        return cal.time
-    }
-
     /**
      * Mark selected chapter as read
-     * @param chapters list of selected chapters
+     *
+     * @param items list of selected chapters
      * @param read read status
      */
-    fun markChapterRead(chapters: List<RecentChapter>, read: Boolean) {
-        Observable.from(chapters)
-                .doOnNext { chapter ->
-                    chapter.read = read
-                    if (!read) {
-                        chapter.last_page_read = 0
-                    }
-                }
-                .toList()
-                .flatMap { db.updateChaptersProgress(it).asRxObservable() }
+    fun markChapterRead(items: List<RecentChapterItem>, read: Boolean) {
+        val chapters = items.map { it.chapter }
+        chapters.forEach {
+            it.read = read
+            if (!read) {
+                it.last_page_read = 0
+            }
+        }
+
+        Observable.fromCallable { db.updateChaptersProgress(chapters).executeAsBlocking() }
                 .subscribeOn(Schedulers.io())
                 .subscribe()
     }
 
     /**
      * Delete selected chapters
+     *
      * @param chapters list of chapters
      */
-    fun deleteChapters(chapters: List<RecentChapter>) {
+    fun deleteChapters(chapters: List<RecentChapterItem>) {
         Observable.from(chapters)
                 .doOnNext { deleteChapter(it) }
                 .toList()
@@ -217,42 +203,29 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
                 .observeOn(AndroidSchedulers.mainThread())
                 .subscribeFirst({ view, result ->
                     view.onChaptersDeleted()
-                }, { view, error ->
-                    view.onChaptersDeletedError(error)
-                })
+                }, RecentChaptersFragment::onChaptersDeletedError)
     }
 
     /**
      * Download selected chapters
-     * @param chapters list of recent chapters seleted.
-     */
-    fun downloadChapters(chapters: List<RecentChapter>) {
-        DownloadService.start(context)
-        Observable.from(chapters)
-                .doOnNext { downloadChapter(it) }
-                .subscribeOn(AndroidSchedulers.mainThread())
-                .subscribe()
-    }
-
-    /**
-     * Download selected chapter
-     * @param chapter chapter that is selected
+     * @param items list of recent chapters seleted.
      */
-    fun downloadChapter(chapter: RecentChapter) {
+    fun downloadChapters(items: List<RecentChapterItem>) {
+        items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) }
         DownloadService.start(context)
-        downloadManager.downloadChapters(chapter.manga, listOf(chapter))
     }
 
     /**
      * Delete selected chapter
-     * @param chapter chapter that is selected
-     */
-    private fun deleteChapter(chapter: RecentChapter) {
-        val source = sourceManager.get(chapter.manga.source) ?: return
-        downloadManager.queue.remove(chapter)
-        downloadManager.deleteChapter(source, chapter.manga, chapter)
-        chapter.status = Download.NOT_DOWNLOADED
-        chapter.download = null
+     *
+     * @param item chapter that is selected
+     */
+    private fun deleteChapter(item: RecentChapterItem) {
+        val source = sourceManager.get(item.manga.source) ?: return
+        downloadManager.queue.remove(item.chapter)
+        downloadManager.deleteChapter(source, item.manga, item.chapter)
+        item.status = Download.NOT_DOWNLOADED
+        item.download = null
     }
 
 }

+ 0 - 25
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/SectionViewHolder.kt

@@ -1,25 +0,0 @@
-package eu.kanade.tachiyomi.ui.recent_updates
-
-import android.support.v7.widget.RecyclerView
-import android.text.format.DateUtils
-import android.text.format.DateUtils.DAY_IN_MILLIS
-import android.view.View
-import kotlinx.android.synthetic.main.item_recent_chapter_section.view.*
-import java.util.*
-
-class SectionViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
-
-    /**
-     * Current date
-     */
-    private val now = Date().time
-
-    /**
-     * Set value of section header
-     *
-     * @param date of section header
-     */
-    fun onSetValues(date: Date) {
-        view.section_text.text = DateUtils.getRelativeTimeSpanString(date.time, now, DAY_IN_MILLIS)
-    }
-}

+ 10 - 6
app/src/main/res/layout/fragment_recent_chapters.xml

@@ -7,13 +7,17 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <android.support.v7.widget.RecyclerView
-        android:id="@+id/recycler"
+    <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:descendantFocusability="blocksDescendants"
-        tools:listitem="@layout/item_recent_chapters">
+        android:layout_height="match_parent">
 
-    </android.support.v7.widget.RecyclerView>
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/recycler"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:descendantFocusability="blocksDescendants"
+            tools:listitem="@layout/item_recent_chapters"/>
+
+    </FrameLayout>
 
 </android.support.v4.widget.SwipeRefreshLayout>

+ 3 - 4
app/src/main/res/layout/item_recent_chapter_section.xml

@@ -9,7 +9,8 @@
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
     android:paddingRight="?android:attr/listPreferredItemPaddingRight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:elevation="4dp">
 
     <TextView
         android:id="@+id/section_text"
@@ -17,8 +18,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:singleLine="true"/>
+        android:maxLines="1"/>
 
 </FrameLayout>
-
-