diff --git a/android/src/main/kotlin/ca/gosyer/jui/android/data/library/AndroidLibraryService.kt b/android/src/main/kotlin/ca/gosyer/jui/android/data/library/AndroidLibraryService.kt index 17875bb2..fbfc4fee 100644 --- a/android/src/main/kotlin/ca/gosyer/jui/android/data/library/AndroidLibraryService.kt +++ b/android/src/main/kotlin/ca/gosyer/jui/android/data/library/AndroidLibraryService.kt @@ -23,18 +23,13 @@ import ca.gosyer.jui.core.lang.throwIfCancellation import ca.gosyer.jui.core.prefs.getAsFlow import ca.gosyer.jui.domain.base.WebsocketService.Actions import ca.gosyer.jui.domain.base.WebsocketService.Status -import ca.gosyer.jui.domain.library.model.JobStatus -import ca.gosyer.jui.domain.library.model.UpdateStatus +import ca.gosyer.jui.domain.library.model.MangaUpdate import ca.gosyer.jui.domain.library.service.LibraryUpdateService import ca.gosyer.jui.domain.library.service.LibraryUpdateService.Companion.status import ca.gosyer.jui.i18n.MR import com.diamondedge.logging.logging import dev.icerock.moko.resources.desc.desc 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.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -43,13 +38,9 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.flow.catch 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.map import kotlinx.coroutines.flow.mapLatest -import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.job import kotlinx.serialization.json.Json @@ -154,31 +145,12 @@ class AndroidLibraryService : Service() { throw CancellationException() } runCatching { - client.ws( - host = serverUrl.host, - port = serverUrl.port, - path = serverUrl.encodedPath + "/api/v1/update", - request = { - if (serverUrl.protocol == URLProtocol.HTTPS) { - url.protocol = URLProtocol.WSS - } - }, - ) { - errorConnectionCount = 0 - status.value = Status.RUNNING - send(Frame.Text("STATUS")) - - incoming.receiveAsFlow() - .filterIsInstance() - .map { json.decodeFromString(it.readText()) } - .distinctUntilChanged() - .drop(1) - .mapLatest(::onReceived) - .catch { - log.warn(it) { "Error running library update" } - } - .collect() - } + appComponent.libraryUpdateService + .getSubscription() + .onEach { + onReceived() + } + .collect() }.throwIfCancellation().isFailure.let { status.value = Status.STARTING if (it) errorConnectionCount++ @@ -193,20 +165,16 @@ class AndroidLibraryService : Service() { .launchIn(ioScope) } - private fun onReceived(status: UpdateStatus) { - LibraryUpdateService.updateStatus.value = status + private fun onReceived() { + val status = LibraryUpdateService.updateStatus.value - val complete = status.mangaStatusMap[JobStatus.COMPLETE]?.size ?: 0 - val failed = status.mangaStatusMap[JobStatus.FAILED]?.size ?: 0 - 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 + val total = status.jobsInfo.totalJobs + val current = status.jobsInfo.finishedJobs if (current != total) { val notification = with(progressNotificationBuilder) { - val updatingText = status.mangaStatusMap[JobStatus.RUNNING] - ?.joinToString("\n") { it.title.chop(40) } + val updatingText = status.mangaUpdates + .filter { it.status == MangaUpdate.Status.RUNNING } + .joinToString("\n") { it.manga.title.chop(40) } setContentTitle( MR.strings.notification_updating .format(current, total) diff --git a/data/src/commonMain/graphql/Category.graphql b/data/src/commonMain/graphql/Category.graphql index cbb1e684..7de5cc0b 100644 --- a/data/src/commonMain/graphql/Category.graphql +++ b/data/src/commonMain/graphql/Category.graphql @@ -57,10 +57,14 @@ mutation DeleteCategory($categoryId: Int!) { } } -query GetCategoryManga($categoryId: [Int!]!) { - mangas(orderBy: ID, condition: {categoryIds: $categoryId}) { - nodes { - ...MangaFragment +query GetCategoryManga($categoryId: Int!) { + category(id: $categoryId) { + id + mangas { + nodes { + ...LibraryMangaFragment + } + totalCount } } } diff --git a/data/src/commonMain/graphql/Library.graphql b/data/src/commonMain/graphql/Library.graphql index e62efefd..c9762189 100644 --- a/data/src/commonMain/graphql/Library.graphql +++ b/data/src/commonMain/graphql/Library.graphql @@ -3,3 +3,43 @@ mutation SetMangaInLibrary($id: Int!, $inLibrary: Boolean!) { 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 + } +} diff --git a/data/src/commonMain/graphql/fragments/LibraryFragments.graphql b/data/src/commonMain/graphql/fragments/LibraryFragments.graphql new file mode 100644 index 00000000..b97bd0a9 --- /dev/null +++ b/data/src/commonMain/graphql/fragments/LibraryFragments.graphql @@ -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 +} diff --git a/data/src/commonMain/kotlin/ca/gosyer/jui/data/category/CategoryRepositoryImpl.kt b/data/src/commonMain/kotlin/ca/gosyer/jui/data/category/CategoryRepositoryImpl.kt index 0468ae89..dbb5ec69 100644 --- a/data/src/commonMain/kotlin/ca/gosyer/jui/data/category/CategoryRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/ca/gosyer/jui/data/category/CategoryRepositoryImpl.kt @@ -20,7 +20,6 @@ import ca.gosyer.jui.data.graphql.SetCategoryMetaMutation import ca.gosyer.jui.data.graphql.fragment.CategoryFragment import ca.gosyer.jui.data.manga.MangaRepositoryImpl.Companion.toManga 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.manga.model.Manga import ca.gosyer.jui.domain.server.Http @@ -133,12 +132,12 @@ class CategoryRepositoryImpl( override fun getMangaFromCategory(categoryId: Long): Flow> = apolloClient.query( - GetCategoryMangaQuery(listOf(categoryId.toInt())), + GetCategoryMangaQuery(categoryId.toInt()), ) .toFlow() .map { val data = it.dataAssertNoErrors - data.mangas.nodes.map { it.mangaFragment.toManga() } + data.category.mangas.nodes.map { it.libraryMangaFragment.toManga() } } override fun updateCategoryMeta( @@ -162,7 +161,7 @@ class CategoryRepositoryImpl( order = order, name = name, default = default, - meta = CategoryMeta(), + meta = Category.CategoryMeta(), ) } } diff --git a/data/src/commonMain/kotlin/ca/gosyer/jui/data/chapter/ChapterRepositoryImpl.kt b/data/src/commonMain/kotlin/ca/gosyer/jui/data/chapter/ChapterRepositoryImpl.kt index 2bbf9e2d..ab8092f9 100644 --- a/data/src/commonMain/kotlin/ca/gosyer/jui/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/ca/gosyer/jui/data/chapter/ChapterRepositoryImpl.kt @@ -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.manga.MangaRepositoryImpl.Companion.toManga 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 ca.gosyer.jui.domain.updates.model.MangaAndChapter @@ -190,7 +189,7 @@ class ChapterRepositoryImpl( pageCount = pageCount, lastReadAt = lastPageRead, downloaded = isDownloaded, - meta = ChapterMeta( + meta = Chapter.ChapterMeta( juiPageOffset = meta.find { it.key == "juiPageOffset" }?.value?.toIntOrNull() ?: 0, ), ) diff --git a/data/src/commonMain/kotlin/ca/gosyer/jui/data/library/LibraryRepositoryImpl.kt b/data/src/commonMain/kotlin/ca/gosyer/jui/data/library/LibraryRepositoryImpl.kt index 7e7647fc..0930618e 100644 --- a/data/src/commonMain/kotlin/ca/gosyer/jui/data/library/LibraryRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/ca/gosyer/jui/data/library/LibraryRepositoryImpl.kt @@ -1,7 +1,19 @@ package ca.gosyer.jui.data.library 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.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.server.Http import com.apollographql.apollo.ApolloClient @@ -33,4 +45,92 @@ class LibraryRepositoryImpl( override fun addMangaToLibrary(mangaId: Long): Flow = setMangaInLibrary(mangaId, true) override fun removeMangaFromLibrary(mangaId: Long): Flow = setMangaInLibrary(mangaId, false) + + override fun libraryUpdateSubscription(): Flow = + 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 = + 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 + }, + ) + } } diff --git a/desktop/src/main/kotlin/ca/gosyer/jui/desktop/main.kt b/desktop/src/main/kotlin/ca/gosyer/jui/desktop/main.kt index 372fded4..6ce413d7 100644 --- a/desktop/src/main/kotlin/ca/gosyer/jui/desktop/main.kt +++ b/desktop/src/main/kotlin/ca/gosyer/jui/desktop/main.kt @@ -100,7 +100,7 @@ suspend fun main() { .filter { it == ServerResult.STARTED || it == ServerResult.UNUSED } .onEach { appComponent.downloadService.getSubscription().launchIn(GlobalScope) - appComponent.libraryUpdateService.init() + appComponent.libraryUpdateService.getSubscription().launchIn(GlobalScope) } .launchIn(GlobalScope) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/SharedDomainComponent.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/SharedDomainComponent.kt index 6db0056b..f369f2be 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/SharedDomainComponent.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/SharedDomainComponent.kt @@ -113,11 +113,6 @@ interface SharedDomainComponent : CoreComponent { val serverHostPreferencesFactory: ServerHostPreferences get() = ServerHostPreferences(preferenceFactory.create("host")) - @get:AppScope - @get:Provides - val libraryUpdateServiceFactory: LibraryUpdateService - get() = LibraryUpdateService(serverPreferences, http) - @get:AppScope @get:Provides val serverListenersFactory: ServerListeners diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/BackupValidationResult.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/BackupValidationResult.kt index c2f73fd7..a3d530d3 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/BackupValidationResult.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/BackupValidationResult.kt @@ -6,9 +6,6 @@ package ca.gosyer.jui.domain.backup.model -import kotlinx.serialization.Serializable - -@Serializable data class BackupValidationResult( val missingSources: List, val missingTrackers: List, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/RestoreStatus.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/RestoreStatus.kt index ce63c8f9..6670d2ef 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/RestoreStatus.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/backup/model/RestoreStatus.kt @@ -6,8 +6,6 @@ package ca.gosyer.jui.domain.backup.model -import kotlinx.serialization.Serializable - enum class RestoreState { IDLE, SUCCESS, @@ -19,7 +17,6 @@ enum class RestoreState { UNKNOWN, } -@Serializable data class RestoreStatus( val state: RestoreState, val completed: Int, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetCategories.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetCategories.kt index 62280533..e6e7dbf8 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetCategories.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetCategories.kt @@ -6,6 +6,7 @@ package ca.gosyer.jui.domain.category.interactor +import ca.gosyer.jui.domain.ServerListeners import ca.gosyer.jui.domain.category.service.CategoryRepository import com.diamondedge.logging.logging import kotlinx.coroutines.flow.catch @@ -16,6 +17,7 @@ import me.tatarka.inject.annotations.Inject @Inject class GetCategories( private val categoryRepository: CategoryRepository, + private val serverListeners: ServerListeners, ) { suspend fun await( dropDefault: Boolean = false, @@ -27,15 +29,16 @@ class GetCategories( } .singleOrNull() - fun asFlow(dropDefault: Boolean = false) = + fun asFlow(dropDefault: Boolean = false) = serverListeners.combineCategoryManga( categoryRepository.getCategories() - .map { categories -> - if (dropDefault) { - categories.filterNot { it.name.equals("default", true) } - } else { - categories - } - } + ).map { categories -> + if (dropDefault) { + categories.filterNot { it.name.equals("default", true) } + } else { + categories + } + } + companion object { private val log = logging() diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/model/Category.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/model/Category.kt index 5070bc72..6becdd86 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/model/Category.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/model/Category.kt @@ -7,9 +7,7 @@ package ca.gosyer.jui.domain.category.model import androidx.compose.runtime.Immutable -import kotlinx.serialization.Serializable -@Serializable @Immutable data class Category( val id: Long, @@ -17,10 +15,9 @@ data class Category( val name: String, val default: Boolean, val meta: CategoryMeta, -) - -@Serializable -@Immutable -data class CategoryMeta( - val example: Int = 0, -) +) { + @Immutable + data class CategoryMeta( + val example: Int = 0, + ) +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/Chapter.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/Chapter.kt index 9a941371..80baea7b 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/Chapter.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/Chapter.kt @@ -7,9 +7,7 @@ package ca.gosyer.jui.domain.chapter.model import androidx.compose.runtime.Immutable -import kotlinx.serialization.Serializable -@Serializable @Immutable data class Chapter( val id: Long, @@ -29,10 +27,10 @@ data class Chapter( val lastReadAt: Int?, val downloaded: Boolean, val meta: ChapterMeta, -) +) { + @Immutable + data class ChapterMeta( + val juiPageOffset: Int = 0, + ) +} -@Serializable -@Immutable -data class ChapterMeta( - val juiPageOffset: Int = 0, -) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/ChapterBatchEditInput.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/ChapterBatchEditInput.kt deleted file mode 100644 index f8765836..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/ChapterBatchEditInput.kt +++ /dev/null @@ -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? = null, - val change: ChapterChange?, -) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/ChapterChange.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/ChapterChange.kt deleted file mode 100644 index 55f86fac..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/ChapterChange.kt +++ /dev/null @@ -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, -) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/MangaChapterBatchEditInput.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/MangaChapterBatchEditInput.kt deleted file mode 100644 index be9e477c..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/model/MangaChapterBatchEditInput.kt +++ /dev/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? = null, - val chapterIndexes: List? = null, - val change: ChapterChange?, -) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/download/model/DownloadEnqueue.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/download/model/DownloadEnqueue.kt deleted file mode 100644 index c419f676..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/download/model/DownloadEnqueue.kt +++ /dev/null @@ -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, -) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/extension/model/Extension.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/extension/model/Extension.kt index cacf798f..e045f500 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/extension/model/Extension.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/extension/model/Extension.kt @@ -7,9 +7,7 @@ package ca.gosyer.jui.domain.extension.model import androidx.compose.runtime.Immutable -import kotlinx.serialization.Serializable -@Serializable @Immutable data class Extension( val name: String, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/CategoryUpdate.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/CategoryUpdate.kt new file mode 100644 index 00000000..5d3f7932 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/CategoryUpdate.kt @@ -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, + ) +} + diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/CategoryUpdateStatus.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/CategoryUpdateStatus.kt deleted file mode 100644 index 70ee673e..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/CategoryUpdateStatus.kt +++ /dev/null @@ -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, -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/JobStatus.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/JobStatus.kt deleted file mode 100644 index a5ed6d88..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/JobStatus.kt +++ /dev/null @@ -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, -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/MangaUpdate.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/MangaUpdate.kt new file mode 100644 index 00000000..74f01a2e --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/MangaUpdate.kt @@ -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, + ) +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdateStatus.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdateStatus.kt index b2cfc136..f9b04e86 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdateStatus.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdateStatus.kt @@ -6,15 +6,8 @@ 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( - val categoryStatusMap: Map> = emptyMap(), - val mangaStatusMap: Map> = emptyMap(), - val running: Boolean, + val categoryUpdates: List, + val mangaUpdates: List, + val jobsInfo: UpdaterJobsInfo, ) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdaterJobsInfo.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdaterJobsInfo.kt new file mode 100644 index 00000000..f3b60881 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdaterJobsInfo.kt @@ -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, +) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdaterUpdates.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdaterUpdates.kt new file mode 100644 index 00000000..449bba3e --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/model/UpdaterUpdates.kt @@ -0,0 +1,9 @@ +package ca.gosyer.jui.domain.library.model + +data class UpdaterUpdates( + val initial: UpdateStatus?, + val categoryUpdates: List, + val mangaUpdates: List, + val jobsInfo: UpdaterJobsInfo, + val omittedUpdates: Boolean, +) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryRepository.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryRepository.kt index fded1ab8..d43aca1c 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryRepository.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryRepository.kt @@ -6,10 +6,17 @@ 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 interface LibraryRepository { fun addMangaToLibrary(mangaId: Long): Flow fun removeMangaFromLibrary(mangaId: Long): Flow + + + fun libraryUpdateSubscription(): Flow + + fun libraryUpdateStatus(): Flow } diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryUpdateService.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryUpdateService.kt index 2a7ebb0a..1bbff676 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryUpdateService.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/service/LibraryUpdateService.kt @@ -8,33 +8,73 @@ package ca.gosyer.jui.domain.library.service import ca.gosyer.jui.domain.base.WebsocketService import ca.gosyer.jui.domain.library.model.UpdateStatus -import ca.gosyer.jui.domain.server.Http -import ca.gosyer.jui.domain.server.service.ServerPreferences +import ca.gosyer.jui.domain.library.model.UpdaterJobsInfo import com.diamondedge.logging.logging -import io.ktor.websocket.Frame -import io.ktor.websocket.readText 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 @Inject class LibraryUpdateService( - serverPreferences: ServerPreferences, - client: Http, -) : WebsocketService(serverPreferences, client) { - override val status: MutableStateFlow - get() = LibraryUpdateService.status + private val libraryUpdateRepository: LibraryRepository, +) { + fun getSubscription() = libraryUpdateRepository.libraryUpdateSubscription() + .onStart { + 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 - get() = "/api/v1/update" - - override suspend fun onReceived(frame: Frame.Text) { - updateStatus.value = json.decodeFromString(frame.readText()) + private suspend fun fetchLibraryUpdateStatus() { + val status = libraryUpdateRepository.libraryUpdateStatus().firstOrNull() + if (status != null) { + updateStatus.value = status + } } companion object { private val log = logging() - val status = MutableStateFlow(Status.STARTING) - val updateStatus = MutableStateFlow(UpdateStatus(emptyMap(), emptyMap(), false)) + val status = MutableStateFlow(WebsocketService.Status.STARTING) + val updateStatus = MutableStateFlow( + UpdateStatus( + emptyList(), + emptyList(), + UpdaterJobsInfo( + 0, + false, + 0, + 0, + 0, + ) + ) + ) } } diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/model/Manga.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/model/Manga.kt index 024ae85c..c6875807 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/model/Manga.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/model/Manga.kt @@ -11,10 +11,8 @@ import androidx.compose.runtime.Stable import ca.gosyer.jui.domain.source.model.Source import ca.gosyer.jui.i18n.MR import dev.icerock.moko.resources.StringResource -import kotlinx.serialization.Serializable import kotlinx.serialization.Transient -@Serializable @Immutable data class Manga( val id: Long, @@ -46,7 +44,6 @@ data class Manga( val chaptersAge: Long?, ) -@Serializable @Immutable data class MangaMeta( val juiReaderMode: String = DEFAULT_READER_MODE, @@ -56,7 +53,6 @@ data class MangaMeta( } } -@Serializable @Stable enum class MangaStatus( @Transient val res: StringResource, @@ -70,7 +66,6 @@ enum class MangaStatus( ON_HIATUS(MR.strings.status_on_hiatus), } -@Serializable @Stable enum class UpdateStrategy { ALWAYS_UPDATE, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/settings/model/About.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/settings/model/About.kt index 8dd30b36..6dee0eed 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/settings/model/About.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/settings/model/About.kt @@ -8,9 +8,7 @@ package ca.gosyer.jui.domain.settings.model import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable -import kotlinx.serialization.Serializable -@Serializable @Immutable data class About( val name: String, @@ -21,7 +19,6 @@ data class About( val discord: String, ) -@Serializable @Stable enum class AboutBuildType { Preview, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/MangaPage.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/MangaPage.kt index dde8110b..2c388928 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/MangaPage.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/MangaPage.kt @@ -8,9 +8,7 @@ package ca.gosyer.jui.domain.source.model import androidx.compose.runtime.Stable import ca.gosyer.jui.domain.manga.model.Manga -import kotlinx.serialization.Serializable -@Serializable @Stable data class MangaPage( val mangaList: List, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/Source.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/Source.kt index 259063ec..9a5c98fc 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/Source.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/Source.kt @@ -7,10 +7,8 @@ package ca.gosyer.jui.domain.source.model import androidx.compose.runtime.Stable -import kotlinx.serialization.Serializable import ca.gosyer.jui.core.io.Serializable as JvmSerializable -@Serializable @Stable data class Source( val id: Long, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/CheckBoxFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/CheckBoxFilterOld.kt deleted file mode 100644 index f45531c8..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/CheckBoxFilterOld.kt +++ /dev/null @@ -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 -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/GroupFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/GroupFilterOld.kt deleted file mode 100644 index cc0cca96..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/GroupFilterOld.kt +++ /dev/null @@ -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, - ) : Props> -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/HeaderFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/HeaderFilterOld.kt deleted file mode 100644 index ae76b670..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/HeaderFilterOld.kt +++ /dev/null @@ -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 -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SelectFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SelectFilterOld.kt deleted file mode 100644 index 83722589..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SelectFilterOld.kt +++ /dev/null @@ -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, - val displayValues: List? = null, - ) : Props -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SeparatorFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SeparatorFilterOld.kt deleted file mode 100644 index ad725638..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SeparatorFilterOld.kt +++ /dev/null @@ -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 -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SortFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SortFilterOld.kt deleted file mode 100644 index e460d10b..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SortFilterOld.kt +++ /dev/null @@ -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, - ) : Props - - @Serializable - data class Selection( - val index: Int, - val ascending: Boolean, - ) -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterChange.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilter.kt similarity index 82% rename from domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterChange.kt rename to domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilter.kt index ff2890de..d53fbf26 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterChange.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilter.kt @@ -6,23 +6,6 @@ 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 { val position: Int diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterData.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterData.kt deleted file mode 100644 index 24c54fc9..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterData.kt +++ /dev/null @@ -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?, -) diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterOld.kt deleted file mode 100644 index 7b7ab9e7..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/SourceFilterOld.kt +++ /dev/null @@ -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 { - val name: String - val state: T -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/TextFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/TextFilterOld.kt deleted file mode 100644 index c28aaec5..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/TextFilterOld.kt +++ /dev/null @@ -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 -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/TriStateFilterOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/TriStateFilterOld.kt deleted file mode 100644 index 0c6f0200..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcefilters/TriStateFilterOld.kt +++ /dev/null @@ -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 -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/CheckBoxPreferenceOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/CheckBoxPreferenceOld.kt deleted file mode 100644 index fbb229e8..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/CheckBoxPreferenceOld.kt +++ /dev/null @@ -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() diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/EditTextPreferenceOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/EditTextPreferenceOld.kt deleted file mode 100644 index e88dd3e4..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/EditTextPreferenceOld.kt +++ /dev/null @@ -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 -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/ListPreferenceOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/ListPreferenceOld.kt deleted file mode 100644 index e55c2c09..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/ListPreferenceOld.kt +++ /dev/null @@ -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, - val entryValues: List, - ) : Props -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/MultiSelectListPreferenceOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/MultiSelectListPreferenceOld.kt deleted file mode 100644 index db6fd087..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/MultiSelectListPreferenceOld.kt +++ /dev/null @@ -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?, - override val defaultValue: List?, - override val defaultValueType: String, - val dialogTitle: String?, - val dialogMessage: String?, - val entries: List, - val entryValues: List, - ) : Props?> -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreference.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreference.kt index f8a6bc97..1ebb455b 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreference.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreference.kt @@ -6,25 +6,6 @@ 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 { - val key: String - val title: String? - val summary: String? - val currentValue: T - val defaultValue: T - val defaultValueType: String -} - sealed interface SourcePreference { val position: Int } diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreferenceChange.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreferenceChange.kt deleted file mode 100644 index 71eeb809..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SourcePreferenceChange.kt +++ /dev/null @@ -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) - } else { - value.toString() - }, - ) -} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SwitchPreferenceOld.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SwitchPreferenceOld.kt deleted file mode 100644 index d1576351..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/SwitchPreferenceOld.kt +++ /dev/null @@ -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() diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/TwoStateProps.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/TwoStateProps.kt deleted file mode 100644 index 6c42742d..00000000 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/source/model/sourcepreference/TwoStateProps.kt +++ /dev/null @@ -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 diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/MangaAndChapter.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/MangaAndChapter.kt index 6b8ca8d3..8322e647 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/MangaAndChapter.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/MangaAndChapter.kt @@ -9,9 +9,7 @@ package ca.gosyer.jui.domain.updates.model import androidx.compose.runtime.Immutable import ca.gosyer.jui.domain.chapter.model.Chapter import ca.gosyer.jui.domain.manga.model.Manga -import kotlinx.serialization.Serializable -@Serializable @Immutable data class MangaAndChapter( val manga: Manga, diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/Updates.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/Updates.kt index 28abdb17..d0752955 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/Updates.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/updates/model/Updates.kt @@ -7,9 +7,7 @@ package ca.gosyer.jui.domain.updates.model import androidx.compose.runtime.Immutable -import kotlinx.serialization.Serializable -@Serializable @Immutable data class Updates( val page: List, diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/main/components/LibraryUpdatesExtraInfo.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/main/components/LibraryUpdatesExtraInfo.kt index f941d56f..00cb688e 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/main/components/LibraryUpdatesExtraInfo.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/main/components/LibraryUpdatesExtraInfo.kt @@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color 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.ui.base.LocalViewModels import ca.gosyer.jui.uicore.resources.stringResource @@ -37,27 +36,18 @@ fun LibraryUpdatesExtraInfo() { val serviceStatus by vm.serviceStatus.collectAsState() val updateStatus by vm.updateStatus.collectAsState() - fun Map>.getSize(jobStatus: JobStatus): Int = get(jobStatus)?.size ?: 0 val current = remember(updateStatus) { - updateStatus.mangaStatusMap.run { - getSize(JobStatus.COMPLETE) + getSize(JobStatus.FAILED) + getSize(JobStatus.SKIPPED) - } + updateStatus.jobsInfo.finishedJobs } val total = remember(updateStatus) { - updateStatus.mangaStatusMap.run { - getSize(JobStatus.COMPLETE) + - getSize(JobStatus.FAILED) + - getSize(JobStatus.PENDING) + - getSize(JobStatus.RUNNING) + - getSize(JobStatus.SKIPPED) - } + updateStatus.jobsInfo.totalJobs } val text = when (serviceStatus) { WebsocketService.Status.STARTING -> stringResource(MR.strings.downloads_loading) WebsocketService.Status.RUNNING -> { - if (updateStatus.running) { + if (updateStatus.jobsInfo.isRunning) { stringResource(MR.strings.notification_updating, current, total) } else { null diff --git a/presentation/src/desktopMain/kotlin/ca/gosyer/jui/ui/main/components/DesktopLibraryUpdatesService.kt b/presentation/src/desktopMain/kotlin/ca/gosyer/jui/ui/main/components/DesktopLibraryUpdatesService.kt index f3dc8dbe..eeb3affd 100644 --- a/presentation/src/desktopMain/kotlin/ca/gosyer/jui/ui/main/components/DesktopLibraryUpdatesService.kt +++ b/presentation/src/desktopMain/kotlin/ca/gosyer/jui/ui/main/components/DesktopLibraryUpdatesService.kt @@ -9,11 +9,13 @@ package ca.gosyer.jui.ui.main.components import ca.gosyer.jui.domain.base.WebsocketService import ca.gosyer.jui.domain.library.service.LibraryUpdateService import ca.gosyer.jui.uicore.vm.ContextWrapper +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.launchIn internal actual fun startLibraryUpdatesService( contextWrapper: ContextWrapper, libraryUpdatesService: LibraryUpdateService, actions: WebsocketService.Actions, ) { - libraryUpdatesService.init() + libraryUpdatesService.getSubscription().launchIn(GlobalScope) } diff --git a/presentation/src/iosMain/kotlin/ca/gosyer/jui/ui/main/components/IosLibraryUpdatesService.kt b/presentation/src/iosMain/kotlin/ca/gosyer/jui/ui/main/components/IosLibraryUpdatesService.kt index f3dc8dbe..eeb3affd 100644 --- a/presentation/src/iosMain/kotlin/ca/gosyer/jui/ui/main/components/IosLibraryUpdatesService.kt +++ b/presentation/src/iosMain/kotlin/ca/gosyer/jui/ui/main/components/IosLibraryUpdatesService.kt @@ -9,11 +9,13 @@ package ca.gosyer.jui.ui.main.components import ca.gosyer.jui.domain.base.WebsocketService import ca.gosyer.jui.domain.library.service.LibraryUpdateService import ca.gosyer.jui.uicore.vm.ContextWrapper +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.launchIn internal actual fun startLibraryUpdatesService( contextWrapper: ContextWrapper, libraryUpdatesService: LibraryUpdateService, actions: WebsocketService.Actions, ) { - libraryUpdatesService.init() + libraryUpdatesService.getSubscription().launchIn(GlobalScope) }