Update chapters list, show already downloaded chapters #95
This commit is contained in:
@@ -162,7 +162,7 @@ class MangaDexRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposit
|
||||
url = id,
|
||||
scanlator = relations["scanlation_group"]?.getStringOrNull("name"),
|
||||
uploadDate = dateFormat.tryParse(attrs.getString("publishAt")),
|
||||
branch = locale.displayName.toTitleCase(locale),
|
||||
branch = locale.getDisplayName(locale).toTitleCase(locale),
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.divider.MaterialDividerItemDecoration
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||
@@ -51,12 +51,7 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
chaptersAdapter = ChaptersAdapter(this)
|
||||
selectionDecoration = ChaptersSelectionDecoration(view.context)
|
||||
with(binding.recyclerViewChapters) {
|
||||
addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
view.context,
|
||||
RecyclerView.VERTICAL
|
||||
)
|
||||
)
|
||||
addItemDecoration(MaterialDividerItemDecoration(view.context, RecyclerView.VERTICAL))
|
||||
addItemDecoration(selectionDecoration!!)
|
||||
setHasFixedSize(true)
|
||||
adapter = chaptersAdapter
|
||||
@@ -117,7 +112,7 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
}
|
||||
return
|
||||
}
|
||||
if (item.isMissing) {
|
||||
if (item.hasFlag(ChapterListItem.FLAG_MISSING)) {
|
||||
(activity as? DetailsActivity)?.showChapterMissingDialog(item.chapter.id)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -18,15 +19,14 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.details.ui.model.toListItem
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.iterator
|
||||
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||
import org.koitharu.kotatsu.utils.ext.toTitleCase
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class DetailsViewModel(
|
||||
intent: MangaIntent,
|
||||
@@ -60,16 +60,6 @@ class DetailsViewModel(
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, 0)
|
||||
|
||||
private val remoteManga = MutableStateFlow<Manga?>(null)
|
||||
/*private val remoteManga = mangaData.mapLatest {
|
||||
if (it?.source == MangaSource.LOCAL) {
|
||||
runCatching {
|
||||
val m = localMangaRepository.getRemoteManga(it) ?: return@mapLatest null
|
||||
MangaRepository(m.source).getDetails(m)
|
||||
}.getOrNull()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)*/
|
||||
|
||||
private val chaptersReversed = settings.observe()
|
||||
.filter { it == AppSettings.KEY_REVERSE_CHAPTERS }
|
||||
@@ -109,10 +99,10 @@ class DetailsViewModel(
|
||||
selectedBranch
|
||||
) { chapters, sourceManga, currentId, newCount, branch ->
|
||||
val sourceChapters = sourceManga?.chapters
|
||||
if (sourceChapters.isNullOrEmpty()) {
|
||||
mapChapters(chapters, currentId, newCount, branch)
|
||||
} else {
|
||||
if (sourceManga?.source != MangaSource.LOCAL && !sourceChapters.isNullOrEmpty()) {
|
||||
mapChaptersWithSource(chapters, sourceChapters, currentId, newCount, branch)
|
||||
} else {
|
||||
mapChapters(chapters, sourceChapters, currentId, newCount, branch)
|
||||
}
|
||||
}.combine(chaptersReversed) { list, reversed ->
|
||||
if (reversed) list.asReversed() else list
|
||||
@@ -132,12 +122,14 @@ class DetailsViewModel(
|
||||
predictBranch(manga.chapters)
|
||||
}
|
||||
mangaData.value = manga
|
||||
if (manga.source == MangaSource.LOCAL) {
|
||||
remoteManga.value = runCatching {
|
||||
remoteManga.value = runCatching {
|
||||
if (manga.source == MangaSource.LOCAL) {
|
||||
val m = localMangaRepository.getRemoteManga(manga) ?: return@runCatching null
|
||||
MangaRepository(m.source).getDetails(m)
|
||||
}.getOrNull()
|
||||
}
|
||||
} else {
|
||||
localMangaRepository.findSavedManga(manga)
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +158,7 @@ class DetailsViewModel(
|
||||
|
||||
private fun mapChapters(
|
||||
chapters: List<MangaChapter>,
|
||||
downloadedChapters: List<MangaChapter>?,
|
||||
currentId: Long?,
|
||||
newCount: Int,
|
||||
branch: String?,
|
||||
@@ -174,19 +167,18 @@ class DetailsViewModel(
|
||||
val dateFormat = settings.dateFormat()
|
||||
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
||||
val firstNewIndex = chapters.size - newCount
|
||||
val downloadedIds = downloadedChapters?.mapToSet { it.id }
|
||||
for (i in chapters.indices) {
|
||||
val chapter = chapters[i]
|
||||
if (chapter.branch != branch) {
|
||||
continue
|
||||
}
|
||||
result += chapter.toListItem(
|
||||
extra = when {
|
||||
i >= firstNewIndex -> ChapterExtra.NEW
|
||||
i == currentIndex -> ChapterExtra.CURRENT
|
||||
i < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isCurrent = i == currentIndex,
|
||||
isUnread = i > currentIndex,
|
||||
isNew = i >= firstNewIndex,
|
||||
isMissing = false,
|
||||
isDownloaded = downloadedIds?.contains(chapter.id) == true,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
}
|
||||
@@ -212,29 +204,32 @@ class DetailsViewModel(
|
||||
}
|
||||
val localChapter = chaptersMap.remove(chapter.id)
|
||||
result += localChapter?.toListItem(
|
||||
extra = when {
|
||||
i >= firstNewIndex -> ChapterExtra.NEW
|
||||
i == currentIndex -> ChapterExtra.CURRENT
|
||||
i < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isCurrent = i == currentIndex,
|
||||
isUnread = i > currentIndex,
|
||||
isNew = i >= firstNewIndex,
|
||||
isMissing = false,
|
||||
isDownloaded = false,
|
||||
dateFormat = dateFormat,
|
||||
) ?: chapter.toListItem(
|
||||
extra = when {
|
||||
i >= firstNewIndex -> ChapterExtra.NEW
|
||||
i == currentIndex -> ChapterExtra.CURRENT
|
||||
i < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isCurrent = i == currentIndex,
|
||||
isUnread = i > currentIndex,
|
||||
isNew = i >= firstNewIndex,
|
||||
isMissing = true,
|
||||
isDownloaded = false,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
}
|
||||
if (chaptersMap.isNotEmpty()) { // some chapters on device but not online source
|
||||
result.ensureCapacity(result.size + chaptersMap.size)
|
||||
chaptersMap.values.mapTo(result) {
|
||||
it.toListItem(ChapterExtra.UNREAD, false, dateFormat)
|
||||
it.toListItem(
|
||||
isCurrent = false,
|
||||
isUnread = true,
|
||||
isNew = false,
|
||||
isMissing = false,
|
||||
isDownloaded = false,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
}
|
||||
result.sortBy { it.chapter.number }
|
||||
}
|
||||
@@ -246,14 +241,15 @@ class DetailsViewModel(
|
||||
return null
|
||||
}
|
||||
val groups = chapters.groupBy { it.branch }
|
||||
val locale = Locale.getDefault()
|
||||
var language = locale.displayLanguage.toTitleCase(locale)
|
||||
if (groups.containsKey(language)) {
|
||||
return language
|
||||
}
|
||||
language = locale.displayName.toTitleCase(locale)
|
||||
if (groups.containsKey(language)) {
|
||||
return language
|
||||
for (locale in LocaleListCompat.getAdjustedDefault()) {
|
||||
var language = locale.getDisplayLanguage(locale).toTitleCase(locale)
|
||||
if (groups.containsKey(language)) {
|
||||
return language
|
||||
}
|
||||
language = locale.getDisplayName(locale).toTitleCase(locale)
|
||||
if (groups.containsKey(language)) {
|
||||
return language
|
||||
}
|
||||
}
|
||||
return groups.maxByOrNull { it.value.size }?.key
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package org.koitharu.kotatsu.details.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.databinding.ItemChapterBinding
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_CURRENT
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_DOWNLOADED
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_MISSING
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_NEW
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_UNREAD
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||
|
||||
@@ -15,37 +21,40 @@ fun chapterListItemAD(
|
||||
{ inflater, parent -> ItemChapterBinding.inflate(inflater, parent, false) }
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
clickListener.onItemClick(item, it)
|
||||
}
|
||||
itemView.setOnLongClickListener {
|
||||
clickListener.onItemLongClick(item, it)
|
||||
val eventListener = object : View.OnClickListener, View.OnLongClickListener {
|
||||
override fun onClick(v: View) = clickListener.onItemClick(item, v)
|
||||
override fun onLongClick(v: View) = clickListener.onItemLongClick(item, v)
|
||||
}
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.chapter.name
|
||||
binding.textViewNumber.text = item.chapter.number.toString()
|
||||
binding.textViewDescription.textAndVisible = item.description()
|
||||
when (item.extra) {
|
||||
ChapterExtra.UNREAD -> {
|
||||
itemView.setOnClickListener(eventListener)
|
||||
itemView.setOnLongClickListener(eventListener)
|
||||
|
||||
bind { payloads ->
|
||||
if (payloads.isEmpty()) {
|
||||
binding.textViewTitle.text = item.chapter.name
|
||||
binding.textViewNumber.text = item.chapter.number.toString()
|
||||
binding.textViewDescription.textAndVisible = item.description()
|
||||
}
|
||||
when (item.status) {
|
||||
FLAG_UNREAD -> {
|
||||
binding.textViewNumber.setBackgroundResource(R.drawable.bg_badge_default)
|
||||
binding.textViewNumber.setTextColor(context.getThemeColor(android.R.attr.textColorSecondaryInverse))
|
||||
}
|
||||
ChapterExtra.READ -> {
|
||||
binding.textViewNumber.setBackgroundResource(R.drawable.bg_badge_outline)
|
||||
binding.textViewNumber.setTextColor(context.getThemeColor(android.R.attr.textColorTertiary))
|
||||
}
|
||||
ChapterExtra.CURRENT -> {
|
||||
binding.textViewNumber.setBackgroundResource(R.drawable.bg_badge_outline_accent)
|
||||
binding.textViewNumber.setTextColor(context.getThemeColor(androidx.appcompat.R.attr.colorAccent))
|
||||
}
|
||||
ChapterExtra.NEW -> {
|
||||
FLAG_CURRENT -> {
|
||||
binding.textViewNumber.setBackgroundResource(R.drawable.bg_badge_accent)
|
||||
binding.textViewNumber.setTextColor(context.getThemeColor(android.R.attr.textColorPrimaryInverse))
|
||||
}
|
||||
else -> {
|
||||
binding.textViewNumber.setBackgroundResource(R.drawable.bg_badge_outline)
|
||||
binding.textViewNumber.setTextColor(context.getThemeColor(android.R.attr.textColorTertiary))
|
||||
}
|
||||
}
|
||||
binding.textViewTitle.alpha = if (item.isMissing) 0.3f else 1f
|
||||
binding.textViewDescription.alpha = if (item.isMissing) 0.3f else 1f
|
||||
binding.textViewNumber.alpha = if (item.isMissing) 0.3f else 1f
|
||||
val isMissing = item.hasFlag(FLAG_MISSING)
|
||||
binding.textViewTitle.alpha = if (isMissing) 0.3f else 1f
|
||||
binding.textViewDescription.alpha = if (isMissing) 0.3f else 1f
|
||||
binding.textViewNumber.alpha = if (isMissing) 0.3f else 1f
|
||||
|
||||
binding.imageViewDownloaded.isVisible = item.hasFlag(FLAG_DOWNLOADED)
|
||||
binding.imageViewNew.isVisible = item.hasFlag(FLAG_NEW)
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,8 @@ class ChaptersAdapter(
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: ChapterListItem, newItem: ChapterListItem): Any? {
|
||||
if (oldItem.extra != newItem.extra && oldItem.chapter == newItem.chapter) {
|
||||
return newItem.extra
|
||||
if (oldItem.flags != newItem.flags && oldItem.chapter == newItem.chapter) {
|
||||
return newItem.flags
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -4,20 +4,14 @@ import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import androidx.collection.ArraySet
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||
|
||||
class ChaptersSelectionDecoration(context: Context) : RecyclerView.ItemDecoration() {
|
||||
|
||||
private val icon = ContextCompat.getDrawable(context, R.drawable.ic_check)
|
||||
private val padding = context.resources.resolveDp(16)
|
||||
private val bounds = Rect()
|
||||
private val selection = ArraySet<Long>()
|
||||
private val selection = HashSet<Long>()
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
|
||||
init {
|
||||
@@ -54,7 +48,6 @@ class ChaptersSelectionDecoration(context: Context) : RecyclerView.ItemDecoratio
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
icon ?: return
|
||||
canvas.save()
|
||||
if (parent.clipToPadding) {
|
||||
canvas.clipRect(
|
||||
@@ -73,36 +66,4 @@ class ChaptersSelectionDecoration(context: Context) : RecyclerView.ItemDecoratio
|
||||
}
|
||||
canvas.restore()
|
||||
}
|
||||
|
||||
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
icon ?: return
|
||||
canvas.save()
|
||||
val left: Int
|
||||
val right: Int
|
||||
if (parent.clipToPadding) {
|
||||
left = parent.paddingLeft
|
||||
right = parent.width - parent.paddingRight
|
||||
canvas.clipRect(
|
||||
left, parent.paddingTop, right,
|
||||
parent.height - parent.paddingBottom
|
||||
)
|
||||
} else {
|
||||
left = 0
|
||||
right = parent.width
|
||||
}
|
||||
|
||||
for (child in parent.children) {
|
||||
val itemId = parent.getChildItemId(child)
|
||||
if (itemId in selection) {
|
||||
parent.getDecoratedBoundsWithMargins(child, bounds)
|
||||
bounds.offset(child.translationX.toInt(), child.translationY.toInt())
|
||||
val hh = (bounds.height() - icon.intrinsicHeight) / 2
|
||||
val top: Int = bounds.top + hh
|
||||
val bottom: Int = bounds.bottom - hh
|
||||
icon.setBounds(right - icon.intrinsicWidth - padding, top, right - padding, bottom)
|
||||
icon.draw(canvas)
|
||||
}
|
||||
}
|
||||
canvas.restore()
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,20 @@
|
||||
package org.koitharu.kotatsu.details.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
|
||||
data class ChapterListItem(
|
||||
class ChapterListItem(
|
||||
val chapter: MangaChapter,
|
||||
val extra: ChapterExtra,
|
||||
val isMissing: Boolean,
|
||||
val flags: Int,
|
||||
val uploadDate: String?,
|
||||
) {
|
||||
|
||||
val status: Int
|
||||
get() = flags and MASK_STATUS
|
||||
|
||||
fun hasFlag(flag: Int): Boolean {
|
||||
return (flags and flag) == flag
|
||||
}
|
||||
|
||||
fun description(): CharSequence? {
|
||||
val scanlator = chapter.scanlator?.takeUnless { it.isBlank() }
|
||||
return when {
|
||||
@@ -18,4 +23,35 @@ data class ChapterListItem(
|
||||
else -> uploadDate
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ChapterListItem
|
||||
|
||||
if (chapter != other.chapter) return false
|
||||
if (flags != other.flags) return false
|
||||
if (uploadDate != other.uploadDate) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = chapter.hashCode()
|
||||
result = 31 * result + flags
|
||||
result = 31 * result + uploadDate.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
const val FLAG_UNREAD = 2
|
||||
const val FLAG_CURRENT = 4
|
||||
const val FLAG_NEW = 8
|
||||
const val FLAG_MISSING = 16
|
||||
const val FLAG_DOWNLOADED = 32
|
||||
const val MASK_STATUS = FLAG_UNREAD or FLAG_CURRENT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
package org.koitharu.kotatsu.details.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_CURRENT
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_DOWNLOADED
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_MISSING
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_NEW
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_UNREAD
|
||||
import java.text.DateFormat
|
||||
|
||||
fun MangaChapter.toListItem(
|
||||
extra: ChapterExtra,
|
||||
isCurrent: Boolean,
|
||||
isUnread: Boolean,
|
||||
isNew: Boolean,
|
||||
isMissing: Boolean,
|
||||
isDownloaded: Boolean,
|
||||
dateFormat: DateFormat,
|
||||
) = ChapterListItem(
|
||||
chapter = this,
|
||||
extra = extra,
|
||||
isMissing = isMissing,
|
||||
uploadDate = if (uploadDate != 0L) dateFormat.format(uploadDate) else null
|
||||
)
|
||||
): ChapterListItem {
|
||||
var flags = 0
|
||||
if (isCurrent) flags = flags or FLAG_CURRENT
|
||||
if (isUnread) flags = flags or FLAG_UNREAD
|
||||
if (isNew) flags = flags or FLAG_NEW
|
||||
if (isMissing) flags = flags or FLAG_MISSING
|
||||
if (isDownloaded) flags = flags or FLAG_DOWNLOADED
|
||||
return ChapterListItem(
|
||||
chapter = this,
|
||||
flags = flags,
|
||||
uploadDate = if (uploadDate != 0L) dateFormat.format(uploadDate) else null
|
||||
)
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package org.koitharu.kotatsu.history.domain
|
||||
|
||||
enum class ChapterExtra {
|
||||
|
||||
READ, CURRENT, UNREAD, NEW
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import org.koitharu.kotatsu.databinding.DialogChaptersBinding
|
||||
import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.details.ui.model.toListItem
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class ChaptersDialog : AlertDialogFragment<DialogChaptersBinding>(),
|
||||
@@ -51,12 +50,11 @@ class ChaptersDialog : AlertDialogFragment<DialogChaptersBinding>(),
|
||||
binding.recyclerViewChapters.adapter = ChaptersAdapter(this).apply {
|
||||
setItems(chapters.mapIndexed { index, chapter ->
|
||||
chapter.toListItem(
|
||||
when {
|
||||
index < currentPosition -> ChapterExtra.READ
|
||||
index == currentPosition -> ChapterExtra.CURRENT
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isCurrent = index == currentPosition,
|
||||
isUnread = index > currentPosition,
|
||||
isNew = false,
|
||||
isMissing = false,
|
||||
isDownloaded = false,
|
||||
dateFormat = dateFormat,
|
||||
)
|
||||
}) {
|
||||
|
||||
@@ -11,6 +11,12 @@ fun LocaleListCompat.toList(): List<Locale> {
|
||||
return list
|
||||
}
|
||||
|
||||
operator fun LocaleListCompat.iterator() = object : Iterator<Locale> {
|
||||
private var index = 0
|
||||
override fun hasNext(): Boolean = index < size()
|
||||
override fun next(): Locale = get(index++)
|
||||
}
|
||||
|
||||
inline fun <R, C : MutableCollection<in R>> LocaleListCompat.mapTo(
|
||||
destination: C,
|
||||
block: (Locale) -> R,
|
||||
|
||||
@@ -8,7 +8,7 @@ class JSONIterator(private val array: JSONArray) : Iterator<JSONObject> {
|
||||
private val total = array.length()
|
||||
private var index = 0
|
||||
|
||||
override fun hasNext() = index < total - 1
|
||||
override fun hasNext() = index < total
|
||||
|
||||
override fun next(): JSONObject = array.getJSONObject(index++)
|
||||
}
|
||||
@@ -7,7 +7,7 @@ class JSONStringIterator(private val array: JSONArray) : Iterator<String> {
|
||||
private val total = array.length()
|
||||
private var index = 0
|
||||
|
||||
override fun hasNext() = index < total - 1
|
||||
override fun hasNext() = index < total
|
||||
|
||||
override fun next(): String = array.getString(index++)
|
||||
}
|
||||
11
app/src/main/res/drawable/ic_new.xml
Normal file
11
app/src/main/res/drawable/ic_new.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M7.25,12.5L4.75,9L3.5,9v6h1.25v-3.5L7.3,15h1.2L8.5,9L7.25,9zM9.5,15h4v-1.25L11,13.75v-1.11h2.5v-1.26L11,11.38v-1.12h2.5L13.5,9h-4zM19.25,9v4.5h-1.12L18.13,9.99h-1.25v3.52h-1.13L15.75,9L14.5,9v5c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1L20.5,9h-1.25z" />
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_save_ok.xml
Normal file
11
app/src/main/res/drawable/ic_save_ok.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M14 12.8C13.5 12.31 12.78 12 12 12C10.34 12 9 13.34 9 15C9 16.31 9.84 17.41 11 17.82C11.07 15.67 12.27 13.8 14 12.8M11.09 19H5V5H16.17L19 7.83V12.35C19.75 12.61 20.42 13 21 13.54V7L17 3H5C3.89 3 3 3.9 3 5V19C3 20.1 3.89 21 5 21H11.81C11.46 20.39 11.21 19.72 11.09 19M6 10H15V6H6V10M15.75 21L13 18L14.16 16.84L15.75 18.43L19.34 14.84L20.5 16.25L15.75 21" />
|
||||
</vector>
|
||||
@@ -1,61 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/chapter_list_item_height"
|
||||
android:background="?selectableItemBackground">
|
||||
android:background="?selectableItemBackground"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_number"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="@drawable/bg_badge_default"
|
||||
android:gravity="center"
|
||||
android:minWidth="26dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?attr/colorOnTertiary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="13" />
|
||||
tools:text="13"
|
||||
tools:textColor="?attr/colorOnPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_toEndOf="@id/textView_number"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
app:layout_constraintBottom_toTopOf="@+id/textView_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/textView_number"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginBottom="8dp"
|
||||
tools:text="@tools:sample/lorem[15]" />
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_description"
|
||||
android:layout_width="0dp"
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
tools:text="@tools:sample/lorem[15]" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:text="05.10.2021 • Scanlator" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_new"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/textView_number"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView_title"
|
||||
tools:text="05.10.2021 • Scanlator" />
|
||||
android:src="@drawable/ic_new" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<ImageView
|
||||
android:id="@+id/imageView_downloaded"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@drawable/ic_save_ok" />
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user