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