mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Last part of GQL conversion
This commit is contained in:
@@ -23,18 +23,13 @@ import ca.gosyer.jui.core.lang.throwIfCancellation
|
|||||||
import ca.gosyer.jui.core.prefs.getAsFlow
|
import ca.gosyer.jui.core.prefs.getAsFlow
|
||||||
import ca.gosyer.jui.domain.base.WebsocketService.Actions
|
import ca.gosyer.jui.domain.base.WebsocketService.Actions
|
||||||
import ca.gosyer.jui.domain.base.WebsocketService.Status
|
import ca.gosyer.jui.domain.base.WebsocketService.Status
|
||||||
import ca.gosyer.jui.domain.library.model.JobStatus
|
import ca.gosyer.jui.domain.library.model.MangaUpdate
|
||||||
import ca.gosyer.jui.domain.library.model.UpdateStatus
|
|
||||||
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
||||||
import ca.gosyer.jui.domain.library.service.LibraryUpdateService.Companion.status
|
import ca.gosyer.jui.domain.library.service.LibraryUpdateService.Companion.status
|
||||||
import ca.gosyer.jui.i18n.MR
|
import ca.gosyer.jui.i18n.MR
|
||||||
import com.diamondedge.logging.logging
|
import com.diamondedge.logging.logging
|
||||||
import dev.icerock.moko.resources.desc.desc
|
import dev.icerock.moko.resources.desc.desc
|
||||||
import dev.icerock.moko.resources.format
|
import dev.icerock.moko.resources.format
|
||||||
import io.ktor.client.plugins.websocket.ws
|
|
||||||
import io.ktor.http.URLProtocol
|
|
||||||
import io.ktor.websocket.Frame
|
|
||||||
import io.ktor.websocket.readText
|
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -43,13 +38,9 @@ import kotlinx.coroutines.cancel
|
|||||||
import kotlinx.coroutines.cancelChildren
|
import kotlinx.coroutines.cancelChildren
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.drop
|
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.job
|
import kotlinx.coroutines.job
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
@@ -154,31 +145,12 @@ class AndroidLibraryService : Service() {
|
|||||||
throw CancellationException()
|
throw CancellationException()
|
||||||
}
|
}
|
||||||
runCatching {
|
runCatching {
|
||||||
client.ws(
|
appComponent.libraryUpdateService
|
||||||
host = serverUrl.host,
|
.getSubscription()
|
||||||
port = serverUrl.port,
|
.onEach {
|
||||||
path = serverUrl.encodedPath + "/api/v1/update",
|
onReceived()
|
||||||
request = {
|
}
|
||||||
if (serverUrl.protocol == URLProtocol.HTTPS) {
|
.collect()
|
||||||
url.protocol = URLProtocol.WSS
|
|
||||||
}
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
errorConnectionCount = 0
|
|
||||||
status.value = Status.RUNNING
|
|
||||||
send(Frame.Text("STATUS"))
|
|
||||||
|
|
||||||
incoming.receiveAsFlow()
|
|
||||||
.filterIsInstance<Frame.Text>()
|
|
||||||
.map { json.decodeFromString<UpdateStatus>(it.readText()) }
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.drop(1)
|
|
||||||
.mapLatest(::onReceived)
|
|
||||||
.catch {
|
|
||||||
log.warn(it) { "Error running library update" }
|
|
||||||
}
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}.throwIfCancellation().isFailure.let {
|
}.throwIfCancellation().isFailure.let {
|
||||||
status.value = Status.STARTING
|
status.value = Status.STARTING
|
||||||
if (it) errorConnectionCount++
|
if (it) errorConnectionCount++
|
||||||
@@ -193,20 +165,16 @@ class AndroidLibraryService : Service() {
|
|||||||
.launchIn(ioScope)
|
.launchIn(ioScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onReceived(status: UpdateStatus) {
|
private fun onReceived() {
|
||||||
LibraryUpdateService.updateStatus.value = status
|
val status = LibraryUpdateService.updateStatus.value
|
||||||
|
|
||||||
val complete = status.mangaStatusMap[JobStatus.COMPLETE]?.size ?: 0
|
val total = status.jobsInfo.totalJobs
|
||||||
val failed = status.mangaStatusMap[JobStatus.FAILED]?.size ?: 0
|
val current = status.jobsInfo.finishedJobs
|
||||||
val running = status.mangaStatusMap[JobStatus.RUNNING]?.size ?: 0
|
|
||||||
val pending = status.mangaStatusMap[JobStatus.PENDING]?.size ?: 0
|
|
||||||
val skipped = status.mangaStatusMap[JobStatus.SKIPPED]?.size ?: 0
|
|
||||||
val total = complete + failed + running + pending + skipped
|
|
||||||
val current = complete + failed + skipped
|
|
||||||
if (current != total) {
|
if (current != total) {
|
||||||
val notification = with(progressNotificationBuilder) {
|
val notification = with(progressNotificationBuilder) {
|
||||||
val updatingText = status.mangaStatusMap[JobStatus.RUNNING]
|
val updatingText = status.mangaUpdates
|
||||||
?.joinToString("\n") { it.title.chop(40) }
|
.filter { it.status == MangaUpdate.Status.RUNNING }
|
||||||
|
.joinToString("\n") { it.manga.title.chop(40) }
|
||||||
setContentTitle(
|
setContentTitle(
|
||||||
MR.strings.notification_updating
|
MR.strings.notification_updating
|
||||||
.format(current, total)
|
.format(current, total)
|
||||||
|
|||||||
@@ -57,10 +57,14 @@ mutation DeleteCategory($categoryId: Int!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query GetCategoryManga($categoryId: [Int!]!) {
|
query GetCategoryManga($categoryId: Int!) {
|
||||||
mangas(orderBy: ID, condition: {categoryIds: $categoryId}) {
|
category(id: $categoryId) {
|
||||||
nodes {
|
id
|
||||||
...MangaFragment
|
mangas {
|
||||||
|
nodes {
|
||||||
|
...LibraryMangaFragment
|
||||||
|
}
|
||||||
|
totalCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,3 +3,43 @@ mutation SetMangaInLibrary($id: Int!, $inLibrary: Boolean!) {
|
|||||||
clientMutationId
|
clientMutationId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query LibraryUpdateStatus {
|
||||||
|
libraryUpdateStatus {
|
||||||
|
categoryUpdates {
|
||||||
|
...CategoryUpdateFragment
|
||||||
|
}
|
||||||
|
jobsInfo {
|
||||||
|
...UpdaterJobsInfoFragment
|
||||||
|
}
|
||||||
|
mangaUpdates {
|
||||||
|
...MangaUpdateFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription LibraryUpdateStatusChanged($maxUpdates: Int = 30) {
|
||||||
|
libraryUpdateStatusChanged(input: {maxUpdates: $maxUpdates}) {
|
||||||
|
initial {
|
||||||
|
categoryUpdates {
|
||||||
|
...CategoryUpdateFragment
|
||||||
|
}
|
||||||
|
jobsInfo {
|
||||||
|
...UpdaterJobsInfoFragment
|
||||||
|
}
|
||||||
|
mangaUpdates {
|
||||||
|
...MangaUpdateFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
categoryUpdates {
|
||||||
|
...CategoryUpdateFragment
|
||||||
|
}
|
||||||
|
mangaUpdates {
|
||||||
|
...MangaUpdateFragment
|
||||||
|
}
|
||||||
|
jobsInfo {
|
||||||
|
...UpdaterJobsInfoFragment
|
||||||
|
}
|
||||||
|
omittedUpdates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
fragment CategoryUpdateFragment on CategoryUpdateType {
|
||||||
|
category {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
status
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment UpdaterJobsInfoFragment on UpdaterJobsInfoType {
|
||||||
|
finishedJobs
|
||||||
|
isRunning
|
||||||
|
skippedCategoriesCount
|
||||||
|
skippedMangasCount
|
||||||
|
totalJobs
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment MangaUpdateFragment on MangaUpdateType {
|
||||||
|
manga {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
status
|
||||||
|
}
|
||||||
@@ -20,7 +20,6 @@ import ca.gosyer.jui.data.graphql.SetCategoryMetaMutation
|
|||||||
import ca.gosyer.jui.data.graphql.fragment.CategoryFragment
|
import ca.gosyer.jui.data.graphql.fragment.CategoryFragment
|
||||||
import ca.gosyer.jui.data.manga.MangaRepositoryImpl.Companion.toManga
|
import ca.gosyer.jui.data.manga.MangaRepositoryImpl.Companion.toManga
|
||||||
import ca.gosyer.jui.domain.category.model.Category
|
import ca.gosyer.jui.domain.category.model.Category
|
||||||
import ca.gosyer.jui.domain.category.model.CategoryMeta
|
|
||||||
import ca.gosyer.jui.domain.category.service.CategoryRepository
|
import ca.gosyer.jui.domain.category.service.CategoryRepository
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.server.Http
|
||||||
@@ -133,12 +132,12 @@ class CategoryRepositoryImpl(
|
|||||||
|
|
||||||
override fun getMangaFromCategory(categoryId: Long): Flow<List<Manga>> =
|
override fun getMangaFromCategory(categoryId: Long): Flow<List<Manga>> =
|
||||||
apolloClient.query(
|
apolloClient.query(
|
||||||
GetCategoryMangaQuery(listOf(categoryId.toInt())),
|
GetCategoryMangaQuery(categoryId.toInt()),
|
||||||
)
|
)
|
||||||
.toFlow()
|
.toFlow()
|
||||||
.map {
|
.map {
|
||||||
val data = it.dataAssertNoErrors
|
val data = it.dataAssertNoErrors
|
||||||
data.mangas.nodes.map { it.mangaFragment.toManga() }
|
data.category.mangas.nodes.map { it.libraryMangaFragment.toManga() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateCategoryMeta(
|
override fun updateCategoryMeta(
|
||||||
@@ -162,7 +161,7 @@ class CategoryRepositoryImpl(
|
|||||||
order = order,
|
order = order,
|
||||||
name = name,
|
name = name,
|
||||||
default = default,
|
default = default,
|
||||||
meta = CategoryMeta(),
|
meta = Category.CategoryMeta(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import ca.gosyer.jui.data.graphql.fragment.ChapterWithMangaFragment
|
|||||||
import ca.gosyer.jui.data.graphql.type.UpdateChapterPatchInput
|
import ca.gosyer.jui.data.graphql.type.UpdateChapterPatchInput
|
||||||
import ca.gosyer.jui.data.manga.MangaRepositoryImpl.Companion.toManga
|
import ca.gosyer.jui.data.manga.MangaRepositoryImpl.Companion.toManga
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
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.chapter.service.ChapterRepository
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.server.Http
|
||||||
import ca.gosyer.jui.domain.updates.model.MangaAndChapter
|
import ca.gosyer.jui.domain.updates.model.MangaAndChapter
|
||||||
@@ -190,7 +189,7 @@ class ChapterRepositoryImpl(
|
|||||||
pageCount = pageCount,
|
pageCount = pageCount,
|
||||||
lastReadAt = lastPageRead,
|
lastReadAt = lastPageRead,
|
||||||
downloaded = isDownloaded,
|
downloaded = isDownloaded,
|
||||||
meta = ChapterMeta(
|
meta = Chapter.ChapterMeta(
|
||||||
juiPageOffset = meta.find { it.key == "juiPageOffset" }?.value?.toIntOrNull() ?: 0,
|
juiPageOffset = meta.find { it.key == "juiPageOffset" }?.value?.toIntOrNull() ?: 0,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
package ca.gosyer.jui.data.library
|
package ca.gosyer.jui.data.library
|
||||||
|
|
||||||
import ca.gosyer.jui.data.ApolloAppClient
|
import ca.gosyer.jui.data.ApolloAppClient
|
||||||
|
import ca.gosyer.jui.data.graphql.LibraryUpdateStatusChangedSubscription
|
||||||
|
import ca.gosyer.jui.data.graphql.LibraryUpdateStatusQuery
|
||||||
import ca.gosyer.jui.data.graphql.SetMangaInLibraryMutation
|
import ca.gosyer.jui.data.graphql.SetMangaInLibraryMutation
|
||||||
|
import ca.gosyer.jui.data.graphql.fragment.CategoryUpdateFragment
|
||||||
|
import ca.gosyer.jui.data.graphql.fragment.MangaUpdateFragment
|
||||||
|
import ca.gosyer.jui.data.graphql.fragment.UpdaterJobsInfoFragment
|
||||||
|
import ca.gosyer.jui.data.graphql.type.CategoryJobStatus
|
||||||
|
import ca.gosyer.jui.data.graphql.type.MangaJobStatus
|
||||||
|
import ca.gosyer.jui.domain.library.model.CategoryUpdate
|
||||||
|
import ca.gosyer.jui.domain.library.model.MangaUpdate
|
||||||
|
import ca.gosyer.jui.domain.library.model.UpdateStatus
|
||||||
|
import ca.gosyer.jui.domain.library.model.UpdaterJobsInfo
|
||||||
|
import ca.gosyer.jui.domain.library.model.UpdaterUpdates
|
||||||
import ca.gosyer.jui.domain.library.service.LibraryRepository
|
import ca.gosyer.jui.domain.library.service.LibraryRepository
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.server.Http
|
||||||
import com.apollographql.apollo.ApolloClient
|
import com.apollographql.apollo.ApolloClient
|
||||||
@@ -33,4 +45,92 @@ class LibraryRepositoryImpl(
|
|||||||
override fun addMangaToLibrary(mangaId: Long): Flow<Unit> = setMangaInLibrary(mangaId, true)
|
override fun addMangaToLibrary(mangaId: Long): Flow<Unit> = setMangaInLibrary(mangaId, true)
|
||||||
|
|
||||||
override fun removeMangaFromLibrary(mangaId: Long): Flow<Unit> = setMangaInLibrary(mangaId, false)
|
override fun removeMangaFromLibrary(mangaId: Long): Flow<Unit> = setMangaInLibrary(mangaId, false)
|
||||||
|
|
||||||
|
override fun libraryUpdateSubscription(): Flow<UpdaterUpdates> =
|
||||||
|
apolloClient.subscription(
|
||||||
|
LibraryUpdateStatusChangedSubscription(),
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
val data = it.dataAssertNoErrors.libraryUpdateStatusChanged
|
||||||
|
UpdaterUpdates(
|
||||||
|
data.initial?.let {
|
||||||
|
UpdateStatus(
|
||||||
|
it.categoryUpdates.map {
|
||||||
|
it.categoryUpdateFragment.toCategoryUpdate()
|
||||||
|
},
|
||||||
|
it.mangaUpdates.map {
|
||||||
|
it.mangaUpdateFragment.toMangaUpdate()
|
||||||
|
},
|
||||||
|
it.jobsInfo.updaterJobsInfoFragment.toUpdaterJobsInfo(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
data.categoryUpdates.map {
|
||||||
|
it.categoryUpdateFragment.toCategoryUpdate()
|
||||||
|
},
|
||||||
|
data.mangaUpdates.map {
|
||||||
|
it.mangaUpdateFragment.toMangaUpdate()
|
||||||
|
},
|
||||||
|
data.jobsInfo.updaterJobsInfoFragment.toUpdaterJobsInfo(),
|
||||||
|
data.omittedUpdates,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun libraryUpdateStatus(): Flow<UpdateStatus> =
|
||||||
|
apolloClient.query(
|
||||||
|
LibraryUpdateStatusQuery(),
|
||||||
|
)
|
||||||
|
.toFlow()
|
||||||
|
.map {
|
||||||
|
val data = it.dataAssertNoErrors.libraryUpdateStatus
|
||||||
|
UpdateStatus(
|
||||||
|
data.categoryUpdates.map {
|
||||||
|
it.categoryUpdateFragment.toCategoryUpdate()
|
||||||
|
},
|
||||||
|
data.mangaUpdates.map {
|
||||||
|
it.mangaUpdateFragment.toMangaUpdate()
|
||||||
|
},
|
||||||
|
data.jobsInfo.updaterJobsInfoFragment.toUpdaterJobsInfo(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun UpdaterJobsInfoFragment.toUpdaterJobsInfo() =
|
||||||
|
UpdaterJobsInfo(
|
||||||
|
finishedJobs,
|
||||||
|
isRunning,
|
||||||
|
skippedCategoriesCount,
|
||||||
|
skippedMangasCount,
|
||||||
|
totalJobs,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun CategoryUpdateFragment.toCategoryUpdate() =
|
||||||
|
CategoryUpdate(
|
||||||
|
CategoryUpdate.UpdateCategory(
|
||||||
|
category.id.toLong(),
|
||||||
|
category.name,
|
||||||
|
),
|
||||||
|
when (status) {
|
||||||
|
CategoryJobStatus.UPDATING -> CategoryUpdate.Status.UPDATING
|
||||||
|
CategoryJobStatus.SKIPPED -> CategoryUpdate.Status.SKIPPED
|
||||||
|
CategoryJobStatus.UNKNOWN__ -> CategoryUpdate.Status.UPDATING
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fun MangaUpdateFragment.toMangaUpdate() =
|
||||||
|
MangaUpdate(
|
||||||
|
MangaUpdate.UpdateManga(
|
||||||
|
manga.id.toLong(),
|
||||||
|
manga.title,
|
||||||
|
),
|
||||||
|
when (status) {
|
||||||
|
MangaJobStatus.PENDING -> MangaUpdate.Status.PENDING
|
||||||
|
MangaJobStatus.RUNNING -> MangaUpdate.Status.RUNNING
|
||||||
|
MangaJobStatus.COMPLETE -> MangaUpdate.Status.COMPLETE
|
||||||
|
MangaJobStatus.FAILED -> MangaUpdate.Status.FAILED
|
||||||
|
MangaJobStatus.SKIPPED -> MangaUpdate.Status.SKIPPED
|
||||||
|
MangaJobStatus.UNKNOWN__ -> MangaUpdate.Status.FAILED
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ suspend fun main() {
|
|||||||
.filter { it == ServerResult.STARTED || it == ServerResult.UNUSED }
|
.filter { it == ServerResult.STARTED || it == ServerResult.UNUSED }
|
||||||
.onEach {
|
.onEach {
|
||||||
appComponent.downloadService.getSubscription().launchIn(GlobalScope)
|
appComponent.downloadService.getSubscription().launchIn(GlobalScope)
|
||||||
appComponent.libraryUpdateService.init()
|
appComponent.libraryUpdateService.getSubscription().launchIn(GlobalScope)
|
||||||
}
|
}
|
||||||
.launchIn(GlobalScope)
|
.launchIn(GlobalScope)
|
||||||
|
|
||||||
|
|||||||
@@ -113,11 +113,6 @@ interface SharedDomainComponent : CoreComponent {
|
|||||||
val serverHostPreferencesFactory: ServerHostPreferences
|
val serverHostPreferencesFactory: ServerHostPreferences
|
||||||
get() = ServerHostPreferences(preferenceFactory.create("host"))
|
get() = ServerHostPreferences(preferenceFactory.create("host"))
|
||||||
|
|
||||||
@get:AppScope
|
|
||||||
@get:Provides
|
|
||||||
val libraryUpdateServiceFactory: LibraryUpdateService
|
|
||||||
get() = LibraryUpdateService(serverPreferences, http)
|
|
||||||
|
|
||||||
@get:AppScope
|
@get:AppScope
|
||||||
@get:Provides
|
@get:Provides
|
||||||
val serverListenersFactory: ServerListeners
|
val serverListenersFactory: ServerListeners
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.backup.model
|
package ca.gosyer.jui.domain.backup.model
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class BackupValidationResult(
|
data class BackupValidationResult(
|
||||||
val missingSources: List<String>,
|
val missingSources: List<String>,
|
||||||
val missingTrackers: List<String>,
|
val missingTrackers: List<String>,
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.backup.model
|
package ca.gosyer.jui.domain.backup.model
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
enum class RestoreState {
|
enum class RestoreState {
|
||||||
IDLE,
|
IDLE,
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
@@ -19,7 +17,6 @@ enum class RestoreState {
|
|||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class RestoreStatus(
|
data class RestoreStatus(
|
||||||
val state: RestoreState,
|
val state: RestoreState,
|
||||||
val completed: Int,
|
val completed: Int,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.category.interactor
|
package ca.gosyer.jui.domain.category.interactor
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.ServerListeners
|
||||||
import ca.gosyer.jui.domain.category.service.CategoryRepository
|
import ca.gosyer.jui.domain.category.service.CategoryRepository
|
||||||
import com.diamondedge.logging.logging
|
import com.diamondedge.logging.logging
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
@@ -16,6 +17,7 @@ import me.tatarka.inject.annotations.Inject
|
|||||||
@Inject
|
@Inject
|
||||||
class GetCategories(
|
class GetCategories(
|
||||||
private val categoryRepository: CategoryRepository,
|
private val categoryRepository: CategoryRepository,
|
||||||
|
private val serverListeners: ServerListeners,
|
||||||
) {
|
) {
|
||||||
suspend fun await(
|
suspend fun await(
|
||||||
dropDefault: Boolean = false,
|
dropDefault: Boolean = false,
|
||||||
@@ -27,15 +29,16 @@ class GetCategories(
|
|||||||
}
|
}
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
|
|
||||||
fun asFlow(dropDefault: Boolean = false) =
|
fun asFlow(dropDefault: Boolean = false) = serverListeners.combineCategoryManga(
|
||||||
categoryRepository.getCategories()
|
categoryRepository.getCategories()
|
||||||
.map { categories ->
|
).map { categories ->
|
||||||
if (dropDefault) {
|
if (dropDefault) {
|
||||||
categories.filterNot { it.name.equals("default", true) }
|
categories.filterNot { it.name.equals("default", true) }
|
||||||
} else {
|
} else {
|
||||||
categories
|
categories
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = logging()
|
private val log = logging()
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
package ca.gosyer.jui.domain.category.model
|
package ca.gosyer.jui.domain.category.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Category(
|
data class Category(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
@@ -17,10 +15,9 @@ data class Category(
|
|||||||
val name: String,
|
val name: String,
|
||||||
val default: Boolean,
|
val default: Boolean,
|
||||||
val meta: CategoryMeta,
|
val meta: CategoryMeta,
|
||||||
)
|
) {
|
||||||
|
@Immutable
|
||||||
@Serializable
|
data class CategoryMeta(
|
||||||
@Immutable
|
val example: Int = 0,
|
||||||
data class CategoryMeta(
|
)
|
||||||
val example: Int = 0,
|
}
|
||||||
)
|
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
package ca.gosyer.jui.domain.chapter.model
|
package ca.gosyer.jui.domain.chapter.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Chapter(
|
data class Chapter(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
@@ -29,10 +27,10 @@ data class Chapter(
|
|||||||
val lastReadAt: Int?,
|
val lastReadAt: Int?,
|
||||||
val downloaded: Boolean,
|
val downloaded: Boolean,
|
||||||
val meta: ChapterMeta,
|
val meta: ChapterMeta,
|
||||||
)
|
) {
|
||||||
|
@Immutable
|
||||||
|
data class ChapterMeta(
|
||||||
|
val juiPageOffset: Int = 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
data class ChapterMeta(
|
|
||||||
val juiPageOffset: Int = 0,
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,15 +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.model
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ChapterBatchEditInput(
|
|
||||||
val chapterIds: List<Long>? = null,
|
|
||||||
val change: ChapterChange?,
|
|
||||||
)
|
|
||||||
@@ -1,17 +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.model
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ChapterChange(
|
|
||||||
val isRead: Boolean? = null,
|
|
||||||
val isBookmarked: Boolean? = null,
|
|
||||||
val lastPageRead: Int? = null,
|
|
||||||
val delete: Boolean? = null,
|
|
||||||
)
|
|
||||||
@@ -1,16 +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.model
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class MangaChapterBatchEditInput(
|
|
||||||
val chapterIds: List<Long>? = null,
|
|
||||||
val chapterIndexes: List<Int>? = null,
|
|
||||||
val change: ChapterChange?,
|
|
||||||
)
|
|
||||||
@@ -1,14 +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.download.model
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class DownloadEnqueue(
|
|
||||||
val chapterIds: List<Long>,
|
|
||||||
)
|
|
||||||
@@ -7,9 +7,7 @@
|
|||||||
package ca.gosyer.jui.domain.extension.model
|
package ca.gosyer.jui.domain.extension.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Extension(
|
data class Extension(
|
||||||
val name: String,
|
val name: String,
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package ca.gosyer.jui.domain.library.model
|
||||||
|
|
||||||
|
data class CategoryUpdate(
|
||||||
|
val category: UpdateCategory,
|
||||||
|
val status: Status,
|
||||||
|
) {
|
||||||
|
enum class Status {
|
||||||
|
UPDATING,
|
||||||
|
SKIPPED
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UpdateCategory(
|
||||||
|
val id: Long,
|
||||||
|
val name: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,17 +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.library.model
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
|
||||||
enum class CategoryUpdateStatus {
|
|
||||||
UPDATING,
|
|
||||||
SKIPPED,
|
|
||||||
}
|
|
||||||
@@ -1,20 +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.library.model
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
|
||||||
enum class JobStatus {
|
|
||||||
PENDING,
|
|
||||||
RUNNING,
|
|
||||||
COMPLETE,
|
|
||||||
FAILED,
|
|
||||||
SKIPPED,
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ca.gosyer.jui.domain.library.model
|
||||||
|
|
||||||
|
data class MangaUpdate(
|
||||||
|
val manga: UpdateManga,
|
||||||
|
val status: Status,
|
||||||
|
) {
|
||||||
|
enum class Status {
|
||||||
|
PENDING,
|
||||||
|
RUNNING,
|
||||||
|
COMPLETE,
|
||||||
|
FAILED,
|
||||||
|
SKIPPED
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UpdateManga(
|
||||||
|
val id: Long,
|
||||||
|
val title: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,15 +6,8 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.library.model
|
package ca.gosyer.jui.domain.library.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import ca.gosyer.jui.domain.category.model.Category
|
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
data class UpdateStatus(
|
data class UpdateStatus(
|
||||||
val categoryStatusMap: Map<CategoryUpdateStatus, List<Category>> = emptyMap(),
|
val categoryUpdates: List<CategoryUpdate>,
|
||||||
val mangaStatusMap: Map<JobStatus, List<Manga>> = emptyMap(),
|
val mangaUpdates: List<MangaUpdate>,
|
||||||
val running: Boolean,
|
val jobsInfo: UpdaterJobsInfo,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package ca.gosyer.jui.domain.library.model
|
||||||
|
|
||||||
|
data class UpdaterJobsInfo(
|
||||||
|
val finishedJobs: Int,
|
||||||
|
val isRunning: Boolean,
|
||||||
|
val skippedCategoriesCount: Int,
|
||||||
|
val skippedMangasCount: Int,
|
||||||
|
val totalJobs: Int,
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package ca.gosyer.jui.domain.library.model
|
||||||
|
|
||||||
|
data class UpdaterUpdates(
|
||||||
|
val initial: UpdateStatus?,
|
||||||
|
val categoryUpdates: List<CategoryUpdate>,
|
||||||
|
val mangaUpdates: List<MangaUpdate>,
|
||||||
|
val jobsInfo: UpdaterJobsInfo,
|
||||||
|
val omittedUpdates: Boolean,
|
||||||
|
)
|
||||||
@@ -6,10 +6,17 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.library.service
|
package ca.gosyer.jui.domain.library.service
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.library.model.UpdateStatus
|
||||||
|
import ca.gosyer.jui.domain.library.model.UpdaterUpdates
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface LibraryRepository {
|
interface LibraryRepository {
|
||||||
fun addMangaToLibrary(mangaId: Long): Flow<Unit>
|
fun addMangaToLibrary(mangaId: Long): Flow<Unit>
|
||||||
|
|
||||||
fun removeMangaFromLibrary(mangaId: Long): Flow<Unit>
|
fun removeMangaFromLibrary(mangaId: Long): Flow<Unit>
|
||||||
|
|
||||||
|
|
||||||
|
fun libraryUpdateSubscription(): Flow<UpdaterUpdates>
|
||||||
|
|
||||||
|
fun libraryUpdateStatus(): Flow<UpdateStatus>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,33 +8,73 @@ package ca.gosyer.jui.domain.library.service
|
|||||||
|
|
||||||
import ca.gosyer.jui.domain.base.WebsocketService
|
import ca.gosyer.jui.domain.base.WebsocketService
|
||||||
import ca.gosyer.jui.domain.library.model.UpdateStatus
|
import ca.gosyer.jui.domain.library.model.UpdateStatus
|
||||||
import ca.gosyer.jui.domain.server.Http
|
import ca.gosyer.jui.domain.library.model.UpdaterJobsInfo
|
||||||
import ca.gosyer.jui.domain.server.service.ServerPreferences
|
|
||||||
import com.diamondedge.logging.logging
|
import com.diamondedge.logging.logging
|
||||||
import io.ktor.websocket.Frame
|
|
||||||
import io.ktor.websocket.readText
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
class LibraryUpdateService(
|
class LibraryUpdateService(
|
||||||
serverPreferences: ServerPreferences,
|
private val libraryUpdateRepository: LibraryRepository,
|
||||||
client: Http,
|
) {
|
||||||
) : WebsocketService(serverPreferences, client) {
|
fun getSubscription() = libraryUpdateRepository.libraryUpdateSubscription()
|
||||||
override val status: MutableStateFlow<Status>
|
.onStart {
|
||||||
get() = LibraryUpdateService.status
|
log.info { "Starting library update status subscription" }
|
||||||
|
status.value = WebsocketService.Status.STARTING
|
||||||
|
}
|
||||||
|
.catch { error ->
|
||||||
|
log.error(error) { "Error in library update status subscription" }
|
||||||
|
status.value = WebsocketService.Status.STOPPED
|
||||||
|
}
|
||||||
|
.map { updates ->
|
||||||
|
status.value = WebsocketService.Status.RUNNING
|
||||||
|
if (updates.omittedUpdates) {
|
||||||
|
log.info { "Omitted updates detected, fetching fresh library update status" }
|
||||||
|
fetchLibraryUpdateStatus()
|
||||||
|
return@map
|
||||||
|
}
|
||||||
|
if (updates.initial != null) {
|
||||||
|
updateStatus.value = updates.initial
|
||||||
|
}
|
||||||
|
updates.jobsInfo.let { jobsInfo ->
|
||||||
|
updateStatus.update {
|
||||||
|
it.copy(
|
||||||
|
jobsInfo = jobsInfo,
|
||||||
|
categoryUpdates = updates.categoryUpdates,
|
||||||
|
mangaUpdates = updates.mangaUpdates
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val query: String
|
private suspend fun fetchLibraryUpdateStatus() {
|
||||||
get() = "/api/v1/update"
|
val status = libraryUpdateRepository.libraryUpdateStatus().firstOrNull()
|
||||||
|
if (status != null) {
|
||||||
override suspend fun onReceived(frame: Frame.Text) {
|
updateStatus.value = status
|
||||||
updateStatus.value = json.decodeFromString<UpdateStatus>(frame.readText())
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = logging()
|
private val log = logging()
|
||||||
|
|
||||||
val status = MutableStateFlow(Status.STARTING)
|
val status = MutableStateFlow(WebsocketService.Status.STARTING)
|
||||||
val updateStatus = MutableStateFlow(UpdateStatus(emptyMap(), emptyMap(), false))
|
val updateStatus = MutableStateFlow(
|
||||||
|
UpdateStatus(
|
||||||
|
emptyList(),
|
||||||
|
emptyList(),
|
||||||
|
UpdaterJobsInfo(
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ import androidx.compose.runtime.Stable
|
|||||||
import ca.gosyer.jui.domain.source.model.Source
|
import ca.gosyer.jui.domain.source.model.Source
|
||||||
import ca.gosyer.jui.i18n.MR
|
import ca.gosyer.jui.i18n.MR
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Manga(
|
data class Manga(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
@@ -46,7 +44,6 @@ data class Manga(
|
|||||||
val chaptersAge: Long?,
|
val chaptersAge: Long?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class MangaMeta(
|
data class MangaMeta(
|
||||||
val juiReaderMode: String = DEFAULT_READER_MODE,
|
val juiReaderMode: String = DEFAULT_READER_MODE,
|
||||||
@@ -56,7 +53,6 @@ data class MangaMeta(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
@Stable
|
||||||
enum class MangaStatus(
|
enum class MangaStatus(
|
||||||
@Transient val res: StringResource,
|
@Transient val res: StringResource,
|
||||||
@@ -70,7 +66,6 @@ enum class MangaStatus(
|
|||||||
ON_HIATUS(MR.strings.status_on_hiatus),
|
ON_HIATUS(MR.strings.status_on_hiatus),
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
@Stable
|
||||||
enum class UpdateStrategy {
|
enum class UpdateStrategy {
|
||||||
ALWAYS_UPDATE,
|
ALWAYS_UPDATE,
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ package ca.gosyer.jui.domain.settings.model
|
|||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class About(
|
data class About(
|
||||||
val name: String,
|
val name: String,
|
||||||
@@ -21,7 +19,6 @@ data class About(
|
|||||||
val discord: String,
|
val discord: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
@Stable
|
||||||
enum class AboutBuildType {
|
enum class AboutBuildType {
|
||||||
Preview,
|
Preview,
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ package ca.gosyer.jui.domain.source.model
|
|||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
@Stable
|
||||||
data class MangaPage(
|
data class MangaPage(
|
||||||
val mangaList: List<Manga>,
|
val mangaList: List<Manga>,
|
||||||
|
|||||||
@@ -7,10 +7,8 @@
|
|||||||
package ca.gosyer.jui.domain.source.model
|
package ca.gosyer.jui.domain.source.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import ca.gosyer.jui.core.io.Serializable as JvmSerializable
|
import ca.gosyer.jui.core.io.Serializable as JvmSerializable
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
@Stable
|
||||||
data class Source(
|
data class Source(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
|
|||||||
@@ -1,22 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("CheckBox")
|
|
||||||
data class CheckBoxFilterOld(
|
|
||||||
override val filter: CheckBoxProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class CheckBoxProps(
|
|
||||||
override val name: String,
|
|
||||||
override val state: Boolean,
|
|
||||||
) : Props<Boolean>
|
|
||||||
}
|
|
||||||
@@ -1,22 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("Group")
|
|
||||||
data class GroupFilterOld(
|
|
||||||
override val filter: GroupProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class GroupProps(
|
|
||||||
override val name: String,
|
|
||||||
override val state: List<SourceFilterOld>,
|
|
||||||
) : Props<List<SourceFilterOld>>
|
|
||||||
}
|
|
||||||
@@ -1,24 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("Header")
|
|
||||||
data class HeaderFilterOld(
|
|
||||||
override val filter: HeaderProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class HeaderProps(
|
|
||||||
override val name: String,
|
|
||||||
@Transient
|
|
||||||
override val state: Int = 0,
|
|
||||||
) : Props<Int>
|
|
||||||
}
|
|
||||||
@@ -1,25 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.JsonElement
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("Select")
|
|
||||||
data class SelectFilterOld(
|
|
||||||
override val filter: SelectProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class SelectProps(
|
|
||||||
override val name: String,
|
|
||||||
override val state: Int,
|
|
||||||
val values: List<JsonElement>,
|
|
||||||
val displayValues: List<String>? = null,
|
|
||||||
) : Props<Int>
|
|
||||||
}
|
|
||||||
@@ -1,24 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("Separator")
|
|
||||||
data class SeparatorFilterOld(
|
|
||||||
override val filter: SeparatorProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class SeparatorProps(
|
|
||||||
override val name: String,
|
|
||||||
@Transient
|
|
||||||
override val state: Int = 0,
|
|
||||||
) : Props<Int>
|
|
||||||
}
|
|
||||||
@@ -1,29 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("Sort")
|
|
||||||
data class SortFilterOld(
|
|
||||||
override val filter: SortProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class SortProps(
|
|
||||||
override val name: String,
|
|
||||||
override val state: Selection?,
|
|
||||||
val values: List<String>,
|
|
||||||
) : Props<Selection?>
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Selection(
|
|
||||||
val index: Int,
|
|
||||||
val ascending: Boolean,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -6,23 +6,6 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.source.model.sourcefilters
|
package ca.gosyer.jui.domain.source.model.sourcefilters
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SourceFilterChangeOld(
|
|
||||||
val position: Int,
|
|
||||||
val state: String,
|
|
||||||
) {
|
|
||||||
constructor(position: Int, state: Any) : this(
|
|
||||||
position,
|
|
||||||
if (state is SortFilterOld.Selection) {
|
|
||||||
Json.encodeToString(state)
|
|
||||||
} else {
|
|
||||||
state.toString()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface SourceFilter {
|
sealed interface SourceFilter {
|
||||||
val position: Int
|
val position: Int
|
||||||
@@ -1,15 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SourceFilterData(
|
|
||||||
val searchTerm: String?,
|
|
||||||
val filter: List<SourceFilterChangeOld>?,
|
|
||||||
)
|
|
||||||
@@ -1,19 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
sealed class SourceFilterOld {
|
|
||||||
abstract val filter: Props<*>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props<T> {
|
|
||||||
val name: String
|
|
||||||
val state: T
|
|
||||||
}
|
|
||||||
@@ -1,22 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("Text")
|
|
||||||
data class TextFilterOld(
|
|
||||||
override val filter: TextProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class TextProps(
|
|
||||||
override val name: String,
|
|
||||||
override val state: String,
|
|
||||||
) : Props<String>
|
|
||||||
}
|
|
||||||
@@ -1,22 +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.source.model.sourcefilters
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("TriState")
|
|
||||||
data class TriStateFilterOld(
|
|
||||||
override val filter: TriStateProps,
|
|
||||||
) : SourceFilterOld() {
|
|
||||||
@Serializable
|
|
||||||
data class TriStateProps(
|
|
||||||
override val name: String,
|
|
||||||
override val state: Int,
|
|
||||||
) : Props<Int>
|
|
||||||
}
|
|
||||||
@@ -1,18 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("CheckBoxPreference")
|
|
||||||
@Immutable
|
|
||||||
data class CheckBoxPreferenceOld(
|
|
||||||
override val props: TwoStateProps,
|
|
||||||
) : SourcePreferenceOld()
|
|
||||||
@@ -1,32 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("EditTextPreference")
|
|
||||||
@Immutable
|
|
||||||
data class EditTextPreferenceOld(
|
|
||||||
override val props: EditTextProps,
|
|
||||||
) : SourcePreferenceOld() {
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
data class EditTextProps(
|
|
||||||
override val key: String,
|
|
||||||
override val title: String?,
|
|
||||||
override val summary: String?,
|
|
||||||
override val currentValue: String?,
|
|
||||||
override val defaultValue: String?,
|
|
||||||
override val defaultValueType: String,
|
|
||||||
val dialogTitle: String?,
|
|
||||||
val dialogMessage: String?,
|
|
||||||
val text: String?,
|
|
||||||
) : Props<String?>
|
|
||||||
}
|
|
||||||
@@ -1,31 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("ListPreference")
|
|
||||||
@Immutable
|
|
||||||
data class ListPreferenceOld(
|
|
||||||
override val props: ListProps,
|
|
||||||
) : SourcePreferenceOld() {
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
data class ListProps(
|
|
||||||
override val key: String,
|
|
||||||
override val title: String,
|
|
||||||
override val summary: String?,
|
|
||||||
override val currentValue: String?,
|
|
||||||
override val defaultValue: String?,
|
|
||||||
override val defaultValueType: String,
|
|
||||||
val entries: List<String>,
|
|
||||||
val entryValues: List<String>,
|
|
||||||
) : Props<String?>
|
|
||||||
}
|
|
||||||
@@ -1,33 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("MultiSelectListPreference")
|
|
||||||
@Immutable
|
|
||||||
data class MultiSelectListPreferenceOld(
|
|
||||||
override val props: MultiSelectListProps,
|
|
||||||
) : SourcePreferenceOld() {
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
data class MultiSelectListProps(
|
|
||||||
override val key: String,
|
|
||||||
override val title: String,
|
|
||||||
override val summary: String?,
|
|
||||||
override val currentValue: List<String>?,
|
|
||||||
override val defaultValue: List<String>?,
|
|
||||||
override val defaultValueType: String,
|
|
||||||
val dialogTitle: String?,
|
|
||||||
val dialogMessage: String?,
|
|
||||||
val entries: List<String>,
|
|
||||||
val entryValues: List<String>,
|
|
||||||
) : Props<List<String>?>
|
|
||||||
}
|
|
||||||
@@ -6,25 +6,6 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.domain.source.model.sourcepreference
|
package ca.gosyer.jui.domain.source.model.sourcepreference
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
sealed class SourcePreferenceOld {
|
|
||||||
abstract val props: Props<*>
|
|
||||||
}
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
interface Props<T> {
|
|
||||||
val key: String
|
|
||||||
val title: String?
|
|
||||||
val summary: String?
|
|
||||||
val currentValue: T
|
|
||||||
val defaultValue: T
|
|
||||||
val defaultValueType: String
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface SourcePreference {
|
sealed interface SourcePreference {
|
||||||
val position: Int
|
val position: Int
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SourcePreferenceChange(
|
|
||||||
val position: Int,
|
|
||||||
val value: String,
|
|
||||||
) {
|
|
||||||
constructor(position: Int, value: Any) : this(
|
|
||||||
position,
|
|
||||||
if (value is List<*>) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
Json.encodeToString(value as List<String>)
|
|
||||||
} else {
|
|
||||||
value.toString()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,18 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("SwitchPreferenceCompat")
|
|
||||||
@Immutable
|
|
||||||
data class SwitchPreferenceOld(
|
|
||||||
override val props: TwoStateProps,
|
|
||||||
) : SourcePreferenceOld()
|
|
||||||
@@ -1,21 +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.source.model.sourcepreference
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
|
||||||
data class TwoStateProps(
|
|
||||||
override val key: String,
|
|
||||||
override val title: String?,
|
|
||||||
override val summary: String?,
|
|
||||||
override val currentValue: Boolean?,
|
|
||||||
override val defaultValue: Boolean?,
|
|
||||||
override val defaultValueType: String,
|
|
||||||
) : Props<Boolean?>
|
|
||||||
@@ -9,9 +9,7 @@ package ca.gosyer.jui.domain.updates.model
|
|||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class MangaAndChapter(
|
data class MangaAndChapter(
|
||||||
val manga: Manga,
|
val manga: Manga,
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
package ca.gosyer.jui.domain.updates.model
|
package ca.gosyer.jui.domain.updates.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Updates(
|
data class Updates(
|
||||||
val page: List<MangaAndChapter>,
|
val page: List<MangaAndChapter>,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import ca.gosyer.jui.domain.base.WebsocketService
|
import ca.gosyer.jui.domain.base.WebsocketService
|
||||||
import ca.gosyer.jui.domain.library.model.JobStatus
|
|
||||||
import ca.gosyer.jui.i18n.MR
|
import ca.gosyer.jui.i18n.MR
|
||||||
import ca.gosyer.jui.ui.base.LocalViewModels
|
import ca.gosyer.jui.ui.base.LocalViewModels
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
@@ -37,27 +36,18 @@ fun LibraryUpdatesExtraInfo() {
|
|||||||
val serviceStatus by vm.serviceStatus.collectAsState()
|
val serviceStatus by vm.serviceStatus.collectAsState()
|
||||||
val updateStatus by vm.updateStatus.collectAsState()
|
val updateStatus by vm.updateStatus.collectAsState()
|
||||||
|
|
||||||
fun Map<JobStatus, List<*>>.getSize(jobStatus: JobStatus): Int = get(jobStatus)?.size ?: 0
|
|
||||||
val current = remember(updateStatus) {
|
val current = remember(updateStatus) {
|
||||||
updateStatus.mangaStatusMap.run {
|
updateStatus.jobsInfo.finishedJobs
|
||||||
getSize(JobStatus.COMPLETE) + getSize(JobStatus.FAILED) + getSize(JobStatus.SKIPPED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val total = remember(updateStatus) {
|
val total = remember(updateStatus) {
|
||||||
updateStatus.mangaStatusMap.run {
|
updateStatus.jobsInfo.totalJobs
|
||||||
getSize(JobStatus.COMPLETE) +
|
|
||||||
getSize(JobStatus.FAILED) +
|
|
||||||
getSize(JobStatus.PENDING) +
|
|
||||||
getSize(JobStatus.RUNNING) +
|
|
||||||
getSize(JobStatus.SKIPPED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val text = when (serviceStatus) {
|
val text = when (serviceStatus) {
|
||||||
WebsocketService.Status.STARTING -> stringResource(MR.strings.downloads_loading)
|
WebsocketService.Status.STARTING -> stringResource(MR.strings.downloads_loading)
|
||||||
|
|
||||||
WebsocketService.Status.RUNNING -> {
|
WebsocketService.Status.RUNNING -> {
|
||||||
if (updateStatus.running) {
|
if (updateStatus.jobsInfo.isRunning) {
|
||||||
stringResource(MR.strings.notification_updating, current, total)
|
stringResource(MR.strings.notification_updating, current, total)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ package ca.gosyer.jui.ui.main.components
|
|||||||
import ca.gosyer.jui.domain.base.WebsocketService
|
import ca.gosyer.jui.domain.base.WebsocketService
|
||||||
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
|
||||||
internal actual fun startLibraryUpdatesService(
|
internal actual fun startLibraryUpdatesService(
|
||||||
contextWrapper: ContextWrapper,
|
contextWrapper: ContextWrapper,
|
||||||
libraryUpdatesService: LibraryUpdateService,
|
libraryUpdatesService: LibraryUpdateService,
|
||||||
actions: WebsocketService.Actions,
|
actions: WebsocketService.Actions,
|
||||||
) {
|
) {
|
||||||
libraryUpdatesService.init()
|
libraryUpdatesService.getSubscription().launchIn(GlobalScope)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ package ca.gosyer.jui.ui.main.components
|
|||||||
import ca.gosyer.jui.domain.base.WebsocketService
|
import ca.gosyer.jui.domain.base.WebsocketService
|
||||||
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
|
||||||
internal actual fun startLibraryUpdatesService(
|
internal actual fun startLibraryUpdatesService(
|
||||||
contextWrapper: ContextWrapper,
|
contextWrapper: ContextWrapper,
|
||||||
libraryUpdatesService: LibraryUpdateService,
|
libraryUpdatesService: LibraryUpdateService,
|
||||||
actions: WebsocketService.Actions,
|
actions: WebsocketService.Actions,
|
||||||
) {
|
) {
|
||||||
libraryUpdatesService.init()
|
libraryUpdatesService.getSubscription().launchIn(GlobalScope)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user