From ca2e3813bbd1168cf7c6bd5737fc5948463c3b2e Mon Sep 17 00:00:00 2001 From: Syer10 Date: Fri, 1 Jul 2022 11:19:17 -0400 Subject: [PATCH] Use interactors for category and library data calls --- .../category/interactor/AddMangaToCategory.kt | 34 ++++++++ .../category/interactor/CreateCategory.kt | 26 ++++++ .../category/interactor/DeleteCategory.kt | 33 ++++++++ .../category/interactor/GetCategories.kt | 26 ++++++ .../category/interactor/GetMangaCategories.kt | 33 ++++++++ .../interactor/GetMangaListFromCategory.kt | 33 ++++++++ .../category/interactor/ModifyCategory.kt | 45 ++++++++++ .../interactor/RemoveMangaFromCategory.kt | 34 ++++++++ .../category/interactor/ReorderCategory.kt | 26 ++++++ .../chapter/interactor/UpdateChapterMeta.kt | 32 ++++--- .../library/interactor/AddMangaToLibrary.kt | 33 ++++++++ .../interactor/RemoveMangaFromLibrary.kt | 33 ++++++++ .../manga/interactor/UpdateMangaMeta.kt | 30 +++++-- .../categories/CategoriesScreenViewModel.kt | 84 +++++++------------ .../jui/ui/library/LibraryScreenViewModel.kt | 30 ++++--- .../jui/ui/manga/MangaScreenViewModel.kt | 62 +++++--------- .../jui/ui/reader/ReaderMenuViewModel.kt | 12 +-- .../jui/ui/settings/SettingsLibraryScreen.kt | 24 ++---- 18 files changed, 470 insertions(+), 160 deletions(-) create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/AddMangaToCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/CreateCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/DeleteCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetCategories.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaCategories.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaListFromCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ModifyCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/RemoveMangaFromCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ReorderCategory.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/AddMangaToLibrary.kt create mode 100644 domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/RemoveMangaFromLibrary.kt diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/AddMangaToCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/AddMangaToCategory.kt new file mode 100644 index 00000000..f1f6584b --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/AddMangaToCategory.kt @@ -0,0 +1,34 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.model.Category +import ca.gosyer.jui.domain.category.service.CategoryRepository +import ca.gosyer.jui.domain.manga.model.Manga +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class AddMangaToCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(mangaId: Long, categoryId: Long) = asFlow(mangaId, categoryId) + .catch { log.warn(it) { "Failed to add $mangaId to category $categoryId" } } + .collect() + + suspend fun await(manga: Manga, category: Category) = asFlow(manga, category) + .catch { log.warn(it) { "Failed to add ${manga.title}(${manga.id}) to category ${category.name}" } } + .collect() + + fun asFlow(mangaId: Long, categoryId: Long) = categoryRepository.addMangaToCategory(mangaId, categoryId) + + fun asFlow(manga: Manga, category: Category) = categoryRepository.addMangaToCategory(manga.id, category.id) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/CreateCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/CreateCategory.kt new file mode 100644 index 00000000..fe9ec370 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/CreateCategory.kt @@ -0,0 +1,26 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.service.CategoryRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class CreateCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(name: String) = asFlow(name) + .catch { log.warn(it) { "Failed to create category $name" } } + .collect() + + fun asFlow(name: String) = categoryRepository.createCategory(name) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/DeleteCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/DeleteCategory.kt new file mode 100644 index 00000000..b53b086f --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/DeleteCategory.kt @@ -0,0 +1,33 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.model.Category +import ca.gosyer.jui.domain.category.service.CategoryRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class DeleteCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(categoryId: Long) = asFlow(categoryId) + .catch { log.warn(it) { "Failed to delete category $categoryId" } } + .collect() + + suspend fun await(category: Category) = asFlow(category) + .catch { log.warn(it) { "Failed to delete category ${category.name}" } } + .collect() + + fun asFlow(categoryId: Long) = categoryRepository.deleteCategory(categoryId) + + fun asFlow(category: Category) = categoryRepository.deleteCategory(category.id) + + companion object { + private val log = logging() + } +} 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 new file mode 100644 index 00000000..e1c8e900 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetCategories.kt @@ -0,0 +1,26 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.service.CategoryRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.singleOrNull +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class GetCategories @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(dropDefault: Boolean = false) = asFlow(dropDefault) + .catch { log.warn(it) { "Failed to get categories" } } + .singleOrNull() + + fun asFlow(dropDefault: Boolean = false) = categoryRepository.getCategories(dropDefault) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaCategories.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaCategories.kt new file mode 100644 index 00000000..11d60ca6 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaCategories.kt @@ -0,0 +1,33 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.service.CategoryRepository +import ca.gosyer.jui.domain.manga.model.Manga +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.singleOrNull +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class GetMangaCategories @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(mangaId: Long) = asFlow(mangaId) + .catch { log.warn(it) { "Failed to get categories for $mangaId" } } + .singleOrNull() + + suspend fun await(manga: Manga) = asFlow(manga) + .catch { log.warn(it) { "Failed to get categories for ${manga.title}(${manga.id})" } } + .singleOrNull() + + fun asFlow(mangaId: Long) = categoryRepository.getMangaCategories(mangaId) + + fun asFlow(manga: Manga) = categoryRepository.getMangaCategories(manga.id) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaListFromCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaListFromCategory.kt new file mode 100644 index 00000000..cad8bc4c --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/GetMangaListFromCategory.kt @@ -0,0 +1,33 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.model.Category +import ca.gosyer.jui.domain.category.service.CategoryRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.singleOrNull +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class GetMangaListFromCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(categoryId: Long) = asFlow(categoryId) + .catch { log.warn(it) { "Failed to get manga list from category $categoryId" } } + .singleOrNull() + + suspend fun await(category: Category) = asFlow(category) + .catch { log.warn(it) { "Failed to get manga list from category ${category.name}" } } + .singleOrNull() + + fun asFlow(categoryId: Long) = categoryRepository.getMangaFromCategory(categoryId) + + fun asFlow(category: Category) = categoryRepository.getMangaFromCategory(category.id) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ModifyCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ModifyCategory.kt new file mode 100644 index 00000000..d6cffa8a --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ModifyCategory.kt @@ -0,0 +1,45 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.model.Category +import ca.gosyer.jui.domain.category.service.CategoryRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class ModifyCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(categoryId: Long, name: String? = null, isLanding: Boolean? = null) = asFlow( + categoryId = categoryId, + name = name, + isLanding = isLanding + ).catch { log.warn(it) { "Failed to modify category $categoryId with options: name=$name,isLanding=$isLanding" } }.collect() + + suspend fun await(category: Category, name: String? = null, isLanding: Boolean? = null) = asFlow( + category = category, + name = name, + isLanding = isLanding + ).catch { log.warn(it) { "Failed to modify category ${category.name} with options: name=$name,isLanding=$isLanding" } }.collect() + + fun asFlow(categoryId: Long, name: String? = null, isLanding: Boolean? = null) = categoryRepository.modifyCategory( + categoryId = categoryId, + name = name, + isLanding = isLanding + ) + + fun asFlow(category: Category, name: String? = null, isLanding: Boolean? = null) = categoryRepository.modifyCategory( + categoryId = category.id, + name = name, + isLanding = isLanding + ) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/RemoveMangaFromCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/RemoveMangaFromCategory.kt new file mode 100644 index 00000000..526e5b21 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/RemoveMangaFromCategory.kt @@ -0,0 +1,34 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.model.Category +import ca.gosyer.jui.domain.category.service.CategoryRepository +import ca.gosyer.jui.domain.manga.model.Manga +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class RemoveMangaFromCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(mangaId: Long, categoryId: Long) = asFlow(mangaId, categoryId) + .catch { log.warn(it) { "Failed to remove $mangaId from category $categoryId" } } + .collect() + + suspend fun await(manga: Manga, category: Category) = asFlow(manga, category) + .catch { log.warn(it) { "Failed to remove ${manga.title}(${manga.id}) from category ${category.name}" } } + .collect() + + fun asFlow(mangaId: Long, categoryId: Long) = categoryRepository.removeMangaFromCategory(mangaId, categoryId) + + fun asFlow(manga: Manga, category: Category) = categoryRepository.removeMangaFromCategory(manga.id, category.id) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ReorderCategory.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ReorderCategory.kt new file mode 100644 index 00000000..0c15f61e --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/category/interactor/ReorderCategory.kt @@ -0,0 +1,26 @@ +/* + * 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.category.interactor + +import ca.gosyer.jui.domain.category.service.CategoryRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class ReorderCategory @Inject constructor(private val categoryRepository: CategoryRepository) { + + suspend fun await(to: Int, from: Int) = asFlow(to, from) + .catch { log.warn(it) { "Failed to move category from $from to $to" } } + .collect() + + fun asFlow(to: Int, from: Int) = categoryRepository.reorderCategory(to, from) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/interactor/UpdateChapterMeta.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/interactor/UpdateChapterMeta.kt index b46e87ef..20b2447c 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/interactor/UpdateChapterMeta.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/chapter/interactor/UpdateChapterMeta.kt @@ -8,25 +8,37 @@ package ca.gosyer.jui.domain.chapter.interactor import ca.gosyer.jui.domain.chapter.model.Chapter import ca.gosyer.jui.domain.chapter.service.ChapterRepository -import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flow import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging class UpdateChapterMeta @Inject constructor(private val chapterRepository: ChapterRepository) { - fun subscribe( + suspend fun await( + chapter: Chapter, + pageOffset: Int = chapter.meta.juiPageOffset + ) = asFlow(chapter, pageOffset) + .catch { log.warn(it) { "Failed to update ${chapter.name}(${chapter.index}) meta" } } + .collect() + + fun asFlow( chapter: Chapter, pageOffset: Int = chapter.meta.juiPageOffset ) = flow { if (pageOffset != chapter.meta.juiPageOffset) { - emitAll( - chapterRepository.updateChapterMeta( - chapter.mangaId, - chapter.index, - "juiPageOffset", - pageOffset.toString() - ) - ) + chapterRepository.updateChapterMeta( + chapter.mangaId, + chapter.index, + "juiPageOffset", + pageOffset.toString() + ).collect() } + emit(Unit) + } + + companion object { + private val log = logging() } } diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/AddMangaToLibrary.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/AddMangaToLibrary.kt new file mode 100644 index 00000000..cc8047e6 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/AddMangaToLibrary.kt @@ -0,0 +1,33 @@ +/* + * 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.interactor + +import ca.gosyer.jui.domain.library.service.LibraryRepository +import ca.gosyer.jui.domain.manga.model.Manga +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.singleOrNull +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class AddMangaToLibrary @Inject constructor(private val libraryRepository: LibraryRepository) { + + suspend fun await(mangaId: Long) = asFlow(mangaId) + .catch { log.warn(it) { "Failed to add $mangaId to library" } } + .singleOrNull() + + suspend fun await(manga: Manga) = asFlow(manga) + .catch { log.warn(it) { "Failed to add ${manga.title}(${manga.id}) to library" } } + .singleOrNull() + + fun asFlow(mangaId: Long) = libraryRepository.addMangaToLibrary(mangaId) + + fun asFlow(manga: Manga) = libraryRepository.addMangaToLibrary(manga.id) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/RemoveMangaFromLibrary.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/RemoveMangaFromLibrary.kt new file mode 100644 index 00000000..d9568c17 --- /dev/null +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/library/interactor/RemoveMangaFromLibrary.kt @@ -0,0 +1,33 @@ +/* + * 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.interactor + +import ca.gosyer.jui.domain.library.service.LibraryRepository +import ca.gosyer.jui.domain.manga.model.Manga +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.singleOrNull +import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging + +class RemoveMangaFromLibrary @Inject constructor(private val libraryRepository: LibraryRepository) { + + suspend fun await(mangaId: Long) = asFlow(mangaId) + .catch { log.warn(it) { "Failed to remove $mangaId from library" } } + .singleOrNull() + + suspend fun await(manga: Manga) = asFlow(manga) + .catch { log.warn(it) { "Failed to remove ${manga.title}(${manga.id}) from library" } } + .singleOrNull() + + fun asFlow(mangaId: Long) = libraryRepository.removeMangaFromLibrary(mangaId) + + fun asFlow(manga: Manga) = libraryRepository.removeMangaFromLibrary(manga.id) + + companion object { + private val log = logging() + } +} diff --git a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/interactor/UpdateMangaMeta.kt b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/interactor/UpdateMangaMeta.kt index abd373b3..b8d40e4c 100644 --- a/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/interactor/UpdateMangaMeta.kt +++ b/domain/src/commonMain/kotlin/ca/gosyer/jui/domain/manga/interactor/UpdateMangaMeta.kt @@ -8,24 +8,36 @@ package ca.gosyer.jui.domain.manga.interactor import ca.gosyer.jui.domain.manga.model.Manga import ca.gosyer.jui.domain.manga.service.MangaRepository -import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flow import me.tatarka.inject.annotations.Inject +import org.lighthousegames.logging.logging class UpdateMangaMeta @Inject constructor(private val mangaRepository: MangaRepository) { - fun subscribe( + suspend fun await( + manga: Manga, + readerMode: String = manga.meta.juiReaderMode + ) = asFlow(manga, readerMode) + .catch { log.warn(it) { "Failed to update ${manga.title}(${manga.id}) meta" } } + .collect() + + fun asFlow( manga: Manga, readerMode: String = manga.meta.juiReaderMode ) = flow { if (readerMode != manga.meta.juiReaderMode) { - emitAll( - mangaRepository.updateMangaMeta( - manga.id, - "juiReaderMode", - readerMode - ) - ) + mangaRepository.updateMangaMeta( + manga.id, + "juiReaderMode", + readerMode + ).collect() } + emit(Unit) + } + + companion object { + private val log = logging() } } diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/categories/CategoriesScreenViewModel.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/categories/CategoriesScreenViewModel.kt index 2bba1226..2969ab83 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/categories/CategoriesScreenViewModel.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/categories/CategoriesScreenViewModel.kt @@ -6,99 +6,71 @@ package ca.gosyer.jui.ui.categories -import ca.gosyer.jui.data.category.CategoryRepositoryImpl +import ca.gosyer.jui.domain.category.interactor.CreateCategory +import ca.gosyer.jui.domain.category.interactor.DeleteCategory +import ca.gosyer.jui.domain.category.interactor.GetCategories +import ca.gosyer.jui.domain.category.interactor.ModifyCategory +import ca.gosyer.jui.domain.category.interactor.ReorderCategory import ca.gosyer.jui.domain.category.model.Category import ca.gosyer.jui.uicore.vm.ContextWrapper import ca.gosyer.jui.uicore.vm.ViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.singleOrNull +import kotlinx.coroutines.launch import me.tatarka.inject.annotations.Inject import org.lighthousegames.logging.logging class CategoriesScreenViewModel @Inject constructor( - private val categoryHandler: CategoryRepositoryImpl, + private val getCategories: GetCategories, + private val createCategory: CreateCategory, + private val deleteCategory: DeleteCategory, + private val modifyCategory: ModifyCategory, + private val reorderCategory: ReorderCategory, contextWrapper: ContextWrapper ) : ViewModel(contextWrapper) { private var originalCategories = emptyList() private val _categories = MutableStateFlow(emptyList()) val categories = _categories.asStateFlow() - private val _isLoading = MutableStateFlow(true) - val isLoading = _isLoading.asStateFlow() - init { - getCategories() + scope.launch { + getCategories() + } } - private fun getCategories() { + private suspend fun getCategories() { _categories.value = emptyList() - _isLoading.value = true - categoryHandler.getCategories(true) - .onEach { - _categories.value = it - .sortedBy { it.order } - .also { originalCategories = it } - .map { it.toMenuCategory() } - _isLoading.value = false - } - .catch { - log.warn(it) { "Error getting categories" } - _isLoading.value = false - } - .launchIn(scope) + val categories = getCategories.await(true) + if (categories != null) { + _categories.value = categories + .sortedBy { it.order } + .also { originalCategories = it } + .map { it.toMenuCategory() } + } } suspend fun updateRemoteCategories(manualUpdate: Boolean = false) { val categories = _categories.value val newCategories = categories.filter { it.id == null } newCategories.forEach { - categoryHandler.createCategory(it.name) - .catch { - log.warn(it) { "Error creating category" } - } - .collect() + createCategory.await(it.name) } originalCategories.forEach { originalCategory -> val category = categories.find { it.id == originalCategory.id } if (category == null) { - categoryHandler.deleteCategory(originalCategory.id) - .catch { - log.warn(it) { "Error deleting category $originalCategory" } - } - .collect() + deleteCategory.await(originalCategory) } else if (category.name != originalCategory.name) { - categoryHandler.modifyCategory(originalCategory.id, category.name) - .catch { - log.warn(it) { "Error modifying category $category" } - } - .collect() + modifyCategory.await(originalCategory, category.name) } } - var updatedCategories = categoryHandler.getCategories(true) - .catch { - log.warn(it) { "Error getting updated categories" } - } - .singleOrNull() + var updatedCategories = getCategories.await(true) categories.forEach { category -> val updatedCategory = updatedCategories?.find { it.id == category.id || it.name == category.name } ?: return@forEach if (category.order != updatedCategory.order) { log.debug { "${category.name}: ${updatedCategory.order} to ${category.order}" } - categoryHandler.reorderCategory(category.order, updatedCategory.order) - .catch { - log.warn(it) { "Error re-ordering categories" } - } - .singleOrNull() + reorderCategory.await(category.order, updatedCategory.order) } - updatedCategories = categoryHandler.getCategories(true) - .catch { - log.warn(it) { "Error getting updated categories" } - } - .singleOrNull() + updatedCategories = getCategories.await(true) } if (manualUpdate) { diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt index c1bc07dd..94fad002 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt @@ -10,10 +10,11 @@ import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.toLowerCase import ca.gosyer.jui.core.lang.withDefaultContext import ca.gosyer.jui.core.prefs.getAsFlow -import ca.gosyer.jui.data.category.CategoryRepositoryImpl -import ca.gosyer.jui.data.library.LibraryRepositoryImpl import ca.gosyer.jui.data.updates.UpdatesRepositoryImpl +import ca.gosyer.jui.domain.category.interactor.GetCategories +import ca.gosyer.jui.domain.category.interactor.GetMangaListFromCategory import ca.gosyer.jui.domain.category.model.Category +import ca.gosyer.jui.domain.library.interactor.RemoveMangaFromLibrary import ca.gosyer.jui.domain.library.model.FilterState import ca.gosyer.jui.domain.library.model.Sort import ca.gosyer.jui.domain.library.service.LibraryPreferences @@ -40,6 +41,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch import me.tatarka.inject.annotations.Inject import org.lighthousegames.logging.logging @@ -74,8 +76,9 @@ private fun LibraryMap.setManga(id: Long, manga: List, getItemsFlow: (Sta } class LibraryScreenViewModel @Inject constructor( - private val categoryHandler: CategoryRepositoryImpl, - private val libraryHandler: LibraryRepositoryImpl, + private val getCategories: GetCategories, + private val getMangaListFromCategory: GetMangaListFromCategory, + private val removeMangaFromLibrary: RemoveMangaFromLibrary, private val updatesHandler: UpdatesRepositoryImpl, libraryPreferences: LibraryPreferences, contextWrapper: ContextWrapper @@ -141,7 +144,7 @@ class LibraryScreenViewModel @Inject constructor( private fun getLibrary() { _isLoading.value = true - categoryHandler.getCategories() + getCategories.asFlow() .onEach { categories -> if (categories.isEmpty()) { throw Exception(MR.strings.library_empty.toPlatformString()) @@ -152,7 +155,7 @@ class LibraryScreenViewModel @Inject constructor( } .catch { _error.value = it.message - log.warn(it) { "Error getting categories" } + log.warn(it) { "Failed to get categories" } _isLoading.value = false } .launchIn(scope) @@ -237,7 +240,7 @@ class LibraryScreenViewModel @Inject constructor( withDefaultContext { categories.map { category -> async { - categoryHandler.getMangaFromCategory(category.id) + getMangaListFromCategory.asFlow(category) .onEach { library.mangaMap.setManga( id = category.id, @@ -246,7 +249,7 @@ class LibraryScreenViewModel @Inject constructor( ) } .catch { - log.warn(it) { "Error getting manga for category $category" } + log.warn(it) { "Failed to get manga list from category ${category.name}" } library.mangaMap.setError(category.id, it) } .collect() @@ -264,14 +267,9 @@ class LibraryScreenViewModel @Inject constructor( } fun removeManga(mangaId: Long) { - libraryHandler.removeMangaFromLibrary(mangaId) - .onEach { - updateCategories(getCategoriesToUpdate(mangaId)) - } - .catch { - log.warn(it) { "Error removing manga from library" } - } - .launchIn(scope) + scope.launch { + removeMangaFromLibrary.await(mangaId) + } } fun updateQuery(query: String) { diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/manga/MangaScreenViewModel.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/manga/MangaScreenViewModel.kt index 77e2b405..8f954518 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/manga/MangaScreenViewModel.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/manga/MangaScreenViewModel.kt @@ -8,13 +8,17 @@ package ca.gosyer.jui.ui.manga import ca.gosyer.jui.core.lang.withIOContext import ca.gosyer.jui.data.base.DateHandler -import ca.gosyer.jui.data.category.CategoryRepositoryImpl import ca.gosyer.jui.data.chapter.ChapterRepositoryImpl -import ca.gosyer.jui.data.library.LibraryRepositoryImpl import ca.gosyer.jui.data.manga.MangaRepositoryImpl +import ca.gosyer.jui.domain.category.interactor.AddMangaToCategory +import ca.gosyer.jui.domain.category.interactor.GetCategories +import ca.gosyer.jui.domain.category.interactor.GetMangaCategories +import ca.gosyer.jui.domain.category.interactor.RemoveMangaFromCategory import ca.gosyer.jui.domain.category.model.Category import ca.gosyer.jui.domain.chapter.model.Chapter import ca.gosyer.jui.domain.download.service.DownloadService +import ca.gosyer.jui.domain.library.interactor.AddMangaToLibrary +import ca.gosyer.jui.domain.library.interactor.RemoveMangaFromLibrary import ca.gosyer.jui.domain.manga.model.Manga import ca.gosyer.jui.domain.ui.service.UiPreferences import ca.gosyer.jui.ui.base.chapter.ChapterDownloadItem @@ -41,8 +45,12 @@ class MangaScreenViewModel @Inject constructor( private val dateHandler: DateHandler, private val mangaHandler: MangaRepositoryImpl, private val chapterHandler: ChapterRepositoryImpl, - private val categoryHandler: CategoryRepositoryImpl, - private val libraryHandler: LibraryRepositoryImpl, + private val getCategories: GetCategories, + private val getMangaCategories: GetMangaCategories, + private val addMangaToCategory: AddMangaToCategory, + private val removeMangaFromCategory: RemoveMangaFromCategory, + private val addMangaToLibrary: AddMangaToLibrary, + private val removeMangaFromLibrary: RemoveMangaFromLibrary, uiPreferences: UiPreferences, contextWrapper: ContextWrapper, private val params: Params, @@ -56,8 +64,9 @@ class MangaScreenViewModel @Inject constructor( private val _isLoading = MutableStateFlow(true) val isLoading = _isLoading.asStateFlow() - private val _categories = MutableStateFlow(emptyList()) - val categories = _categories.asStateFlow() + val categories = getCategories.asFlow(true) + .catch { log.warn(it) { "Failed to get categories" } } + .stateIn(scope, SharingStarted.Eagerly, emptyList()) private val _mangaCategories = MutableStateFlow(emptyList()) val mangaCategories = _mangaCategories.asStateFlow() @@ -86,15 +95,6 @@ class MangaScreenViewModel @Inject constructor( refreshMangaAsync(params.mangaId).await() to refreshChaptersAsync(params.mangaId).await() _isLoading.value = false } - - categoryHandler.getCategories(true) - .onEach { - _categories.value = it - } - .catch { - log.warn(it) { "Error getting categories" } - } - .launchIn(scope) } fun loadManga() { @@ -138,14 +138,10 @@ class MangaScreenViewModel @Inject constructor( log.warn(it) { "Error getting manga" } } .collect() - categoryHandler.getMangaCategories(mangaId) - .onEach { + getMangaCategories.await(mangaId) + ?.let { _mangaCategories.value = it } - .catch { - log.warn(it) { "Error getting manga" } - } - .collect() } } @@ -165,11 +161,7 @@ class MangaScreenViewModel @Inject constructor( scope.launch { manga.value?.let { manga -> if (manga.inLibrary) { - libraryHandler.removeMangaFromLibrary(manga.id) - .catch { - log.warn(it) { "Error toggling favorite" } - } - .collect() + removeMangaFromLibrary.await(manga) refreshMangaAsync(manga.id).await() } else { if (categories.value.isEmpty()) { @@ -187,25 +179,13 @@ class MangaScreenViewModel @Inject constructor( manga.value?.let { manga -> if (manga.inLibrary) { oldCategories.filterNot { it in categories }.forEach { - categoryHandler.removeMangaFromCategory(manga.id, it.id) - .catch { - log.warn(it) { "Error removing manga from category" } - } - .collect() + removeMangaFromCategory.await(manga, it) } } else { - libraryHandler.addMangaToLibrary(manga.id) - .catch { - log.warn(it) { "Error Adding manga to library" } - } - .collect() + addMangaToLibrary.await(manga) } categories.filterNot { it in oldCategories }.forEach { - categoryHandler.addMangaToCategory(manga.id, it.id) - .catch { - log.warn(it) { "Error adding manga to category" } - } - .collect() + addMangaToCategory.await(manga, it) } refreshMangaAsync(manga.id).await() } diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt index bcf02144..578eef23 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt @@ -166,11 +166,7 @@ class ReaderMenuViewModel @Inject constructor( fun setMangaReaderMode(mode: String) { scope.launchDefault { _manga.value?.let { - updateMangaMeta.subscribe(it, mode) - .catch { - log.warn(it) { "Error updating manga reader mode" } - } - .collect() + updateMangaMeta.await(it, mode) } initManga(params.mangaId) } @@ -308,11 +304,7 @@ class ReaderMenuViewModel @Inject constructor( @OptIn(DelicateCoroutinesApi::class) private fun updateLastPageReadOffset(chapter: Chapter, offset: Int) { - updateChapterMeta.subscribe(chapter, offset) - .catch { - log.warn(it) { "Error updating chapter offset" } - } - .launchIn(GlobalScope) + GlobalScope.launch { updateChapterMeta.await(chapter, offset) } } override fun onDispose() { diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/settings/SettingsLibraryScreen.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/settings/SettingsLibraryScreen.kt index 665aa634..116c59d8 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/settings/SettingsLibraryScreen.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/settings/SettingsLibraryScreen.kt @@ -33,7 +33,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import ca.gosyer.jui.data.category.CategoryRepositoryImpl +import ca.gosyer.jui.domain.category.interactor.GetCategories import ca.gosyer.jui.domain.library.model.DisplayMode import ca.gosyer.jui.domain.library.service.LibraryPreferences import ca.gosyer.jui.i18n.MR @@ -59,11 +59,8 @@ import com.vanpra.composematerialdialogs.rememberMaterialDialogState import com.vanpra.composematerialdialogs.title import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import me.tatarka.inject.annotations.Inject -import org.lighthousegames.logging.logging import kotlin.math.roundToInt class SettingsLibraryScreen : Screen { @@ -88,7 +85,7 @@ class SettingsLibraryScreen : Screen { class SettingsLibraryViewModel @Inject constructor( libraryPreferences: LibraryPreferences, - private val categoryHandler: CategoryRepositoryImpl, + private val getCategories: GetCategories, contextWrapper: ContextWrapper ) : ViewModel(contextWrapper) { @@ -105,23 +102,14 @@ class SettingsLibraryViewModel @Inject constructor( } fun refreshCategoryCount() { - categoryHandler.getCategories(true) - .onEach { - _categories.value = it.size - } - .catch { - log.warn(it) { "Error getting categories" } - } - .launchIn(scope) + scope.launch { + _categories.value = getCategories.await(true)?.size ?: 0 + } } @Composable fun getDisplayModeChoices() = DisplayMode.values() .associateWith { stringResource(it.res) } - - private companion object { - private val log = logging() - } } @Composable