Fix chapters counter

This commit is contained in:
Koitharu
2023-04-26 09:45:01 +03:00
parent a89ff4d15d
commit 259c845912
8 changed files with 68 additions and 45 deletions

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.model
import androidx.core.os.LocaleListCompat
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.toTitleCase
@@ -8,6 +9,18 @@ import org.koitharu.kotatsu.utils.ext.iterator
fun Collection<Manga>.ids() = mapToSet { it.id }
fun Collection<ChapterListItem>.countChaptersByBranch(): Int {
if (size <= 1) {
return size
}
val acc = HashMap<String?, Int>()
for (item in this) {
val branch = item.chapter.branch
acc[branch] = (acc[branch] ?: 0) + 1
}
return acc.values.max()
}
fun Manga.getPreferredBranch(history: MangaHistory?): String? {
val ch = chapters
if (ch.isNullOrEmpty()) {
@@ -31,4 +44,4 @@ fun Manga.getPreferredBranch(history: MangaHistory?): String? {
}
}
return groups.maxByOrNull { it.value.size }?.key
}
}

View File

@@ -27,6 +27,7 @@ import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.base.ui.widgets.ChipsView
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter
import org.koitharu.kotatsu.core.model.countChaptersByBranch
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
@@ -177,12 +178,9 @@ class DetailsFragment :
if (chapters.isNullOrEmpty()) {
infoLayout.textViewChapters.isVisible = false
} else {
val count = chapters.countChaptersByBranch()
infoLayout.textViewChapters.isVisible = true
infoLayout.textViewChapters.text = resources.getQuantityString(
R.plurals.chapters,
chapters.size,
chapters.size,
)
infoLayout.textViewChapters.text = resources.getQuantityString(R.plurals.chapters, count, count)
}
}

View File

@@ -95,13 +95,14 @@ class DetailsViewModel @Inject constructor(
val historyInfo: LiveData<HistoryInfo> = combine(
delegate.manga,
delegate.selectedBranch,
history,
historyRepository.observeShouldSkip(delegate.manga),
) { m, h, im ->
HistoryInfo(m, h, im)
) { m, b, h, im ->
HistoryInfo(m, b, h, im)
}.asFlowLiveData(
context = viewModelScope.coroutineContext + Dispatchers.Default,
defaultValue = HistoryInfo(null, null, false),
defaultValue = HistoryInfo(null, null, null, false),
)
val bookmarks = delegate.manga.flatMapLatest {

View File

@@ -36,8 +36,13 @@ class HistoryInfo(
}
}
fun HistoryInfo(manga: Manga?, history: MangaHistory?, isIncognitoMode: Boolean): HistoryInfo {
val chapters = manga?.chapters
fun HistoryInfo(
manga: Manga?,
branch: String?,
history: MangaHistory?,
isIncognitoMode: Boolean
): HistoryInfo {
val chapters = manga?.getChapters(branch)
return HistoryInfo(
totalChapters = chapters?.size ?: -1,
currentChapter = if (history != null && !chapters.isNullOrEmpty()) {

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.domain
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.annotation.AnyThread
import androidx.collection.LongSparseArray
import androidx.collection.set
import dagger.hilt.android.ActivityRetainedLifecycle
@@ -76,6 +77,7 @@ class PageLoader @Inject constructor(
return repository is RemoteMangaRepository && settings.isPagesPreloadEnabled()
}
@AnyThread
fun prefetch(pages: List<ReaderPage>) = loaderScope.launch {
prefetchLock.withLock {
for (page in pages.asReversed()) {

View File

@@ -15,9 +15,6 @@ import androidx.annotation.AttrRes
import androidx.core.graphics.ColorUtils
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.R as materialR
import java.text.SimpleDateFormat
import java.util.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.parsers.util.format
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
@@ -25,6 +22,9 @@ import org.koitharu.kotatsu.utils.ext.getThemeColor
import org.koitharu.kotatsu.utils.ext.measureDimension
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.resolveDp
import java.text.SimpleDateFormat
import java.util.Date
import com.google.android.material.R as materialR
class ReaderInfoBarView @JvmOverloads constructor(
context: Context,
@@ -121,15 +121,14 @@ class ReaderInfoBarView @JvmOverloads constructor(
fun update(state: ReaderUiState?) {
text = if (state != null) {
val percent = state.computePercent()
context.getString(
R.string.reader_info_pattern,
state.chapterNumber,
state.chaptersTotal,
state.currentPage + 1,
state.totalPages,
) + if (percent in 0f..1f) {
" " + context.getString(R.string.percent_string_pattern, (percent * 100).format())
) + if (state.percent in 0f..1f) {
" " + context.getString(R.string.percent_string_pattern, (state.percent * 100).format())
} else {
""
}

View File

@@ -4,6 +4,8 @@ import android.net.Uri
import android.util.LongSparseArray
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.AnyThread
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
@@ -13,6 +15,7 @@ import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
@@ -80,6 +83,7 @@ class ReaderViewModel @Inject constructor(
private var loadingJob: Job? = null
private var pageSaveJob: Job? = null
private var bookmarkJob: Job? = null
private var stateChangeJob: Job? = null
private val currentState = MutableStateFlow<ReaderState?>(savedStateHandle[ReaderActivity.EXTRA_STATE])
private val mangaData = MutableStateFlow(intent.manga)
private val chapters: LongSparseArray<MangaChapter>
@@ -143,7 +147,7 @@ class ReaderViewModel @Inject constructor(
settings.observe()
.onEach { key ->
if (key == AppSettings.KEY_READER_SLIDER) notifyStateChanged()
}.launchIn(viewModelScope)
}.launchIn(viewModelScope + Dispatchers.Default)
}
fun reload() {
@@ -234,26 +238,31 @@ class ReaderViewModel @Inject constructor(
}
}
// TODO move to background?
@MainThread
fun onCurrentPageChanged(position: Int) {
val pages = content.value?.pages ?: return
pages.getOrNull(position)?.let { page ->
currentState.update { cs ->
cs?.copy(chapterId = page.chapterId, page = page.index)
val prevJob = stateChangeJob
stateChangeJob = launchJob(Dispatchers.Default) {
prevJob?.cancelAndJoin()
val pages = content.value?.pages ?: return@launchJob
pages.getOrNull(position)?.let { page ->
currentState.update { cs ->
cs?.copy(chapterId = page.chapterId, page = page.index)
}
}
notifyStateChanged()
if (pages.isEmpty() || loadingJob?.isActive == true) {
return@launchJob
}
ensureActive()
if (position <= BOUNDS_PAGE_OFFSET) {
loadPrevNextChapter(pages.first().chapterId, isNext = false)
}
if (position >= pages.lastIndex - BOUNDS_PAGE_OFFSET) {
loadPrevNextChapter(pages.last().chapterId, isNext = true)
}
if (pageLoader.isPrefetchApplicable()) {
pageLoader.prefetch(pages.trySublist(position + 1, position + PREFETCH_LIMIT))
}
}
notifyStateChanged()
if (pages.isEmpty() || loadingJob?.isActive == true) {
return
}
if (position <= BOUNDS_PAGE_OFFSET) {
loadPrevNextChapter(pages.first().chapterId, isNext = false)
}
if (position >= pages.size - BOUNDS_PAGE_OFFSET) {
loadPrevNextChapter(pages.last().chapterId, isNext = true)
}
if (pageLoader.isPrefetchApplicable()) {
pageLoader.prefetch(pages.trySublist(position + 1, position + PREFETCH_LIMIT))
}
}
@@ -328,6 +337,7 @@ class ReaderViewModel @Inject constructor(
}
}
@AnyThread
private fun loadPrevNextChapter(currentId: Long, isNext: Boolean) {
loadingJob = launchLoadingJob(Dispatchers.Default) {
chaptersLoader.loadPrevNextChapter(mangaData.requireValue(), currentId, isNext)
@@ -365,7 +375,7 @@ class ReaderViewModel @Inject constructor(
}.getOrDefault(defaultMode)
}
@AnyThread
@WorkerThread
private fun notifyStateChanged() {
val state = getCurrentState()
val chapter = state?.chapterId?.let(chapters::get)
@@ -373,10 +383,11 @@ class ReaderViewModel @Inject constructor(
mangaName = manga?.title,
chapterName = chapter?.name,
chapterNumber = chapter?.number ?: 0,
chaptersTotal = chapters.size(),
chaptersTotal = manga?.getChapters(chapter?.branch)?.size ?: 0,
totalPages = if (chapter != null) chaptersLoader.getPagesCount(chapter.id) else 0,
currentPage = state?.page ?: 0,
isSliderEnabled = settings.isReaderSliderEnabled,
percent = if (state != null) computePercent(state.chapterId, state.page) else PROGRESS_NONE,
)
uiState.postValue(newState)
}

View File

@@ -7,17 +7,11 @@ data class ReaderUiState(
val chaptersTotal: Int,
val currentPage: Int,
val totalPages: Int,
val percent: Float,
private val isSliderEnabled: Boolean,
) {
fun isSliderAvailable(): Boolean {
return isSliderEnabled && totalPages > 1 && currentPage < totalPages
}
fun computePercent(): Float {
val ppc = 1f / chaptersTotal
val chapterIndex = chapterNumber - 1
val pagePercent = (currentPage + 1) / totalPages.toFloat()
return ppc * chapterIndex + ppc * pagePercent
}
}