Use Compose for Category screen (#7454)

* Use Compose for Category screen

* Use correct string for CategoryRenameDialog title

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
This commit is contained in:
Andreas
2022-07-09 18:31:14 +02:00
committed by GitHub
parent 14a08f0668
commit 86bacbe586
27 changed files with 676 additions and 859 deletions

View File

@@ -6,9 +6,11 @@ import eu.kanade.data.history.HistoryRepositoryImpl
import eu.kanade.data.manga.MangaRepositoryImpl
import eu.kanade.data.source.SourceRepositoryImpl
import eu.kanade.data.track.TrackRepositoryImpl
import eu.kanade.domain.category.interactor.CreateCategoryWithName
import eu.kanade.domain.category.interactor.DeleteCategory
import eu.kanade.domain.category.interactor.GetCategories
import eu.kanade.domain.category.interactor.InsertCategory
import eu.kanade.domain.category.interactor.RenameCategory
import eu.kanade.domain.category.interactor.ReorderCategory
import eu.kanade.domain.category.interactor.SetMangaCategories
import eu.kanade.domain.category.interactor.UpdateCategory
import eu.kanade.domain.category.repository.CategoryRepository
@@ -69,7 +71,9 @@ class DomainModule : InjektModule {
override fun InjektRegistrar.registerInjectables() {
addSingletonFactory<CategoryRepository> { CategoryRepositoryImpl(get()) }
addFactory { GetCategories(get()) }
addFactory { InsertCategory(get()) }
addFactory { CreateCategoryWithName(get()) }
addFactory { RenameCategory(get()) }
addFactory { ReorderCategory(get()) }
addFactory { UpdateCategory(get()) }
addFactory { DeleteCategory(get()) }

View File

@@ -0,0 +1,43 @@
package eu.kanade.domain.category.interactor
import eu.kanade.domain.category.model.Category
import eu.kanade.domain.category.model.anyWithName
import eu.kanade.domain.category.repository.CategoryRepository
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
import logcat.LogPriority
class CreateCategoryWithName(
private val categoryRepository: CategoryRepository,
) {
suspend fun await(name: String): Result = withContext(NonCancellable) await@{
val categories = categoryRepository.getAll()
if (categories.anyWithName(name)) {
return@await Result.NameAlreadyExistsError
}
val nextOrder = categories.maxOfOrNull { it.order }?.plus(1) ?: 0
val newCategory = Category(
id = 0,
name = name,
order = nextOrder,
flags = 0,
)
try {
categoryRepository.insert(newCategory)
Result.Success
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
Result.InternalError(e)
}
}
sealed class Result {
object Success : Result()
object NameAlreadyExistsError : Result()
data class InternalError(val error: Throwable) : Result()
}
}

View File

@@ -1,12 +1,43 @@
package eu.kanade.domain.category.interactor
import eu.kanade.domain.category.model.CategoryUpdate
import eu.kanade.domain.category.repository.CategoryRepository
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
import logcat.LogPriority
class DeleteCategory(
private val categoryRepository: CategoryRepository,
) {
suspend fun await(categoryId: Long) {
categoryRepository.delete(categoryId)
suspend fun await(categoryId: Long) = withContext(NonCancellable) await@{
try {
categoryRepository.delete(categoryId)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
return@await Result.InternalError(e)
}
val categories = categoryRepository.getAll()
val updates = categories.mapIndexed { index, category ->
CategoryUpdate(
id = category.id,
order = index.toLong(),
)
}
try {
categoryRepository.updatePartial(updates)
Result.Success
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
Result.InternalError(e)
}
}
sealed class Result {
object Success : Result()
data class InternalError(val error: Throwable) : Result()
}
}

View File

@@ -1,22 +0,0 @@
package eu.kanade.domain.category.interactor
import eu.kanade.domain.category.repository.CategoryRepository
class InsertCategory(
private val categoryRepository: CategoryRepository,
) {
suspend fun await(name: String, order: Long): Result {
return try {
categoryRepository.insert(name, order)
Result.Success
} catch (e: Exception) {
Result.Error(e)
}
}
sealed class Result {
object Success : Result()
data class Error(val error: Exception) : Result()
}
}

View File

@@ -0,0 +1,43 @@
package eu.kanade.domain.category.interactor
import eu.kanade.domain.category.model.Category
import eu.kanade.domain.category.model.CategoryUpdate
import eu.kanade.domain.category.model.anyWithName
import eu.kanade.domain.category.repository.CategoryRepository
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
import logcat.LogPriority
class RenameCategory(
private val categoryRepository: CategoryRepository,
) {
suspend fun await(categoryId: Long, name: String) = withContext(NonCancellable) await@{
val categories = categoryRepository.getAll()
if (categories.anyWithName(name)) {
return@await Result.NameAlreadyExistsError
}
val update = CategoryUpdate(
id = categoryId,
name = name,
)
try {
categoryRepository.updatePartial(update)
Result.Success
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
Result.InternalError(e)
}
}
suspend fun await(category: Category, name: String) = await(category.id, name)
sealed class Result {
object Success : Result()
object NameAlreadyExistsError : Result()
data class InternalError(val error: Throwable) : Result()
}
}

View File

@@ -0,0 +1,51 @@
package eu.kanade.domain.category.interactor
import eu.kanade.domain.category.model.Category
import eu.kanade.domain.category.model.CategoryUpdate
import eu.kanade.domain.category.repository.CategoryRepository
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
import logcat.LogPriority
class ReorderCategory(
private val categoryRepository: CategoryRepository,
) {
suspend fun await(categoryId: Long, newPosition: Int) = withContext(NonCancellable) await@{
val categories = categoryRepository.getAll()
val currentIndex = categories.indexOfFirst { it.id == categoryId }
if (currentIndex == newPosition) {
return@await Result.Unchanged
}
val reorderedCategories = categories.toMutableList()
val reorderedCategory = reorderedCategories.removeAt(currentIndex)
reorderedCategories.add(newPosition, reorderedCategory)
val updates = reorderedCategories.mapIndexed { index, category ->
CategoryUpdate(
id = category.id,
order = index.toLong(),
)
}
try {
categoryRepository.updatePartial(updates)
Result.Success
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
Result.InternalError(e)
}
}
suspend fun await(category: Category, newPosition: Long): Result =
await(category.id, newPosition.toInt())
sealed class Result {
object Success : Result()
object Unchanged : Result()
data class InternalError(val error: Throwable) : Result()
}
}

View File

@@ -2,14 +2,16 @@ package eu.kanade.domain.category.interactor
import eu.kanade.domain.category.model.CategoryUpdate
import eu.kanade.domain.category.repository.CategoryRepository
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
class UpdateCategory(
private val categoryRepository: CategoryRepository,
) {
suspend fun await(payload: CategoryUpdate): Result {
return try {
categoryRepository.update(payload)
suspend fun await(payload: CategoryUpdate): Result = withContext(NonCancellable) {
try {
categoryRepository.updatePartial(payload)
Result.Success
} catch (e: Exception) {
Result.Error(e)

View File

@@ -37,6 +37,10 @@ data class Category(
}
}
internal fun List<Category>.anyWithName(name: String): Boolean {
return any { name.equals(it.name, ignoreCase = true) }
}
fun Category.toDbCategory(): DbCategory = CategoryImpl().also {
it.name = name
it.id = id.toInt()

View File

@@ -14,15 +14,11 @@ interface CategoryRepository {
fun getCategoriesByMangaIdAsFlow(mangaId: Long): Flow<List<Category>>
@Throws(DuplicateNameException::class)
suspend fun insert(name: String, order: Long)
suspend fun insert(category: Category)
@Throws(DuplicateNameException::class)
suspend fun update(payload: CategoryUpdate)
suspend fun updatePartial(update: CategoryUpdate)
suspend fun updatePartial(updates: List<CategoryUpdate>)
suspend fun delete(categoryId: Long)
suspend fun checkDuplicateName(name: String): Boolean
}
class DuplicateNameException(name: String) : Exception("There's a category which is named \"$name\" already")