|
|
|
|
@ -11,7 +11,11 @@ import org.koitharu.kotatsu.base.domain.MangaIntent
|
|
|
|
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
|
|
|
|
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
|
|
|
|
|
import org.koitharu.kotatsu.core.model.Manga
|
|
|
|
|
import org.koitharu.kotatsu.core.model.MangaChapter
|
|
|
|
|
import org.koitharu.kotatsu.core.model.MangaSource
|
|
|
|
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
|
|
|
|
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
|
|
|
|
|
@ -29,7 +33,7 @@ class DetailsViewModel(
|
|
|
|
|
private val localMangaRepository: LocalMangaRepository,
|
|
|
|
|
private val trackingRepository: TrackingRepository,
|
|
|
|
|
private val mangaDataRepository: MangaDataRepository,
|
|
|
|
|
private val settings: AppSettings
|
|
|
|
|
private val settings: AppSettings,
|
|
|
|
|
) : BaseViewModel() {
|
|
|
|
|
|
|
|
|
|
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
|
|
|
|
@ -53,6 +57,18 @@ class DetailsViewModel(
|
|
|
|
|
trackingRepository.getNewChaptersCount(mangaId)
|
|
|
|
|
}.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 }
|
|
|
|
|
.map { settings.chaptersReverse }
|
|
|
|
|
@ -85,24 +101,19 @@ class DetailsViewModel(
|
|
|
|
|
|
|
|
|
|
val chapters = combine(
|
|
|
|
|
mangaData.map { it?.chapters.orEmpty() },
|
|
|
|
|
remoteManga,
|
|
|
|
|
history.map { it?.chapterId },
|
|
|
|
|
newChapters,
|
|
|
|
|
chaptersReversed,
|
|
|
|
|
selectedBranch
|
|
|
|
|
) { chapters, currentId, newCount, reversed, branch ->
|
|
|
|
|
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
|
|
|
|
val firstNewIndex = chapters.size - newCount
|
|
|
|
|
val res = chapters.mapIndexed { index, chapter ->
|
|
|
|
|
chapter.toListItem(
|
|
|
|
|
when {
|
|
|
|
|
index >= firstNewIndex -> ChapterExtra.NEW
|
|
|
|
|
index == currentIndex -> ChapterExtra.CURRENT
|
|
|
|
|
index < currentIndex -> ChapterExtra.READ
|
|
|
|
|
else -> ChapterExtra.UNREAD
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}.filter { it.chapter.branch == branch }
|
|
|
|
|
if (reversed) res.asReversed() else res
|
|
|
|
|
) { chapters, sourceManga, currentId, newCount, branch ->
|
|
|
|
|
val sourceChapters = sourceManga?.chapters
|
|
|
|
|
if (sourceChapters.isNullOrEmpty()) {
|
|
|
|
|
mapChapters(chapters, currentId, newCount, branch)
|
|
|
|
|
} else {
|
|
|
|
|
mapChaptersWithSource(chapters, sourceChapters, currentId, newCount, branch)
|
|
|
|
|
}
|
|
|
|
|
}.combine(chaptersReversed) { list, reversed ->
|
|
|
|
|
if (reversed) list.asReversed() else list
|
|
|
|
|
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
|
|
|
|
|
|
|
|
|
init {
|
|
|
|
|
@ -121,6 +132,12 @@ class DetailsViewModel(
|
|
|
|
|
?.maxByOrNull { it.value.size }?.key
|
|
|
|
|
}
|
|
|
|
|
mangaData.value = manga
|
|
|
|
|
if (manga.source == MangaSource.LOCAL) {
|
|
|
|
|
remoteManga.value = runCatching {
|
|
|
|
|
val m = localMangaRepository.getRemoteManga(manga) ?: return@runCatching null
|
|
|
|
|
MangaRepository(m.source).getDetails(m)
|
|
|
|
|
}.getOrNull()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -142,4 +159,80 @@ class DetailsViewModel(
|
|
|
|
|
fun setSelectedBranch(branch: String?) {
|
|
|
|
|
selectedBranch.value = branch
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun getRemoteManga(): Manga? {
|
|
|
|
|
return remoteManga.value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun mapChapters(
|
|
|
|
|
chapters: List<MangaChapter>,
|
|
|
|
|
currentId: Long?,
|
|
|
|
|
newCount: Int,
|
|
|
|
|
branch: String?,
|
|
|
|
|
): List<ChapterListItem> {
|
|
|
|
|
val result = ArrayList<ChapterListItem>(chapters.size)
|
|
|
|
|
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
|
|
|
|
val firstNewIndex = chapters.size - newCount
|
|
|
|
|
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
|
|
|
|
|
},
|
|
|
|
|
isMissing = false
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun mapChaptersWithSource(
|
|
|
|
|
chapters: List<MangaChapter>,
|
|
|
|
|
sourceChapters: List<MangaChapter>,
|
|
|
|
|
currentId: Long?,
|
|
|
|
|
newCount: Int,
|
|
|
|
|
branch: String?,
|
|
|
|
|
): List<ChapterListItem> {
|
|
|
|
|
val chaptersMap = chapters.associateByTo(HashMap(chapters.size)) { it.id }
|
|
|
|
|
val result = ArrayList<ChapterListItem>(sourceChapters.size)
|
|
|
|
|
val currentIndex = sourceChapters.indexOfFirst { it.id == currentId }
|
|
|
|
|
val firstNewIndex = sourceChapters.size - newCount
|
|
|
|
|
for (i in sourceChapters.indices) {
|
|
|
|
|
val chapter = sourceChapters[i]
|
|
|
|
|
if (chapter.branch != branch) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
},
|
|
|
|
|
isMissing = false
|
|
|
|
|
) ?: chapter.toListItem(
|
|
|
|
|
extra = when {
|
|
|
|
|
i >= firstNewIndex -> ChapterExtra.NEW
|
|
|
|
|
i == currentIndex -> ChapterExtra.CURRENT
|
|
|
|
|
i < currentIndex -> ChapterExtra.READ
|
|
|
|
|
else -> ChapterExtra.UNREAD
|
|
|
|
|
},
|
|
|
|
|
isMissing = true
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
result.sortBy { it.chapter.number }
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
}
|