mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user