mirror of
https://github.com/mihonapp/mihon.git
synced 2026-10-16 13:48:09 -07:00
Assign category positions inside the database
A new category's position is computed by its insert, one after the highest, so two categories created at once can't take the same one. Inserts take a NewCategory rather than a Category whose id and position would be ignored. Reordering places any category missing from the given order after the rest instead of leaving it at a stale position. Restore still creates missing categories all or none, in backup order, and the create dialog no longer accepts an empty name.
This commit is contained in:
@@ -110,7 +110,7 @@ fun CategoryRenameDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
enabled = valueHasChanged && !nameAlreadyExists,
|
||||
enabled = valueHasChanged && name.isNotEmpty() && !nameAlreadyExists,
|
||||
onClick = {
|
||||
onRename(name)
|
||||
onDismissRequest()
|
||||
|
||||
@@ -11,14 +11,7 @@ class BackupCategory(
|
||||
@ProtoNumber(3) var id: Long = 0,
|
||||
// @ProtoNumber(3) val updateInterval: Int = 0, 1.x value not used in 0.x
|
||||
@ProtoNumber(100) var flags: Long = 0,
|
||||
) {
|
||||
fun toCategory(id: Long) = Category(
|
||||
id = id,
|
||||
name = this@BackupCategory.name,
|
||||
flags = this@BackupCategory.flags,
|
||||
order = this@BackupCategory.order,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val backupCategoryMapper = { category: Category ->
|
||||
BackupCategory(
|
||||
|
||||
+13
-14
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||
import dev.zacsweers.metro.Inject
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.model.NewCategory
|
||||
import tachiyomi.domain.category.repository.CategoryRepository
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
@@ -14,22 +15,20 @@ class CategoriesRestorer(
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(backupCategories: List<BackupCategory>) {
|
||||
if (backupCategories.isNotEmpty()) {
|
||||
val dbCategories = getCategories.await()
|
||||
val dbCategoriesByName = dbCategories.associateBy { it.name }
|
||||
var nextOrder = dbCategories.maxOfOrNull { it.order }?.plus(1) ?: 0
|
||||
if (backupCategories.isEmpty()) return
|
||||
|
||||
val categories = backupCategories
|
||||
.sortedBy { it.order }
|
||||
.filter { it.name !in dbCategoriesByName }
|
||||
.map { it.toCategory(id = 0).copy(order = nextOrder++) }
|
||||
categoryRepository.insertAll(categories)
|
||||
val dbCategories = getCategories.await()
|
||||
val dbCategoryNames = dbCategories.mapTo(HashSet()) { it.name }
|
||||
|
||||
libraryPreferences.categorizedDisplaySettings.set(
|
||||
(dbCategories + categories)
|
||||
.distinctBy { it.flags }
|
||||
.size > 1,
|
||||
)
|
||||
val newCategories = backupCategories
|
||||
.filter { it.name !in dbCategoryNames }
|
||||
.sortedBy { it.order }
|
||||
categoryRepository.insertAll(newCategories.map { NewCategory(name = it.name, flags = it.flags) })
|
||||
|
||||
val flags = buildSet {
|
||||
dbCategories.mapTo(this) { it.flags }
|
||||
newCategories.mapTo(this) { it.flags }
|
||||
}
|
||||
libraryPreferences.categorizedDisplaySettings.set(flags.size > 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.data.Database
|
||||
import tachiyomi.data.subscribeToList
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.category.model.NewCategory
|
||||
import tachiyomi.domain.category.repository.CategoryRepository
|
||||
|
||||
@Inject
|
||||
@@ -49,15 +50,11 @@ class CategoryRepositoryImpl(
|
||||
.subscribeToList()
|
||||
}
|
||||
|
||||
override suspend fun insert(category: Category) {
|
||||
database.categoriesQueries.insert(
|
||||
name = category.name,
|
||||
order = category.order,
|
||||
flags = category.flags,
|
||||
)
|
||||
override suspend fun insert(category: NewCategory) {
|
||||
database.categoriesQueries.insert(name = category.name, flags = category.flags)
|
||||
}
|
||||
|
||||
override suspend fun insertAll(categories: List<Category>) {
|
||||
override suspend fun insertAll(categories: List<NewCategory>) {
|
||||
database.transaction {
|
||||
categories.forEach { insert(it) }
|
||||
}
|
||||
@@ -77,10 +74,12 @@ class CategoryRepositoryImpl(
|
||||
|
||||
override suspend fun updateAllOrders(orderedIds: List<Long>) {
|
||||
database.transaction {
|
||||
orderedIds.forEachIndexed { index, categoryId ->
|
||||
val current = database.categoriesQueries.getUserCategoryIds().awaitAsList()
|
||||
val ids = orderedIds.filter { it in current } + current.filterNot { it in orderedIds }
|
||||
ids.forEachIndexed { index, categoryId ->
|
||||
database.categoriesQueries.updateOrder(order = -index - 2L, categoryId = categoryId)
|
||||
}
|
||||
orderedIds.forEachIndexed { index, categoryId ->
|
||||
ids.forEachIndexed { index, categoryId ->
|
||||
database.categoriesQueries.updateOrder(order = index.toLong(), categoryId = categoryId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ WHERE MC.manga_id = :mangaId;
|
||||
|
||||
insert:
|
||||
INSERT INTO categories(name, sort, flags)
|
||||
VALUES (:name, :order, :flags);
|
||||
SELECT :name, coalesce(max(sort), -1) + 1, :flags
|
||||
FROM categories;
|
||||
|
||||
delete:
|
||||
DELETE FROM categories
|
||||
@@ -55,6 +56,12 @@ UPDATE categories
|
||||
SET name = :name
|
||||
WHERE _id = :categoryId;
|
||||
|
||||
getUserCategoryIds:
|
||||
SELECT _id
|
||||
FROM categories
|
||||
WHERE _id > 0
|
||||
ORDER BY sort;
|
||||
|
||||
updateOrder:
|
||||
UPDATE categories
|
||||
SET sort = :order
|
||||
|
||||
+2
-11
@@ -4,7 +4,7 @@ import dev.zacsweers.metro.Inject
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.category.model.NewCategory
|
||||
import tachiyomi.domain.category.repository.CategoryRepository
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
@@ -21,17 +21,8 @@ class CreateCategoryWithName(
|
||||
}
|
||||
|
||||
suspend fun await(name: String): Result = withNonCancellableContext {
|
||||
val categories = categoryRepository.getAll()
|
||||
val nextOrder = categories.maxOfOrNull { it.order }?.plus(1) ?: 0
|
||||
val newCategory = Category(
|
||||
id = 0,
|
||||
name = name,
|
||||
order = nextOrder,
|
||||
flags = initialFlags,
|
||||
)
|
||||
|
||||
try {
|
||||
categoryRepository.insert(newCategory)
|
||||
categoryRepository.insert(NewCategory(name = name, flags = initialFlags))
|
||||
Result.Success
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package tachiyomi.domain.category.model
|
||||
|
||||
data class NewCategory(
|
||||
val name: String,
|
||||
val flags: Long,
|
||||
)
|
||||
@@ -2,6 +2,7 @@ package tachiyomi.domain.category.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.category.model.NewCategory
|
||||
|
||||
interface CategoryRepository {
|
||||
|
||||
@@ -15,9 +16,9 @@ interface CategoryRepository {
|
||||
|
||||
fun getCategoriesByMangaIdAsFlow(mangaId: Long): Flow<List<Category>>
|
||||
|
||||
suspend fun insert(category: Category)
|
||||
suspend fun insert(category: NewCategory)
|
||||
|
||||
suspend fun insertAll(categories: List<Category>)
|
||||
suspend fun insertAll(categories: List<NewCategory>)
|
||||
|
||||
suspend fun updateName(categoryId: Long, name: String)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user