mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Use interactors for category and library data calls
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Category>()
|
||||
private val _categories = MutableStateFlow(emptyList<MenuCategory>())
|
||||
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) {
|
||||
|
||||
@@ -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<Manga>, 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) {
|
||||
|
||||
@@ -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<Category>())
|
||||
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<Category>())
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user