Refactoring ChapterItem to make the download button more reusable

This commit is contained in:
Jay 2020-03-28 15:07:21 -04:00
parent d82b6fbe04
commit 0d658d4b05
11 changed files with 128 additions and 168 deletions

View File

@ -61,6 +61,9 @@ import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.updateLayoutParams import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePadding import eu.kanade.tachiyomi.util.view.updatePadding
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.math.abs
import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.main_activity.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -68,9 +71,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.math.abs
open class MainActivity : BaseActivity(), DownloadServiceListener { open class MainActivity : BaseActivity(), DownloadServiceListener {

View File

@ -2,14 +2,12 @@ package eu.kanade.tachiyomi.ui.manga
import android.content.Context import android.content.Context
import android.view.View import android.view.View
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import eu.davidea.flexibleadapter.FlexibleAdapter
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.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
@ -18,7 +16,7 @@ import uy.kohesive.injekt.injectLazy
class MangaDetailsAdapter( class MangaDetailsAdapter(
val controller: MangaDetailsController, val controller: MangaDetailsController,
context: Context context: Context
) : FlexibleAdapter<IFlexible<*>>(null, controller, true) { ) : BaseChapterAdapter<IFlexible<*>>(controller) {
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
@ -44,11 +42,6 @@ class MangaDetailsAdapter(
return items.indexOf(item) return items.indexOf(item)
} }
fun unlock() {
val activity = controller.activity as? FragmentActivity ?: return
SecureActivityDelegate.promptLockIfNeeded(activity)
}
fun performFilter() { fun performFilter() {
val s = getFilter(String::class.java) val s = getFilter(String::class.java)
if (s.isNullOrBlank()) { if (s.isNullOrBlank()) {
@ -84,9 +77,4 @@ class MangaDetailsAdapter(
fun zoomImageFromThumb(thumbView: View) fun zoomImageFromThumb(thumbView: View)
fun showTrackingSheet() fun showTrackingSheet()
} }
interface DownloadInterface {
fun downloadChapter(position: Int)
fun startDownloadNow(position: Int)
}
} }

View File

@ -0,0 +1,16 @@
package eu.kanade.tachiyomi.ui.manga.chapter
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
open class BaseChapterAdapter<T : IFlexible<*>>(
obj: DownloadInterface
) : FlexibleAdapter<T>(null, obj, true) {
val baseDelegate = obj
interface DownloadInterface {
fun downloadChapter(position: Int)
fun startDownloadNow(position: Int)
}
}

View File

@ -0,0 +1,52 @@
package eu.kanade.tachiyomi.ui.manga.chapter
import android.view.View
import androidx.appcompat.widget.PopupMenu
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.download_button.*
open class BaseChapterHolder(
view: View,
private val adapter: BaseChapterAdapter<*>
) : BaseFlexibleViewHolder(view, adapter) {
init {
download_button.setOnClickListener { downloadOrRemoveMenu() }
}
private fun downloadOrRemoveMenu() {
val chapter = adapter.getItem(adapterPosition) as? BaseChapterItem ?: return
if (chapter.status == Download.NOT_DOWNLOADED || chapter.status == Download.ERROR) {
adapter.baseDelegate.downloadChapter(adapterPosition)
} else {
download_button.post {
// Create a PopupMenu, giving it the clicked view for an anchor
val popup = PopupMenu(download_button.context, download_button)
// Inflate our menu resource into the PopupMenu's Menu
popup.menuInflater.inflate(R.menu.chapter_download, popup.menu)
popup.menu.findItem(R.id.action_start).isVisible = chapter.status == Download.QUEUE
// Hide download and show delete if the chapter is downloaded
if (chapter.status != Download.DOWNLOADED) popup.menu.findItem(R.id.action_delete).title = download_button.context.getString(
R.string.action_cancel
)
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_delete -> adapter.baseDelegate.downloadChapter(adapterPosition)
R.id.action_start -> adapter.baseDelegate.startDownloadNow(adapterPosition)
}
true
}
// Finally show the PopupMenu
popup.show()
}
}
}
}

View File

@ -0,0 +1,40 @@
package eu.kanade.tachiyomi.ui.manga.chapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.model.Page
abstract class BaseChapterItem<T : BaseChapterHolder>(val chapter: Chapter) :
AbstractFlexibleItem<T>(),
Chapter by chapter {
private var _status: Int = 0
val progress: Int
get() {
val pages = download?.pages ?: return 0
return pages.map(Page::progress).average().toInt()
}
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 equals(other: Any?): Boolean {
if (this === other) return true
if (other is BaseChapterItem<*>) {
return chapter.id!! == other.chapter.id!!
}
return false
}
override fun hashCode(): Int {
return chapter.id!!.hashCode()
}
}

View File

@ -2,13 +2,11 @@ package eu.kanade.tachiyomi.ui.manga.chapter
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.View import android.view.View
import androidx.appcompat.widget.PopupMenu
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
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.data.download.model.Download
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter
import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.visibleIf import eu.kanade.tachiyomi.util.view.visibleIf
@ -17,53 +15,18 @@ import kotlinx.android.synthetic.main.chapters_item.*
import kotlinx.android.synthetic.main.download_button.* import kotlinx.android.synthetic.main.download_button.*
class ChapterHolder( class ChapterHolder(
private val view: View, view: View,
private val adapter: MangaDetailsAdapter private val adapter: MangaDetailsAdapter
) : BaseFlexibleViewHolder(view, adapter) { ) : BaseChapterHolder(view, adapter) {
private var localSource = false private var localSource = false
init { init {
download_button.setOnClickListener { downloadOrRemoveMenu() }
download_button.setOnLongClickListener { download_button.setOnLongClickListener {
adapter.delegate.startDownloadRange(adapterPosition) adapter.delegate.startDownloadRange(adapterPosition)
true true
} }
} }
private fun downloadOrRemoveMenu() {
val chapter = adapter.getItem(adapterPosition) as? ChapterItem ?: return
if (chapter.status == Download.NOT_DOWNLOADED || chapter.status == Download.ERROR) {
adapter.delegate.downloadChapter(adapterPosition)
} else {
download_button.post {
// Create a PopupMenu, giving it the clicked view for an anchor
val popup = PopupMenu(download_button.context, download_button)
// Inflate our menu resource into the PopupMenu's Menu
popup.menuInflater.inflate(R.menu.chapter_download, popup.menu)
popup.menu.findItem(R.id.action_start).isVisible = chapter.status == Download.QUEUE
// Hide download and show delete if the chapter is downloaded
if (chapter.status != Download.DOWNLOADED) popup.menu.findItem(R.id.action_delete).title = download_button.context.getString(
R.string.action_cancel
)
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_delete -> adapter.delegate.downloadChapter(adapterPosition)
R.id.action_start -> adapter.delegate.startDownloadNow(adapterPosition)
}
true
}
// Finally show the PopupMenu
popup.show()
}
}
}
fun bind(item: ChapterItem, manga: Manga) { fun bind(item: ChapterItem, manga: Manga) {
val chapter = item.chapter val chapter = item.chapter
val isLocked = item.isLocked val isLocked = item.isLocked

View File

@ -3,37 +3,17 @@ package eu.kanade.tachiyomi.ui.manga.chapter
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.AbstractFlexibleItem
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.source.model.Page
import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter
class ChapterItem(val chapter: Chapter, val manga: Manga) : class ChapterItem(chapter: Chapter, val manga: Manga) :
AbstractFlexibleItem<ChapterHolder>(), BaseChapterItem<ChapterHolder>(chapter) {
Chapter by chapter {
private var _status: Int = 0
val progress: Int
get() {
val pages = download?.pages ?: return 0
return pages.map(Page::progress).average().toInt()
}
var isLocked = false var isLocked = false
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.chapters_item return R.layout.chapters_item
} }
@ -58,16 +38,4 @@ class ChapterItem(val chapter: Chapter, val manga: Manga) :
) { ) {
holder.bind(this, manga) 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()
}
} }

View File

@ -2,20 +2,19 @@ package eu.kanade.tachiyomi.ui.recents
import android.widget.ImageView import android.widget.ImageView
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
class RecentMangaAdapter(val delegate: RecentsInterface) : class RecentMangaAdapter(val delegate: RecentsInterface) :
FlexibleAdapter<IFlexible<RecentMangaHolder>>(null, delegate, true) { BaseChapterAdapter<IFlexible<RecentMangaHolder>>(delegate) {
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols() val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
.apply { decimalSeparator = '.' }) .apply { decimalSeparator = '.' })
interface RecentsInterface : RecentMangaInterface, MangaDetailsAdapter.DownloadInterface interface RecentsInterface : RecentMangaInterface, DownloadInterface
interface RecentMangaInterface { interface RecentMangaInterface {
fun onCoverClick(position: Int) fun onCoverClick(position: Int)

View File

@ -2,11 +2,10 @@ package eu.kanade.tachiyomi.ui.recents
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.View import android.view.View
import androidx.appcompat.widget.PopupMenu
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterHolder
import eu.kanade.tachiyomi.util.view.visibleIf import eu.kanade.tachiyomi.util.view.visibleIf
import java.util.Date import java.util.Date
import kotlinx.android.synthetic.main.download_button.* import kotlinx.android.synthetic.main.download_button.*
@ -15,45 +14,10 @@ import kotlinx.android.synthetic.main.recent_manga_item.*
class RecentMangaHolder( class RecentMangaHolder(
view: View, view: View,
val adapter: RecentMangaAdapter val adapter: RecentMangaAdapter
) : BaseFlexibleViewHolder(view, adapter) { ) : BaseChapterHolder(view, adapter) {
init { init {
cover_thumbnail.setOnClickListener { adapter.delegate.onCoverClick(adapterPosition) } cover_thumbnail.setOnClickListener { adapter.delegate.onCoverClick(adapterPosition) }
download_button.setOnClickListener { downloadOrRemoveMenu() }
}
private fun downloadOrRemoveMenu() {
val chapter = adapter.getItem(adapterPosition) as? RecentMangaItem ?: return
if (chapter.status == Download.NOT_DOWNLOADED || chapter.status == Download.ERROR) {
adapter.delegate.downloadChapter(adapterPosition)
} else {
download_button.post {
// Create a PopupMenu, giving it the clicked view for an anchor
val popup = PopupMenu(download_button.context, download_button)
// Inflate our menu resource into the PopupMenu's Menu
popup.menuInflater.inflate(R.menu.chapter_download, popup.menu)
popup.menu.findItem(R.id.action_start).isVisible = chapter.status == Download.QUEUE
// Hide download and show delete if the chapter is downloaded
if (chapter.status != Download.DOWNLOADED) popup.menu.findItem(R.id.action_delete).title = download_button.context.getString(
R.string.action_cancel
)
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_delete -> adapter.delegate.downloadChapter(adapterPosition)
R.id.action_start -> adapter.delegate.startDownloadNow(adapterPosition)
}
true
}
// Finally show the PopupMenu
popup.show()
}
}
} }
fun bind(item: RecentMangaItem) { fun bind(item: RecentMangaItem) {
@ -102,9 +66,8 @@ class RecentMangaHolder(
) )
} }
fun notifyStatus(status: Int, progress: Int) = with(download_button) { fun notifyStatus(status: Int, progress: Int) =
setDownloadStatus(status, progress) download_button.setDownloadStatus(status, progress)
}
override fun getFrontView(): View { override fun getFrontView(): View {
return front_view return front_view

View File

@ -3,31 +3,14 @@ package eu.kanade.tachiyomi.ui.recents
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.AbstractFlexibleItem
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.MangaChapterHistory import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterItem
import eu.kanade.tachiyomi.source.model.Page
class RecentMangaItem(val mch: MangaChapterHistory, val chapter: Chapter) : class RecentMangaItem(val mch: MangaChapterHistory, chapter: Chapter) :
AbstractFlexibleItem<RecentMangaHolder> BaseChapterItem<RecentMangaHolder>(chapter) {
() {
private var _status: Int = 0
val progress: Int
get() {
val pages = download?.pages ?: return 0
return pages.map(Page::progress).average().toInt()
}
var status: Int
get() = download?.status ?: _status
set(value) { _status = value }
@Transient var download: Download? = null
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return R.layout.recent_manga_item return R.layout.recent_manga_item
@ -46,18 +29,6 @@ class RecentMangaItem(val mch: MangaChapterHistory, val chapter: Chapter) :
position: Int, position: Int,
payloads: MutableList<Any?>? payloads: MutableList<Any?>?
) { ) {
holder.bind(this) holder.bind(this)
} }
override fun equals(other: Any?): Boolean {
if (other is RecentMangaItem) {
return chapter.id == other.chapter.id
}
return false
}
override fun hashCode(): Int {
return chapter.id!!.hashCode()
}
} }

View File

@ -134,7 +134,7 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
} }
} }
fun refreshItem(chapterId: Long) { private fun refreshItem(chapterId: Long) {
for (i in 0 until adapter.itemCount) { for (i in 0 until adapter.itemCount) {
val holder = recycler.findViewHolderForAdapterPosition(i) as? RecentsHolder ?: continue val holder = recycler.findViewHolderForAdapterPosition(i) as? RecentsHolder ?: continue
holder.refreshChapter(chapterId) holder.refreshChapter(chapterId)