mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-14 17:25:09 +01:00
Update Recents updates items to new style
Also removed newly added manga from flooding recent updates (closing #52)
This commit is contained in:
parent
4e33b93c08
commit
83206ded5e
@ -57,7 +57,9 @@ fun getLibraryMangaQuery(id: Long) = """
|
|||||||
fun getRecentsQuery() = """
|
fun getRecentsQuery() = """
|
||||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE}
|
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE}
|
||||||
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
|
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
|
||||||
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_UPLOAD} > ?
|
WHERE ${Manga.COL_FAVORITE} = 1
|
||||||
|
AND ${Chapter.COL_DATE_UPLOAD} > ?
|
||||||
|
AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED}
|
||||||
ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC
|
ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -114,8 +114,7 @@ class ChapterHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resetFrontView() {
|
private fun resetFrontView() {
|
||||||
if (front_view.translationX == 0f) return
|
if (front_view.translationX != 0f) itemView.post { adapter.notifyItemChanged(adapterPosition) }
|
||||||
itemView.post { adapter.notifyItemChanged(adapterPosition) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyStatus(status: Int, locked: Boolean, progress: Int) = with(download_button) {
|
fun notifyStatus(status: Int, locked: Boolean, progress: Int) = with(download_button) {
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent_updates
|
package eu.kanade.tachiyomi.ui.recent_updates
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.core.content.ContextCompat
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
|
||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterHolder
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
import kotlinx.android.synthetic.main.download_button.*
|
||||||
import kotlinx.android.synthetic.main.recent_chapters_item.*
|
import kotlinx.android.synthetic.main.recent_chapters_item.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +21,7 @@ import kotlinx.android.synthetic.main.recent_chapters_item.*
|
|||||||
* @constructor creates a new recent chapter holder.
|
* @constructor creates a new recent chapter holder.
|
||||||
*/
|
*/
|
||||||
class RecentChapterHolder(private val view: View, private val adapter: RecentChaptersAdapter) :
|
class RecentChapterHolder(private val view: View, private val adapter: RecentChaptersAdapter) :
|
||||||
BaseFlexibleViewHolder(view, adapter) {
|
BaseChapterHolder(view, adapter) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color of read chapter
|
* Color of read chapter
|
||||||
@ -40,10 +39,6 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha
|
|||||||
private var item: RecentChapterItem? = null
|
private var item: RecentChapterItem? = null
|
||||||
|
|
||||||
init {
|
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.
|
|
||||||
chapter_menu.setOnClickListener { it.post { showPopupMenu(it) } }
|
|
||||||
manga_cover.setOnClickListener {
|
manga_cover.setOnClickListener {
|
||||||
adapter.coverClickListener.onCoverClick(adapterPosition)
|
adapter.coverClickListener.onCoverClick(adapterPosition)
|
||||||
}
|
}
|
||||||
@ -63,8 +58,14 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha
|
|||||||
// Set manga title
|
// Set manga title
|
||||||
manga_full_title.text = item.manga.title
|
manga_full_title.text = item.manga.title
|
||||||
|
|
||||||
// Set the correct drawable for dropdown and update the tint to match theme.
|
if (front_view.translationX == 0f) {
|
||||||
chapter_menu_icon.setVectorCompat(R.drawable.ic_more_horiz_black_24dp, view.context.getResourceColor(R.attr.icon_color))
|
read.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
read.context, if (item.read) R.drawable.eye_off
|
||||||
|
else R.drawable.eye
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Set cover
|
// Set cover
|
||||||
GlideApp.with(itemView.context).clear(manga_cover)
|
GlideApp.with(itemView.context).clear(manga_cover)
|
||||||
@ -86,7 +87,20 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set chapter status
|
// Set chapter status
|
||||||
notifyStatus(item.status)
|
notifyStatus(item.status, item.progress)
|
||||||
|
resetFrontView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetFrontView() {
|
||||||
|
if (front_view.translationX != 0f) itemView.post { adapter.notifyItemChanged(adapterPosition) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFrontView(): View {
|
||||||
|
return front_view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRearRightView(): View {
|
||||||
|
return right_view
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,59 +108,6 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha
|
|||||||
*
|
*
|
||||||
* @param status download status
|
* @param status download status
|
||||||
*/
|
*/
|
||||||
fun notifyStatus(status: Int) = with(download_text) {
|
fun notifyStatus(status: Int, progress: Int) =
|
||||||
when (status) {
|
download_button.setDownloadStatus(status, progress)
|
||||||
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 = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show pop up menu
|
|
||||||
*
|
|
||||||
* @param view view containing popup menu.
|
|
||||||
*/
|
|
||||||
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)
|
|
||||||
|
|
||||||
// Inflate our menu resource into the PopupMenu's Menu
|
|
||||||
popup.menuInflater.inflate(R.menu.chapter_recent, popup.menu)
|
|
||||||
|
|
||||||
// Hide download and show delete if the chapter is downloaded and
|
|
||||||
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 (!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 (item.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 ->
|
|
||||||
with(adapter.controller) {
|
|
||||||
when (menuItem.itemId) {
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally show the PopupMenu
|
|
||||||
popup.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,26 +3,14 @@ package eu.kanade.tachiyomi.ui.recent_updates
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterItem
|
||||||
|
|
||||||
class RecentChapterItem(val chapter: Chapter, val manga: Manga, header: DateItem) :
|
class RecentChapterItem(chapter: Chapter, val manga: Manga, header: DateItem) :
|
||||||
AbstractSectionableItem<RecentChapterHolder, DateItem>(header) {
|
BaseChapterItem<RecentChapterHolder, DateItem>(chapter, 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 {
|
override fun getLayoutRes(): Int {
|
||||||
return R.layout.recent_chapters_item
|
return R.layout.recent_chapters_item
|
||||||
@ -38,7 +26,6 @@ class RecentChapterItem(val chapter: Chapter, val manga: Manga, header: DateItem
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: MutableList<Any?>?
|
payloads: MutableList<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,16 +33,4 @@ class RecentChapterItem(val chapter: Chapter, val manga: Manga, header: DateItem
|
|||||||
return chapter.name.contains(text, false) ||
|
return chapter.name.contains(text, false) ||
|
||||||
manga.title.contains(text, false)
|
manga.title.contains(text, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent_updates
|
package eu.kanade.tachiyomi.ui.recent_updates
|
||||||
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter
|
||||||
|
|
||||||
class RecentChaptersAdapter(val controller: RecentChaptersController) :
|
class RecentChaptersAdapter(val controller: RecentChaptersController) :
|
||||||
FlexibleAdapter<IFlexible<*>>(null, controller, true) {
|
BaseChapterAdapter<IFlexible<*>>(controller) {
|
||||||
|
|
||||||
val coverClickListener: OnCoverClickListener = controller
|
val coverClickListener: OnCoverClickListener = controller
|
||||||
var recents = emptyList<RecentChapterItem>()
|
var recents = emptyList<RecentChapterItem>()
|
||||||
|
private var isAnimating = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setDisplayHeadersAtStartUp(true)
|
setDisplayHeadersAtStartUp(true)
|
||||||
@ -22,13 +24,22 @@ class RecentChaptersAdapter(val controller: RecentChaptersController) :
|
|||||||
fun performFilter() {
|
fun performFilter() {
|
||||||
val s = getFilter(String::class.java)
|
val s = getFilter(String::class.java)
|
||||||
if (s.isNullOrBlank()) {
|
if (s.isNullOrBlank()) {
|
||||||
updateDataSet(recents)
|
updateDataSet(recents, isAnimating)
|
||||||
} else {
|
} else {
|
||||||
updateDataSet(recents.filter { it.filter(s) })
|
updateDataSet(recents.filter { it.filter(s) }, isAnimating)
|
||||||
}
|
}
|
||||||
|
isAnimating = false
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnCoverClickListener {
|
interface OnCoverClickListener {
|
||||||
fun onCoverClick(position: Int)
|
fun onCoverClick(position: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onItemSwiped(position: Int, direction: Int) {
|
||||||
|
super.onItemSwiped(position, direction)
|
||||||
|
isAnimating = true
|
||||||
|
when (direction) {
|
||||||
|
ItemTouchHelper.LEFT -> controller.toggleMarkAsRead(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent_updates
|
package eu.kanade.tachiyomi.ui.recent_updates
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.appcompat.view.ActionMode
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.jakewharton.rxbinding.support.v7.widget.scrollStateChanges
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
|
import kotlinx.android.synthetic.main.download_bottom_sheet.*
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.android.synthetic.main.recent_chapters_controller.*
|
import kotlinx.android.synthetic.main.recent_chapters_controller.*
|
||||||
|
import kotlinx.android.synthetic.main.recent_chapters_controller.empty_view
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,21 +37,10 @@ import timber.log.Timber
|
|||||||
* Uses [R.layout.recent_chapters_controller].
|
* Uses [R.layout.recent_chapters_controller].
|
||||||
* UI related actions should be called from here.
|
* UI related actions should be called from here.
|
||||||
*/
|
*/
|
||||||
class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
class RecentChaptersController(bundle: Bundle? = null) : BaseController(bundle),
|
||||||
ActionMode.Callback,
|
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnUpdateListener,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemMoveListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
RecentChaptersAdapter.OnCoverClickListener, BaseChapterAdapter.DownloadInterface {
|
||||||
FlexibleAdapter.OnUpdateListener,
|
|
||||||
ConfirmDeleteChaptersDialog.Listener,
|
|
||||||
RecentChaptersAdapter.OnCoverClickListener {
|
|
||||||
|
|
||||||
init {
|
|
||||||
setHasOptionsMenu(true)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Action mode for multiple selection.
|
|
||||||
*/
|
|
||||||
private var actionMode: ActionMode? = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter containing the recent chapters.
|
* Adapter containing the recent chapters.
|
||||||
@ -57,16 +48,14 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
var adapter: RecentChaptersAdapter? = null
|
var adapter: RecentChaptersAdapter? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private var query = ""
|
private var presenter = RecentChaptersPresenter(this)
|
||||||
|
private var snack: Snackbar? = null
|
||||||
|
private var lastChapterId: Long? = null
|
||||||
|
|
||||||
override fun getTitle(): String? {
|
override fun getTitle(): String? {
|
||||||
return resources?.getString(R.string.label_recent_updates)
|
return resources?.getString(R.string.label_recent_updates)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createPresenter(): RecentChaptersPresenter {
|
|
||||||
return RecentChaptersPresenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
return inflater.inflate(R.layout.recent_chapters_controller, container, false)
|
return inflater.inflate(R.layout.recent_chapters_controller, container, false)
|
||||||
}
|
}
|
||||||
@ -88,14 +77,14 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
adapter = RecentChaptersAdapter(this@RecentChaptersController)
|
adapter = RecentChaptersAdapter(this@RecentChaptersController)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
|
|
||||||
recycler.scrollStateChanges().subscribeUntilDestroy {
|
adapter?.isSwipeEnabled = true
|
||||||
// Disable swipe refresh when view is not at the top
|
adapter?.itemTouchHelperCallback?.setSwipeFlags(
|
||||||
val firstPos = layoutManager.findFirstCompletelyVisibleItemPosition()
|
ItemTouchHelper.LEFT
|
||||||
swipe_refresh.isEnabled = firstPos <= 0
|
)
|
||||||
}
|
if (presenter.chapters.isNotEmpty()) adapter?.updateDataSet(presenter.chapters.toList())
|
||||||
|
|
||||||
swipe_refresh.setDistanceToTriggerSync((2 * 64 * view.resources.displayMetrics.density).toInt())
|
swipe_refresh.setDistanceToTriggerSync((2 * 64 * view.resources.displayMetrics.density).toInt())
|
||||||
swipe_refresh.refreshes().subscribeUntilDestroy {
|
swipe_refresh.setOnRefreshListener {
|
||||||
if (!LibraryUpdateService.isRunning()) {
|
if (!LibraryUpdateService.isRunning()) {
|
||||||
LibraryUpdateService.start(view.context)
|
LibraryUpdateService.start(view.context)
|
||||||
view.snack(R.string.updating_library) {
|
view.snack(R.string.updating_library) {
|
||||||
@ -107,23 +96,31 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
swipe_refresh.isRefreshing = false
|
swipe_refresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh)
|
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh, padBottom = true)
|
||||||
|
|
||||||
|
presenter.onCreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
presenter.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
adapter = null
|
adapter = null
|
||||||
actionMode = null
|
snack = null
|
||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun onActivityResumed(activity: Activity) {
|
||||||
* Returns selected chapters
|
super.onActivityResumed(activity)
|
||||||
* @return list of selected chapters
|
if (view != null) {
|
||||||
*/
|
refresh()
|
||||||
fun getSelectedChapters(): List<RecentChapterItem> {
|
dl_bottom_sheet?.update()
|
||||||
val adapter = adapter ?: return emptyList()
|
|
||||||
return adapter.selectedPositions.mapNotNull { adapter.getItem(it) as? RecentChapterItem }
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refresh() = presenter.getUpdates()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when item in list is clicked
|
* Called when item in list is clicked
|
||||||
@ -134,35 +131,9 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
|
|
||||||
// Get item from position
|
// Get item from position
|
||||||
val item = adapter.getItem(position) as? RecentChapterItem ?: return false
|
val item = adapter.getItem(position) as? RecentChapterItem ?: return false
|
||||||
if (actionMode != null && adapter.mode == SelectableAdapter.Mode.MULTI) {
|
|
||||||
toggleSelection(position)
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
openChapter(item)
|
openChapter(item)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when item in list is long clicked
|
|
||||||
* @param position position of clicked item
|
|
||||||
*/
|
|
||||||
override fun onItemLongClick(position: Int) {
|
|
||||||
if (actionMode == null)
|
|
||||||
actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
|
|
||||||
|
|
||||||
toggleSelection(position)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called to toggle selection
|
|
||||||
* @param position position of selected item
|
|
||||||
*/
|
|
||||||
private fun toggleSelection(position: Int) {
|
|
||||||
val adapter = adapter ?: return
|
|
||||||
adapter.toggleSelection(position)
|
|
||||||
actionMode?.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open chapter in reader
|
* Open chapter in reader
|
||||||
@ -174,24 +145,21 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Download selected items
|
|
||||||
* @param chapters list of selected [RecentChapter]s
|
|
||||||
*/
|
|
||||||
fun downloadChapters(chapters: List<RecentChapterItem>) {
|
|
||||||
destroyActionModeIfNeeded()
|
|
||||||
presenter.downloadChapters(chapters)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate adapter with chapters
|
* Populate adapter with chapters
|
||||||
* @param chapters list of [Any]
|
* @param chapters list of [Any]
|
||||||
*/
|
*/
|
||||||
fun onNextRecentChapters(chapters: List<RecentChapterItem>) {
|
fun onNextRecentChapters(chapters: List<RecentChapterItem>) {
|
||||||
destroyActionModeIfNeeded()
|
|
||||||
adapter?.setItems(chapters)
|
adapter?.setItems(chapters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateChapterDownload(download: Download) {
|
||||||
|
if (view == null) return
|
||||||
|
val id = download.chapter.id ?: return
|
||||||
|
val holder = recycler.findViewHolderForItemId(id) as? RecentChapterHolder ?: return
|
||||||
|
holder.notifyStatus(download.status, download.progress)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onUpdateEmptyView(size: Int) {
|
override fun onUpdateEmptyView(size: Int) {
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
empty_view?.hide()
|
empty_view?.hide()
|
||||||
@ -200,12 +168,19 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onItemMove(fromPosition: Int, toPosition: Int) { }
|
||||||
|
override fun shouldMoveItem(fromPosition: Int, toPosition: Int) = true
|
||||||
|
|
||||||
|
override fun onActionStateChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||||
|
swipe_refresh.isEnabled = actionState != ItemTouchHelper.ACTION_STATE_SWIPE
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update download status of chapter
|
* Update download status of chapter
|
||||||
* @param download [Download] object containing download progress.
|
* @param download [Download] object containing download progress.
|
||||||
*/
|
*/
|
||||||
fun onChapterStatusChange(download: Download) {
|
fun onChapterStatusChange(download: Download) {
|
||||||
getHolder(download)?.notifyStatus(download.status)
|
getHolder(download)?.notifyStatus(download.status, download.progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,49 +193,54 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark chapter as read
|
* Mark chapter as read
|
||||||
* @param chapters list of chapters
|
* @param position position of chapter item
|
||||||
*/
|
*/
|
||||||
fun markAsRead(chapters: List<RecentChapterItem>) {
|
fun toggleMarkAsRead(position: Int) {
|
||||||
presenter.markChapterRead(chapters, true)
|
val item = adapter?.getItem(position) as? RecentChapterItem ?: return
|
||||||
if (presenter.preferences.removeAfterMarkedAsRead()) {
|
val chapter = item.chapter
|
||||||
deleteChapters(chapters)
|
val lastRead = chapter.last_page_read
|
||||||
|
val pagesLeft = chapter.pages_left
|
||||||
|
val read = item.chapter.read
|
||||||
|
lastChapterId = chapter.id
|
||||||
|
presenter.markChapterRead(item, !read)
|
||||||
|
if (!read) {
|
||||||
|
snack = view?.snack(R.string.marked_as_read, Snackbar.LENGTH_INDEFINITE) {
|
||||||
|
var undoing = false
|
||||||
|
setAction(R.string.action_undo) {
|
||||||
|
presenter.markChapterRead(item, !item.chapter.read, lastRead, pagesLeft)
|
||||||
|
undoing = true
|
||||||
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!undoing && presenter.preferences.removeAfterMarkedAsRead()) {
|
||||||
|
lastChapterId = chapter.id
|
||||||
|
presenter.deleteChapter(chapter, item.manga)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
|
}
|
||||||
|
// presenter.markChapterRead(item, !item.chapter.read)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun downloadChapter(position: Int) {
|
||||||
|
val view = view ?: return
|
||||||
|
val item = adapter?.getItem(position) as? RecentChapterItem ?: return
|
||||||
|
val chapter = item.chapter
|
||||||
|
val manga = item.manga
|
||||||
|
if (item.status != Download.NOT_DOWNLOADED && item.status != Download.ERROR) {
|
||||||
|
presenter.deleteChapter(chapter, manga)
|
||||||
|
} else {
|
||||||
|
if (item.status == Download.ERROR) DownloadService.start(view.context)
|
||||||
|
else presenter.downloadChapters(listOf(item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteChapters(chaptersToDelete: List<RecentChapterItem>) {
|
override fun startDownloadNow(position: Int) {
|
||||||
destroyActionModeIfNeeded()
|
val chapter = (adapter?.getItem(position) as? RecentChapterItem)?.chapter ?: return
|
||||||
presenter.deleteChapters(chaptersToDelete)
|
presenter.startDownloadChapterNow(chapter)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destory [ActionMode] if it's shown
|
|
||||||
*/
|
|
||||||
private fun destroyActionModeIfNeeded() {
|
|
||||||
actionMode?.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark chapter as unread
|
|
||||||
* @param chapters list of selected [RecentChapter]
|
|
||||||
*/
|
|
||||||
fun markAsUnread(chapters: List<RecentChapterItem>) {
|
|
||||||
presenter.markChapterRead(chapters, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start downloading chapter
|
|
||||||
* @param chapter selected chapter with manga
|
|
||||||
*/
|
|
||||||
fun downloadChapter(chapter: RecentChapterItem) {
|
|
||||||
presenter.downloadChapters(listOf(chapter))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start deleting chapter
|
|
||||||
* @param chapter selected chapter with manga
|
|
||||||
*/
|
|
||||||
fun deleteChapter(chapter: RecentChapterItem) {
|
|
||||||
presenter.deleteChapters(listOf(chapter))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCoverClick(position: Int) {
|
override fun onCoverClick(position: Int) {
|
||||||
@ -286,69 +266,4 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
fun onChaptersDeletedError(error: Throwable) {
|
fun onChaptersDeletedError(error: Throwable) {
|
||||||
Timber.e(error)
|
Timber.e(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when ActionMode created.
|
|
||||||
* @param mode the ActionMode object
|
|
||||||
* @param menu menu object of ActionMode
|
|
||||||
*/
|
|
||||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
|
||||||
mode.menuInflater.inflate(R.menu.chapter_recent_selection, menu)
|
|
||||||
adapter?.mode = SelectableAdapter.Mode.MULTI
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
|
||||||
val count = adapter?.selectedItemCount ?: 0
|
|
||||||
if (count == 0) {
|
|
||||||
// Destroy action mode if there are no items selected.
|
|
||||||
destroyActionModeIfNeeded()
|
|
||||||
} else {
|
|
||||||
mode.title = resources?.getString(R.string.label_selected, count)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when ActionMode item clicked
|
|
||||||
* @param mode the ActionMode object
|
|
||||||
* @param item item from ActionMode.
|
|
||||||
*/
|
|
||||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.action_mark_as_read -> markAsRead(getSelectedChapters())
|
|
||||||
R.id.action_mark_as_unread -> markAsUnread(getSelectedChapters())
|
|
||||||
R.id.action_download -> downloadChapters(getSelectedChapters())
|
|
||||||
R.id.action_delete -> ConfirmDeleteChaptersDialog(this, getSelectedChapters())
|
|
||||||
.showDialog(router)
|
|
||||||
else -> return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when ActionMode destroyed
|
|
||||||
* @param mode the ActionMode object
|
|
||||||
*/
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
|
||||||
adapter?.mode = SelectableAdapter.Mode.IDLE
|
|
||||||
adapter?.clearSelection()
|
|
||||||
actionMode = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
||||||
inflater.inflate(R.menu.recent_updates, menu)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.action_sort -> {
|
|
||||||
/*router.setRoot(
|
|
||||||
RecentlyReadController().withFadeTransaction().tag(R.id.nav_recents.toString()))
|
|
||||||
Injekt.get<PreferencesHelper>().showRecentUpdates().set(false)
|
|
||||||
(activity as? MainActivity)?.updateRecentsIcon()*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent_updates
|
package eu.kanade.tachiyomi.ui.recent_updates
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||||
|
import eu.kanade.tachiyomi.data.library.LibraryServiceListener
|
||||||
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.util.system.executeOnIO
|
||||||
import rx.Observable
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import rx.schedulers.Schedulers
|
import kotlinx.coroutines.Job
|
||||||
import timber.log.Timber
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
@ -19,67 +26,64 @@ import java.util.Date
|
|||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
|
|
||||||
class RecentChaptersPresenter(
|
class RecentChaptersPresenter(
|
||||||
|
private val controller: RecentChaptersController,
|
||||||
val preferences: PreferencesHelper = Injekt.get(),
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
private val db: DatabaseHelper = Injekt.get(),
|
private val db: DatabaseHelper = Injekt.get(),
|
||||||
private val downloadManager: DownloadManager = Injekt.get(),
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val sourceManager: SourceManager = Injekt.get()
|
private val sourceManager: SourceManager = Injekt.get()
|
||||||
) : BasePresenter<RecentChaptersController>() {
|
) : DownloadQueue.DownloadListener, LibraryServiceListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List containing chapter and manga information
|
* List containing chapter and manga information
|
||||||
*/
|
*/
|
||||||
private var chapters: List<RecentChapterItem> = emptyList()
|
var chapters: List<RecentChapterItem> = emptyList()
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
private var scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||||
super.onCreate(savedState)
|
|
||||||
|
|
||||||
getRecentChaptersObservable()
|
fun onCreate() {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
downloadManager.addListener(this)
|
||||||
.subscribeLatestCache(RecentChaptersController::onNextRecentChapters)
|
LibraryUpdateService.setListener(this)
|
||||||
|
getUpdates()
|
||||||
getChapterStatusObservable()
|
|
||||||
.subscribeLatestCache(RecentChaptersController::onChapterStatusChange) {
|
|
||||||
_, error -> Timber.e(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun getUpdates() {
|
||||||
* Get observable containing recent chapters and date
|
scope.launch {
|
||||||
*
|
|
||||||
* @return observable containing recent chapters and date
|
|
||||||
*/
|
|
||||||
fun getRecentChaptersObservable(): Observable<List<RecentChapterItem>> {
|
|
||||||
// Set date limit for recent chapters
|
|
||||||
val cal = Calendar.getInstance().apply {
|
val cal = Calendar.getInstance().apply {
|
||||||
time = Date()
|
time = Date()
|
||||||
add(Calendar.MONTH, -1)
|
add(Calendar.MONTH, -1)
|
||||||
}
|
}
|
||||||
|
val mangaChapters = db.getRecentChapters(cal.time).executeOnIO()
|
||||||
return db.getRecentChapters(cal.time).asRxObservable()
|
|
||||||
// Convert to a list of recent chapters.
|
|
||||||
.map { mangaChapters ->
|
|
||||||
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
|
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
|
||||||
val byDay = mangaChapters
|
val byDay = mangaChapters.groupByTo(map, { getMapKey(it.chapter.date_fetch) })
|
||||||
.groupByTo(map, { getMapKey(it.chapter.date_fetch) })
|
val items = byDay.flatMap {
|
||||||
byDay.flatMap {
|
|
||||||
val dateItem = DateItem(it.key)
|
val dateItem = DateItem(it.key)
|
||||||
it.value.map { RecentChapterItem(it.chapter, it.manga, dateItem) }
|
it.value.map { mc ->
|
||||||
|
RecentChapterItem(mc.chapter, mc.manga, dateItem) }
|
||||||
|
}
|
||||||
|
setDownloadedChapters(items)
|
||||||
|
chapters = items
|
||||||
|
withContext(Dispatchers.Main) { controller.onNextRecentChapters(chapters) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.doOnNext {
|
|
||||||
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
|
fun onDestroy() {
|
||||||
// the chapter is downloaded and assign it to the status.
|
downloadManager.removeListener(this)
|
||||||
if (download != null) {
|
LibraryUpdateService.removeListener(this)
|
||||||
item.download = download
|
}
|
||||||
|
|
||||||
|
fun cancelScope() {
|
||||||
|
scope.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDownload(download: Download) {
|
||||||
|
chapters.find { it.chapter.id == download.chapter.id }?.download = download
|
||||||
|
scope.launch(Dispatchers.Main) {
|
||||||
|
controller.updateChapterDownload(download)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setDownloadedChapters(it)
|
|
||||||
chapters = it
|
override fun onUpdateManga(manga: LibraryManga) {
|
||||||
}
|
getUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,44 +102,18 @@ class RecentChaptersPresenter(
|
|||||||
return cal.time
|
return cal.time
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns observable containing chapter status.
|
|
||||||
*
|
|
||||||
* @return download object containing download progress.
|
|
||||||
*/
|
|
||||||
private fun getChapterStatusObservable(): Observable<Download> {
|
|
||||||
return downloadManager.queue.getStatusObservable()
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.doOnNext { download -> onDownloadStatusChange(download) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds and assigns the list of downloaded chapters.
|
* Finds and assigns the list of downloaded chapters.
|
||||||
*
|
*
|
||||||
* @param items the list of chapter from the database.
|
* @param chapters the list of chapter from the database.
|
||||||
*/
|
*/
|
||||||
private fun setDownloadedChapters(items: List<RecentChapterItem>) {
|
private fun setDownloadedChapters(chapters: List<RecentChapterItem>) {
|
||||||
for (item in items) {
|
for (item in chapters) {
|
||||||
val manga = item.manga
|
if (downloadManager.isChapterDownloaded(item.chapter, item.manga)) {
|
||||||
val chapter = item.chapter
|
|
||||||
|
|
||||||
if (downloadManager.isChapterDownloaded(chapter, manga)) {
|
|
||||||
item.status = Download.DOWNLOADED
|
item.status = Download.DOWNLOADED
|
||||||
}
|
} else if (downloadManager.hasQueue()) {
|
||||||
}
|
item.status = downloadManager.queue.find { it.chapter.id == item.chapter.id }
|
||||||
}
|
?.status ?: 0
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.chapter.id == download.chapter.id }
|
|
||||||
if (chapter != null && chapter.download == null) {
|
|
||||||
chapter.download = download
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,34 +124,44 @@ class RecentChaptersPresenter(
|
|||||||
* @param items list of selected chapters
|
* @param items list of selected chapters
|
||||||
* @param read read status
|
* @param read read status
|
||||||
*/
|
*/
|
||||||
fun markChapterRead(items: List<RecentChapterItem>, read: Boolean) {
|
fun markChapterRead(
|
||||||
val chapters = items.map { it.chapter }
|
item: RecentChapterItem,
|
||||||
chapters.forEach {
|
read: Boolean,
|
||||||
it.read = read
|
lastRead: Int? = null,
|
||||||
|
pagesLeft: Int? = null
|
||||||
|
) {
|
||||||
|
item.chapter.apply {
|
||||||
|
this.read = read
|
||||||
if (!read) {
|
if (!read) {
|
||||||
it.last_page_read = 0
|
last_page_read = lastRead ?: 0
|
||||||
it.pages_left = 0
|
pages_left = pagesLeft ?: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
db.updateChapterProgress(item.chapter).executeAsBlocking()
|
||||||
|
controller.onNextRecentChapters(this.chapters)
|
||||||
|
}
|
||||||
|
|
||||||
Observable.fromCallable { db.updateChaptersProgress(chapters).executeAsBlocking() }
|
fun startDownloadChapterNow(chapter: Chapter) {
|
||||||
.subscribeOn(Schedulers.io())
|
downloadManager.startDownloadNow(chapter)
|
||||||
.subscribe()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete selected chapters
|
* Deletes the given list of chapter.
|
||||||
*
|
* @param chapter the chapter to delete.
|
||||||
* @param chapters list of chapters
|
|
||||||
*/
|
*/
|
||||||
fun deleteChapters(chapters: List<RecentChapterItem>) {
|
fun deleteChapter(chapter: Chapter, manga: Manga, update: Boolean = true) {
|
||||||
Observable.just(chapters)
|
val source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
||||||
.doOnNext { deleteChaptersInternal(it) }
|
downloadManager.deleteChapters(listOf(chapter), manga, source)
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
if (update) {
|
||||||
.subscribeFirst({ view, _ ->
|
val item = chapters.find { it.chapter.id == chapter.id } ?: return
|
||||||
view.onChaptersDeleted()
|
item.apply {
|
||||||
}, RecentChaptersController::onChaptersDeletedError)
|
status = Download.NOT_DOWNLOADED
|
||||||
|
download = null
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.onNextRecentChapters(chapters)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,24 +171,4 @@ class RecentChaptersPresenter(
|
|||||||
fun downloadChapters(items: List<RecentChapterItem>) {
|
fun downloadChapters(items: List<RecentChapterItem>) {
|
||||||
items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) }
|
items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete selected chapters
|
|
||||||
*
|
|
||||||
* @param items chapters selected
|
|
||||||
*/
|
|
||||||
private fun deleteChaptersInternal(chapterItems: List<RecentChapterItem>) {
|
|
||||||
val itemsByManga = chapterItems.groupBy { it.manga.id }
|
|
||||||
for ((_, items) in itemsByManga) {
|
|
||||||
val manga = items.first().manga
|
|
||||||
val source = sourceManager.get(manga.source) ?: continue
|
|
||||||
val chapters = items.map { it.chapter }
|
|
||||||
|
|
||||||
downloadManager.deleteChapters(chapters, manga, source)
|
|
||||||
items.forEach {
|
|
||||||
it.status = Download.NOT_DOWNLOADED
|
|
||||||
it.download = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ class RecentlyReadController(bundle: Bundle? = null) : BaseController(bundle),
|
|||||||
recycler.setHasFixedSize(true)
|
recycler.setHasFixedSize(true)
|
||||||
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||||
resetProgressItem()
|
resetProgressItem()
|
||||||
scrollViewWith(recycler)
|
scrollViewWith(recycler, padBottom = true)
|
||||||
|
|
||||||
if (recentItems != null)
|
if (recentItems != null)
|
||||||
adapter?.updateDataSet(recentItems!!.toList())
|
adapter?.updateDataSet(recentItems!!.toList())
|
||||||
|
@ -1,9 +1,34 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/material_component_lists_two_line_height">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/right_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:background="@color/material_green_800"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/read"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:tint="@color/md_white_1000"
|
||||||
|
android:layout_gravity="end|center"
|
||||||
|
android:layout_marginEnd="21dp"
|
||||||
|
android:src="@drawable/eye" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/front_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/material_component_lists_two_line_height"
|
android:layout_height="@dimen/material_component_lists_two_line_height"
|
||||||
android:background="?attr/selectable_list_drawable">
|
android:background="?attr/selectable_list_drawable">
|
||||||
|
|
||||||
@ -27,8 +52,8 @@
|
|||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textAppearance="@style/TextAppearance.Regular.Body1"
|
android:textAppearance="@style/TextAppearance.Regular.Body1"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/chapter_title"
|
app:layout_constraintBottom_toTopOf="@+id/chapter_title"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/download_button"
|
||||||
app:layout_constraintStart_toEndOf="@+id/manga_cover"
|
app:layout_constraintStart_toEndOf="@+id/manga_cover"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/chapter_menu"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
tools:text="Manga title" />
|
tools:text="Manga title" />
|
||||||
@ -42,40 +67,20 @@
|
|||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textAppearance="@style/TextAppearance.Regular.Caption"
|
android:textAppearance="@style/TextAppearance.Regular.Caption"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/download_button"
|
||||||
app:layout_constraintStart_toEndOf="@+id/manga_cover"
|
app:layout_constraintStart_toEndOf="@+id/manga_cover"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_full_title"
|
app:layout_constraintTop_toBottomOf="@+id/manga_full_title"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/download_text"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
tools:text="Chapter title" />
|
tools:text="Chapter title" />
|
||||||
|
|
||||||
<TextView
|
<include
|
||||||
android:id="@+id/download_text"
|
layout="@layout/download_button"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="3dp"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textSize="12sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
tools:text="Downloaded" />
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/chapter_menu"
|
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:paddingBottom="18dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageView
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
android:id="@+id/chapter_menu_icon"
|
</FrameLayout>
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_gravity="center|end"
|
|
||||||
android:layout_marginEnd="16dp" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -137,7 +137,7 @@
|
|||||||
<string name="action_restore">Restore</string>
|
<string name="action_restore">Restore</string>
|
||||||
<string name="action_webview_back">Back</string>
|
<string name="action_webview_back">Back</string>
|
||||||
<string name="action_webview_forward">Forward</string>
|
<string name="action_webview_forward">Forward</string>
|
||||||
<string name="action_auto_check_extensions">Auto-check for updates</string>
|
<string name="action_auto_check_extensions">Notify for extension updates</string>
|
||||||
<string name="action_search_manually">Search manually</string>
|
<string name="action_search_manually">Search manually</string>
|
||||||
<string name="action_migrate_now">Migrate now</string>
|
<string name="action_migrate_now">Migrate now</string>
|
||||||
<string name="action_copy_now">Copy now</string>
|
<string name="action_copy_now">Copy now</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user