Implement click events for chapter download icons

This commit is contained in:
arkon 2020-12-31 18:14:51 -05:00
parent bf32bf28da
commit 63398fe491
14 changed files with 180 additions and 88 deletions

View file

@ -34,6 +34,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
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.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MangaControllerBinding import eu.kanade.tachiyomi.databinding.MangaControllerBinding
@ -59,6 +60,7 @@ import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog
import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog
import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChaptersAdapter
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter
import eu.kanade.tachiyomi.ui.manga.track.TrackController import eu.kanade.tachiyomi.ui.manga.track.TrackController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
@ -90,6 +92,7 @@ class MangaController :
ActionMode.Callback, ActionMode.Callback,
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener, FlexibleAdapter.OnItemLongClickListener,
BaseChaptersAdapter.OnChapterClickListener,
ChangeMangaCoverDialog.Listener, ChangeMangaCoverDialog.Listener,
ChangeMangaCategoriesDialog.Listener, ChangeMangaCategoriesDialog.Listener,
DownloadCustomChaptersDialog.Listener, DownloadCustomChaptersDialog.Listener,
@ -866,6 +869,22 @@ class MangaController :
super.onDetach(view) super.onDetach(view)
} }
override fun downloadChapter(position: Int) {
val item = chaptersAdapter?.getItem(position) ?: return
if (item.status == Download.State.ERROR) {
DownloadService.start(activity!!)
} else {
downloadChapters(listOf(item))
}
chaptersAdapter?.updateItem(item)
}
override fun deleteChapter(position: Int) {
val item = chaptersAdapter?.getItem(position) ?: return
deleteChapters(listOf(item))
chaptersAdapter?.updateItem(item)
}
// SELECTION MODE ACTIONS // SELECTION MODE ACTIONS
private fun selectAll() { private fun selectAll() {

View file

@ -56,6 +56,4 @@ class ChapterDownloadView @JvmOverloads constructor(context: Context, attrs: Att
binding.errorIcon.isVisible = state == Download.State.ERROR binding.errorIcon.isVisible = state == Download.State.ERROR
} }
// TODO: onClick actions
} }

View file

@ -5,20 +5,24 @@ import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import eu.davidea.viewholders.FlexibleViewHolder
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.databinding.ChaptersItemBinding import eu.kanade.tachiyomi.databinding.ChaptersItemBinding
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChapterHolder
import java.util.Date import java.util.Date
class ChapterHolder( class ChapterHolder(
view: View, view: View,
private val adapter: ChaptersAdapter private val adapter: ChaptersAdapter
) : FlexibleViewHolder(view, adapter) { ) : BaseChapterHolder(view, adapter) {
private val binding = ChaptersItemBinding.bind(view) private val binding = ChaptersItemBinding.bind(view)
init {
binding.download.setOnClickListener { onDownloadClick(it) }
}
fun bind(item: ChapterItem, manga: Manga) { fun bind(item: ChapterItem, manga: Manga) {
val chapter = item.chapter val chapter = item.chapter

View file

@ -3,37 +3,16 @@ 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.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
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.base.BaseChapterItem
import eu.kanade.tachiyomi.source.model.Page
class ChapterItem(val chapter: Chapter, val manga: Manga) : class ChapterItem(chapter: Chapter, val manga: Manga) :
AbstractFlexibleItem<ChapterHolder>(), BaseChapterItem<ChapterHolder, AbstractHeaderItem<FlexibleViewHolder>>(chapter) {
Chapter by chapter {
private var _status: Download.State = Download.State.NOT_DOWNLOADED
var status: Download.State
get() = download?.status ?: _status
set(value) {
_status = value
}
val progress: Int
get() {
val pages = download?.pages ?: return 0
return pages.map(Page::progress).average().toInt()
}
@Transient
var download: Download? = null
val isDownloaded: Boolean
get() = status == Download.State.DOWNLOADED
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return R.layout.chapters_item return R.layout.chapters_item
@ -51,16 +30,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

@ -1,10 +1,10 @@
package eu.kanade.tachiyomi.ui.manga.chapter package eu.kanade.tachiyomi.ui.manga.chapter
import android.content.Context import android.content.Context
import eu.davidea.flexibleadapter.FlexibleAdapter
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.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChaptersAdapter
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.text.DateFormat import java.text.DateFormat
@ -14,7 +14,7 @@ import java.text.DecimalFormatSymbols
class ChaptersAdapter( class ChaptersAdapter(
controller: MangaController, controller: MangaController,
context: Context context: Context
) : FlexibleAdapter<ChapterItem>(null, controller, true) { ) : BaseChaptersAdapter<ChapterItem>(controller) {
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()

View file

@ -0,0 +1,38 @@
package eu.kanade.tachiyomi.ui.manga.chapter.base
import android.view.View
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.util.view.popupMenu
open class BaseChapterHolder(
view: View,
private val adapter: BaseChaptersAdapter<*>
) : FlexibleViewHolder(view, adapter) {
fun onDownloadClick(view: View) {
val item = adapter.getItem(bindingAdapterPosition) as? BaseChapterItem<*, *> ?: return
when (item.status) {
Download.State.NOT_DOWNLOADED, Download.State.ERROR -> {
adapter.clickListener.downloadChapter(bindingAdapterPosition)
}
else -> {
view.popupMenu(
R.menu.chapter_download,
initMenu = {
// Download.State.DOWNLOADED
findItem(R.id.delete_download).isVisible = item.status == Download.State.DOWNLOADED
// Download.State.DOWNLOADING, Download.State.QUEUE
findItem(R.id.cancel_download).isVisible = item.status != Download.State.DOWNLOADED
},
onMenuItemClick = {
adapter.clickListener.deleteChapter(bindingAdapterPosition)
true
}
)
}
}
}
}

View file

@ -0,0 +1,47 @@
package eu.kanade.tachiyomi.ui.manga.chapter.base
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
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, H : AbstractHeaderItem<*>>(
val chapter: Chapter,
header: H? = null
) :
AbstractSectionableItem<T, H?>(header),
Chapter by chapter {
private var _status: Download.State = Download.State.NOT_DOWNLOADED
var status: Download.State
get() = download?.status ?: _status
set(value) {
_status = value
}
val progress: Int
get() {
val pages = download?.pages ?: return 0
return pages.map(Page::progress).average().toInt()
}
@Transient
var download: Download? = null
val isDownloaded: Boolean
get() = status == Download.State.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

@ -0,0 +1,22 @@
package eu.kanade.tachiyomi.ui.manga.chapter.base
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
abstract class BaseChaptersAdapter<T : IFlexible<*>>(
controller: OnChapterClickListener
) : FlexibleAdapter<T>(null, controller, true) {
/**
* Listener for browse item clicks.
*/
val clickListener: OnChapterClickListener = controller
/**
* Listener which should be called when user clicks the download icons.
*/
interface OnChapterClickListener {
fun downloadChapter(position: Int)
fun deleteChapter(position: Int)
}
}

View file

@ -1,15 +1,15 @@
package eu.kanade.tachiyomi.ui.recent.updates package eu.kanade.tachiyomi.ui.recent.updates
import android.content.Context import android.content.Context
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.ui.manga.chapter.base.BaseChaptersAdapter
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
class UpdatesAdapter( class UpdatesAdapter(
val controller: UpdatesController, val controller: UpdatesController,
context: Context context: Context
) : FlexibleAdapter<IFlexible<*>>(null, controller, true) { ) : BaseChaptersAdapter<IFlexible<*>>(controller) {
var readColor = context.getResourceColor(R.attr.colorOnSurface, 0.38f) var readColor = context.getResourceColor(R.attr.colorOnSurface, 0.38f)
var unreadColor = context.getResourceColor(R.attr.colorOnSurface) var unreadColor = context.getResourceColor(R.attr.colorOnSurface)

View file

@ -13,6 +13,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter import eu.davidea.flexibleadapter.SelectableAdapter
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.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
@ -23,6 +24,7 @@ import eu.kanade.tachiyomi.ui.base.controller.RootController
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.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChaptersAdapter
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.system.toast import eu.kanade.tachiyomi.util.system.toast
@ -45,6 +47,7 @@ class UpdatesController :
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener, FlexibleAdapter.OnItemLongClickListener,
FlexibleAdapter.OnUpdateListener, FlexibleAdapter.OnUpdateListener,
BaseChaptersAdapter.OnChapterClickListener,
ConfirmDeleteChaptersDialog.Listener, ConfirmDeleteChaptersDialog.Listener,
UpdatesAdapter.OnCoverClickListener { UpdatesAdapter.OnCoverClickListener {
@ -291,6 +294,22 @@ class UpdatesController :
Timber.e(error) Timber.e(error)
} }
override fun downloadChapter(position: Int) {
val item = adapter?.getItem(position) as? UpdatesItem ?: return
if (item.status == Download.State.ERROR) {
DownloadService.start(activity!!)
} else {
downloadChapters(listOf(item))
}
adapter?.updateItem(item)
}
override fun deleteChapter(position: Int) {
val item = adapter?.getItem(position) as? UpdatesItem ?: return
deleteChapters(listOf(item))
adapter?.updateItem(item)
}
/** /**
* Called when ActionMode created. * Called when ActionMode created.
* @param mode the ActionMode object * @param mode the ActionMode object

View file

@ -6,12 +6,12 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.CenterCrop import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.databinding.UpdatesItemBinding import eu.kanade.tachiyomi.databinding.UpdatesItemBinding
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChapterHolder
/** /**
* Holder that contains chapter item * Holder that contains chapter item
@ -23,7 +23,7 @@ import eu.kanade.tachiyomi.source.LocalSource
* @constructor creates a new recent chapter holder. * @constructor creates a new recent chapter holder.
*/ */
class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter) : class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter) :
FlexibleViewHolder(view, adapter) { BaseChapterHolder(view, adapter) {
private val binding = UpdatesItemBinding.bind(view) private val binding = UpdatesItemBinding.bind(view)
@ -31,6 +31,8 @@ class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter)
binding.mangaCover.setOnClickListener { binding.mangaCover.setOnClickListener {
adapter.coverClickListener.onCoverClick(bindingAdapterPosition) adapter.coverClickListener.onCoverClick(bindingAdapterPosition)
} }
binding.download.setOnClickListener { onDownloadClick(it) }
} }
fun bind(item: UpdatesItem) { fun bind(item: UpdatesItem) {

View file

@ -3,37 +3,15 @@ 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.base.BaseChapterItem
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.recent.DateSectionItem import eu.kanade.tachiyomi.ui.recent.DateSectionItem
class UpdatesItem(val chapter: Chapter, val manga: Manga, header: DateSectionItem) : class UpdatesItem(chapter: Chapter, val manga: Manga, header: DateSectionItem) :
AbstractSectionableItem<UpdatesHolder, DateSectionItem>(header) { BaseChapterItem<UpdatesHolder, DateSectionItem>(chapter, header) {
private var _status: Download.State = Download.State.NOT_DOWNLOADED
var status: Download.State
get() = download?.status ?: _status
set(value) {
_status = value
}
val progress: Int
get() {
val pages = download?.pages ?: return 0
return pages.map(Page::progress).average().toInt()
}
@Transient
var download: Download? = null
val isDownloaded: Boolean
get() = status == Download.State.DOWNLOADED
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return R.layout.updates_item return R.layout.updates_item
@ -51,16 +29,4 @@ class UpdatesItem(val chapter: Chapter, val manga: Manga, header: DateSectionIte
) { ) {
holder.bind(this) holder.bind(this)
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is UpdatesItem) {
return chapter.id!! == other.chapter.id!!
}
return false
}
override fun hashCode(): Int {
return chapter.id!!.hashCode()
}
} }

View file

@ -4,9 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="28dp" android:layout_width="28dp"
android:layout_height="28dp" android:layout_height="28dp"
android:background="?selectableItemBackgroundBorderless" android:background="?selectableItemBackgroundBorderless">
android:clickable="true"
android:focusable="true">
<ImageView <ImageView
android:id="@+id/download_icon_border" android:id="@+id/download_icon_border"

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/delete_download"
android:title="@string/action_delete" />
<item
android:id="@+id/cancel_download"
android:title="@string/action_cancel" />
</menu>