mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Chapters graphql, reader is broken
This commit is contained in:
@@ -20,11 +20,11 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
fun newIntent(
|
fun newIntent(
|
||||||
context: Context,
|
context: Context,
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
): Intent =
|
): Intent =
|
||||||
Intent(context, ReaderActivity::class.java).apply {
|
Intent(context, ReaderActivity::class.java).apply {
|
||||||
putExtra("manga", mangaId)
|
putExtra("manga", mangaId)
|
||||||
putExtra("chapter", chapterIndex)
|
putExtra("chapter", chapterId)
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,8 +34,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
val hooks = AppComponent.getInstance(applicationContext).hooks
|
val hooks = AppComponent.getInstance(applicationContext).hooks
|
||||||
|
|
||||||
val mangaId = intent.extras!!.getLong("manga", -1)
|
val mangaId = intent.extras!!.getLong("manga", -1)
|
||||||
val chapterIndex = intent.extras!!.getInt("chapter", -1)
|
val chapterId = intent.extras!!.getLong("chapter", -1)
|
||||||
if (mangaId == -1L || chapterIndex == -1) {
|
if (mangaId == -1L || chapterId == -1L) {
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
CompositionLocalProvider(*hooks) {
|
CompositionLocalProvider(*hooks) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
ReaderMenu(
|
ReaderMenu(
|
||||||
chapterIndex = chapterIndex,
|
chapterId = chapterId,
|
||||||
mangaId = mangaId,
|
mangaId = mangaId,
|
||||||
onCloseRequest = onBackPressedDispatcher::onBackPressed,
|
onCloseRequest = onBackPressedDispatcher::onBackPressed,
|
||||||
)
|
)
|
||||||
|
|||||||
84
data/src/commonMain/graphql/Chapters.graphql
Normal file
84
data/src/commonMain/graphql/Chapters.graphql
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
fragment ChapterFragment on ChapterType {
|
||||||
|
chapterNumber
|
||||||
|
fetchedAt
|
||||||
|
id
|
||||||
|
isBookmarked
|
||||||
|
isDownloaded
|
||||||
|
isRead
|
||||||
|
lastPageRead
|
||||||
|
lastReadAt
|
||||||
|
mangaId
|
||||||
|
name
|
||||||
|
pageCount
|
||||||
|
realUrl
|
||||||
|
scanlator
|
||||||
|
sourceOrder
|
||||||
|
uploadDate
|
||||||
|
url
|
||||||
|
meta {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetChapter($id: Int!) {
|
||||||
|
chapter(id: $id) {
|
||||||
|
...ChapterFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetMangaChapters($id: Int!) {
|
||||||
|
chapters(
|
||||||
|
condition: {mangaId: $id}
|
||||||
|
orderBy: SOURCE_ORDER,
|
||||||
|
orderByType: DESC,
|
||||||
|
) {
|
||||||
|
nodes {
|
||||||
|
...ChapterFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation UpdateChapter($id: Int!, $patch: UpdateChapterPatchInput!) {
|
||||||
|
updateChapter(input: {id: $id, patch: $patch}) {
|
||||||
|
clientMutationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation UpdateChapters($id: [Int!]!, $patch: UpdateChapterPatchInput!) {
|
||||||
|
updateChapters(input: {ids: $id, patch: $patch}) {
|
||||||
|
clientMutationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation UpdateChapterMeta($id: Int!, $key: String!, $value: String!) {
|
||||||
|
setChapterMeta(input: {meta: {chapterId: $id, key: $key, value: $value}}) {
|
||||||
|
clientMutationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation DeleteDownloadedChapter($id: Int!) {
|
||||||
|
deleteDownloadedChapter(input: {id: $id}) {
|
||||||
|
clientMutationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation DeleteDownloadedChapters($ids: [Int!]!) {
|
||||||
|
deleteDownloadedChapters(input: {ids: $ids}) {
|
||||||
|
clientMutationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation FetchChapters($mangaId: Int!) {
|
||||||
|
fetchChapters(input: {mangaId: $mangaId}) {
|
||||||
|
chapters {
|
||||||
|
...ChapterFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation FetchChapterPages($id: Int!) {
|
||||||
|
fetchChapterPages(input: {chapterId: $id}) {
|
||||||
|
pages
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
package ca.gosyer.jui.data
|
package ca.gosyer.jui.data
|
||||||
|
|
||||||
import ca.gosyer.jui.core.lang.addSuffix
|
import ca.gosyer.jui.core.lang.addSuffix
|
||||||
|
import ca.gosyer.jui.data.chapter.ChapterRepositoryImpl
|
||||||
import ca.gosyer.jui.data.settings.SettingsRepositoryImpl
|
import ca.gosyer.jui.data.settings.SettingsRepositoryImpl
|
||||||
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.server.Http
|
||||||
import ca.gosyer.jui.domain.server.service.ServerPreferences
|
import ca.gosyer.jui.domain.server.service.ServerPreferences
|
||||||
import ca.gosyer.jui.domain.settings.service.SettingsRepository
|
import ca.gosyer.jui.domain.settings.service.SettingsRepository
|
||||||
@@ -50,4 +52,11 @@ interface DataComponent : SharedDataComponent {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun settingsRepository(apolloClient: ApolloClient): SettingsRepository = SettingsRepositoryImpl(apolloClient)
|
fun settingsRepository(apolloClient: ApolloClient): SettingsRepository = SettingsRepositoryImpl(apolloClient)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun chapterRepository(
|
||||||
|
apolloClient: ApolloClient,
|
||||||
|
http: Http,
|
||||||
|
serverPreferences: ServerPreferences,
|
||||||
|
): ChapterRepository = ChapterRepositoryImpl(apolloClient, http, serverPreferences.serverUrl().get())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
package ca.gosyer.jui.data.chapter
|
||||||
|
|
||||||
|
import ca.gosyer.jui.data.graphql.DeleteDownloadedChapterMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.DeleteDownloadedChaptersMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.FetchChapterPagesMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.FetchChaptersMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.GetChapterQuery
|
||||||
|
import ca.gosyer.jui.data.graphql.GetMangaChaptersQuery
|
||||||
|
import ca.gosyer.jui.data.graphql.UpdateChapterMetaMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.UpdateChapterMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.UpdateChaptersMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.fragment.ChapterFragment
|
||||||
|
import ca.gosyer.jui.data.graphql.type.UpdateChapterPatchInput
|
||||||
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
|
import ca.gosyer.jui.domain.chapter.model.ChapterMeta
|
||||||
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
|
import ca.gosyer.jui.domain.server.Http
|
||||||
|
import com.apollographql.apollo.ApolloClient
|
||||||
|
import com.apollographql.apollo.api.Optional
|
||||||
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.statement.readBytes
|
||||||
|
import io.ktor.http.Url
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
class ChapterRepositoryImpl(
|
||||||
|
private val apolloClient: ApolloClient,
|
||||||
|
private val http: Http,
|
||||||
|
private val serverUrl: Url,
|
||||||
|
) : ChapterRepository {
|
||||||
|
override fun getChapter(chapterId: Long): Flow<Chapter> {
|
||||||
|
return apolloClient.query(
|
||||||
|
GetChapterQuery(chapterId.toInt())
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
val data = it.dataAssertNoErrors
|
||||||
|
data.chapter.chapterFragment.toChapter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getChapters(mangaId: Long): Flow<List<Chapter>> {
|
||||||
|
return apolloClient.query(
|
||||||
|
GetMangaChaptersQuery(mangaId.toInt())
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
val data = it.dataAssertNoErrors
|
||||||
|
data.chapters.nodes.map { it.chapterFragment.toChapter() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateChapter(
|
||||||
|
chapterId: Long,
|
||||||
|
bookmarked: Boolean?,
|
||||||
|
read: Boolean?,
|
||||||
|
lastPageRead: Int?,
|
||||||
|
): Flow<Unit> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
UpdateChapterMutation(
|
||||||
|
chapterId.toInt(),
|
||||||
|
UpdateChapterPatchInput(
|
||||||
|
isBookmarked = Optional.presentIfNotNull(bookmarked),
|
||||||
|
isRead = Optional.presentIfNotNull(read),
|
||||||
|
lastPageRead = Optional.presentIfNotNull(lastPageRead)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
it.dataAssertNoErrors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateChapters(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
bookmarked: Boolean?,
|
||||||
|
read: Boolean?,
|
||||||
|
lastPageRead: Int?,
|
||||||
|
): Flow<Unit> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
UpdateChaptersMutation(
|
||||||
|
chapterIds.map { it.toInt() },
|
||||||
|
UpdateChapterPatchInput(
|
||||||
|
isBookmarked = Optional.presentIfNotNull(bookmarked),
|
||||||
|
isRead = Optional.presentIfNotNull(read),
|
||||||
|
lastPageRead = Optional.presentIfNotNull(lastPageRead)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
it.dataAssertNoErrors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteDownloadedChapter(
|
||||||
|
chapterId: Long,
|
||||||
|
): Flow<Unit> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
DeleteDownloadedChapterMutation(
|
||||||
|
chapterId.toInt(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
it.dataAssertNoErrors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteDownloadedChapters(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
): Flow<Unit> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
DeleteDownloadedChaptersMutation(
|
||||||
|
chapterIds.map { it.toInt() },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
it.dataAssertNoErrors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateChapterMeta(
|
||||||
|
chapterId: Long,
|
||||||
|
key: String,
|
||||||
|
value: String,
|
||||||
|
): Flow<Unit> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
UpdateChapterMetaMutation(
|
||||||
|
chapterId.toInt(),
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
it.dataAssertNoErrors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fetchChapters(
|
||||||
|
mangaId: Long,
|
||||||
|
): Flow<List<Chapter>> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
FetchChaptersMutation(
|
||||||
|
mangaId.toInt(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
val chapters = it.dataAssertNoErrors
|
||||||
|
chapters.fetchChapters.chapters.map { it.chapterFragment.toChapter() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPages(chapterId: Long): Flow<List<String>> {
|
||||||
|
return apolloClient.mutation(
|
||||||
|
FetchChapterPagesMutation(
|
||||||
|
chapterId.toInt(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
val chapters = it.dataAssertNoErrors
|
||||||
|
chapters.fetchChapterPages.pages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPage(
|
||||||
|
url: String,
|
||||||
|
block: HttpRequestBuilder.() -> Unit,
|
||||||
|
): Flow<ByteArray> {
|
||||||
|
val realUrl = Url("$serverUrl$url")
|
||||||
|
|
||||||
|
return flow { http.get(realUrl, block).readBytes() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal fun ChapterFragment.toChapter(): Chapter {
|
||||||
|
return Chapter(
|
||||||
|
id = id.toLong(),
|
||||||
|
url = url,
|
||||||
|
name = name,
|
||||||
|
uploadDate = uploadDate,
|
||||||
|
chapterNumber = chapterNumber.toFloat(),
|
||||||
|
scanlator = scanlator,
|
||||||
|
mangaId = mangaId.toLong(),
|
||||||
|
read = isRead,
|
||||||
|
bookmarked = isBookmarked,
|
||||||
|
lastPageRead = lastPageRead,
|
||||||
|
index = sourceOrder,
|
||||||
|
fetchedAt = fetchedAt,
|
||||||
|
realUrl = realUrl,
|
||||||
|
pageCount = pageCount,
|
||||||
|
lastReadAt = lastPageRead,
|
||||||
|
downloaded = isDownloaded,
|
||||||
|
meta = ChapterMeta(
|
||||||
|
juiPageOffset = meta.find { it.key == "juiPageOffset" }?.value?.toIntOrNull() ?: 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.buffer
|
import kotlinx.coroutines.flow.buffer
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
@@ -35,12 +34,7 @@ class ServerListeners
|
|||||||
)
|
)
|
||||||
val mangaListener = _mangaListener.asSharedFlow()
|
val mangaListener = _mangaListener.asSharedFlow()
|
||||||
|
|
||||||
private val _chapterIndexesListener = MutableSharedFlow<Pair<Long, List<Int>?>>(
|
private val _chapterIdsListener = MutableSharedFlow<List<Long>>(
|
||||||
extraBufferCapacity = Channel.UNLIMITED,
|
|
||||||
)
|
|
||||||
val chapterIndexesListener = _chapterIndexesListener.asSharedFlow()
|
|
||||||
|
|
||||||
private val _chapterIdsListener = MutableSharedFlow<Pair<Long?, List<Long>>>(
|
|
||||||
extraBufferCapacity = Channel.UNLIMITED,
|
extraBufferCapacity = Channel.UNLIMITED,
|
||||||
)
|
)
|
||||||
val chapterIdsListener = _chapterIdsListener.asSharedFlow()
|
val chapterIdsListener = _chapterIdsListener.asSharedFlow()
|
||||||
@@ -91,58 +85,32 @@ class ServerListeners
|
|||||||
|
|
||||||
fun <T> combineChapters(
|
fun <T> combineChapters(
|
||||||
flow: Flow<T>,
|
flow: Flow<T>,
|
||||||
indexPredate: (suspend (Long, List<Int>?) -> Boolean)? = null,
|
idPredate: (suspend (List<Long>) -> Boolean)? = null,
|
||||||
idPredate: (suspend (Long?, List<Long>) -> Boolean)? = null,
|
|
||||||
): Flow<T> {
|
): Flow<T> {
|
||||||
val indexListener = if (indexPredate != null) {
|
|
||||||
_chapterIndexesListener.filter { indexPredate(it.first, it.second) }.startWith(Unit)
|
|
||||||
} else {
|
|
||||||
_chapterIndexesListener.startWith(Unit)
|
|
||||||
}
|
|
||||||
val idsListener = if (idPredate != null) {
|
val idsListener = if (idPredate != null) {
|
||||||
_chapterIdsListener.filter { idPredate(it.first, it.second) }.startWith(Unit)
|
_chapterIdsListener.filter { idPredate(it) }.startWith(Unit)
|
||||||
} else {
|
} else {
|
||||||
_chapterIdsListener.startWith(Unit)
|
_chapterIdsListener.startWith(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
return combine(indexListener, idsListener) { _, _ -> }
|
return idsListener
|
||||||
.buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
.buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||||
.flatMapLatest { flow }
|
.flatMapLatest { flow }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateChapters(
|
fun updateChapters(
|
||||||
mangaId: Long,
|
|
||||||
chapterIndexes: List<Int>,
|
|
||||||
) {
|
|
||||||
scope.launch {
|
|
||||||
_chapterIndexesListener.emit(mangaId to chapterIndexes.ifEmpty { null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateChapters(
|
|
||||||
mangaId: Long,
|
|
||||||
vararg chapterIndexes: Int,
|
|
||||||
) {
|
|
||||||
scope.launch {
|
|
||||||
_chapterIndexesListener.emit(mangaId to chapterIndexes.toList().ifEmpty { null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateChapters(
|
|
||||||
mangaId: Long?,
|
|
||||||
chapterIds: List<Long>,
|
chapterIds: List<Long>,
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
_chapterIdsListener.emit(mangaId to chapterIds)
|
_chapterIdsListener.emit(chapterIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateChapters(
|
fun updateChapters(
|
||||||
mangaId: Long?,
|
|
||||||
vararg chapterIds: Long,
|
vararg chapterIds: Long,
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
_chapterIdsListener.emit(mangaId to chapterIds.toList())
|
_chapterIdsListener.emit(chapterIds.toList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,256 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ca.gosyer.jui.domain.chapter.interactor
|
|
||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.ChapterBatchEditInput
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.ChapterChange
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.MangaChapterBatchEditInput
|
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import me.tatarka.inject.annotations.Inject
|
|
||||||
import org.lighthousegames.logging.logging
|
|
||||||
import kotlin.jvm.JvmName
|
|
||||||
|
|
||||||
class BatchUpdateChapter
|
|
||||||
@Inject
|
|
||||||
constructor(
|
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
|
||||||
private val serverListeners: ServerListeners,
|
|
||||||
) {
|
|
||||||
@JvmName("awaitChapters")
|
|
||||||
suspend fun await(
|
|
||||||
mangaId: Long,
|
|
||||||
chapters: List<Chapter>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(mangaId, chapters, isRead, isBookmarked, lastPageRead, delete)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update multiple chapters of $mangaId" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
mangaId: Long,
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(mangaId, chapterIds, isRead, isBookmarked, lastPageRead, delete)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update multiple chapters of $mangaId" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
@JvmName("awaitChapters")
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
chapters: List<Chapter>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, chapters, isRead, isBookmarked, lastPageRead, delete)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update multiple chapters of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, chapterIds, isRead, isBookmarked, lastPageRead, delete)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update multiple chapters of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
@JvmName("awaitChapters")
|
|
||||||
suspend fun await(
|
|
||||||
chapters: List<Chapter>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(chapters, isRead, isBookmarked, lastPageRead, delete)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update multiple chapters" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(chapterIds, isRead, isBookmarked, lastPageRead, delete)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update update multiple chapters" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
@JvmName("asFlowChapters")
|
|
||||||
fun asFlow(
|
|
||||||
mangaId: Long,
|
|
||||||
chapters: List<Chapter>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = getFlow(
|
|
||||||
mangaId = mangaId,
|
|
||||||
chapterIds = chapters.map { it.id },
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
mangaId: Long,
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = getFlow(
|
|
||||||
mangaId = mangaId,
|
|
||||||
chapterIds = chapterIds,
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JvmName("asFlowChapters")
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
chapters: List<Chapter>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = getFlow(
|
|
||||||
mangaId = manga.id,
|
|
||||||
chapterIds = chapters.map { it.id },
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = getFlow(
|
|
||||||
mangaId = manga.id,
|
|
||||||
chapterIds = chapterIds,
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JvmName("asFlowChapters")
|
|
||||||
fun asFlow(
|
|
||||||
chapters: List<Chapter>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = getFlow(
|
|
||||||
mangaId = null,
|
|
||||||
chapterIds = chapters.map { it.id },
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = getFlow(
|
|
||||||
mangaId = null,
|
|
||||||
chapterIds = chapterIds,
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getFlow(
|
|
||||||
mangaId: Long?,
|
|
||||||
chapterIds: List<Long>,
|
|
||||||
isRead: Boolean? = null,
|
|
||||||
isBookmarked: Boolean? = null,
|
|
||||||
lastPageRead: Int? = null,
|
|
||||||
delete: Boolean? = null,
|
|
||||||
) = if (mangaId != null) {
|
|
||||||
chapterRepositoryOld.batchUpdateChapter(
|
|
||||||
mangaId,
|
|
||||||
MangaChapterBatchEditInput(
|
|
||||||
chapterIds = chapterIds,
|
|
||||||
change = ChapterChange(
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
chapterRepositoryOld.batchUpdateChapter(
|
|
||||||
ChapterBatchEditInput(
|
|
||||||
chapterIds = chapterIds,
|
|
||||||
change = ChapterChange(
|
|
||||||
isRead = isRead,
|
|
||||||
isBookmarked = isBookmarked,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
delete = delete,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}.onEach {
|
|
||||||
serverListeners.updateChapters(mangaId, chapterIds)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = logging()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,42 +8,31 @@ package ca.gosyer.jui.domain.chapter.interactor
|
|||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
import org.lighthousegames.logging.logging
|
import org.lighthousegames.logging.logging
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
class DeleteChapterDownload
|
class DeleteChapterDownload
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
) = asFlow(mangaId, index)
|
) = asFlow(chapterId)
|
||||||
.catch {
|
.catch {
|
||||||
onError(it)
|
onError(it)
|
||||||
log.warn(it) { "Failed to delete chapter download for $index of $mangaId" }
|
log.warn(it) { "Failed to delete chapter download for $chapterId" }
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to delete chapter download for $index of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
}
|
||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
|
@JvmName("awaitChapter")
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
chapter: Chapter,
|
chapter: Chapter,
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
@@ -54,21 +43,46 @@ class DeleteChapterDownload
|
|||||||
}
|
}
|
||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
fun asFlow(
|
suspend fun await(
|
||||||
mangaId: Long,
|
chapterIds: List<Long>,
|
||||||
index: Int,
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
) = chapterRepositoryOld.deleteChapterDownload(mangaId, index)
|
) = asFlow(chapterIds)
|
||||||
.onEach { serverListeners.updateChapters(mangaId, index) }
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to delete chapter download for $chapterIds" }
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
|
||||||
|
@JvmName("awaitChapters")
|
||||||
|
suspend fun await(
|
||||||
|
chapters: List<Chapter>,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
) = asFlow(chapters)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to delete chapter download for ${chapters.joinToString { it.id.toString() }}" }
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
manga: Manga,
|
chapterId: Long,
|
||||||
index: Int,
|
) = chapterRepository.deleteDownloadedChapter(chapterId)
|
||||||
) = chapterRepositoryOld.deleteChapterDownload(manga.id, index)
|
.onEach { serverListeners.updateChapters(chapterId) }
|
||||||
.onEach { serverListeners.updateChapters(manga.id, index) }
|
|
||||||
|
|
||||||
|
@JvmName("asFlowChapter")
|
||||||
fun asFlow(chapter: Chapter) =
|
fun asFlow(chapter: Chapter) =
|
||||||
chapterRepositoryOld.deleteChapterDownload(chapter.mangaId, chapter.index)
|
chapterRepository.deleteDownloadedChapter(chapter.id)
|
||||||
.onEach { serverListeners.updateChapters(chapter.mangaId, chapter.index) }
|
.onEach { serverListeners.updateChapters(chapter.id) }
|
||||||
|
|
||||||
|
fun asFlow(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
) = chapterRepository.deleteDownloadedChapters(chapterIds)
|
||||||
|
.onEach { serverListeners.updateChapters(chapterIds) }
|
||||||
|
|
||||||
|
@JvmName("asFlowChapters")
|
||||||
|
fun asFlow(chapter: List<Chapter>) =
|
||||||
|
chapterRepository.deleteDownloadedChapters(chapter.map { it.id })
|
||||||
|
.onEach { serverListeners.updateChapters(chapter.map { it.id }) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = logging()
|
private val log = logging()
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ package ca.gosyer.jui.domain.chapter.interactor
|
|||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.singleOrNull
|
import kotlinx.coroutines.flow.singleOrNull
|
||||||
import kotlinx.coroutines.flow.take
|
import kotlinx.coroutines.flow.take
|
||||||
@@ -19,30 +18,17 @@ import org.lighthousegames.logging.logging
|
|||||||
class GetChapter
|
class GetChapter
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
) = asFlow(mangaId, index)
|
) = asFlow(chapterId)
|
||||||
.take(1)
|
.take(1)
|
||||||
.catch {
|
.catch {
|
||||||
onError(it)
|
onError(it)
|
||||||
log.warn(it) { "Failed to get chapter $index for $mangaId" }
|
log.warn(it) { "Failed to get chapter $chapterId" }
|
||||||
}
|
|
||||||
.singleOrNull()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index)
|
|
||||||
.take(1)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to get chapter $index for ${manga.title}(${manga.id})" }
|
|
||||||
}
|
}
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
|
|
||||||
@@ -58,34 +44,16 @@ class GetChapter
|
|||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
) = serverListeners.combineChapters(
|
) = serverListeners.combineChapters(
|
||||||
chapterRepositoryOld.getChapter(mangaId, index),
|
chapterRepository.getChapter(chapterId),
|
||||||
indexPredate = { id, chapterIndexes ->
|
idPredate = { ids -> chapterId in ids },
|
||||||
id == mangaId && (chapterIndexes == null || index in chapterIndexes)
|
|
||||||
},
|
|
||||||
idPredate = { id, _ -> id == mangaId },
|
|
||||||
)
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
) = serverListeners.combineChapters(
|
|
||||||
chapterRepositoryOld.getChapter(manga.id, index),
|
|
||||||
indexPredate = { id, chapterIndexes ->
|
|
||||||
id == manga.id && (chapterIndexes == null || index in chapterIndexes)
|
|
||||||
},
|
|
||||||
idPredate = { id, _ -> id == manga.id },
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun asFlow(chapter: Chapter) =
|
fun asFlow(chapter: Chapter) =
|
||||||
serverListeners.combineChapters(
|
serverListeners.combineChapters(
|
||||||
chapterRepositoryOld.getChapter(chapter.mangaId, chapter.index),
|
chapterRepository.getChapter(chapter.id),
|
||||||
indexPredate = { id, chapterIndexes ->
|
idPredate = { ids -> chapter.id in ids },
|
||||||
id == chapter.mangaId && (chapterIndexes == null || chapter.index in chapterIndexes)
|
|
||||||
},
|
|
||||||
idPredate = { id, _ -> id == chapter.mangaId },
|
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ca.gosyer.jui.domain.chapter.interactor
|
|
||||||
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import io.ktor.client.request.HttpRequestBuilder
|
|
||||||
import kotlinx.coroutines.flow.catch
|
|
||||||
import kotlinx.coroutines.flow.singleOrNull
|
|
||||||
import me.tatarka.inject.annotations.Inject
|
|
||||||
import org.lighthousegames.logging.logging
|
|
||||||
|
|
||||||
class GetChapterPage
|
|
||||||
@Inject
|
|
||||||
constructor(
|
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
|
||||||
) {
|
|
||||||
suspend fun await(
|
|
||||||
mangaId: Long,
|
|
||||||
index: Int,
|
|
||||||
pageNum: Int,
|
|
||||||
block: HttpRequestBuilder.() -> Unit,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(mangaId, index, pageNum, block)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to get page $pageNum for chapter $index for $mangaId" }
|
|
||||||
}
|
|
||||||
.singleOrNull()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
pageNum: Int,
|
|
||||||
block: HttpRequestBuilder.() -> Unit,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index, pageNum, block)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to get page $pageNum for chapter $index for ${manga.title}(${manga.id})" }
|
|
||||||
}
|
|
||||||
.singleOrNull()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
chapter: Chapter,
|
|
||||||
pageNum: Int,
|
|
||||||
block: HttpRequestBuilder.() -> Unit,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(chapter, pageNum, block)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to get page $pageNum for chapter ${chapter.index} for ${chapter.mangaId}" }
|
|
||||||
}
|
|
||||||
.singleOrNull()
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
mangaId: Long,
|
|
||||||
index: Int,
|
|
||||||
pageNum: Int,
|
|
||||||
block: HttpRequestBuilder.() -> Unit,
|
|
||||||
) = chapterRepositoryOld.getPage(mangaId, index, pageNum, block)
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
pageNum: Int,
|
|
||||||
block: HttpRequestBuilder.() -> Unit,
|
|
||||||
) = chapterRepositoryOld.getPage(manga.id, index, pageNum, block)
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
chapter: Chapter,
|
|
||||||
pageNum: Int,
|
|
||||||
block: HttpRequestBuilder.() -> Unit,
|
|
||||||
) = chapterRepositoryOld.getPage(chapter.mangaId, chapter.index, pageNum, block)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = logging()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ca.gosyer.jui.domain.chapter.interactor
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.singleOrNull
|
||||||
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
import org.lighthousegames.logging.logging
|
||||||
|
|
||||||
|
class GetChapterPages
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val chapterRepository: ChapterRepository,
|
||||||
|
) {
|
||||||
|
suspend fun await(
|
||||||
|
chapterId: Long,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
) = asFlow(chapterId)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to get pages for $chapterId" }
|
||||||
|
}
|
||||||
|
.singleOrNull()
|
||||||
|
|
||||||
|
suspend fun await(
|
||||||
|
url: String,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
block: HttpRequestBuilder.() -> Unit,
|
||||||
|
) = asFlow(url, block)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to get page $url" }
|
||||||
|
}
|
||||||
|
.singleOrNull()
|
||||||
|
|
||||||
|
fun asFlow(
|
||||||
|
chapterId: Long,
|
||||||
|
) = chapterRepository.getPages(chapterId)
|
||||||
|
|
||||||
|
fun asFlow(
|
||||||
|
url: String,
|
||||||
|
block: HttpRequestBuilder.() -> Unit,
|
||||||
|
) = chapterRepository.getPage(url, block)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log = logging()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
package ca.gosyer.jui.domain.chapter.interactor
|
package ca.gosyer.jui.domain.chapter.interactor
|
||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.singleOrNull
|
import kotlinx.coroutines.flow.singleOrNull
|
||||||
@@ -18,7 +18,7 @@ import org.lighthousegames.logging.logging
|
|||||||
class GetChapters
|
class GetChapters
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
@@ -45,16 +45,14 @@ class GetChapters
|
|||||||
|
|
||||||
fun asFlow(mangaId: Long) =
|
fun asFlow(mangaId: Long) =
|
||||||
serverListeners.combineChapters(
|
serverListeners.combineChapters(
|
||||||
chapterRepositoryOld.getChapters(mangaId),
|
chapterRepository.getChapters(mangaId),
|
||||||
indexPredate = { id, _ -> id == mangaId },
|
idPredate = { ids -> false }, // todo
|
||||||
idPredate = { id, _ -> id == mangaId },
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun asFlow(manga: Manga) =
|
fun asFlow(manga: Manga) =
|
||||||
serverListeners.combineChapters(
|
serverListeners.combineChapters(
|
||||||
chapterRepositoryOld.getChapters(manga.id),
|
chapterRepository.getChapters(manga.id),
|
||||||
indexPredate = { id, _ -> id == manga.id },
|
idPredate = { ids -> false }, // todo
|
||||||
idPredate = { id, _ -> id == manga.id },
|
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
package ca.gosyer.jui.domain.chapter.interactor
|
package ca.gosyer.jui.domain.chapter.interactor
|
||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -18,7 +18,7 @@ import org.lighthousegames.logging.logging
|
|||||||
class RefreshChapters
|
class RefreshChapters
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
@@ -42,11 +42,11 @@ class RefreshChapters
|
|||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
|
|
||||||
fun asFlow(mangaId: Long) =
|
fun asFlow(mangaId: Long) =
|
||||||
chapterRepositoryOld.getChapters(mangaId, true)
|
chapterRepository.fetchChapters(mangaId)
|
||||||
.onEach { serverListeners.updateChapters(mangaId) }
|
.onEach { serverListeners.updateChapters(mangaId) }
|
||||||
|
|
||||||
fun asFlow(manga: Manga) =
|
fun asFlow(manga: Manga) =
|
||||||
chapterRepositoryOld.getChapters(manga.id, true)
|
chapterRepository.fetchChapters(manga.id)
|
||||||
.onEach { serverListeners.updateChapters(manga.id) }
|
.onEach { serverListeners.updateChapters(manga.id) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ca.gosyer.jui.domain.chapter.interactor
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
import org.lighthousegames.logging.logging
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
|
class UpdateChapter
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val chapterRepository: ChapterRepository,
|
||||||
|
private val serverListeners: ServerListeners,
|
||||||
|
) {
|
||||||
|
suspend fun await(
|
||||||
|
chapterId: Long,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
) = asFlow(chapterId, bookmarked, read, lastPageRead)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to update chapter bookmark for chapter $chapterId" }
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
|
||||||
|
suspend fun await(
|
||||||
|
chapter: Chapter,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
) = asFlow(chapter, bookmarked, read, lastPageRead)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to update chapter bookmark for chapter ${chapter.index} of ${chapter.mangaId}" }
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
|
||||||
|
suspend fun await(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
) = asFlow(chapterIds, bookmarked, read, lastPageRead)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to update chapter bookmark for chapters $chapterIds" }
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
|
||||||
|
@JvmName("awaitChapters")
|
||||||
|
suspend fun await(
|
||||||
|
chapters: List<Chapter>,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
|
) = asFlow(chapters, bookmarked, read, lastPageRead)
|
||||||
|
.catch {
|
||||||
|
onError(it)
|
||||||
|
log.warn(it) { "Failed to update chapter bookmark for chapters ${chapters.joinToString { it.id.toString() }}" }
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
|
||||||
|
fun asFlow(
|
||||||
|
chapterId: Long,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
) = chapterRepository.updateChapter(
|
||||||
|
chapterId = chapterId,
|
||||||
|
bookmarked = bookmarked,
|
||||||
|
read = read,
|
||||||
|
lastPageRead = lastPageRead,
|
||||||
|
).onEach { serverListeners.updateChapters(chapterId) }
|
||||||
|
|
||||||
|
fun asFlow(
|
||||||
|
chapter: Chapter,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null
|
||||||
|
) = chapterRepository.updateChapter(
|
||||||
|
chapterId = chapter.id,
|
||||||
|
bookmarked = bookmarked,
|
||||||
|
read = read,
|
||||||
|
lastPageRead = lastPageRead,
|
||||||
|
).onEach { serverListeners.updateChapters(chapter.id) }
|
||||||
|
|
||||||
|
fun asFlow(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
) = chapterRepository.updateChapters(
|
||||||
|
chapterIds = chapterIds,
|
||||||
|
bookmarked = bookmarked,
|
||||||
|
read = read,
|
||||||
|
lastPageRead = lastPageRead,
|
||||||
|
).onEach { serverListeners.updateChapters(chapterIds) }
|
||||||
|
|
||||||
|
@JvmName("asFlowChapters")
|
||||||
|
fun asFlow(
|
||||||
|
chapters: List<Chapter>,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null
|
||||||
|
) = chapterRepository.updateChapters(
|
||||||
|
chapterIds = chapters.map { it.id },
|
||||||
|
bookmarked = bookmarked,
|
||||||
|
read = read,
|
||||||
|
lastPageRead = lastPageRead,
|
||||||
|
).onEach { serverListeners.updateChapters(chapters.map { it.id }) }
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log = logging()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ca.gosyer.jui.domain.chapter.interactor
|
|
||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import me.tatarka.inject.annotations.Inject
|
|
||||||
import org.lighthousegames.logging.logging
|
|
||||||
|
|
||||||
class UpdateChapterBookmarked
|
|
||||||
@Inject
|
|
||||||
constructor(
|
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
|
||||||
private val serverListeners: ServerListeners,
|
|
||||||
) {
|
|
||||||
suspend fun await(
|
|
||||||
mangaId: Long,
|
|
||||||
index: Int,
|
|
||||||
bookmarked: Boolean,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(mangaId, index, bookmarked)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter bookmark for chapter $index of $mangaId" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
bookmarked: Boolean,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index, bookmarked)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter bookmark for chapter $index of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
chapter: Chapter,
|
|
||||||
bookmarked: Boolean,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(chapter, bookmarked)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter bookmark for chapter ${chapter.index} of ${chapter.mangaId}" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
mangaId: Long,
|
|
||||||
index: Int,
|
|
||||||
bookmarked: Boolean,
|
|
||||||
) = chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = mangaId,
|
|
||||||
chapterIndex = index,
|
|
||||||
bookmarked = bookmarked,
|
|
||||||
).onEach { serverListeners.updateChapters(mangaId, index) }
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
bookmarked: Boolean,
|
|
||||||
) = chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = manga.id,
|
|
||||||
chapterIndex = index,
|
|
||||||
bookmarked = bookmarked,
|
|
||||||
).onEach { serverListeners.updateChapters(manga.id, index) }
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
chapter: Chapter,
|
|
||||||
bookmarked: Boolean,
|
|
||||||
) = chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = chapter.mangaId,
|
|
||||||
chapterIndex = chapter.index,
|
|
||||||
bookmarked = bookmarked,
|
|
||||||
).onEach { serverListeners.updateChapters(chapter.mangaId, chapter.index) }
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = logging()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,8 +8,7 @@ package ca.gosyer.jui.domain.chapter.interactor
|
|||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -19,30 +18,17 @@ import org.lighthousegames.logging.logging
|
|||||||
class UpdateChapterLastPageRead
|
class UpdateChapterLastPageRead
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
lastPageRead: Int,
|
lastPageRead: Int,
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
) = asFlow(mangaId, index, lastPageRead)
|
) = asFlow(chapterId, lastPageRead)
|
||||||
.catch {
|
.catch {
|
||||||
onError(it)
|
onError(it)
|
||||||
log.warn(it) { "Failed to update chapter last page read for chapter $index of $mangaId" }
|
log.warn(it) { "Failed to update chapter last page read for chapter $chapterId" }
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
lastPageRead: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index, lastPageRead)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter last page read for chapter $index of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
}
|
||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
@@ -58,33 +44,20 @@ class UpdateChapterLastPageRead
|
|||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
lastPageRead: Int,
|
lastPageRead: Int,
|
||||||
) = chapterRepositoryOld.updateChapter(
|
) = chapterRepository.updateChapter(
|
||||||
mangaId = mangaId,
|
chapterId = chapterId,
|
||||||
chapterIndex = index,
|
|
||||||
lastPageRead = lastPageRead,
|
lastPageRead = lastPageRead,
|
||||||
).onEach { serverListeners.updateChapters(mangaId, index) }
|
).onEach { serverListeners.updateChapters(chapterId) }
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
lastPageRead: Int,
|
|
||||||
) = chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = manga.id,
|
|
||||||
chapterIndex = index,
|
|
||||||
lastPageRead = lastPageRead,
|
|
||||||
).onEach { serverListeners.updateChapters(manga.id, index) }
|
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
chapter: Chapter,
|
chapter: Chapter,
|
||||||
lastPageRead: Int,
|
lastPageRead: Int,
|
||||||
) = chapterRepositoryOld.updateChapter(
|
) = chapterRepository.updateChapter(
|
||||||
mangaId = chapter.mangaId,
|
chapterId = chapter.id,
|
||||||
chapterIndex = chapter.index,
|
|
||||||
lastPageRead = lastPageRead,
|
lastPageRead = lastPageRead,
|
||||||
).onEach { serverListeners.updateChapters(chapter.mangaId, chapter.index) }
|
).onEach { serverListeners.updateChapters(chapter.id) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = logging()
|
private val log = logging()
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ca.gosyer.jui.domain.chapter.interactor
|
|
||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import me.tatarka.inject.annotations.Inject
|
|
||||||
import org.lighthousegames.logging.logging
|
|
||||||
|
|
||||||
class UpdateChapterMarkPreviousRead
|
|
||||||
@Inject
|
|
||||||
constructor(
|
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
|
||||||
private val serverListeners: ServerListeners,
|
|
||||||
) {
|
|
||||||
suspend fun await(
|
|
||||||
mangaId: Long,
|
|
||||||
index: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(mangaId, index)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter read status for chapter $index of $mangaId" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter read status for chapter $index of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
chapter: Chapter,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(chapter)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter read status for chapter ${chapter.index} of ${chapter.mangaId}" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
mangaId: Long,
|
|
||||||
index: Int,
|
|
||||||
) = chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = mangaId,
|
|
||||||
chapterIndex = index,
|
|
||||||
markPreviousRead = true,
|
|
||||||
).onEach { serverListeners.updateChapters(mangaId, index) }
|
|
||||||
|
|
||||||
fun asFlow(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
) = chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = manga.id,
|
|
||||||
chapterIndex = index,
|
|
||||||
markPreviousRead = true,
|
|
||||||
).onEach { serverListeners.updateChapters(manga.id, index) }
|
|
||||||
|
|
||||||
fun asFlow(chapter: Chapter) =
|
|
||||||
chapterRepositoryOld.updateChapter(
|
|
||||||
mangaId = chapter.mangaId,
|
|
||||||
chapterIndex = chapter.index,
|
|
||||||
markPreviousRead = true,
|
|
||||||
).onEach { serverListeners.updateChapters(chapter.mangaId, chapter.index) }
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = logging()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ package ca.gosyer.jui.domain.chapter.interactor
|
|||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
@@ -18,7 +18,7 @@ import org.lighthousegames.logging.logging
|
|||||||
class UpdateChapterMeta
|
class UpdateChapterMeta
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
@@ -37,13 +37,12 @@ class UpdateChapterMeta
|
|||||||
pageOffset: Int = chapter.meta.juiPageOffset,
|
pageOffset: Int = chapter.meta.juiPageOffset,
|
||||||
) = flow {
|
) = flow {
|
||||||
if (pageOffset != chapter.meta.juiPageOffset) {
|
if (pageOffset != chapter.meta.juiPageOffset) {
|
||||||
chapterRepositoryOld.updateChapterMeta(
|
chapterRepository.updateChapterMeta(
|
||||||
chapter.mangaId,
|
chapter.id,
|
||||||
chapter.index,
|
|
||||||
"juiPageOffset",
|
"juiPageOffset",
|
||||||
pageOffset.toString(),
|
pageOffset.toString(),
|
||||||
).collect()
|
).collect()
|
||||||
serverListeners.updateChapters(chapter.mangaId, chapter.index)
|
serverListeners.updateChapters(chapter.id)
|
||||||
}
|
}
|
||||||
emit(Unit)
|
emit(Unit)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ package ca.gosyer.jui.domain.chapter.interactor
|
|||||||
|
|
||||||
import ca.gosyer.jui.domain.ServerListeners
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepositoryOld
|
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -19,30 +18,17 @@ import org.lighthousegames.logging.logging
|
|||||||
class UpdateChapterRead
|
class UpdateChapterRead
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val chapterRepositoryOld: ChapterRepositoryOld,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val serverListeners: ServerListeners,
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
onError: suspend (Throwable) -> Unit = {},
|
||||||
) = asFlow(mangaId, index, read)
|
) = asFlow(chapterId, read)
|
||||||
.catch {
|
.catch {
|
||||||
onError(it)
|
onError(it)
|
||||||
log.warn(it) { "Failed to update chapter read status for chapter $index of $mangaId" }
|
log.warn(it) { "Failed to update chapter read status for chapter $chapterId" }
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
suspend fun await(
|
|
||||||
manga: Manga,
|
|
||||||
index: Int,
|
|
||||||
read: Boolean,
|
|
||||||
onError: suspend (Throwable) -> Unit = {},
|
|
||||||
) = asFlow(manga, index, read)
|
|
||||||
.catch {
|
|
||||||
onError(it)
|
|
||||||
log.warn(it) { "Failed to update chapter read status for chapter $index of ${manga.title}(${manga.id})" }
|
|
||||||
}
|
}
|
||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
@@ -58,33 +44,28 @@ class UpdateChapterRead
|
|||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
mangaId: Long,
|
chapterId: Long,
|
||||||
index: Int,
|
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
) = chapterRepositoryOld.updateChapter(
|
) = chapterRepository.updateChapter(
|
||||||
mangaId = mangaId,
|
chapterId = chapterId,
|
||||||
chapterIndex = index,
|
|
||||||
read = read,
|
read = read,
|
||||||
).onEach { serverListeners.updateChapters(mangaId, index) }
|
).onEach { serverListeners.updateChapters(chapterId) }
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
manga: Manga,
|
chapterIds: List<Long>,
|
||||||
index: Int,
|
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
) = chapterRepositoryOld.updateChapter(
|
) = chapterRepository.updateChapters(
|
||||||
mangaId = manga.id,
|
chapterIds = chapterIds,
|
||||||
chapterIndex = index,
|
|
||||||
read = read,
|
read = read,
|
||||||
).onEach { serverListeners.updateChapters(manga.id, index) }
|
).onEach { serverListeners.updateChapters(chapterIds) }
|
||||||
|
|
||||||
fun asFlow(
|
fun asFlow(
|
||||||
chapter: Chapter,
|
chapter: Chapter,
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
) = chapterRepositoryOld.updateChapter(
|
) = chapterRepository.updateChapter(
|
||||||
mangaId = chapter.mangaId,
|
chapterId = chapter.id,
|
||||||
chapterIndex = chapter.index,
|
|
||||||
read = read,
|
read = read,
|
||||||
).onEach { serverListeners.updateChapters(chapter.mangaId, chapter.index) }
|
).onEach { serverListeners.updateChapters(chapter.id) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = logging()
|
private val log = logging()
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ data class Chapter(
|
|||||||
val index: Int,
|
val index: Int,
|
||||||
val fetchedAt: Long,
|
val fetchedAt: Long,
|
||||||
val realUrl: String?,
|
val realUrl: String?,
|
||||||
val chapterCount: Int?,
|
|
||||||
val pageCount: Int?,
|
val pageCount: Int?,
|
||||||
val lastReadAt: Int?,
|
val lastReadAt: Int?,
|
||||||
val downloaded: Boolean,
|
val downloaded: Boolean,
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package ca.gosyer.jui.domain.chapter.service
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface ChapterRepository {
|
||||||
|
fun getChapter(
|
||||||
|
chapterId: Long,
|
||||||
|
): Flow<Chapter>
|
||||||
|
|
||||||
|
fun getChapters(
|
||||||
|
mangaId: Long,
|
||||||
|
): Flow<List<Chapter>>
|
||||||
|
|
||||||
|
fun updateChapter(
|
||||||
|
chapterId: Long,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
): Flow<Unit>
|
||||||
|
|
||||||
|
fun updateChapters(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
bookmarked: Boolean? = null,
|
||||||
|
read: Boolean? = null,
|
||||||
|
lastPageRead: Int? = null,
|
||||||
|
): Flow<Unit>
|
||||||
|
|
||||||
|
fun deleteDownloadedChapter(
|
||||||
|
chapterId: Long,
|
||||||
|
): Flow<Unit>
|
||||||
|
|
||||||
|
fun deleteDownloadedChapters(
|
||||||
|
chapterIds: List<Long>,
|
||||||
|
): Flow<Unit>
|
||||||
|
|
||||||
|
fun updateChapterMeta(
|
||||||
|
chapterId: Long,
|
||||||
|
key: String,
|
||||||
|
value: String,
|
||||||
|
): Flow<Unit>
|
||||||
|
|
||||||
|
fun fetchChapters(
|
||||||
|
mangaId: Long,
|
||||||
|
): Flow<List<Chapter>>
|
||||||
|
|
||||||
|
fun getPages(
|
||||||
|
chapterId: Long,
|
||||||
|
): Flow<List<String>>
|
||||||
|
|
||||||
|
fun getPage(
|
||||||
|
url: String,
|
||||||
|
block: HttpRequestBuilder.() -> Unit,
|
||||||
|
): Flow<ByteArray>
|
||||||
|
}
|
||||||
@@ -81,7 +81,7 @@ class UpdatesPager
|
|||||||
updates.filterIsInstance<Updates.Update>().map { it.manga.id }
|
updates.filterIsInstance<Updates.Update>().map { it.manga.id }
|
||||||
}.stateIn(this, SharingStarted.Eagerly, emptyList())
|
}.stateIn(this, SharingStarted.Eagerly, emptyList())
|
||||||
private val chapterIds = foldedUpdates.map { updates ->
|
private val chapterIds = foldedUpdates.map { updates ->
|
||||||
updates.filterIsInstance<Updates.Update>().map { Triple(it.manga.id, it.chapter.index, it.chapter.id) }
|
updates.filterIsInstance<Updates.Update>().map { it.chapter.id }
|
||||||
}.stateIn(this, SharingStarted.Eagerly, emptyList())
|
}.stateIn(this, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
private val changedManga = serverListeners.mangaListener.runningFold(emptyMap<Long, Manga>()) { manga, updatedMangaIds ->
|
private val changedManga = serverListeners.mangaListener.runningFold(emptyMap<Long, Manga>()) { manga, updatedMangaIds ->
|
||||||
@@ -97,36 +97,12 @@ class UpdatesPager
|
|||||||
private val changedChapters = MutableStateFlow(emptyMap<Long, Chapter>())
|
private val changedChapters = MutableStateFlow(emptyMap<Long, Chapter>())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
serverListeners.chapterIndexesListener
|
|
||||||
.onEach { (mangaId, chapterIndexes) ->
|
|
||||||
if (chapterIndexes == null) {
|
|
||||||
val chapters = coroutineScope {
|
|
||||||
foldedUpdates.value.filterIsInstance<Updates.Update>().filter { it.manga.id == mangaId }.map {
|
|
||||||
async {
|
|
||||||
getChapter.await(it.manga.id, it.chapter.index)
|
|
||||||
}
|
|
||||||
}.awaitAll().filterNotNull().associateBy { it.id }
|
|
||||||
}
|
|
||||||
changedChapters.update { it + chapters }
|
|
||||||
} else {
|
|
||||||
val chapters = coroutineScope {
|
|
||||||
chapterIndexes.mapNotNull { index -> chapterIds.value.find { it.first == mangaId && it.second == index } }
|
|
||||||
.map {
|
|
||||||
async {
|
|
||||||
getChapter.await(it.first, it.second)
|
|
||||||
}
|
|
||||||
}.awaitAll().filterNotNull().associateBy { it.id }
|
|
||||||
}
|
|
||||||
changedChapters.update { it + chapters }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.launchIn(this)
|
|
||||||
serverListeners.chapterIdsListener
|
serverListeners.chapterIdsListener
|
||||||
.onEach { (_, updatedChapterIds) ->
|
.onEach { updatedChapterIds ->
|
||||||
val chapters = coroutineScope {
|
val chapters = coroutineScope {
|
||||||
updatedChapterIds.mapNotNull { id -> chapterIds.value.find { it.third == id } }.map {
|
updatedChapterIds.mapNotNull { id -> chapterIds.value.find { it == id } }.map {
|
||||||
async {
|
async {
|
||||||
getChapter.await(it.first, it.second)
|
getChapter.await(it)
|
||||||
}
|
}
|
||||||
}.awaitAll().filterNotNull().associateBy { it.id }
|
}.awaitAll().filterNotNull().associateBy { it.id }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ actual class ReaderLauncher(
|
|||||||
private val context: Context,
|
private val context: Context,
|
||||||
) {
|
) {
|
||||||
actual fun launch(
|
actual fun launch(
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
) {
|
) {
|
||||||
Intent(context, Class.forName("ca.gosyer.jui.android.ReaderActivity")).apply {
|
Intent(context, Class.forName("ca.gosyer.jui.android.ReaderActivity")).apply {
|
||||||
putExtra("manga", mangaId)
|
putExtra("manga", mangaId)
|
||||||
putExtra("chapter", chapterIndex)
|
putExtra("chapter", chapterId)
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
}.let(context::startActivity)
|
}.let(context::startActivity)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ import ca.gosyer.jui.domain.category.interactor.GetCategories
|
|||||||
import ca.gosyer.jui.domain.category.interactor.GetMangaCategories
|
import ca.gosyer.jui.domain.category.interactor.GetMangaCategories
|
||||||
import ca.gosyer.jui.domain.category.interactor.RemoveMangaFromCategory
|
import ca.gosyer.jui.domain.category.interactor.RemoveMangaFromCategory
|
||||||
import ca.gosyer.jui.domain.category.model.Category
|
import ca.gosyer.jui.domain.category.model.Category
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.BatchUpdateChapter
|
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.DeleteChapterDownload
|
import ca.gosyer.jui.domain.chapter.interactor.DeleteChapterDownload
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapters
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapters
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.RefreshChapters
|
import ca.gosyer.jui.domain.chapter.interactor.RefreshChapters
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterMarkPreviousRead
|
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapter
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.download.interactor.BatchChapterDownload
|
import ca.gosyer.jui.domain.download.interactor.BatchChapterDownload
|
||||||
import ca.gosyer.jui.domain.download.interactor.QueueChapterDownload
|
import ca.gosyer.jui.domain.download.interactor.QueueChapterDownload
|
||||||
@@ -63,8 +62,7 @@ class MangaScreenViewModel
|
|||||||
private val refreshManga: RefreshManga,
|
private val refreshManga: RefreshManga,
|
||||||
private val getChapters: GetChapters,
|
private val getChapters: GetChapters,
|
||||||
private val refreshChapters: RefreshChapters,
|
private val refreshChapters: RefreshChapters,
|
||||||
private val batchUpdateChapter: BatchUpdateChapter,
|
private val updateChapter: UpdateChapter,
|
||||||
private val updateChapterMarkPreviousRead: UpdateChapterMarkPreviousRead,
|
|
||||||
private val queueChapterDownload: QueueChapterDownload,
|
private val queueChapterDownload: QueueChapterDownload,
|
||||||
private val stopChapterDownload: StopChapterDownload,
|
private val stopChapterDownload: StopChapterDownload,
|
||||||
private val deleteChapterDownload: DeleteChapterDownload,
|
private val deleteChapterDownload: DeleteChapterDownload,
|
||||||
@@ -253,8 +251,8 @@ class MangaScreenViewModel
|
|||||||
read: Boolean,
|
read: Boolean,
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
manga.value?.let { manga ->
|
manga.value?.let {
|
||||||
batchUpdateChapter.await(manga, chapterIds, isRead = read, onError = { toast(it.message.orEmpty()) })
|
updateChapter.await(chapterIds, read = read, onError = { toast(it.message.orEmpty()) })
|
||||||
_selectedIds.value = persistentListOf()
|
_selectedIds.value = persistentListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,8 +267,8 @@ class MangaScreenViewModel
|
|||||||
bookmark: Boolean,
|
bookmark: Boolean,
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
manga.value?.let { manga ->
|
manga.value?.let {
|
||||||
batchUpdateChapter.await(manga, chapterIds, isBookmarked = bookmark, onError = { toast(it.message.orEmpty()) })
|
updateChapter.await(chapterIds, bookmarked = bookmark, onError = { toast(it.message.orEmpty()) })
|
||||||
_selectedIds.value = persistentListOf()
|
_selectedIds.value = persistentListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,8 +280,11 @@ class MangaScreenViewModel
|
|||||||
|
|
||||||
fun markPreviousRead(index: Int) {
|
fun markPreviousRead(index: Int) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
manga.value?.let { manga ->
|
manga.value?.let {
|
||||||
updateChapterMarkPreviousRead.await(manga, index, onError = { toast(it.message.orEmpty()) })
|
val chapters = chapters.value
|
||||||
|
.sortedBy { it.chapter.index }
|
||||||
|
.subList(0, index).map{it.chapter.id} // todo test
|
||||||
|
updateChapter.await(chapters, read = true, onError = { toast(it.message.orEmpty()) })
|
||||||
_selectedIds.value = persistentListOf()
|
_selectedIds.value = persistentListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,9 +299,8 @@ class MangaScreenViewModel
|
|||||||
fun deleteDownload(id: Long?) {
|
fun deleteDownload(id: Long?) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
val manga = _manga.value ?: return@launch
|
|
||||||
val chapterIds = _selectedIds.value
|
val chapterIds = _selectedIds.value
|
||||||
batchUpdateChapter.await(manga, chapterIds, delete = true, onError = { toast(it.message.orEmpty()) })
|
deleteChapterDownload.await(chapterIds, onError = { toast(it.message.orEmpty()) })
|
||||||
selectedItems.value.forEach {
|
selectedItems.value.forEach {
|
||||||
it.setNotDownloaded()
|
it.setNotDownloaded()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ expect fun Modifier.chapterItemModifier(
|
|||||||
fun ChapterItem(
|
fun ChapterItem(
|
||||||
chapterDownload: ChapterDownloadItem,
|
chapterDownload: ChapterDownloadItem,
|
||||||
format: (Instant) -> String,
|
format: (Instant) -> String,
|
||||||
onClick: (Int) -> Unit,
|
onClick: (Long) -> Unit,
|
||||||
markRead: (Long) -> Unit,
|
markRead: (Long) -> Unit,
|
||||||
markUnread: (Long) -> Unit,
|
markUnread: (Long) -> Unit,
|
||||||
bookmarkChapter: (Long) -> Unit,
|
bookmarkChapter: (Long) -> Unit,
|
||||||
@@ -78,7 +78,7 @@ fun ChapterItem(
|
|||||||
.height(70.dp)
|
.height(70.dp)
|
||||||
.selectedBackground(isSelected)
|
.selectedBackground(isSelected)
|
||||||
.chapterItemModifier(
|
.chapterItemModifier(
|
||||||
onClick = { onClick(chapter.index) },
|
onClick = { onClick(chapter.id) },
|
||||||
markRead = { markRead(chapter.id) }.takeUnless { chapter.read },
|
markRead = { markRead(chapter.id) }.takeUnless { chapter.read },
|
||||||
markUnread = { markUnread(chapter.id) }.takeIf { chapter.read },
|
markUnread = { markUnread(chapter.id) }.takeIf { chapter.read },
|
||||||
bookmarkChapter = { bookmarkChapter(chapter.id) }.takeUnless { chapter.bookmarked },
|
bookmarkChapter = { bookmarkChapter(chapter.id) }.takeUnless { chapter.bookmarked },
|
||||||
|
|||||||
@@ -228,11 +228,9 @@ fun MangaScreenContent(
|
|||||||
onClick = if (inActionMode) {
|
onClick = if (inActionMode) {
|
||||||
{
|
{
|
||||||
if (chapter.isSelected.value) {
|
if (chapter.isSelected.value) {
|
||||||
onUnselectChapter(
|
onUnselectChapter(it)
|
||||||
chapter.chapter.id,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
onSelectChapter(chapter.chapter.id)
|
onSelectChapter(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.ui.reader
|
package ca.gosyer.jui.ui.reader
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPages
|
||||||
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.server.Http
|
||||||
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
||||||
@@ -26,6 +27,7 @@ class ChapterLoader(
|
|||||||
private val http: Http,
|
private val http: Http,
|
||||||
private val chapterCache: DiskCache,
|
private val chapterCache: DiskCache,
|
||||||
private val bitmapDecoderFactory: BitmapDecoderFactory,
|
private val bitmapDecoderFactory: BitmapDecoderFactory,
|
||||||
|
private val getChapterPages: GetChapterPages,
|
||||||
) {
|
) {
|
||||||
fun loadChapter(chapter: ReaderChapter): StateFlow<PagesState> {
|
fun loadChapter(chapter: ReaderChapter): StateFlow<PagesState> {
|
||||||
if (chapterIsReady(chapter)) {
|
if (chapterIsReady(chapter)) {
|
||||||
@@ -34,7 +36,7 @@ class ChapterLoader(
|
|||||||
chapter.state = ReaderChapter.State.Loading
|
chapter.state = ReaderChapter.State.Loading
|
||||||
log.debug { "Loading pages for ${chapter.chapter.name}" }
|
log.debug { "Loading pages for ${chapter.chapter.name}" }
|
||||||
|
|
||||||
val loader = TachideskPageLoader(chapter, readerPreferences, http, chapterCache, bitmapDecoderFactory)
|
val loader = TachideskPageLoader(chapter, readerPreferences, http, chapterCache, bitmapDecoderFactory, getChapterPages)
|
||||||
|
|
||||||
val pages = loader.getPages()
|
val pages = loader.getPages()
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
expect class ReaderLauncher {
|
expect class ReaderLauncher {
|
||||||
fun launch(
|
fun launch(
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -114,12 +114,12 @@ expect fun rememberReaderLauncher(): ReaderLauncher
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReaderMenu(
|
fun ReaderMenu(
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
onCloseRequest: () -> Unit,
|
onCloseRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val viewModels = LocalViewModels.current
|
val viewModels = LocalViewModels.current
|
||||||
val vm = remember { viewModels.readerViewModel(ReaderMenuViewModel.Params(chapterIndex, mangaId)) }
|
val vm = remember { viewModels.readerViewModel(ReaderMenuViewModel.Params(chapterId, mangaId)) }
|
||||||
DisposableEffect(vm) {
|
DisposableEffect(vm) {
|
||||||
onDispose(vm::onDispose)
|
onDispose(vm::onDispose)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ package ca.gosyer.jui.ui.reader
|
|||||||
import ca.gosyer.jui.core.lang.launchDefault
|
import ca.gosyer.jui.core.lang.launchDefault
|
||||||
import ca.gosyer.jui.core.prefs.getAsFlow
|
import ca.gosyer.jui.core.prefs.getAsFlow
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapter
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapter
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPage
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPages
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapters
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapters
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterLastPageRead
|
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapter
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterMeta
|
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterMeta
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterRead
|
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.manga.interactor.GetManga
|
import ca.gosyer.jui.domain.manga.interactor.GetManga
|
||||||
import ca.gosyer.jui.domain.manga.interactor.UpdateMangaMeta
|
import ca.gosyer.jui.domain.manga.interactor.UpdateMangaMeta
|
||||||
@@ -77,9 +76,8 @@ class ReaderMenuViewModel
|
|||||||
private val getManga: GetManga,
|
private val getManga: GetManga,
|
||||||
private val getChapters: GetChapters,
|
private val getChapters: GetChapters,
|
||||||
private val getChapter: GetChapter,
|
private val getChapter: GetChapter,
|
||||||
private val getChapterPage: GetChapterPage,
|
private val getChapterPages: GetChapterPages,
|
||||||
private val updateChapterRead: UpdateChapterRead,
|
private val updateChapter: UpdateChapter,
|
||||||
private val updateChapterLastPageRead: UpdateChapterLastPageRead,
|
|
||||||
private val updateMangaMeta: UpdateMangaMeta,
|
private val updateMangaMeta: UpdateMangaMeta,
|
||||||
private val updateChapterMeta: UpdateChapterMeta,
|
private val updateChapterMeta: UpdateChapterMeta,
|
||||||
private val chapterCache: ChapterCache,
|
private val chapterCache: ChapterCache,
|
||||||
@@ -157,6 +155,7 @@ class ReaderMenuViewModel
|
|||||||
http = http,
|
http = http,
|
||||||
chapterCache = chapterCache,
|
chapterCache = chapterCache,
|
||||||
bitmapDecoderFactory = BitmapDecoderFactory(contextWrapper),
|
bitmapDecoderFactory = BitmapDecoderFactory(contextWrapper),
|
||||||
|
getChapterPages = getChapterPages,
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -167,7 +166,7 @@ class ReaderMenuViewModel
|
|||||||
scope.launchDefault {
|
scope.launchDefault {
|
||||||
runCatching {
|
runCatching {
|
||||||
initManga(params.mangaId)
|
initManga(params.mangaId)
|
||||||
initChapters(params.mangaId, params.chapterIndex)
|
initChapters(params.mangaId, params.chapterId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,11 +178,13 @@ class ReaderMenuViewModel
|
|||||||
.collectLatest { page ->
|
.collectLatest { page ->
|
||||||
page.chapter.pageLoader?.loadPage(page)
|
page.chapter.pageLoader?.loadPage(page)
|
||||||
if (page.chapter == chapter.value) {
|
if (page.chapter == chapter.value) {
|
||||||
if ((page.index + 1) >= page.chapter.chapter.pageCount!!) {
|
val pages = page.chapter.pages.value as? PagesState.Success
|
||||||
|
?: return@collectLatest
|
||||||
|
if ((page.index2 + 1) >= pages.pages.size) {
|
||||||
markChapterRead(page.chapter)
|
markChapterRead(page.chapter)
|
||||||
}
|
}
|
||||||
val nextChapter = nextChapter.value
|
val nextChapter = nextChapter.value
|
||||||
if (nextChapter != null && (page.index + 1) >= (page.chapter.chapter.pageCount!! - 5)) {
|
if (nextChapter != null && (page.index2 + 1) >= ((pages.pages.size - 5).coerceAtLeast(1))) {
|
||||||
requestPreloadChapter(nextChapter)
|
requestPreloadChapter(nextChapter)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -191,10 +192,10 @@ class ReaderMenuViewModel
|
|||||||
val nextChapter = nextChapter.value
|
val nextChapter = nextChapter.value
|
||||||
if (page.chapter == previousChapter) {
|
if (page.chapter == previousChapter) {
|
||||||
viewerChapters.value = viewerChapters.value.movePrev()
|
viewerChapters.value = viewerChapters.value.movePrev()
|
||||||
initChapters(params.mangaId, page.chapter.chapter.index, fromMenuButton = false)
|
initChapters(params.mangaId, page.chapter.chapter.id, fromMenuButton = false)
|
||||||
} else if (page.chapter == nextChapter) {
|
} else if (page.chapter == nextChapter) {
|
||||||
viewerChapters.value = viewerChapters.value.moveNext()
|
viewerChapters.value = viewerChapters.value.moveNext()
|
||||||
initChapters(params.mangaId, page.chapter.chapter.index, fromMenuButton = false)
|
initChapters(params.mangaId, page.chapter.chapter.id, fromMenuButton = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +254,7 @@ class ReaderMenuViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun retry(page: ReaderPage) {
|
fun retry(page: ReaderPage) {
|
||||||
log.info { "Retrying ${page.index}" }
|
log.info { "Retrying ${page.index2}" }
|
||||||
chapter.value?.pageLoader?.retryPage(page)
|
chapter.value?.pageLoader?.retryPage(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +278,7 @@ class ReaderMenuViewModel
|
|||||||
_state.value = ReaderChapter.State.Wait
|
_state.value = ReaderChapter.State.Wait
|
||||||
sendProgress()
|
sendProgress()
|
||||||
viewerChapters.value = viewerChapters.value.movePrev()
|
viewerChapters.value = viewerChapters.value.movePrev()
|
||||||
initChapters(params.mangaId, prevChapter.chapter.index, fromMenuButton = true)
|
initChapters(params.mangaId, prevChapter.chapter.id, fromMenuButton = true)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.warn(e) { "Error loading prev chapter" }
|
log.warn(e) { "Error loading prev chapter" }
|
||||||
}
|
}
|
||||||
@@ -291,7 +292,7 @@ class ReaderMenuViewModel
|
|||||||
_state.value = ReaderChapter.State.Wait
|
_state.value = ReaderChapter.State.Wait
|
||||||
sendProgress()
|
sendProgress()
|
||||||
viewerChapters.value = viewerChapters.value.moveNext()
|
viewerChapters.value = viewerChapters.value.moveNext()
|
||||||
initChapters(params.mangaId, nextChapter.chapter.index, fromMenuButton = true)
|
initChapters(params.mangaId, nextChapter.chapter.id, fromMenuButton = true)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.warn(e) { "Error loading next chapter" }
|
log.warn(e) { "Error loading next chapter" }
|
||||||
}
|
}
|
||||||
@@ -313,52 +314,45 @@ class ReaderMenuViewModel
|
|||||||
|
|
||||||
private suspend fun initChapters(
|
private suspend fun initChapters(
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
fromMenuButton: Boolean = true,
|
fromMenuButton: Boolean = true,
|
||||||
) {
|
) {
|
||||||
log.debug { "Loading chapter index $chapterIndex" }
|
log.debug { "Loading chapter index $chapterId" }
|
||||||
val (chapter, pages) = coroutineScope {
|
val (chapter, pages) = coroutineScope {
|
||||||
val getCurrentChapter = async {
|
val chapters = getChapters.asFlow(mangaId)
|
||||||
val chapter = getReaderChapter(chapterIndex) ?: return@async null
|
.take(1)
|
||||||
val pages = loader.loadChapter(chapter)
|
.catch {
|
||||||
viewerChapters.update { it.copy(currChapter = chapter) }
|
_state.value = ReaderChapter.State.Error(it)
|
||||||
chapter to pages
|
log.warn(it) { "Error getting chapters for $mangaId" }
|
||||||
|
}
|
||||||
|
.singleOrNull()
|
||||||
|
?: return@coroutineScope null
|
||||||
|
val chapter = chapters.find { it.id == chapterId }
|
||||||
|
?.let { ReaderChapter(it) }
|
||||||
|
?: return@coroutineScope null
|
||||||
|
val pages = loader.loadChapter(chapter)
|
||||||
|
viewerChapters.update { it.copy(currChapter = chapter) }
|
||||||
|
|
||||||
|
if (viewerChapters.value.nextChapter == null) {
|
||||||
|
val nextChapter = chapters.find { it.index == chapter.chapter.index + 1 }
|
||||||
|
if (nextChapter != null) {
|
||||||
|
val nextReaderChapter = ReaderChapter(nextChapter)
|
||||||
|
viewerChapters.update { it.copy(nextChapter = nextReaderChapter) }
|
||||||
|
} else {
|
||||||
|
viewerChapters.update { it.copy(nextChapter = null) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val getAdjacentChapters = async {
|
if (viewerChapters.value.prevChapter == null) {
|
||||||
val chapters = getChapters.await(
|
val prevChapter = chapters.find { it.index == chapter.chapter.index - 1 }
|
||||||
mangaId,
|
if (prevChapter != null) {
|
||||||
onError = { /* TODO: 2022-07-01 Error toast */ },
|
val prevReaderChapter = ReaderChapter(prevChapter)
|
||||||
).orEmpty()
|
viewerChapters.update { it.copy(prevChapter = prevReaderChapter) }
|
||||||
|
} else {
|
||||||
val nextChapter = async {
|
viewerChapters.update { it.copy(prevChapter = null) }
|
||||||
if (viewerChapters.value.nextChapter == null) {
|
|
||||||
val nextChapter = chapters.find { it.index == chapterIndex + 1 }
|
|
||||||
if (nextChapter != null) {
|
|
||||||
val nextReaderChapter = getReaderChapter(nextChapter.index)
|
|
||||||
viewerChapters.update { it.copy(nextChapter = nextReaderChapter) }
|
|
||||||
} else {
|
|
||||||
viewerChapters.update { it.copy(nextChapter = null) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val prevChapter = async {
|
|
||||||
if (viewerChapters.value.prevChapter == null) {
|
|
||||||
val prevChapter = chapters.find { it.index == chapterIndex - 1 }
|
|
||||||
if (prevChapter != null) {
|
|
||||||
val prevReaderChapter = getReaderChapter(prevChapter.index)
|
|
||||||
viewerChapters.update { it.copy(prevChapter = prevReaderChapter) }
|
|
||||||
} else {
|
|
||||||
viewerChapters.update { it.copy(prevChapter = null) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nextChapter.await()
|
|
||||||
prevChapter.await()
|
|
||||||
}
|
}
|
||||||
|
chapter to pages
|
||||||
getAdjacentChapters.await()
|
|
||||||
getCurrentChapter.await()
|
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
if (fromMenuButton) {
|
if (fromMenuButton) {
|
||||||
@@ -386,18 +380,6 @@ class ReaderMenuViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getReaderChapter(chapterIndex: Int): ReaderChapter? {
|
|
||||||
return ReaderChapter(
|
|
||||||
getChapter.asFlow(params.mangaId, chapterIndex)
|
|
||||||
.take(1)
|
|
||||||
.catch {
|
|
||||||
_state.value = ReaderChapter.State.Error(it)
|
|
||||||
log.warn(it) { "Error getting chapter $chapterIndex" }
|
|
||||||
}
|
|
||||||
.singleOrNull() ?: return null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestPreloadChapter(chapter: ReaderChapter) {
|
fun requestPreloadChapter(chapter: ReaderChapter) {
|
||||||
if (chapter.state != ReaderChapter.State.Wait && chapter.state !is ReaderChapter.State.Error) {
|
if (chapter.state != ReaderChapter.State.Wait && chapter.state !is ReaderChapter.State.Error) {
|
||||||
return
|
return
|
||||||
@@ -408,19 +390,19 @@ class ReaderMenuViewModel
|
|||||||
|
|
||||||
private fun markChapterRead(chapter: ReaderChapter) {
|
private fun markChapterRead(chapter: ReaderChapter) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
updateChapterRead.await(chapter.chapter, read = true, onError = { toast(it.message.orEmpty()) })
|
updateChapter.await(chapter.chapter, read = true, onError = { toast(it.message.orEmpty()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
fun sendProgress(
|
fun sendProgress(
|
||||||
chapter: Chapter? = this.chapter.value?.chapter,
|
chapter: Chapter? = this.chapter.value?.chapter,
|
||||||
lastPageRead: Int = (currentPage.value as? ReaderPage)?.index ?: 0,
|
lastPageRead: Int = (currentPage.value as? ReaderPage)?.index2 ?: 0,
|
||||||
) {
|
) {
|
||||||
chapter ?: return
|
chapter ?: return
|
||||||
if (chapter.read) return
|
if (chapter.read) return
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
updateChapterLastPageRead.await(
|
updateChapter.await(
|
||||||
chapter,
|
chapter,
|
||||||
lastPageRead = lastPageRead,
|
lastPageRead = lastPageRead,
|
||||||
onError = { toast(it.message.orEmpty()) },
|
onError = { toast(it.message.orEmpty()) },
|
||||||
@@ -448,7 +430,7 @@ class ReaderMenuViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Params(
|
data class Params(
|
||||||
val chapterIndex: Int,
|
val chapterId: Long,
|
||||||
val mangaId: Long,
|
val mangaId: Long,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ import androidx.compose.material.icons.rounded.ChevronLeft
|
|||||||
import androidx.compose.material.icons.rounded.SkipNext
|
import androidx.compose.material.icons.rounded.SkipNext
|
||||||
import androidx.compose.material.icons.rounded.SkipPrevious
|
import androidx.compose.material.icons.rounded.SkipPrevious
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.key
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@@ -56,6 +58,7 @@ import ca.gosyer.jui.core.util.replace
|
|||||||
import ca.gosyer.jui.domain.manga.model.MangaMeta
|
import ca.gosyer.jui.domain.manga.model.MangaMeta
|
||||||
import ca.gosyer.jui.domain.reader.model.Direction
|
import ca.gosyer.jui.domain.reader.model.Direction
|
||||||
import ca.gosyer.jui.i18n.MR
|
import ca.gosyer.jui.i18n.MR
|
||||||
|
import ca.gosyer.jui.ui.reader.loader.PagesState
|
||||||
import ca.gosyer.jui.ui.reader.model.ReaderChapter
|
import ca.gosyer.jui.ui.reader.model.ReaderChapter
|
||||||
import ca.gosyer.jui.ui.reader.model.ReaderItem
|
import ca.gosyer.jui.ui.reader.model.ReaderItem
|
||||||
import ca.gosyer.jui.uicore.components.AroundLayout
|
import ca.gosyer.jui.uicore.components.AroundLayout
|
||||||
@@ -82,7 +85,6 @@ fun ReaderSideMenu(
|
|||||||
) {
|
) {
|
||||||
Surface(Modifier.fillMaxHeight().width(260.dp)) {
|
Surface(Modifier.fillMaxHeight().width(260.dp)) {
|
||||||
Column(Modifier.fillMaxSize()) {
|
Column(Modifier.fillMaxSize()) {
|
||||||
val pageCount = chapter.chapter.pageCount!!
|
|
||||||
ReaderMenuToolbar(onCloseSideMenuClicked = onCloseSideMenuClicked)
|
ReaderMenuToolbar(onCloseSideMenuClicked = onCloseSideMenuClicked)
|
||||||
Spacer(Modifier.height(4.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
ReaderModeSetting(
|
ReaderModeSetting(
|
||||||
@@ -91,6 +93,12 @@ fun ReaderSideMenu(
|
|||||||
onSetReaderMode = onSetReaderMode,
|
onSetReaderMode = onSetReaderMode,
|
||||||
)
|
)
|
||||||
Spacer(Modifier.height(4.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
|
val chapterPages by key(chapter.chapter.id) { chapter.pages.collectAsState() }
|
||||||
|
val pageCount = when (chapterPages) {
|
||||||
|
PagesState.Empty -> null
|
||||||
|
PagesState.Loading -> null
|
||||||
|
is PagesState.Success -> (chapterPages as? PagesState.Success)?.pages?.size
|
||||||
|
}
|
||||||
ReaderProgressSlider(
|
ReaderProgressSlider(
|
||||||
pages = pages,
|
pages = pages,
|
||||||
currentPage = currentPage,
|
currentPage = currentPage,
|
||||||
@@ -183,6 +191,12 @@ fun ReaderExpandBottomMenu(
|
|||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
backgroundColor = MaterialTheme.colors.surface.copy(alpha = 0.5F),
|
backgroundColor = MaterialTheme.colors.surface.copy(alpha = 0.5F),
|
||||||
) {
|
) {
|
||||||
|
val chapterPages by key(chapter.chapter.id) { chapter.pages.collectAsState() }
|
||||||
|
val pageCount = when (chapterPages) {
|
||||||
|
PagesState.Empty -> null
|
||||||
|
PagesState.Loading -> null
|
||||||
|
is PagesState.Success -> (chapterPages as? PagesState.Success)?.pages?.size
|
||||||
|
}
|
||||||
AroundLayout(
|
AroundLayout(
|
||||||
Modifier.padding(horizontal = 8.dp),
|
Modifier.padding(horizontal = 8.dp),
|
||||||
startLayout = {
|
startLayout = {
|
||||||
@@ -190,7 +204,7 @@ fun ReaderExpandBottomMenu(
|
|||||||
val text = if (!isRtL) {
|
val text = if (!isRtL) {
|
||||||
pages.indexOf(currentPage)
|
pages.indexOf(currentPage)
|
||||||
} else {
|
} else {
|
||||||
chapter.chapter.pageCount!!
|
pageCount ?: "1"
|
||||||
}.toString()
|
}.toString()
|
||||||
Text(text, fontSize = 15.sp)
|
Text(text, fontSize = 15.sp)
|
||||||
}
|
}
|
||||||
@@ -200,7 +214,7 @@ fun ReaderExpandBottomMenu(
|
|||||||
val text = if (isRtL) {
|
val text = if (isRtL) {
|
||||||
pages.indexOf(currentPage)
|
pages.indexOf(currentPage)
|
||||||
} else {
|
} else {
|
||||||
chapter.chapter.pageCount!!
|
pageCount ?: "1"
|
||||||
}.toString()
|
}.toString()
|
||||||
Text(text, fontSize = 15.sp)
|
Text(text, fontSize = 15.sp)
|
||||||
}
|
}
|
||||||
@@ -212,7 +226,7 @@ fun ReaderExpandBottomMenu(
|
|||||||
.padding(horizontal = 4.dp),
|
.padding(horizontal = 4.dp),
|
||||||
pages = pages,
|
pages = pages,
|
||||||
currentPage = currentPage,
|
currentPage = currentPage,
|
||||||
pageCount = chapter.chapter.pageCount!!,
|
pageCount = pageCount,
|
||||||
onNewPageClicked = navigate,
|
onNewPageClicked = navigate,
|
||||||
isRtL = isRtL,
|
isRtL = isRtL,
|
||||||
)
|
)
|
||||||
@@ -278,7 +292,7 @@ private fun ReaderProgressSlider(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
pages: ImmutableList<ReaderItem>,
|
pages: ImmutableList<ReaderItem>,
|
||||||
currentPage: ReaderItem?,
|
currentPage: ReaderItem?,
|
||||||
pageCount: Int,
|
pageCount: Int?,
|
||||||
onNewPageClicked: (Int) -> Unit,
|
onNewPageClicked: (Int) -> Unit,
|
||||||
isRtL: Boolean,
|
isRtL: Boolean,
|
||||||
) {
|
) {
|
||||||
@@ -295,9 +309,10 @@ private fun ReaderProgressSlider(
|
|||||||
onNewPageClicked(it.roundToInt())
|
onNewPageClicked(it.roundToInt())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
valueRange = 0F..pageCount.toFloat(),
|
valueRange = 0F..(pageCount ?: 1).toFloat(),
|
||||||
steps = pageCount,
|
steps = (pageCount ?: 1),
|
||||||
onValueChangeFinished = { isValueChanging = false },
|
onValueChangeFinished = { isValueChanging = false },
|
||||||
|
enabled = pageCount != null,
|
||||||
modifier = modifier.let {
|
modifier = modifier.let {
|
||||||
if (isRtL) {
|
if (isRtL) {
|
||||||
it then Modifier.rotate(180F)
|
it then Modifier.rotate(180F)
|
||||||
|
|||||||
@@ -8,15 +8,16 @@ package ca.gosyer.jui.ui.reader.loader
|
|||||||
|
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import ca.gosyer.jui.core.io.SYSTEM
|
import ca.gosyer.jui.core.io.SYSTEM
|
||||||
|
import ca.gosyer.jui.core.io.source
|
||||||
import ca.gosyer.jui.core.lang.PriorityChannel
|
import ca.gosyer.jui.core.lang.PriorityChannel
|
||||||
import ca.gosyer.jui.core.lang.throwIfCancellation
|
import ca.gosyer.jui.core.lang.throwIfCancellation
|
||||||
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPages
|
||||||
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.server.Http
|
||||||
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
||||||
import ca.gosyer.jui.ui.base.model.StableHolder
|
import ca.gosyer.jui.ui.base.model.StableHolder
|
||||||
import ca.gosyer.jui.ui.reader.model.ReaderChapter
|
import ca.gosyer.jui.ui.reader.model.ReaderChapter
|
||||||
import ca.gosyer.jui.ui.reader.model.ReaderPage
|
import ca.gosyer.jui.ui.reader.model.ReaderPage
|
||||||
import ca.gosyer.jui.ui.util.lang.toSource
|
|
||||||
import cafe.adriel.voyager.core.concurrent.AtomicInt32
|
import cafe.adriel.voyager.core.concurrent.AtomicInt32
|
||||||
import com.seiko.imageloader.asImageBitmap
|
import com.seiko.imageloader.asImageBitmap
|
||||||
import com.seiko.imageloader.cache.disk.DiskCache
|
import com.seiko.imageloader.cache.disk.DiskCache
|
||||||
@@ -25,9 +26,6 @@ import com.seiko.imageloader.model.DataSource
|
|||||||
import com.seiko.imageloader.model.ImageResult
|
import com.seiko.imageloader.model.ImageResult
|
||||||
import com.seiko.imageloader.option.Options
|
import com.seiko.imageloader.option.Options
|
||||||
import io.ktor.client.plugins.onDownload
|
import io.ktor.client.plugins.onDownload
|
||||||
import io.ktor.client.request.get
|
|
||||||
import io.ktor.client.statement.HttpResponse
|
|
||||||
import io.ktor.client.statement.bodyAsChannel
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.IO
|
import kotlinx.coroutines.IO
|
||||||
@@ -39,6 +37,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.emitAll
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -57,6 +56,7 @@ class TachideskPageLoader(
|
|||||||
private val http: Http,
|
private val http: Http,
|
||||||
private val chapterCache: DiskCache,
|
private val chapterCache: DiskCache,
|
||||||
private val bitmapDecoderFactory: BitmapDecoderFactory,
|
private val bitmapDecoderFactory: BitmapDecoderFactory,
|
||||||
|
private val getChapterPages: GetChapterPages,
|
||||||
) : PageLoader() {
|
) : PageLoader() {
|
||||||
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||||
|
|
||||||
@@ -109,15 +109,15 @@ class TachideskPageLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchImage(page: ReaderPage) {
|
private suspend fun fetchImage(page: ReaderPage) {
|
||||||
log.debug { "Loading page ${page.index}" }
|
log.debug { "Loading page ${page.index2}" }
|
||||||
flow {
|
flow {
|
||||||
val response = http.get("api/v1/manga/${chapter.chapter.mangaId}/chapter/${chapter.chapter.index}/page/${page.index}") {
|
val response = getChapterPages.asFlow(page.url) {
|
||||||
onDownload { bytesSentTotal, contentLength ->
|
onDownload { bytesSentTotal, contentLength ->
|
||||||
page.progress.value = (bytesSentTotal.toFloat() / contentLength).coerceAtMost(1.0F)
|
page.progress.value = (bytesSentTotal.toFloat() / contentLength).coerceAtMost(1.0F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(response)
|
emitAll(response)
|
||||||
}
|
}
|
||||||
.onEach {
|
.onEach {
|
||||||
putImageInCache(it, page)
|
putImageInCache(it, page)
|
||||||
@@ -129,21 +129,21 @@ class TachideskPageLoader(
|
|||||||
page.bitmap.value = StableHolder(null)
|
page.bitmap.value = StableHolder(null)
|
||||||
page.status.value = ReaderPage.Status.ERROR
|
page.status.value = ReaderPage.Status.ERROR
|
||||||
page.error.value = it.message
|
page.error.value = it.message
|
||||||
log.warn(it) { "Failed to get page ${page.index} for chapter ${chapter.chapter.index} for ${chapter.chapter.mangaId}" }
|
log.warn(it) { "Failed to get page ${page.index2} for chapter ${chapter.chapter.index} for ${chapter.chapter.mangaId}" }
|
||||||
}
|
}
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun putImageInCache(
|
private suspend fun putImageInCache(
|
||||||
response: HttpResponse,
|
response: ByteArray,
|
||||||
page: ReaderPage,
|
page: ReaderPage,
|
||||||
) {
|
) {
|
||||||
val editor = chapterCache.openEditor(page.cacheKey)
|
val editor = chapterCache.openEditor(page.cacheKey)
|
||||||
?: throw Exception("Couldn't open cache")
|
?: throw Exception("Couldn't open cache")
|
||||||
try {
|
try {
|
||||||
FileSystem.SYSTEM.write(editor.data) {
|
FileSystem.SYSTEM.write(editor.data) {
|
||||||
response.bodyAsChannel().toSource().use {
|
response.source().use {
|
||||||
writeAll(it)
|
writeAll(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ class TachideskPageLoader(
|
|||||||
currentPage: ReaderPage,
|
currentPage: ReaderPage,
|
||||||
amount: Int,
|
amount: Int,
|
||||||
): List<PriorityPage> {
|
): List<PriorityPage> {
|
||||||
val pageIndex = currentPage.index
|
val pageIndex = currentPage.index2
|
||||||
val pages = (currentPage.chapter.pages.value as? PagesState.Success)?.pages ?: return emptyList()
|
val pages = (currentPage.chapter.pages.value as? PagesState.Success)?.pages ?: return emptyList()
|
||||||
if (pageIndex >= pages.lastIndex) return emptyList()
|
if (pageIndex >= pages.lastIndex) return emptyList()
|
||||||
|
|
||||||
@@ -214,14 +214,15 @@ class TachideskPageLoader(
|
|||||||
override fun getPages(): StateFlow<PagesState> {
|
override fun getPages(): StateFlow<PagesState> {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (pagesFlow.value != PagesState.Loading) return@launch
|
if (pagesFlow.value != PagesState.Loading) return@launch
|
||||||
val pageRange = chapter.chapter.pageCount?.let { 0..it.minus(1) }
|
val pages = getChapterPages.await(chapter.chapter.id)
|
||||||
pagesFlow.value = if (pageRange == null || pageRange.isEmpty()) {
|
pagesFlow.value = if (pages.isNullOrEmpty()) {
|
||||||
PagesState.Empty
|
PagesState.Empty
|
||||||
} else {
|
} else {
|
||||||
PagesState.Success(
|
PagesState.Success(
|
||||||
pageRange.map {
|
pages.mapIndexed { index, url ->
|
||||||
ReaderPage(
|
ReaderPage(
|
||||||
index = it,
|
url = url,
|
||||||
|
index2 = index,
|
||||||
bitmap = MutableStateFlow(StableHolder(null)),
|
bitmap = MutableStateFlow(StableHolder(null)),
|
||||||
bitmapInfo = MutableStateFlow(null),
|
bitmapInfo = MutableStateFlow(null),
|
||||||
progress = MutableStateFlow(0.0F),
|
progress = MutableStateFlow(0.0F),
|
||||||
@@ -295,7 +296,7 @@ class TachideskPageLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val ReaderPage.cacheKey
|
private val ReaderPage.cacheKey
|
||||||
get() = "${chapter.chapter.mangaId}-${chapter.chapter.index}-$index"
|
get() = "${chapter.chapter.id}-$url"
|
||||||
|
|
||||||
private fun DiskCache.Snapshot.source(): BufferedSource = FileSystem.SYSTEM.source(data).buffer()
|
private fun DiskCache.Snapshot.source(): BufferedSource = FileSystem.SYSTEM.source(data).buffer()
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class ReaderPage(
|
data class ReaderPage(
|
||||||
val index: Int,
|
val url: String,
|
||||||
|
val index2: Int,
|
||||||
val bitmap: MutableStateFlow<StableHolder<(suspend () -> ImageDecodeState)?>>,
|
val bitmap: MutableStateFlow<StableHolder<(suspend () -> ImageDecodeState)?>>,
|
||||||
val bitmapInfo: MutableStateFlow<BitmapInfo?>,
|
val bitmapInfo: MutableStateFlow<BitmapInfo?>,
|
||||||
val progress: MutableStateFlow<Float>,
|
val progress: MutableStateFlow<Float>,
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ fun ContinuousReader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun retry(index: Int) {
|
fun retry(index: Int) {
|
||||||
pages.find { it is ReaderPage && it.index == index }?.let { retry(it as ReaderPage) }
|
pages.find { it is ReaderPage && it.index2 == index }?.let { retry(it as ReaderPage) }
|
||||||
}
|
}
|
||||||
|
|
||||||
when (direction.isVertical) {
|
when (direction.isVertical) {
|
||||||
@@ -199,7 +199,7 @@ private fun LazyListScope.items(
|
|||||||
pages,
|
pages,
|
||||||
key = {
|
key = {
|
||||||
when (it) {
|
when (it) {
|
||||||
is ReaderPage -> it.chapter.chapter.index to it.index
|
is ReaderPage -> it.chapter.chapter.index to it.index2
|
||||||
is ReaderPageSeparator -> it.previousChapter?.chapter?.index to it.nextChapter?.chapter?.index
|
is ReaderPageSeparator -> it.previousChapter?.chapter?.index to it.nextChapter?.chapter?.index
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -207,7 +207,7 @@ private fun LazyListScope.items(
|
|||||||
when (image) {
|
when (image) {
|
||||||
is ReaderPage -> Box(modifier, contentAlignment = Alignment.Center) {
|
is ReaderPage -> Box(modifier, contentAlignment = Alignment.Center) {
|
||||||
ReaderImage(
|
ReaderImage(
|
||||||
imageIndex = image.index,
|
imageIndex = image.index2,
|
||||||
drawableHolder = image.bitmap.collectAsState().value,
|
drawableHolder = image.bitmap.collectAsState().value,
|
||||||
bitmapInfo = image.bitmapInfo.collectAsState().value,
|
bitmapInfo = image.bitmapInfo.collectAsState().value,
|
||||||
progress = image.progress.collectAsState().value,
|
progress = image.progress.collectAsState().value,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fun PagerReader(
|
|||||||
val modifier = parentModifier then Modifier.fillMaxSize()
|
val modifier = parentModifier then Modifier.fillMaxSize()
|
||||||
|
|
||||||
fun retry(index: Int) {
|
fun retry(index: Int) {
|
||||||
pages.find { it is ReaderPage && it.index == index }?.let { retry(it as ReaderPage) }
|
pages.find { it is ReaderPage && it.index2 == index }?.let { retry(it as ReaderPage) }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction.isVertical) {
|
if (direction.isVertical) {
|
||||||
@@ -95,7 +95,7 @@ fun PagerReader(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
key = {
|
key = {
|
||||||
when (val page = pages.getOrNull(it)) {
|
when (val page = pages.getOrNull(it)) {
|
||||||
is ReaderPage -> page.chapter.chapter.index to page.index
|
is ReaderPage -> page.chapter.chapter.index to page.index2
|
||||||
is ReaderPageSeparator -> page.previousChapter?.chapter?.index to page.nextChapter?.chapter?.index
|
is ReaderPageSeparator -> page.previousChapter?.chapter?.index to page.nextChapter?.chapter?.index
|
||||||
else -> it
|
else -> it
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ fun PagerReader(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
key = {
|
key = {
|
||||||
when (val page = pages.getOrNull(it)) {
|
when (val page = pages.getOrNull(it)) {
|
||||||
is ReaderPage -> page.chapter.chapter.index to page.index
|
is ReaderPage -> page.chapter.chapter.index to page.index2
|
||||||
is ReaderPageSeparator -> page.previousChapter?.chapter?.index to page.nextChapter?.chapter?.index
|
is ReaderPageSeparator -> page.previousChapter?.chapter?.index to page.nextChapter?.chapter?.index
|
||||||
else -> it
|
else -> it
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ fun HandlePager(
|
|||||||
when (val image = pages[page]) {
|
when (val image = pages[page]) {
|
||||||
is ReaderPage -> {
|
is ReaderPage -> {
|
||||||
ReaderImage(
|
ReaderImage(
|
||||||
imageIndex = image.index,
|
imageIndex = image.index2,
|
||||||
drawableHolder = image.bitmap.collectAsState().value,
|
drawableHolder = image.bitmap.collectAsState().value,
|
||||||
bitmapInfo = image.bitmapInfo.collectAsState().value,
|
bitmapInfo = image.bitmapInfo.collectAsState().value,
|
||||||
progress = image.progress.collectAsState().value,
|
progress = image.progress.collectAsState().value,
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
package ca.gosyer.jui.ui.updates
|
package ca.gosyer.jui.ui.updates
|
||||||
|
|
||||||
import ca.gosyer.jui.core.lang.launchDefault
|
import ca.gosyer.jui.core.lang.launchDefault
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.BatchUpdateChapter
|
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.DeleteChapterDownload
|
import ca.gosyer.jui.domain.chapter.interactor.DeleteChapterDownload
|
||||||
|
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapter
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.download.interactor.BatchChapterDownload
|
import ca.gosyer.jui.domain.download.interactor.BatchChapterDownload
|
||||||
import ca.gosyer.jui.domain.download.interactor.QueueChapterDownload
|
import ca.gosyer.jui.domain.download.interactor.QueueChapterDownload
|
||||||
@@ -47,7 +47,7 @@ class UpdatesScreenViewModel
|
|||||||
private val stopChapterDownload: StopChapterDownload,
|
private val stopChapterDownload: StopChapterDownload,
|
||||||
private val deleteChapterDownload: DeleteChapterDownload,
|
private val deleteChapterDownload: DeleteChapterDownload,
|
||||||
private val getRecentUpdates: GetRecentUpdates,
|
private val getRecentUpdates: GetRecentUpdates,
|
||||||
private val batchUpdateChapter: BatchUpdateChapter,
|
private val updateChapter: UpdateChapter,
|
||||||
private val batchChapterDownload: BatchChapterDownload,
|
private val batchChapterDownload: BatchChapterDownload,
|
||||||
private val updateLibrary: UpdateLibrary,
|
private val updateLibrary: UpdateLibrary,
|
||||||
private val updatesPager: UpdatesPager,
|
private val updatesPager: UpdatesPager,
|
||||||
@@ -119,7 +119,7 @@ class UpdatesScreenViewModel
|
|||||||
read: Boolean,
|
read: Boolean,
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
batchUpdateChapter.await(chapterIds, isRead = read, onError = { toast(it.message.orEmpty()) })
|
updateChapter.await(chapterIds, read = read, onError = { toast(it.message.orEmpty()) })
|
||||||
_selectedIds.value = persistentListOf()
|
_selectedIds.value = persistentListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ class UpdatesScreenViewModel
|
|||||||
bookmark: Boolean,
|
bookmark: Boolean,
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
batchUpdateChapter.await(chapterIds, isBookmarked = bookmark, onError = { toast(it.message.orEmpty()) })
|
updateChapter.await(chapterIds, bookmarked = bookmark, onError = { toast(it.message.orEmpty()) })
|
||||||
_selectedIds.value = persistentListOf()
|
_selectedIds.value = persistentListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ class UpdatesScreenViewModel
|
|||||||
scope.launchDefault {
|
scope.launchDefault {
|
||||||
if (chapter == null) {
|
if (chapter == null) {
|
||||||
val selectedIds = _selectedIds.value
|
val selectedIds = _selectedIds.value
|
||||||
batchUpdateChapter.await(selectedIds, delete = true, onError = { toast(it.message.orEmpty()) })
|
deleteChapterDownload.await(selectedIds, onError = { toast(it.message.orEmpty()) })
|
||||||
selectedItems.value.forEach {
|
selectedItems.value.forEach {
|
||||||
it.setNotDownloaded()
|
it.setNotDownloaded()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ fun UpdatesScreenContent(
|
|||||||
inActionMode: Boolean,
|
inActionMode: Boolean,
|
||||||
selectedItems: ImmutableList<ChapterDownloadItem>,
|
selectedItems: ImmutableList<ChapterDownloadItem>,
|
||||||
loadNextPage: () -> Unit,
|
loadNextPage: () -> Unit,
|
||||||
openChapter: (index: Int, mangaId: Long) -> Unit,
|
openChapter: (id: Long, mangaId: Long) -> Unit,
|
||||||
openManga: (Long) -> Unit,
|
openManga: (Long) -> Unit,
|
||||||
markRead: (Long?) -> Unit,
|
markRead: (Long?) -> Unit,
|
||||||
markUnread: (Long?) -> Unit,
|
markUnread: (Long?) -> Unit,
|
||||||
@@ -201,7 +201,7 @@ fun UpdatesScreenContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
{ openChapter(chapter.index, manga.id) }
|
{ openChapter(chapter.id, manga.id) }
|
||||||
},
|
},
|
||||||
markRead = markRead,
|
markRead = markRead,
|
||||||
markUnread = markUnread,
|
markUnread = markUnread,
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ import ca.gosyer.jui.ui.util.lang.launchApplication
|
|||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
|
||||||
actual class ReaderLauncher {
|
actual class ReaderLauncher {
|
||||||
private var isOpen by mutableStateOf<Pair<Int, Long>?>(null)
|
private var isOpen by mutableStateOf<Pair<Long, Long>?>(null)
|
||||||
|
|
||||||
actual fun launch(
|
actual fun launch(
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
) {
|
) {
|
||||||
isOpen = chapterIndex to mangaId
|
isOpen = chapterId to mangaId
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
@@ -38,7 +38,7 @@ actual class ReaderLauncher {
|
|||||||
actual fun Reader() {
|
actual fun Reader() {
|
||||||
val localParams = currentCompositionLocalContext
|
val localParams = currentCompositionLocalContext
|
||||||
DisposableEffect(isOpen) {
|
DisposableEffect(isOpen) {
|
||||||
isOpen?.let { (chapterIndex, mangaId) ->
|
isOpen?.let { (chapterId, mangaId) ->
|
||||||
launchApplication {
|
launchApplication {
|
||||||
val windowState = rememberWindowState(
|
val windowState = rememberWindowState(
|
||||||
position = WindowPosition.Aligned(Alignment.Center),
|
position = WindowPosition.Aligned(Alignment.Center),
|
||||||
@@ -52,7 +52,7 @@ actual class ReaderLauncher {
|
|||||||
state = windowState,
|
state = windowState,
|
||||||
) {
|
) {
|
||||||
ReaderMenu(
|
ReaderMenu(
|
||||||
chapterIndex = chapterIndex,
|
chapterId = chapterId,
|
||||||
mangaId = mangaId,
|
mangaId = mangaId,
|
||||||
onCloseRequest = ::exitApplication,
|
onCloseRequest = ::exitApplication,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ import cafe.adriel.voyager.navigator.Navigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
|
||||||
class ReaderScreen(
|
class ReaderScreen(
|
||||||
val chapterIndex: Int,
|
val chapterId: Long,
|
||||||
val mangaId: Long,
|
val mangaId: Long,
|
||||||
) : Screen {
|
) : Screen {
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
ReaderMenu(
|
ReaderMenu(
|
||||||
chapterIndex,
|
chapterId,
|
||||||
mangaId,
|
mangaId,
|
||||||
navigator::pop,
|
navigator::pop,
|
||||||
)
|
)
|
||||||
@@ -32,10 +32,10 @@ actual class ReaderLauncher(
|
|||||||
private val navigator: Navigator?,
|
private val navigator: Navigator?,
|
||||||
) {
|
) {
|
||||||
actual fun launch(
|
actual fun launch(
|
||||||
chapterIndex: Int,
|
chapterId: Long,
|
||||||
mangaId: Long,
|
mangaId: Long,
|
||||||
) {
|
) {
|
||||||
navigator?.push(ReaderScreen(chapterIndex, mangaId))
|
navigator?.push(ReaderScreen(chapterId, mangaId))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
Reference in New Issue
Block a user