mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Update chapters adapter
This commit is contained in:
		@@ -1,128 +1,116 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.chapter
 | 
			
		||||
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.PopupMenu
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
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_chapter.view.*
 | 
			
		||||
import java.text.DateFormat
 | 
			
		||||
import java.text.DecimalFormat
 | 
			
		||||
import java.text.DecimalFormatSymbols
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
class ChaptersHolder(
 | 
			
		||||
        private val view: View,
 | 
			
		||||
        private val adapter: ChaptersAdapter,
 | 
			
		||||
        listener: FlexibleViewHolder.OnListItemClickListener)
 | 
			
		||||
: FlexibleViewHolder(view, adapter, listener) {
 | 
			
		||||
 | 
			
		||||
    private val readColor = view.context.getResourceColor(android.R.attr.textColorHint)
 | 
			
		||||
    private val unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary)
 | 
			
		||||
    private val bookmarkedColor = view.context.getResourceColor(R.attr.colorAccent)
 | 
			
		||||
    private val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
 | 
			
		||||
    private val df = DateFormat.getDateInstance(DateFormat.SHORT)
 | 
			
		||||
 | 
			
		||||
    private var item: ChapterModel? = 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) } }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onSetValues(chapter: ChapterModel, manga: Manga?) = with(view) {
 | 
			
		||||
        item = chapter
 | 
			
		||||
 | 
			
		||||
        chapter_title.text = when (manga?.displayMode) {
 | 
			
		||||
            Manga.DISPLAY_NUMBER -> {
 | 
			
		||||
                val formattedNumber = decimalFormat.format(chapter.chapter_number.toDouble())
 | 
			
		||||
                context.getString(R.string.display_mode_chapter, formattedNumber)
 | 
			
		||||
            }
 | 
			
		||||
            else -> chapter.name
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set correct text color
 | 
			
		||||
        chapter_title.setTextColor(if (chapter.read) readColor else unreadColor)
 | 
			
		||||
        if (chapter.bookmark) chapter_title.setTextColor(bookmarkedColor)
 | 
			
		||||
 | 
			
		||||
        if (chapter.date_upload > 0) {
 | 
			
		||||
            chapter_date.text = df.format(Date(chapter.date_upload))
 | 
			
		||||
            chapter_date.setTextColor(if (chapter.read) readColor else unreadColor)
 | 
			
		||||
        } else {
 | 
			
		||||
            chapter_date.text = ""
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0) {
 | 
			
		||||
            context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
 | 
			
		||||
        } else {
 | 
			
		||||
            ""
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        notifyStatus(chapter.status)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun notifyStatus(status: Int) = with(view.download_text) {
 | 
			
		||||
        when (status) {
 | 
			
		||||
            Download.QUEUE -> setText(R.string.chapter_queued)
 | 
			
		||||
            Download.DOWNLOADING -> setText(R.string.chapter_downloading)
 | 
			
		||||
            Download.DOWNLOADED -> setText(R.string.chapter_downloaded)
 | 
			
		||||
            Download.ERROR -> setText(R.string.chapter_error)
 | 
			
		||||
            else -> text = ""
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun showPopupMenu(view: View) = item?.let { chapter ->
 | 
			
		||||
        // Create a PopupMenu, giving it the clicked view for an anchor
 | 
			
		||||
        val popup = PopupMenu(view.context, view)
 | 
			
		||||
 | 
			
		||||
        // Inflate our menu resource into the PopupMenu's Menu
 | 
			
		||||
        popup.menuInflater.inflate(R.menu.chapter_single, popup.menu)
 | 
			
		||||
 | 
			
		||||
        // Hide download and show delete if the chapter is downloaded
 | 
			
		||||
        if (chapter.isDownloaded) {
 | 
			
		||||
            popup.menu.findItem(R.id.action_download).isVisible = false
 | 
			
		||||
            popup.menu.findItem(R.id.action_delete).isVisible = true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Hide bookmark if bookmark
 | 
			
		||||
        popup.menu.findItem(R.id.action_bookmark).isVisible = !chapter.bookmark
 | 
			
		||||
        popup.menu.findItem(R.id.action_remove_bookmark).isVisible = chapter.bookmark
 | 
			
		||||
 | 
			
		||||
        // Hide mark as unread when the chapter is unread
 | 
			
		||||
        if (!chapter.read && 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) {
 | 
			
		||||
            popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set a listener so we are notified if a menu item is clicked
 | 
			
		||||
        popup.setOnMenuItemClickListener { menuItem ->
 | 
			
		||||
            val chapterList = listOf(chapter)
 | 
			
		||||
 | 
			
		||||
            with(adapter.fragment) {
 | 
			
		||||
                when (menuItem.itemId) {
 | 
			
		||||
                    R.id.action_download -> downloadChapters(chapterList)
 | 
			
		||||
                    R.id.action_bookmark -> bookmarkChapters(chapterList, true)
 | 
			
		||||
                    R.id.action_remove_bookmark -> bookmarkChapters(chapterList, false)
 | 
			
		||||
                    R.id.action_delete -> deleteChapters(chapterList)
 | 
			
		||||
                    R.id.action_mark_as_read -> markAsRead(chapterList)
 | 
			
		||||
                    R.id.action_mark_as_unread -> markAsUnread(chapterList)
 | 
			
		||||
                    R.id.action_mark_previous_as_read -> markPreviousAsRead(chapter)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Finally show the PopupMenu
 | 
			
		||||
        popup.show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.chapter
 | 
			
		||||
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.PopupMenu
 | 
			
		||||
import eu.davidea.viewholders.FlexibleViewHolder
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.util.getResourceColor
 | 
			
		||||
import kotlinx.android.synthetic.main.item_chapter.view.*
 | 
			
		||||
import java.text.DateFormat
 | 
			
		||||
import java.text.DecimalFormat
 | 
			
		||||
import java.text.DecimalFormatSymbols
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
class ChapterHolder(
 | 
			
		||||
        private val view: View,
 | 
			
		||||
        private val adapter: ChaptersAdapter)
 | 
			
		||||
: FlexibleViewHolder(view, adapter) {
 | 
			
		||||
 | 
			
		||||
    private val readColor = view.context.getResourceColor(android.R.attr.textColorHint)
 | 
			
		||||
    private val unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary)
 | 
			
		||||
    private val bookmarkedColor = view.context.getResourceColor(R.attr.colorAccent)
 | 
			
		||||
    private val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
 | 
			
		||||
    private val df = DateFormat.getDateInstance(DateFormat.SHORT)
 | 
			
		||||
 | 
			
		||||
    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) } }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun bind(item: ChapterItem, manga: Manga) = with(view) {
 | 
			
		||||
        val chapter = item.chapter
 | 
			
		||||
 | 
			
		||||
        chapter_title.text = when (manga.displayMode) {
 | 
			
		||||
            Manga.DISPLAY_NUMBER -> {
 | 
			
		||||
                val formattedNumber = decimalFormat.format(chapter.chapter_number.toDouble())
 | 
			
		||||
                context.getString(R.string.display_mode_chapter, formattedNumber)
 | 
			
		||||
            }
 | 
			
		||||
            else -> chapter.name
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set correct text color
 | 
			
		||||
        chapter_title.setTextColor(if (chapter.read) readColor else unreadColor)
 | 
			
		||||
        if (chapter.bookmark) chapter_title.setTextColor(bookmarkedColor)
 | 
			
		||||
 | 
			
		||||
        if (chapter.date_upload > 0) {
 | 
			
		||||
            chapter_date.text = df.format(Date(chapter.date_upload))
 | 
			
		||||
            chapter_date.setTextColor(if (chapter.read) readColor else unreadColor)
 | 
			
		||||
        } else {
 | 
			
		||||
            chapter_date.text = ""
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0) {
 | 
			
		||||
            context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
 | 
			
		||||
        } else {
 | 
			
		||||
            ""
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        notifyStatus(item.status)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun notifyStatus(status: Int) = with(view.download_text) {
 | 
			
		||||
        when (status) {
 | 
			
		||||
            Download.QUEUE -> setText(R.string.chapter_queued)
 | 
			
		||||
            Download.DOWNLOADING -> setText(R.string.chapter_downloading)
 | 
			
		||||
            Download.DOWNLOADED -> setText(R.string.chapter_downloaded)
 | 
			
		||||
            Download.ERROR -> setText(R.string.chapter_error)
 | 
			
		||||
            else -> text = ""
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun showPopupMenu(view: View) {
 | 
			
		||||
        val item = adapter.getItem(adapterPosition) ?: return
 | 
			
		||||
 | 
			
		||||
        // Create a PopupMenu, giving it the clicked view for an anchor
 | 
			
		||||
        val popup = PopupMenu(view.context, view)
 | 
			
		||||
 | 
			
		||||
        // Inflate our menu resource into the PopupMenu's Menu
 | 
			
		||||
        popup.menuInflater.inflate(R.menu.chapter_single, popup.menu)
 | 
			
		||||
 | 
			
		||||
        val chapter = item.chapter
 | 
			
		||||
 | 
			
		||||
        // Hide download and show delete if the chapter is downloaded
 | 
			
		||||
        if (item.isDownloaded) {
 | 
			
		||||
            popup.menu.findItem(R.id.action_download).isVisible = false
 | 
			
		||||
            popup.menu.findItem(R.id.action_delete).isVisible = true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Hide bookmark if bookmark
 | 
			
		||||
        popup.menu.findItem(R.id.action_bookmark).isVisible = !chapter.bookmark
 | 
			
		||||
        popup.menu.findItem(R.id.action_remove_bookmark).isVisible = chapter.bookmark
 | 
			
		||||
 | 
			
		||||
        // Hide mark as unread when the chapter is unread
 | 
			
		||||
        if (!chapter.read && 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) {
 | 
			
		||||
            popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set a listener so we are notified if a menu item is clicked
 | 
			
		||||
        popup.setOnMenuItemClickListener { menuItem ->
 | 
			
		||||
            adapter.menuItemListener(adapterPosition, menuItem)
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Finally show the PopupMenu
 | 
			
		||||
        popup.show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.chapter
 | 
			
		||||
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 | 
			
		||||
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 ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem<ChapterHolder>(),
 | 
			
		||||
        Chapter by chapter {
 | 
			
		||||
 | 
			
		||||
    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_chapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): ChapterHolder {
 | 
			
		||||
        return ChapterHolder(inflater.inflate(layoutRes, parent, false), adapter as ChaptersAdapter)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: ChapterHolder, position: Int, payloads: List<Any?>?) {
 | 
			
		||||
        holder.bind(this, manga)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun equals(other: Any?): Boolean {
 | 
			
		||||
        if (this === other) return true
 | 
			
		||||
        if (other is ChapterItem) {
 | 
			
		||||
            return chapter.id!! == other.chapter.id!!
 | 
			
		||||
        }
 | 
			
		||||
        return false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun hashCode(): Int {
 | 
			
		||||
        return chapter.id!!.hashCode()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.chapter
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
 | 
			
		||||
class ChapterModel(c: Chapter) : Chapter by c {
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,42 +1,19 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.chapter
 | 
			
		||||
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import eu.davidea.flexibleadapter4.FlexibleAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.util.inflate
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
 | 
			
		||||
class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<ChaptersHolder, ChapterModel>() {
 | 
			
		||||
class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<ChapterItem>(null, fragment, true) {
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasStableIds(true)
 | 
			
		||||
    var items: List<ChapterItem> = emptyList()
 | 
			
		||||
 | 
			
		||||
    val menuItemListener: (Int, MenuItem) -> Unit = { position, item ->
 | 
			
		||||
        fragment.onItemMenuClick(position, item)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var items: List<ChapterModel>
 | 
			
		||||
        get() = mItems
 | 
			
		||||
        set(value) {
 | 
			
		||||
            mItems = value
 | 
			
		||||
            notifyDataSetChanged()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun updateDataSet(param: String) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChaptersHolder {
 | 
			
		||||
        val v = parent.inflate(R.layout.item_chapter)
 | 
			
		||||
        return ChaptersHolder(v, this, fragment)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(holder: ChaptersHolder, position: Int) {
 | 
			
		||||
        val chapter = getItem(position)
 | 
			
		||||
        val manga = fragment.presenter.manga
 | 
			
		||||
        holder.onSetValues(chapter, manga)
 | 
			
		||||
 | 
			
		||||
        //When user scrolls this bind the correct selection status
 | 
			
		||||
        holder.itemView.isActivated = isSelected(position)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getItemId(position: Int): Long {
 | 
			
		||||
        return mItems[position].id!!
 | 
			
		||||
    override fun updateDataSet(items: List<ChapterItem>) {
 | 
			
		||||
        this.items = items
 | 
			
		||||
        super.updateDataSet(items.toList())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,12 +12,11 @@ import android.support.v7.widget.DividerItemDecoration
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
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.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
 | 
			
		||||
@@ -30,7 +29,10 @@ import nucleus.factory.RequiresPresenter
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
 | 
			
		||||
@RequiresPresenter(ChaptersPresenter::class)
 | 
			
		||||
class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
 | 
			
		||||
class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(),
 | 
			
		||||
        ActionMode.Callback,
 | 
			
		||||
        FlexibleAdapter.OnItemClickListener,
 | 
			
		||||
        FlexibleAdapter.OnItemLongClickListener {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        /**
 | 
			
		||||
@@ -71,38 +73,31 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        recycler.layoutManager = LinearLayoutManager(activity)
 | 
			
		||||
        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()
 | 
			
		||||
 | 
			
		||||
        swipe_refresh.setOnRefreshListener { fetchChapters() }
 | 
			
		||||
 | 
			
		||||
        fab.setOnClickListener {
 | 
			
		||||
            val chapter = presenter.getNextUnreadChapter()
 | 
			
		||||
            if (chapter != null) {
 | 
			
		||||
            val item = presenter.getNextUnreadChapter()
 | 
			
		||||
            if (item != null) {
 | 
			
		||||
                // Create animation listener
 | 
			
		||||
                val revealAnimationListener: Animator.AnimatorListener = object : AnimatorListenerAdapter() {
 | 
			
		||||
                    override fun onAnimationStart(animation: Animator?) {
 | 
			
		||||
                        openChapter(chapter, true)
 | 
			
		||||
                        openChapter(item.chapter, true)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Get coordinates and start animation
 | 
			
		||||
                val coordinates = fab.getCoordinates()
 | 
			
		||||
                if (!reveal_view.showRevealEffect(coordinates.x, coordinates.y, revealAnimationListener)) {
 | 
			
		||||
                    openChapter(chapter)
 | 
			
		||||
                    openChapter(item.chapter)
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                context.toast(R.string.no_next_chapter)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPause() {
 | 
			
		||||
        // Stop recycler's scrolling when onPause is called. If the activity is finishing
 | 
			
		||||
        // the presenter will be destroyed, and it could cause NPE
 | 
			
		||||
        // https://github.com/inorichi/tachiyomi/issues/159
 | 
			
		||||
        recycler.stopScroll()
 | 
			
		||||
 | 
			
		||||
        super.onPause()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
@@ -173,19 +168,20 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Suppress("UNUSED_PARAMETER")
 | 
			
		||||
    fun onNextManga(manga: Manga) {
 | 
			
		||||
        // Set initial values
 | 
			
		||||
        activity.supportInvalidateOptionsMenu()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onNextChapters(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun onNextChapters(chapters: List<ChapterItem>) {
 | 
			
		||||
        // If the list is empty, fetch chapters from source if the conditions are met
 | 
			
		||||
        // We use presenter chapters instead because they are always unfiltered
 | 
			
		||||
        if (presenter.chapters.isEmpty())
 | 
			
		||||
            initialFetchChapters()
 | 
			
		||||
 | 
			
		||||
        destroyActionModeIfNeeded()
 | 
			
		||||
        adapter.items = chapters
 | 
			
		||||
        adapter.updateDataSet(chapters)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun initialFetchChapters() {
 | 
			
		||||
@@ -230,7 +226,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
                .title(R.string.action_display_mode)
 | 
			
		||||
                .items(modes.map { getString(it) })
 | 
			
		||||
                .itemsIds(ids)
 | 
			
		||||
                .itemsCallbackSingleChoice(selectedIndex) { dialog, itemView, which, text ->
 | 
			
		||||
                .itemsCallbackSingleChoice(selectedIndex) { _, itemView, _, _ ->
 | 
			
		||||
                    // Save the new display mode
 | 
			
		||||
                    presenter.setDisplayMode(itemView.id)
 | 
			
		||||
                    // Refresh ui
 | 
			
		||||
@@ -250,7 +246,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
                .title(R.string.sorting_mode)
 | 
			
		||||
                .items(modes.map { getString(it) })
 | 
			
		||||
                .itemsIds(ids)
 | 
			
		||||
                .itemsCallbackSingleChoice(selectedIndex) { dialog, itemView, which, text ->
 | 
			
		||||
                .itemsCallbackSingleChoice(selectedIndex) { _, itemView, _, _ ->
 | 
			
		||||
                    // Save the new sorting mode
 | 
			
		||||
                    presenter.setSorting(itemView.id)
 | 
			
		||||
                    true
 | 
			
		||||
@@ -267,7 +263,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
                .title(R.string.manga_download)
 | 
			
		||||
                .negativeText(android.R.string.cancel)
 | 
			
		||||
                .items(modes.map { getString(it) })
 | 
			
		||||
                .itemsCallback { dialog, view, i, charSequence ->
 | 
			
		||||
                .itemsCallback { _, _, i, _ ->
 | 
			
		||||
 | 
			
		||||
                    fun getUnreadChaptersSorted() = presenter.chapters
 | 
			
		||||
                            .filter { !it.read && it.status == Download.NOT_DOWNLOADED }
 | 
			
		||||
@@ -299,8 +295,8 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        getHolder(download.chapter)?.notifyStatus(download.status)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getHolder(chapter: Chapter): ChaptersHolder? {
 | 
			
		||||
        return recycler.findViewHolderForItemId(chapter.id!!) as? ChaptersHolder
 | 
			
		||||
    private fun getHolder(chapter: Chapter): ChapterHolder? {
 | 
			
		||||
        return recycler.findViewHolderForItemId(chapter.id!!) as? ChapterHolder
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
 | 
			
		||||
@@ -324,7 +320,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
                        .content(R.string.confirm_delete_chapters)
 | 
			
		||||
                        .positiveText(android.R.string.yes)
 | 
			
		||||
                        .negativeText(android.R.string.no)
 | 
			
		||||
                        .onPositive { dialog, action -> deleteChapters(getSelectedChapters()) }
 | 
			
		||||
                        .onPositive { _, _ -> deleteChapters(getSelectedChapters()) }
 | 
			
		||||
                        .show()
 | 
			
		||||
            }
 | 
			
		||||
            else -> return false
 | 
			
		||||
@@ -338,8 +334,8 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        actionMode = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getSelectedChapters(): List<ChapterModel> {
 | 
			
		||||
        return adapter.selectedItems.map { adapter.getItem(it) }
 | 
			
		||||
    fun getSelectedChapters(): List<ChapterItem> {
 | 
			
		||||
        return adapter.selectedPositions.map { adapter.getItem(it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun destroyActionModeIfNeeded() {
 | 
			
		||||
@@ -351,18 +347,18 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        setContextTitle(adapter.selectedItemCount)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun markAsRead(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun markAsRead(chapters: List<ChapterItem>) {
 | 
			
		||||
        presenter.markChaptersRead(chapters, true)
 | 
			
		||||
        if (presenter.preferences.removeAfterMarkedAsRead()) {
 | 
			
		||||
            deleteChapters(chapters)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun markAsUnread(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun markAsUnread(chapters: List<ChapterItem>) {
 | 
			
		||||
        presenter.markChaptersRead(chapters, false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun markPreviousAsRead(chapter: ChapterModel) {
 | 
			
		||||
    fun markPreviousAsRead(chapter: ChapterItem) {
 | 
			
		||||
        val chapters = if (presenter.sortDescending()) adapter.items.reversed() else adapter.items
 | 
			
		||||
        val chapterPos = chapters.indexOf(chapter)
 | 
			
		||||
        if (chapterPos != -1) {
 | 
			
		||||
@@ -370,7 +366,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun downloadChapters(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun downloadChapters(chapters: List<ChapterItem>) {
 | 
			
		||||
        destroyActionModeIfNeeded()
 | 
			
		||||
        presenter.downloadChapters(chapters)
 | 
			
		||||
        if (!presenter.manga.favorite){
 | 
			
		||||
@@ -382,12 +378,12 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun bookmarkChapters(chapters: List<ChapterModel>, bookmarked: Boolean) {
 | 
			
		||||
    fun bookmarkChapters(chapters: List<ChapterItem>, bookmarked: Boolean) {
 | 
			
		||||
        destroyActionModeIfNeeded()
 | 
			
		||||
        presenter.bookmarkChapters(chapters, bookmarked)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun deleteChapters(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun deleteChapters(chapters: List<ChapterItem>) {
 | 
			
		||||
        destroyActionModeIfNeeded()
 | 
			
		||||
        DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
 | 
			
		||||
        presenter.deleteChapters(chapters)
 | 
			
		||||
@@ -408,26 +404,40 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 | 
			
		||||
                ?.dismissAllowingStateLoss()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onListItemClick(position: Int): Boolean {
 | 
			
		||||
    override fun onItemClick(position: Int): Boolean {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return false
 | 
			
		||||
        if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
 | 
			
		||||
            toggleSelection(position)
 | 
			
		||||
            return true
 | 
			
		||||
        } else {
 | 
			
		||||
            openChapter(item)
 | 
			
		||||
            openChapter(item.chapter)
 | 
			
		||||
            return false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onListItemLongClick(position: Int) {
 | 
			
		||||
    override fun onItemLongClick(position: Int) {
 | 
			
		||||
        if (actionMode == null)
 | 
			
		||||
            actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
 | 
			
		||||
 | 
			
		||||
        toggleSelection(position)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onItemMenuClick(position: Int, item: MenuItem) {
 | 
			
		||||
        val chapter = adapter.getItem(position)?.let { listOf(it) } ?: return
 | 
			
		||||
 | 
			
		||||
        when (item.itemId) {
 | 
			
		||||
            R.id.action_download -> downloadChapters(chapter)
 | 
			
		||||
            R.id.action_bookmark -> bookmarkChapters(chapter, true)
 | 
			
		||||
            R.id.action_remove_bookmark -> bookmarkChapters(chapter, false)
 | 
			
		||||
            R.id.action_delete -> deleteChapters(chapter)
 | 
			
		||||
            R.id.action_mark_as_read -> markAsRead(chapter)
 | 
			
		||||
            R.id.action_mark_as_unread -> markAsUnread(chapter)
 | 
			
		||||
            R.id.action_mark_previous_as_read -> markPreviousAsRead(chapter[0])
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun toggleSelection(position: Int) {
 | 
			
		||||
        adapter.toggleSelection(position, false)
 | 
			
		||||
        adapter.toggleSelection(position)
 | 
			
		||||
 | 
			
		||||
        val count = adapter.selectedItemCount
 | 
			
		||||
        if (count == 0) {
 | 
			
		||||
 
 | 
			
		||||
@@ -65,14 +65,14 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
    /**
 | 
			
		||||
     * List of chapters of the manga. It's always unfiltered and unsorted.
 | 
			
		||||
     */
 | 
			
		||||
    var chapters: List<ChapterModel> = emptyList()
 | 
			
		||||
    var chapters: List<ChapterItem> = emptyList()
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subject of list of chapters to allow updating the view without going to DB.
 | 
			
		||||
     */
 | 
			
		||||
    val chaptersRelay: PublishRelay<List<ChapterModel>>
 | 
			
		||||
            by lazy { PublishRelay.create<List<ChapterModel>>() }
 | 
			
		||||
    val chaptersRelay: PublishRelay<List<ChapterItem>>
 | 
			
		||||
            by lazy { PublishRelay.create<List<ChapterItem>>() }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the chapter list has been requested to the source.
 | 
			
		||||
@@ -103,7 +103,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
        chaptersRelay.flatMap { applyChapterFilters(it) }
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribeLatestCache(ChaptersFragment::onNextChapters,
 | 
			
		||||
                        { view, error -> Timber.e(error) })
 | 
			
		||||
                        { _, error -> Timber.e(error) })
 | 
			
		||||
 | 
			
		||||
        // Add the subscription that retrieves the chapters from the database, keeps subscribed to
 | 
			
		||||
        // changes, and sends the list of chapters to the relay.
 | 
			
		||||
@@ -135,15 +135,15 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
                .filter { download -> download.manga.id == manga.id }
 | 
			
		||||
                .doOnNext { onDownloadStatusChange(it) }
 | 
			
		||||
                .subscribeLatestCache(ChaptersFragment::onChapterStatusChange,
 | 
			
		||||
                        { view, error -> Timber.e(error) })
 | 
			
		||||
                        { _, error -> Timber.e(error) })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts a chapter from the database to an extended model, allowing to store new fields.
 | 
			
		||||
     */
 | 
			
		||||
    private fun Chapter.toModel(): ChapterModel {
 | 
			
		||||
    private fun Chapter.toModel(): ChapterItem {
 | 
			
		||||
        // Create the model object.
 | 
			
		||||
        val model = ChapterModel(this)
 | 
			
		||||
        val model = ChapterItem(this, manga)
 | 
			
		||||
 | 
			
		||||
        // Find an active download for this chapter.
 | 
			
		||||
        val download = downloadManager.queue.find { it.chapter.id == id }
 | 
			
		||||
@@ -160,7 +160,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     *
 | 
			
		||||
     * @param chapters the list of chapter from the database.
 | 
			
		||||
     */
 | 
			
		||||
    private fun setDownloadedChapters(chapters: List<ChapterModel>) {
 | 
			
		||||
    private fun setDownloadedChapters(chapters: List<ChapterItem>) {
 | 
			
		||||
        val files = downloadManager.findMangaDir(source, manga)?.listFiles() ?: return
 | 
			
		||||
        val cached = mutableMapOf<Chapter, String>()
 | 
			
		||||
        files.mapNotNull { it.name }
 | 
			
		||||
@@ -181,7 +181,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .map { syncChaptersWithSource(db, it, manga, source) }
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribeFirst({ view, chapters ->
 | 
			
		||||
                .subscribeFirst({ view, _ ->
 | 
			
		||||
                    view.onFetchChaptersDone()
 | 
			
		||||
                }, ChaptersFragment::onFetchChaptersError)
 | 
			
		||||
    }
 | 
			
		||||
@@ -198,7 +198,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     * @param chapters the list of chapters from the database
 | 
			
		||||
     * @return an observable of the list of chapters filtered and sorted.
 | 
			
		||||
     */
 | 
			
		||||
    private fun applyChapterFilters(chapters: List<ChapterModel>): Observable<List<ChapterModel>> {
 | 
			
		||||
    private fun applyChapterFilters(chapters: List<ChapterItem>): Observable<List<ChapterItem>> {
 | 
			
		||||
        var observable = Observable.from(chapters).subscribeOn(Schedulers.io())
 | 
			
		||||
        if (onlyUnread()) {
 | 
			
		||||
            observable = observable.filter { !it.read }
 | 
			
		||||
@@ -248,7 +248,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the next unread chapter or null if everything is read.
 | 
			
		||||
     */
 | 
			
		||||
    fun getNextUnreadChapter(): ChapterModel? {
 | 
			
		||||
    fun getNextUnreadChapter(): ChapterItem? {
 | 
			
		||||
        return chapters.sortedByDescending { it.source_order }.find { !it.read }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -257,7 +257,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     * @param selectedChapters the list of selected chapters.
 | 
			
		||||
     * @param read whether to mark chapters as read or unread.
 | 
			
		||||
     */
 | 
			
		||||
    fun markChaptersRead(selectedChapters: List<ChapterModel>, read: Boolean) {
 | 
			
		||||
    fun markChaptersRead(selectedChapters: List<ChapterItem>, read: Boolean) {
 | 
			
		||||
        Observable.from(selectedChapters)
 | 
			
		||||
                .doOnNext { chapter ->
 | 
			
		||||
                    chapter.read = read
 | 
			
		||||
@@ -275,7 +275,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     * Downloads the given list of chapters with the manager.
 | 
			
		||||
     * @param chapters the list of chapters to download.
 | 
			
		||||
     */
 | 
			
		||||
    fun downloadChapters(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun downloadChapters(chapters: List<ChapterItem>) {
 | 
			
		||||
        DownloadService.start(context)
 | 
			
		||||
        downloadManager.downloadChapters(manga, chapters)
 | 
			
		||||
    }
 | 
			
		||||
@@ -284,7 +284,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     * Bookmarks the given list of chapters.
 | 
			
		||||
     * @param selectedChapters the list of chapters to bookmark.
 | 
			
		||||
     */
 | 
			
		||||
    fun bookmarkChapters(selectedChapters: List<ChapterModel>, bookmarked: Boolean) {
 | 
			
		||||
    fun bookmarkChapters(selectedChapters: List<ChapterItem>, bookmarked: Boolean) {
 | 
			
		||||
        Observable.from(selectedChapters)
 | 
			
		||||
                .doOnNext { chapter ->
 | 
			
		||||
                    chapter.bookmark = bookmarked
 | 
			
		||||
@@ -299,14 +299,14 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     * Deletes the given list of chapter.
 | 
			
		||||
     * @param chapters the list of chapters to delete.
 | 
			
		||||
     */
 | 
			
		||||
    fun deleteChapters(chapters: List<ChapterModel>) {
 | 
			
		||||
    fun deleteChapters(chapters: List<ChapterItem>) {
 | 
			
		||||
        Observable.from(chapters)
 | 
			
		||||
                .doOnNext { deleteChapter(it) }
 | 
			
		||||
                .toList()
 | 
			
		||||
                .doOnNext { if (onlyDownloaded()) refreshChapters() }
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribeFirst({ view, result ->
 | 
			
		||||
                .subscribeFirst({ view, _ ->
 | 
			
		||||
                    view.onChaptersDeleted()
 | 
			
		||||
                }, ChaptersFragment::onChaptersDeletedError)
 | 
			
		||||
    }
 | 
			
		||||
@@ -315,7 +315,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 | 
			
		||||
     * Deletes a chapter from disk. This method is called in a background thread.
 | 
			
		||||
     * @param chapter the chapter to delete.
 | 
			
		||||
     */
 | 
			
		||||
    private fun deleteChapter(chapter: ChapterModel) {
 | 
			
		||||
    private fun deleteChapter(chapter: ChapterItem) {
 | 
			
		||||
        downloadManager.queue.remove(chapter)
 | 
			
		||||
        downloadManager.deleteChapter(source, manga, chapter)
 | 
			
		||||
        chapter.status = Download.NOT_DOWNLOADED
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,7 @@
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        android:background="?attr/colorAccent"
 | 
			
		||||
        android:elevation="5dp"
 | 
			
		||||
        android:visibility="invisible"
 | 
			
		||||
        />
 | 
			
		||||
        android:visibility="invisible"/>
 | 
			
		||||
 | 
			
		||||
    <android.support.v4.widget.SwipeRefreshLayout
 | 
			
		||||
        android:id="@+id/swipe_refresh"
 | 
			
		||||
@@ -36,6 +35,17 @@
 | 
			
		||||
 | 
			
		||||
    </android.support.v4.widget.SwipeRefreshLayout>
 | 
			
		||||
 | 
			
		||||
    <eu.davidea.fastscroller.FastScroller
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:id="@+id/fast_scroller"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        android:layout_centerHorizontal="true"
 | 
			
		||||
        android:layout_gravity="end"
 | 
			
		||||
        android:visibility="gone"
 | 
			
		||||
        tools:visibility="visible"/>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.FloatingActionButton
 | 
			
		||||
        android:id="@+id/fab"
 | 
			
		||||
        style="@style/Theme.Widget.FAB"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user