refactor: category entity
* Merge CategorySortEntity with CategoryEntity
This commit is contained in:
parent
1d9f5514ff
commit
6d7e178d4c
31 changed files with 421 additions and 425 deletions
|
|
@ -50,18 +50,19 @@ object AppModule {
|
|||
@Singleton
|
||||
fun provideBookDatabase(app: Application): BookDatabase {
|
||||
// Additional Migrations
|
||||
DatabaseHelper.MIGRATION_7_8.removeBooksDir(app)
|
||||
DatabaseHelper.AUTO_MIGRATION_7_8.removeBooksDir(app)
|
||||
|
||||
return Room.databaseBuilder(
|
||||
app,
|
||||
BookDatabase::class.java,
|
||||
"book_db"
|
||||
).addMigrations(
|
||||
DatabaseHelper.MIGRATION_2_3, // creates LanguageHistoryEntity table(if does not exist)
|
||||
DatabaseHelper.MIGRATION_4_5, // creates ColorPresetEntity table(if does not exist)
|
||||
DatabaseHelper.MIGRATION_5_6, // creates FavoriteDirectoryEntity table(if does not exist)
|
||||
DatabaseHelper.MIGRATION_13_14, // remove nullability from ColorPresetEntity
|
||||
DatabaseHelper.MIGRATION_14_15, // remove author nullability from BookEntity
|
||||
DatabaseHelper.MANUAL_MIGRATION_2_3, // creates LanguageHistoryEntity table(if does not exist)
|
||||
DatabaseHelper.MANUAL_MIGRATION_4_5, // creates ColorPresetEntity table(if does not exist)
|
||||
DatabaseHelper.MANUAL_MIGRATION_5_6, // creates FavoriteDirectoryEntity table(if does not exist)
|
||||
DatabaseHelper.MANUAL_MIGRATION_13_14, // remove nullability from ColorPresetEntity
|
||||
DatabaseHelper.MANUAL_MIGRATION_14_15, // remove author nullability from BookEntity
|
||||
DatabaseHelper.MANUAL_MIGRATION_15_16, // merge CategoryEntity and CategorySortEntity
|
||||
).allowMainThreadQueries().build()
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,6 @@ import ua.acclorite.book_story.data.mapper.book.BookMapper
|
|||
import ua.acclorite.book_story.data.mapper.book.BookMapperImpl
|
||||
import ua.acclorite.book_story.data.mapper.category.CategoryMapper
|
||||
import ua.acclorite.book_story.data.mapper.category.CategoryMapperImpl
|
||||
import ua.acclorite.book_story.data.mapper.category_sort.CategorySortMapper
|
||||
import ua.acclorite.book_story.data.mapper.category_sort.CategorySortSortMapperImpl
|
||||
import ua.acclorite.book_story.data.mapper.color_preset.ColorPresetMapper
|
||||
import ua.acclorite.book_story.data.mapper.color_preset.ColorPresetMapperImpl
|
||||
import ua.acclorite.book_story.data.mapper.file.FileMapper
|
||||
|
|
@ -111,12 +109,6 @@ abstract class RepositoryModule {
|
|||
categoryMapperImpl: CategoryMapperImpl
|
||||
): CategoryMapper
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindCategorySortMapper(
|
||||
categorySortSortMapperImpl: CategorySortSortMapperImpl
|
||||
): CategorySortMapper
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindFileMapper(
|
||||
|
|
|
|||
|
|
@ -6,13 +6,16 @@
|
|||
|
||||
package ua.acclorite.book_story.data.local.dto
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
||||
@Entity
|
||||
data class CategoryEntity(
|
||||
@PrimaryKey(true)
|
||||
val id: Int = 0,
|
||||
@PrimaryKey(true) val id: Int = 0,
|
||||
val title: String,
|
||||
val order: Int
|
||||
val order: Int,
|
||||
@ColumnInfo(defaultValue = "LAST_READ") val sortOrder: LibrarySortOrder,
|
||||
@ColumnInfo(defaultValue = "1") val sortOrderDescending: Boolean
|
||||
)
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.data.local.dto
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
||||
@Entity
|
||||
data class CategorySortEntity(
|
||||
@PrimaryKey(false)
|
||||
val categoryId: Int,
|
||||
val sortOrder: LibrarySortOrder,
|
||||
val sortOrderDescending: Boolean
|
||||
)
|
||||
|
|
@ -12,15 +12,10 @@ import androidx.room.Insert
|
|||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import androidx.room.Upsert
|
||||
import ua.acclorite.book_story.data.local.dto.BookEntity
|
||||
import ua.acclorite.book_story.data.local.dto.CategoryEntity
|
||||
import ua.acclorite.book_story.data.local.dto.CategorySortEntity
|
||||
|
||||
@Dao
|
||||
interface BookDao {
|
||||
|
||||
/* ------ BookEntity ------------------------ */
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertBook(
|
||||
book: BookEntity
|
||||
|
|
@ -42,48 +37,4 @@ interface BookDao {
|
|||
|
||||
@Update
|
||||
suspend fun updateBook(book: BookEntity): Int
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
/* ------ CategoryEntity ----------------- */
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertCategory(
|
||||
category: CategoryEntity
|
||||
)
|
||||
|
||||
@Query("SELECT * FROM categoryentity")
|
||||
suspend fun getCategories(): List<CategoryEntity>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM categoryentity")
|
||||
suspend fun getCategoriesCount(): Int
|
||||
|
||||
@Query("UPDATE categoryentity SET title=:title WHERE id=:id")
|
||||
suspend fun updateCategoryTitle(
|
||||
id: Int,
|
||||
title: String
|
||||
)
|
||||
|
||||
@Query("UPDATE categoryentity SET `order`=:order WHERE id=:id")
|
||||
suspend fun updateCategoryOrder(
|
||||
id: Int,
|
||||
order: Int
|
||||
)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteCategory(
|
||||
category: CategoryEntity
|
||||
)
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
/* ------ CategorySortEntity ----------------- */
|
||||
@Upsert
|
||||
suspend fun updateCategorySort(categorySort: CategorySortEntity)
|
||||
|
||||
@Query("SELECT * FROM categorysortentity")
|
||||
suspend fun getCategorySortEntities(): List<CategorySortEntity>
|
||||
|
||||
@Query("DELETE FROM categorysortentity WHERE categoryId=:categoryId")
|
||||
suspend fun deleteCategorySortEntity(categoryId: Int)
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - */
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ import androidx.room.migration.Migration
|
|||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import ua.acclorite.book_story.data.local.dto.BookEntity
|
||||
import ua.acclorite.book_story.data.local.dto.CategoryEntity
|
||||
import ua.acclorite.book_story.data.local.dto.CategorySortEntity
|
||||
import ua.acclorite.book_story.data.local.dto.ColorPresetEntity
|
||||
import ua.acclorite.book_story.data.local.dto.HistoryEntity
|
||||
import java.io.File
|
||||
|
|
@ -27,25 +26,25 @@ import java.io.File
|
|||
BookEntity::class,
|
||||
HistoryEntity::class,
|
||||
ColorPresetEntity::class,
|
||||
CategoryEntity::class,
|
||||
CategorySortEntity::class
|
||||
CategoryEntity::class
|
||||
],
|
||||
version = 15,
|
||||
version = 16,
|
||||
autoMigrations = [
|
||||
AutoMigration(1, 2),
|
||||
AutoMigration(2, 3),
|
||||
AutoMigration(3, 4, spec = DatabaseHelper.MIGRATION_3_4::class),
|
||||
AutoMigration(3, 4, spec = DatabaseHelper.AUTO_MIGRATION_3_4::class),
|
||||
AutoMigration(4, 5),
|
||||
AutoMigration(5, 6),
|
||||
AutoMigration(6, 7),
|
||||
AutoMigration(7, 8, spec = DatabaseHelper.MIGRATION_7_8::class),
|
||||
AutoMigration(8, 9, spec = DatabaseHelper.MIGRATION_8_9::class),
|
||||
AutoMigration(9, 10, spec = DatabaseHelper.MIGRATION_9_10::class),
|
||||
AutoMigration(7, 8, spec = DatabaseHelper.AUTO_MIGRATION_7_8::class),
|
||||
AutoMigration(8, 9, spec = DatabaseHelper.AUTO_MIGRATION_8_9::class),
|
||||
AutoMigration(9, 10, spec = DatabaseHelper.AUTO_MIGRATION_9_10::class),
|
||||
AutoMigration(10, 11),
|
||||
AutoMigration(11, 12),
|
||||
AutoMigration(12, 13),
|
||||
AutoMigration(13, 14),
|
||||
AutoMigration(14, 15),
|
||||
AutoMigration(15, 16, spec = DatabaseHelper.AUTO_MIGRATION_15_16::class),
|
||||
],
|
||||
exportSchema = true
|
||||
)
|
||||
|
|
@ -53,12 +52,13 @@ abstract class BookDatabase : RoomDatabase() {
|
|||
abstract val bookDao: BookDao
|
||||
abstract val historyDao: HistoryDao
|
||||
abstract val colorPresetDao: ColorPresetDao
|
||||
abstract val categoryDao: CategoryDao
|
||||
}
|
||||
|
||||
@Suppress("ClassName")
|
||||
object DatabaseHelper {
|
||||
|
||||
val MIGRATION_2_3 = object : Migration(2, 3) {
|
||||
val MANUAL_MIGRATION_2_3 = object : Migration(2, 3) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"CREATE TABLE IF NOT EXISTS `LanguageHistoryEntity` (" +
|
||||
|
|
@ -76,9 +76,9 @@ object DatabaseHelper {
|
|||
@DeleteColumn("BookEntity", "doubleClickTranslation")
|
||||
@DeleteColumn("BookEntity", "translateWhenOpen")
|
||||
@DeleteTable("LanguageHistoryEntity")
|
||||
class MIGRATION_3_4 : AutoMigrationSpec
|
||||
class AUTO_MIGRATION_3_4 : AutoMigrationSpec
|
||||
|
||||
val MIGRATION_4_5 = object : Migration(4, 5) {
|
||||
val MANUAL_MIGRATION_4_5 = object : Migration(4, 5) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"CREATE TABLE IF NOT EXISTS `ColorPresetEntity` (" +
|
||||
|
|
@ -93,7 +93,7 @@ object DatabaseHelper {
|
|||
}
|
||||
}
|
||||
|
||||
val MIGRATION_5_6 = object : Migration(5, 6) {
|
||||
val MANUAL_MIGRATION_5_6 = object : Migration(5, 6) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"CREATE TABLE IF NOT EXISTS `FavoriteDirectoryEntity` (" +
|
||||
|
|
@ -106,7 +106,7 @@ object DatabaseHelper {
|
|||
|
||||
@DeleteColumn("BookEntity", "textPath")
|
||||
@DeleteColumn("BookEntity", "chapters")
|
||||
class MIGRATION_7_8 : AutoMigrationSpec {
|
||||
class AUTO_MIGRATION_7_8 : AutoMigrationSpec {
|
||||
companion object {
|
||||
/**
|
||||
* Along with textPath deletion,
|
||||
|
|
@ -124,12 +124,12 @@ object DatabaseHelper {
|
|||
}
|
||||
|
||||
@DeleteTable("FavoriteDirectoryEntity")
|
||||
class MIGRATION_8_9 : AutoMigrationSpec
|
||||
class AUTO_MIGRATION_8_9 : AutoMigrationSpec
|
||||
|
||||
@DeleteColumn("BookEntity", "category")
|
||||
class MIGRATION_9_10 : AutoMigrationSpec
|
||||
class AUTO_MIGRATION_9_10 : AutoMigrationSpec
|
||||
|
||||
val MIGRATION_13_14 = object : Migration(13, 14) {
|
||||
val MANUAL_MIGRATION_13_14 = object : Migration(13, 14) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
|
|
@ -161,7 +161,7 @@ object DatabaseHelper {
|
|||
}
|
||||
}
|
||||
|
||||
val MIGRATION_14_15 = object : Migration(14, 15) {
|
||||
val MANUAL_MIGRATION_14_15 = object : Migration(14, 15) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
|
|
@ -190,4 +190,46 @@ object DatabaseHelper {
|
|||
database.execSQL("ALTER TABLE BookEntity_new RENAME TO BookEntity")
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteTable("CategorySortEntity")
|
||||
class AUTO_MIGRATION_15_16 : AutoMigrationSpec
|
||||
|
||||
val MANUAL_MIGRATION_15_16 = object : Migration(15, 16) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS CategoryEntity_new (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
`order` INTEGER NOT NULL,
|
||||
sortOrder TEXT NOT NULL DEFAULT 'LAST_READ',
|
||||
sortOrderDescending INTEGER NOT NULL DEFAULT 1
|
||||
)
|
||||
"""
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO CategoryEntity_new (id, title, `order`, sortOrder, sortOrderDescending)
|
||||
SELECT
|
||||
c.id,
|
||||
c.title,
|
||||
c.`order`,
|
||||
COALESCE(cs.sortOrder, 'LAST_READ'),
|
||||
COALESCE(cs.sortOrderDescending, 1)
|
||||
FROM CategoryEntity c
|
||||
LEFT JOIN CategorySortEntity cs
|
||||
ON c.id = cs.categoryId
|
||||
"""
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO CategoryEntity_new (id, title, `order`, sortOrder, sortOrderDescending)
|
||||
VALUES (-1, '', -1, 'LAST_READ', 1)
|
||||
"""
|
||||
)
|
||||
database.execSQL("DROP TABLE CategoryEntity")
|
||||
database.execSQL("DROP TABLE CategorySortEntity")
|
||||
database.execSQL("ALTER TABLE CategoryEntity_new RENAME TO CategoryEntity")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.data.local.room
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import ua.acclorite.book_story.data.local.dto.CategoryEntity
|
||||
|
||||
@Dao
|
||||
interface CategoryDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertCategory(
|
||||
category: CategoryEntity
|
||||
)
|
||||
|
||||
@Query("SELECT * FROM categoryentity ORDER BY `order` ASC")
|
||||
suspend fun getCategories(): List<CategoryEntity>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM categoryentity")
|
||||
suspend fun getCategoriesCount(): Int
|
||||
|
||||
@Update
|
||||
suspend fun updateCategory(
|
||||
category: CategoryEntity
|
||||
)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteCategory(
|
||||
category: CategoryEntity
|
||||
)
|
||||
}
|
||||
|
|
@ -15,7 +15,9 @@ class CategoryMapperImpl @Inject constructor() : CategoryMapper {
|
|||
return CategoryEntity(
|
||||
id = category.id,
|
||||
title = category.title,
|
||||
order = category.order
|
||||
order = category.order,
|
||||
sortOrder = category.sortOrder,
|
||||
sortOrderDescending = category.sortOrderDescending
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +25,9 @@ class CategoryMapperImpl @Inject constructor() : CategoryMapper {
|
|||
return Category(
|
||||
id = categoryEntity.id,
|
||||
title = categoryEntity.title,
|
||||
order = categoryEntity.order
|
||||
order = categoryEntity.order,
|
||||
sortOrder = categoryEntity.sortOrder,
|
||||
sortOrderDescending = categoryEntity.sortOrderDescending
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.data.mapper.category_sort
|
||||
|
||||
import ua.acclorite.book_story.data.local.dto.CategorySortEntity
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
|
||||
interface CategorySortMapper {
|
||||
fun toCategorySortEntity(categorySort: CategorySort): CategorySortEntity
|
||||
fun toCategorySort(categorySortEntity: CategorySortEntity): CategorySort
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.data.mapper.category_sort
|
||||
|
||||
import ua.acclorite.book_story.data.local.dto.CategorySortEntity
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import javax.inject.Inject
|
||||
|
||||
class CategorySortSortMapperImpl @Inject constructor() : CategorySortMapper {
|
||||
override fun toCategorySortEntity(categorySort: CategorySort): CategorySortEntity {
|
||||
return CategorySortEntity(
|
||||
categoryId = categorySort.categoryId,
|
||||
sortOrder = categorySort.sortOrder,
|
||||
sortOrderDescending = categorySort.sortOrderDescending
|
||||
)
|
||||
}
|
||||
|
||||
override fun toCategorySort(categorySortEntity: CategorySortEntity): CategorySort {
|
||||
return CategorySort(
|
||||
categoryId = categorySortEntity.categoryId,
|
||||
sortOrder = categorySortEntity.sortOrder,
|
||||
sortOrderDescending = categorySortEntity.sortOrderDescending
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,9 +10,7 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.withContext
|
||||
import ua.acclorite.book_story.data.local.room.BookDatabase
|
||||
import ua.acclorite.book_story.data.mapper.category.CategoryMapper
|
||||
import ua.acclorite.book_story.data.mapper.category_sort.CategorySortMapper
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.domain.repository.CategoryRepository
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
|
@ -20,16 +18,15 @@ import javax.inject.Singleton
|
|||
@Singleton
|
||||
class CategoryRepositoryImpl @Inject constructor(
|
||||
private val database: BookDatabase,
|
||||
private val categoryMapper: CategoryMapper,
|
||||
private val categorySortMapper: CategorySortMapper,
|
||||
private val categoryMapper: CategoryMapper
|
||||
) : CategoryRepository {
|
||||
|
||||
override suspend fun addCategory(category: Category): Result<Unit> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.bookDao.insertCategory(
|
||||
database.categoryDao.insertCategory(
|
||||
categoryMapper.toCategoryEntity(
|
||||
category.copy(
|
||||
order = database.bookDao.getCategoriesCount()
|
||||
order = database.categoryDao.getCategoriesCount()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -38,16 +35,19 @@ class CategoryRepositoryImpl @Inject constructor(
|
|||
|
||||
override suspend fun getCategories(): Result<List<Category>> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.bookDao.getCategories().map { categoryMapper.toCategory(it) }
|
||||
.sortedBy { it.order }
|
||||
database.categoryDao.getCategories().map { categoryMapper.toCategory(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateCategory(category: Category): Result<Unit> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.bookDao.updateCategoryTitle(
|
||||
id = category.id,
|
||||
title = category.title
|
||||
database.categoryDao.updateCategory(
|
||||
category = categoryMapper.toCategoryEntity(
|
||||
if (category.id != -1) category else category.copy(
|
||||
title = "",
|
||||
order = -1
|
||||
)
|
||||
)
|
||||
)
|
||||
updateOrder(getCategories().getOrThrow())
|
||||
}
|
||||
|
|
@ -56,35 +56,21 @@ class CategoryRepositoryImpl @Inject constructor(
|
|||
override suspend fun updateOrder(categories: List<Category>): Result<Unit> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
categories.forEachIndexed { index, category ->
|
||||
database.bookDao.updateCategoryOrder(category.id, index)
|
||||
if (category.id == -1) return@forEachIndexed
|
||||
database.categoryDao.updateCategory(
|
||||
categoryMapper.toCategoryEntity(
|
||||
category.copy(order = index)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteCategory(category: Category): Result<Unit> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.bookDao.deleteCategory(categoryMapper.toCategoryEntity(category))
|
||||
database.bookDao.deleteCategorySortEntity(category.id)
|
||||
|
||||
if (category.id == -1) throw IllegalArgumentException("Id should not be -1.")
|
||||
database.categoryDao.deleteCategory(categoryMapper.toCategoryEntity(category))
|
||||
updateOrder(getCategories().getOrThrow())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateCategorySorting(
|
||||
categorySort: CategorySort
|
||||
): Result<Unit> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.bookDao.updateCategorySort(
|
||||
categorySortMapper.toCategorySortEntity(categorySort)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getCategorySorting(): Result<List<CategorySort>> = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.bookDao.getCategorySortEntities().map {
|
||||
categorySortMapper.toCategorySort(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,10 +7,13 @@
|
|||
package ua.acclorite.book_story.domain.model.library
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
||||
@Immutable
|
||||
data class Category(
|
||||
val id: Int = 0,
|
||||
val title: String,
|
||||
val order: Int = 0
|
||||
val order: Int = 0,
|
||||
val sortOrder: LibrarySortOrder = LibrarySortOrder.LAST_READ,
|
||||
val sortOrderDescending: Boolean = true
|
||||
)
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.domain.model.library
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
||||
@Immutable
|
||||
data class CategorySort(
|
||||
val categoryId: Int,
|
||||
val sortOrder: LibrarySortOrder,
|
||||
val sortOrderDescending: Boolean
|
||||
)
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
package ua.acclorite.book_story.domain.repository
|
||||
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
|
||||
interface CategoryRepository {
|
||||
suspend fun addCategory(
|
||||
|
|
@ -27,10 +26,4 @@ interface CategoryRepository {
|
|||
suspend fun deleteCategory(
|
||||
category: Category
|
||||
): Result<Unit>
|
||||
|
||||
suspend fun updateCategorySorting(
|
||||
categorySort: CategorySort
|
||||
): Result<Unit>
|
||||
|
||||
suspend fun getCategorySorting(): Result<List<CategorySort>>
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.domain.use_case.category
|
||||
|
||||
import ua.acclorite.book_story.core.log.logE
|
||||
import ua.acclorite.book_story.core.log.logI
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.domain.repository.CategoryRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetCategorySortingUseCase @Inject constructor(
|
||||
private val categoryRepository: CategoryRepository
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): List<CategorySort> {
|
||||
logI("Getting category sorting.")
|
||||
|
||||
return categoryRepository.getCategorySorting().fold(
|
||||
onSuccess = {
|
||||
logI("Successfully got category sorting.")
|
||||
it
|
||||
},
|
||||
onFailure = {
|
||||
logE("Could not get category sorting with error: ${it.message}")
|
||||
emptyList()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Book's Story — free and open-source Material You eBook reader.
|
||||
* Copyright (C) 2024-2025 Acclorite
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package ua.acclorite.book_story.domain.use_case.category
|
||||
|
||||
import ua.acclorite.book_story.core.log.logE
|
||||
import ua.acclorite.book_story.core.log.logI
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.domain.repository.CategoryRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class UpdateCategorySortingUseCase @Inject constructor(
|
||||
private val categoryRepository: CategoryRepository
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(categorySort: CategorySort) {
|
||||
logI("Updating category sorting of [${categorySort.categoryId}].")
|
||||
|
||||
categoryRepository.updateCategorySorting(categorySort).fold(
|
||||
onSuccess = {
|
||||
logI("Successfully updated category sorting of [${categorySort.categoryId}].")
|
||||
},
|
||||
onFailure = {
|
||||
logE(
|
||||
"Could not update category sorting of [${categorySort.categoryId}] with error: ${it.message}"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,15 +15,15 @@ class UpdateCategoryUseCase @Inject constructor(
|
|||
private val categoryRepository: CategoryRepository
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(categoryId: Int, newTitle: String) {
|
||||
logI("Updating category [$categoryId].")
|
||||
suspend operator fun invoke(category: Category) {
|
||||
logI("Updating category [${category.id}].")
|
||||
|
||||
categoryRepository.updateCategory(Category(id = categoryId, title = newTitle)).fold(
|
||||
categoryRepository.updateCategory(category).fold(
|
||||
onSuccess = {
|
||||
logI("Successfully updated [$categoryId].")
|
||||
logI("Successfully updated [${category.id}].")
|
||||
},
|
||||
onFailure = {
|
||||
logI("Could not update [$categoryId] with error: ${it.message}")
|
||||
logI("Could not update [${category.id}] with error: ${it.message}")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
|
|
@ -50,6 +51,10 @@ data class BookInfoScreen(val bookId: Int) : Screen, Parcelable {
|
|||
val state = screenModel.state.collectAsStateWithLifecycle()
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
val categories = remember(settingsState.value.categories) {
|
||||
settingsState.value.categories.filterNot { it.id == -1 }
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
screenModel.init(
|
||||
bookId = bookId,
|
||||
|
|
@ -74,7 +79,7 @@ data class BookInfoScreen(val bookId: Int) : Screen, Parcelable {
|
|||
BookInfoContent(
|
||||
book = state.value.book,
|
||||
file = state.value.file,
|
||||
categories = settingsState.value.categories,
|
||||
categories = categories,
|
||||
bottomSheet = state.value.bottomSheet,
|
||||
dialog = state.value.dialog,
|
||||
listState = listState,
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ object LibraryScreen : Screen, Parcelable {
|
|||
val pagerState = rememberPagerState(
|
||||
initialPage = initialPage
|
||||
) {
|
||||
settingsState.value.categories.count().plus(if (showDefaultCategory.value) 1 else 0)
|
||||
settingsState.value.categories.count().minus(if (!showDefaultCategory.value) 1 else 0)
|
||||
}
|
||||
DisposableEffect(Unit) { onDispose { initialPage = pagerState.currentPage } }
|
||||
|
||||
|
|
@ -126,14 +126,13 @@ object LibraryScreen : Screen, Parcelable {
|
|||
autoGridSize = settings.libraryAutoGridSize.value,
|
||||
categories = settingsState.value.categories,
|
||||
showDefaultCategory = showDefaultCategory.value,
|
||||
categoriesSort = settingsState.value.categoriesSort,
|
||||
sortOrder = settings.librarySortOrder.value,
|
||||
sortOrderDescending = settings.librarySortOrderDescending.value,
|
||||
perCategorySort = settings.libraryPerCategorySort.value,
|
||||
refreshState = refreshState,
|
||||
dialog = state.value.dialog,
|
||||
bottomSheet = state.value.bottomSheet,
|
||||
updateCategorySort = settingsModel::onEvent,
|
||||
updateCategory = settingsModel::onEvent,
|
||||
changeSortOrder = { settings.librarySortOrder.update(it) },
|
||||
changeSortOrderDescending = { settings.librarySortOrderDescending.update(it) },
|
||||
selectBook = screenModel::onEvent,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import androidx.compose.runtime.Immutable
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import ua.acclorite.book_story.core.language.Language
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
||||
@Immutable
|
||||
sealed class SettingsEvent {
|
||||
|
|
@ -30,9 +29,8 @@ sealed class SettingsEvent {
|
|||
val title: String
|
||||
) : SettingsEvent()
|
||||
|
||||
data class OnUpdateCategoryTitle(
|
||||
val id: Int,
|
||||
val title: String
|
||||
data class OnUpdateCategory(
|
||||
val category: Category
|
||||
) : SettingsEvent()
|
||||
|
||||
data class OnUpdateCategoryOrder(
|
||||
|
|
@ -43,12 +41,6 @@ sealed class SettingsEvent {
|
|||
val category: Category
|
||||
) : SettingsEvent()
|
||||
|
||||
data class OnUpdateCategorySort(
|
||||
val categoryId: Int,
|
||||
val sortOrder: LibrarySortOrder,
|
||||
val sortOrderDescending: Boolean
|
||||
) : SettingsEvent()
|
||||
|
||||
data class OnSelectColorPreset(
|
||||
val id: Int,
|
||||
) : SettingsEvent()
|
||||
|
|
|
|||
|
|
@ -20,14 +20,11 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.domain.model.reader.ColorPreset
|
||||
import ua.acclorite.book_story.domain.use_case.category.AddCategoryUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.category.DeleteCategoryUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.category.GetCategoriesUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.category.GetCategorySortingUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.category.UpdateCategoriesOrderUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.category.UpdateCategorySortingUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.category.UpdateCategoryUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.color_preset.DeleteColorPresetUseCase
|
||||
import ua.acclorite.book_story.domain.use_case.color_preset.GetColorPresetsUseCase
|
||||
|
|
@ -55,9 +52,7 @@ class SettingsModel @Inject constructor(
|
|||
private val getCategoriesUseCase: GetCategoriesUseCase,
|
||||
private val updateCategoryUseCase: UpdateCategoryUseCase,
|
||||
private val updateCategoriesOrderUseCase: UpdateCategoriesOrderUseCase,
|
||||
private val deleteCategoryUseCase: DeleteCategoryUseCase,
|
||||
private val updateCategorySortingUseCase: UpdateCategorySortingUseCase,
|
||||
private val getCategorySortingUseCase: GetCategorySortingUseCase
|
||||
private val deleteCategoryUseCase: DeleteCategoryUseCase
|
||||
) : ViewModel() {
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
|
@ -98,8 +93,7 @@ class SettingsModel @Inject constructor(
|
|||
it.copy(
|
||||
selectedColorPreset = colorPresets.getSelectedColorPreset(),
|
||||
colorPresets = colorPresets,
|
||||
categories = getCategoriesUseCase(),
|
||||
categoriesSort = getCategorySortingUseCase()
|
||||
categories = getCategoriesUseCase()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -131,10 +125,9 @@ class SettingsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
is SettingsEvent.OnUpdateCategoryTitle -> {
|
||||
is SettingsEvent.OnUpdateCategory -> {
|
||||
updateCategoryUseCase(
|
||||
categoryId = event.id,
|
||||
newTitle = event.title
|
||||
category = event.category
|
||||
)
|
||||
_state.update {
|
||||
it.copy(
|
||||
|
|
@ -165,21 +158,6 @@ class SettingsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
is SettingsEvent.OnUpdateCategorySort -> {
|
||||
updateCategorySortingUseCase(
|
||||
categorySort = CategorySort(
|
||||
categoryId = event.categoryId,
|
||||
sortOrder = event.sortOrder,
|
||||
sortOrderDescending = event.sortOrderDescending
|
||||
)
|
||||
)
|
||||
_state.update {
|
||||
it.copy(
|
||||
categoriesSort = getCategorySortingUseCase()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is SettingsEvent.OnSelectColorPreset -> {
|
||||
withContext(Dispatchers.IO) {
|
||||
colorPresetJob?.join()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ package ua.acclorite.book_story.presentation.settings
|
|||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Immutable
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.domain.model.reader.ColorPreset
|
||||
|
||||
@Immutable
|
||||
|
|
@ -19,6 +18,5 @@ data class SettingsState(
|
|||
val animateColorPreset: Boolean = false,
|
||||
val colorPresetListState: LazyListState = LazyListState(),
|
||||
|
||||
val categories: List<Category> = emptyList(),
|
||||
val categoriesSort: List<CategorySort> = emptyList(),
|
||||
val categories: List<Category> = emptyList()
|
||||
)
|
||||
|
|
@ -10,7 +10,6 @@ import androidx.compose.foundation.pager.PagerState
|
|||
import androidx.compose.runtime.Composable
|
||||
import ua.acclorite.book_story.core.BottomSheet
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.presentation.library.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.library.LibraryScreen
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
|
@ -22,13 +21,12 @@ fun LibraryBottomSheet(
|
|||
categories: List<Category>,
|
||||
showDefaultCategory: Boolean,
|
||||
pagerState: PagerState,
|
||||
categoriesSort: List<CategorySort>,
|
||||
sortOrder: LibrarySortOrder,
|
||||
sortOrderDescending: Boolean,
|
||||
perCategorySort: Boolean,
|
||||
changeSortOrder: (LibrarySortOrder) -> Unit,
|
||||
changeSortOrderDescending: (Boolean) -> Unit,
|
||||
updateCategorySort: (SettingsEvent.OnUpdateCategorySort) -> Unit,
|
||||
updateCategory: (SettingsEvent.OnUpdateCategory) -> Unit,
|
||||
dismissBottomSheet: (LibraryEvent.OnDismissBottomSheet) -> Unit
|
||||
) {
|
||||
when (bottomSheet) {
|
||||
|
|
@ -39,11 +37,10 @@ fun LibraryBottomSheet(
|
|||
categoriesPagerState = pagerState,
|
||||
sortOrder = sortOrder,
|
||||
sortOrderDescending = sortOrderDescending,
|
||||
categoriesSort = categoriesSort,
|
||||
perCategorySort = perCategorySort,
|
||||
changeSortOrder = changeSortOrder,
|
||||
changeSortOrderDescending = changeSortOrderDescending,
|
||||
updateCategorySort = updateCategorySort,
|
||||
updateCategory = updateCategory,
|
||||
dismissBottomSheet = dismissBottomSheet
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import ua.acclorite.book_story.core.BottomSheet
|
||||
import ua.acclorite.book_story.core.Dialog
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.presentation.library.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.library.model.LibraryLayout
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
|
@ -44,7 +43,6 @@ fun LibraryContent(
|
|||
categories: List<Category>,
|
||||
showDefaultCategory: Boolean,
|
||||
perCategorySort: Boolean,
|
||||
categoriesSort: List<CategorySort>,
|
||||
sortOrder: LibrarySortOrder,
|
||||
sortOrderDescending: Boolean,
|
||||
layout: LibraryLayout,
|
||||
|
|
@ -53,7 +51,7 @@ fun LibraryContent(
|
|||
refreshState: PullRefreshState,
|
||||
dialog: Dialog?,
|
||||
bottomSheet: BottomSheet?,
|
||||
updateCategorySort: (SettingsEvent.OnUpdateCategorySort) -> Unit,
|
||||
updateCategory: (SettingsEvent.OnUpdateCategory) -> Unit,
|
||||
changeSortOrder: (LibrarySortOrder) -> Unit,
|
||||
changeSortOrderDescending: (Boolean) -> Unit,
|
||||
selectBook: (LibraryEvent.OnSelectBook) -> Unit,
|
||||
|
|
@ -90,13 +88,12 @@ fun LibraryContent(
|
|||
categories = categories,
|
||||
showDefaultCategory = showDefaultCategory,
|
||||
pagerState = pagerState,
|
||||
categoriesSort = categoriesSort,
|
||||
sortOrder = sortOrder,
|
||||
sortOrderDescending = sortOrderDescending,
|
||||
perCategorySort = perCategorySort,
|
||||
changeSortOrder = changeSortOrder,
|
||||
changeSortOrderDescending = changeSortOrderDescending,
|
||||
updateCategorySort = updateCategorySort,
|
||||
updateCategory = updateCategory,
|
||||
dismissBottomSheet = dismissBottomSheet
|
||||
)
|
||||
|
||||
|
|
@ -122,7 +119,6 @@ fun LibraryContent(
|
|||
categories = categories,
|
||||
showDefaultCategory = showDefaultCategory,
|
||||
perCategorySort = perCategorySort,
|
||||
categoriesSort = categoriesSort,
|
||||
sortOrder = sortOrder,
|
||||
sortOrderDescending = sortOrderDescending,
|
||||
searchVisibility = searchVisibility,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.presentation.library.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
import ua.acclorite.book_story.presentation.settings.SettingsEvent
|
||||
|
|
@ -42,11 +41,10 @@ fun LibraryFilterBottomSheet(
|
|||
categoriesPagerState: PagerState,
|
||||
sortOrder: LibrarySortOrder,
|
||||
sortOrderDescending: Boolean,
|
||||
categoriesSort: List<CategorySort>,
|
||||
perCategorySort: Boolean,
|
||||
changeSortOrder: (LibrarySortOrder) -> Unit,
|
||||
changeSortOrderDescending: (Boolean) -> Unit,
|
||||
updateCategorySort: (SettingsEvent.OnUpdateCategorySort) -> Unit,
|
||||
updateCategory: (SettingsEvent.OnUpdateCategory) -> Unit,
|
||||
dismissBottomSheet: (LibraryEvent.OnDismissBottomSheet) -> Unit
|
||||
) {
|
||||
val currentCategory = remember(
|
||||
|
|
@ -55,25 +53,12 @@ fun LibraryFilterBottomSheet(
|
|||
categoriesPagerState.currentPage
|
||||
) {
|
||||
derivedStateOf {
|
||||
categories.toMutableList().apply {
|
||||
if (showDefaultCategory) {
|
||||
add(0, Category(id = -1, title = ""))
|
||||
}
|
||||
categories.filterNot {
|
||||
if (!showDefaultCategory) it.id == -1 else false
|
||||
}[categoriesPagerState.currentPage]
|
||||
}
|
||||
}
|
||||
|
||||
val currentCategorySort = remember(currentCategory, categoriesSort) {
|
||||
derivedStateOf {
|
||||
categoriesSort.firstOrNull { it.categoryId == currentCategory.value.id }
|
||||
?: CategorySort(
|
||||
categoryId = currentCategory.value.id,
|
||||
sortOrder = LibrarySortOrder.LAST_READ,
|
||||
sortOrderDescending = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val pagerState = rememberPagerState(initialPage) { 2 }
|
||||
DisposableEffect(Unit) { onDispose { initialPage = pagerState.currentPage } }
|
||||
|
|
@ -106,19 +91,18 @@ fun LibraryFilterBottomSheet(
|
|||
contentPadding = PaddingValues(top = 18.dp)
|
||||
) {
|
||||
LibrarySortOption(
|
||||
sortOrder = if (perCategorySort) {
|
||||
currentCategorySort.value.sortOrder
|
||||
} else sortOrder,
|
||||
sortOrderDescending = if (perCategorySort) {
|
||||
currentCategorySort.value.sortOrderDescending
|
||||
} else sortOrderDescending,
|
||||
sortOrder = if (perCategorySort) currentCategory.value.sortOrder
|
||||
else sortOrder,
|
||||
sortOrderDescending = if (perCategorySort) currentCategory.value.sortOrderDescending
|
||||
else sortOrderDescending,
|
||||
onChange = { sortOrder, sortOrderDescending ->
|
||||
if (perCategorySort) {
|
||||
updateCategorySort(
|
||||
SettingsEvent.OnUpdateCategorySort(
|
||||
categoryId = currentCategorySort.value.categoryId,
|
||||
sortOrder = sortOrder,
|
||||
sortOrderDescending = sortOrderDescending
|
||||
updateCategory(
|
||||
SettingsEvent.OnUpdateCategory(
|
||||
currentCategory.value.copy(
|
||||
sortOrder = sortOrder,
|
||||
sortOrderDescending = sortOrderDescending
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ fun LibraryMoveDialog(
|
|||
val selectedCategories = remember {
|
||||
mutableStateListOf<Category>().apply {
|
||||
clear()
|
||||
categories.forEach { category ->
|
||||
categories.filterNot { it.id == -1 }.forEach { category ->
|
||||
if (selectedBooks.value.all { it.data.categories.any { it == category.id } }) {
|
||||
add(category)
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ fun LibraryMoveDialog(
|
|||
},
|
||||
withContent = true,
|
||||
items = {
|
||||
items(categories) { category ->
|
||||
items(categories.filterNot { it.id == -1 }) { category ->
|
||||
val selected = remember(
|
||||
category,
|
||||
selectedCategories
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Modifier
|
||||
import ua.acclorite.book_story.core.helpers.compareByWithOrder
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.presentation.library.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.library.model.LibraryLayout
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
|
@ -31,7 +30,6 @@ fun LibraryPager(
|
|||
categories: List<Category>,
|
||||
showDefaultCategory: Boolean,
|
||||
perCategorySort: Boolean,
|
||||
categoriesSort: List<CategorySort>,
|
||||
sortOrder: LibrarySortOrder,
|
||||
sortOrderDescending: Boolean,
|
||||
layout: LibraryLayout,
|
||||
|
|
@ -51,7 +49,6 @@ fun LibraryPager(
|
|||
val categorizedBooks = remember(
|
||||
books,
|
||||
categories,
|
||||
categoriesSort,
|
||||
perCategorySort,
|
||||
sortOrder,
|
||||
sortOrderDescending,
|
||||
|
|
@ -76,61 +73,35 @@ fun LibraryPager(
|
|||
derivedStateOf {
|
||||
val categorizedBooks = mutableListOf<List<SelectableBook>>()
|
||||
|
||||
if (showDefaultCategory) {
|
||||
val categoryIds = categories.map { it.id }.toSet()
|
||||
categorizedBooks.add(
|
||||
books.filter { book ->
|
||||
book.data.categories.none { category -> category in categoryIds }
|
||||
}.let {
|
||||
if (perCategorySort) {
|
||||
val categorySort = categoriesSort.firstOrNull {
|
||||
it.categoryId == -1
|
||||
} ?: CategorySort(
|
||||
categoryId = -1,
|
||||
sortOrder = LibrarySortOrder.LAST_READ,
|
||||
sortOrderDescending = true
|
||||
)
|
||||
|
||||
return@let it.sortBooks(
|
||||
categorySort.sortOrder,
|
||||
categorySort.sortOrderDescending
|
||||
)
|
||||
}
|
||||
|
||||
return@let it
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
categories.sortedBy { it.order }.forEach { category ->
|
||||
categorizedBooks.add(
|
||||
books
|
||||
.filter { it.data.categories.any { category.id == it } }
|
||||
.let {
|
||||
val categoryIds = categories.map { it.id }.toSet()
|
||||
categories
|
||||
.filterNot { if (!showDefaultCategory) it.id == -1 else false }
|
||||
.sortedBy { it.order }
|
||||
.forEach { category ->
|
||||
categorizedBooks.add(
|
||||
books.filter { book ->
|
||||
if (category.id == -1) {
|
||||
book.data.categories.none { it in categoryIds }
|
||||
} else {
|
||||
book.data.categories.any { it == category.id }
|
||||
}
|
||||
}.let { books ->
|
||||
if (perCategorySort) {
|
||||
val categorySort = categoriesSort.firstOrNull {
|
||||
it.categoryId == category.id
|
||||
} ?: CategorySort(
|
||||
categoryId = category.id,
|
||||
sortOrder = LibrarySortOrder.LAST_READ,
|
||||
sortOrderDescending = true
|
||||
)
|
||||
|
||||
return@let it.sortBooks(
|
||||
categorySort.sortOrder,
|
||||
categorySort.sortOrderDescending
|
||||
return@let books.sortBooks(
|
||||
category.sortOrder,
|
||||
category.sortOrderDescending
|
||||
)
|
||||
}
|
||||
|
||||
return@let it
|
||||
return@let books
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return@derivedStateOf categorizedBooks.let {
|
||||
if (!perCategorySort) {
|
||||
return@let it.map {
|
||||
it.sortBooks(
|
||||
return@let it.map { books ->
|
||||
books.sortBooks(
|
||||
sortOrder,
|
||||
sortOrderDescending
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import ua.acclorite.book_story.domain.model.library.Category
|
||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||
import ua.acclorite.book_story.presentation.library.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.library.model.LibraryLayout
|
||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||
|
|
@ -51,7 +50,6 @@ fun LibraryScaffold(
|
|||
categories: List<Category>,
|
||||
showDefaultCategory: Boolean,
|
||||
perCategorySort: Boolean,
|
||||
categoriesSort: List<CategorySort>,
|
||||
sortOrder: LibrarySortOrder,
|
||||
sortOrderDescending: Boolean,
|
||||
searchVisibility: (LibraryEvent.OnSearchVisibility) -> Unit,
|
||||
|
|
@ -110,7 +108,6 @@ fun LibraryScaffold(
|
|||
categories = categories,
|
||||
showDefaultCategory = showDefaultCategory,
|
||||
perCategorySort = perCategorySort,
|
||||
categoriesSort = categoriesSort,
|
||||
sortOrder = sortOrder,
|
||||
sortOrderDescending = sortOrderDescending,
|
||||
layout = layout,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ fun LibraryTopBar(
|
|||
defaultCategory
|
||||
) {
|
||||
derivedStateOf {
|
||||
categories.map { category ->
|
||||
categories.filterNot { it.id == -1 }.map { category ->
|
||||
category to books.count { it.data.categories.any { it == category.id } }
|
||||
}.toMutableList().apply {
|
||||
if (showDefaultCategory) {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ fun LibraryCategoriesOption() {
|
|||
val settingsModel = hiltViewModel<SettingsModel>()
|
||||
val state = settingsModel.state.collectAsStateWithLifecycle()
|
||||
|
||||
val categories = remember(state.value.categories) {
|
||||
state.value.categories.filterNot { it.id == -1 }
|
||||
}
|
||||
val dialog = remember {
|
||||
mutableStateOf<String?>(null)
|
||||
}
|
||||
|
|
@ -94,12 +97,15 @@ fun LibraryCategoriesOption() {
|
|||
initialValue = selectedCategory.value?.title ?: "",
|
||||
onDismiss = { dialog.value = null },
|
||||
onAction = { title ->
|
||||
settingsModel.onEvent(
|
||||
SettingsEvent.OnUpdateCategoryTitle(
|
||||
id = selectedCategory.value?.id ?: -1,
|
||||
title = title
|
||||
selectedCategory.value?.let { selectedCategory ->
|
||||
settingsModel.onEvent(
|
||||
SettingsEvent.OnUpdateCategory(
|
||||
category = selectedCategory.copy(
|
||||
title = title
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -108,10 +114,10 @@ fun LibraryCategoriesOption() {
|
|||
LibraryCategoriesRemoveDialog(
|
||||
onDismiss = { dialog.value = null },
|
||||
onAction = {
|
||||
if (selectedCategory.value != null) {
|
||||
selectedCategory.value?.let { selectedCategory ->
|
||||
LibraryScreen.scrollToPageCompositionChannel.trySend(0)
|
||||
settingsModel.onEvent(
|
||||
SettingsEvent.OnRemoveCategory(selectedCategory.value!!)
|
||||
SettingsEvent.OnRemoveCategory(selectedCategory)
|
||||
)
|
||||
}
|
||||
dialog.value = null
|
||||
|
|
@ -124,12 +130,12 @@ fun LibraryCategoriesOption() {
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize(),
|
||||
list = state.value.categories,
|
||||
list = categories,
|
||||
onSettle = { from, to ->
|
||||
LibraryScreen.scrollToPageCompositionChannel.trySend(0)
|
||||
settingsModel.onEvent(
|
||||
SettingsEvent.OnUpdateCategoryOrder(
|
||||
state.value.categories.toMutableList().apply {
|
||||
categories.toMutableList().apply {
|
||||
add(to, removeAt(from))
|
||||
}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue