Move default category into database (#7676)
This commit is contained in:
parent
5315467908
commit
914831d51f
23 changed files with 269 additions and 216 deletions
|
@ -64,6 +64,12 @@ class CategoryRepositoryImpl(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun updateAllFlags(flags: Long?) {
|
||||
handler.await {
|
||||
categoriesQueries.updateAllFlags(flags)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun delete(categoryId: Long) {
|
||||
handler.await {
|
||||
categoriesQueries.delete(
|
||||
|
|
|
@ -13,7 +13,10 @@ import eu.kanade.domain.category.interactor.DeleteCategory
|
|||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.RenameCategory
|
||||
import eu.kanade.domain.category.interactor.ReorderCategory
|
||||
import eu.kanade.domain.category.interactor.ResetCategoryFlags
|
||||
import eu.kanade.domain.category.interactor.SetDisplayModeForCategory
|
||||
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||
import eu.kanade.domain.category.interactor.SetSortModeForCategory
|
||||
import eu.kanade.domain.category.interactor.UpdateCategory
|
||||
import eu.kanade.domain.category.repository.CategoryRepository
|
||||
import eu.kanade.domain.chapter.interactor.GetChapter
|
||||
|
@ -73,6 +76,9 @@ class DomainModule : InjektModule {
|
|||
override fun InjektRegistrar.registerInjectables() {
|
||||
addSingletonFactory<CategoryRepository> { CategoryRepositoryImpl(get()) }
|
||||
addFactory { GetCategories(get()) }
|
||||
addFactory { ResetCategoryFlags(get(), get()) }
|
||||
addFactory { SetDisplayModeForCategory(get(), get()) }
|
||||
addFactory { SetSortModeForCategory(get(), get()) }
|
||||
addFactory { CreateCategoryWithName(get()) }
|
||||
addFactory { RenameCategory(get()) }
|
||||
addFactory { ReorderCategory(get()) }
|
||||
|
|
|
@ -13,7 +13,7 @@ class ReorderCategory(
|
|||
) {
|
||||
|
||||
suspend fun await(categoryId: Long, newPosition: Int) = withContext(NonCancellable) await@{
|
||||
val categories = categoryRepository.getAll()
|
||||
val categories = categoryRepository.getAll().filterNot(Category::isSystemCategory)
|
||||
|
||||
val currentIndex = categories.indexOfFirst { it.id == categoryId }
|
||||
if (currentIndex == newPosition) {
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package eu.kanade.domain.category.interactor
|
||||
|
||||
import eu.kanade.domain.category.repository.CategoryRepository
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
||||
|
||||
class ResetCategoryFlags(
|
||||
private val preferences: PreferencesHelper,
|
||||
private val categoryRepository: CategoryRepository,
|
||||
) {
|
||||
|
||||
suspend fun await() {
|
||||
val display = preferences.libraryDisplayMode().get()
|
||||
val sort = preferences.librarySortingMode().get()
|
||||
val sortDirection = preferences.librarySortingAscending().get()
|
||||
|
||||
var flags = 0L
|
||||
flags = flags and DisplayModeSetting.MASK.inv() or (display.flag and DisplayModeSetting.MASK)
|
||||
flags = flags and SortModeSetting.MASK.inv() or (sort.flag and SortModeSetting.MASK)
|
||||
flags = flags and SortDirectionSetting.MASK.inv() or (sortDirection.flag and SortDirectionSetting.MASK)
|
||||
categoryRepository.updateAllFlags(flags)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package eu.kanade.domain.category.interactor
|
||||
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.domain.category.model.CategoryUpdate
|
||||
import eu.kanade.domain.category.repository.CategoryRepository
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
|
||||
|
||||
class SetDisplayModeForCategory(
|
||||
private val preferences: PreferencesHelper,
|
||||
private val categoryRepository: CategoryRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(category: Category, displayModeSetting: DisplayModeSetting) {
|
||||
val flags = category.flags and DisplayModeSetting.MASK.inv() or (displayModeSetting.flag and DisplayModeSetting.MASK)
|
||||
if (preferences.categorizedDisplaySettings().get()) {
|
||||
categoryRepository.updatePartial(
|
||||
CategoryUpdate(
|
||||
id = category.id,
|
||||
flags = flags,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
preferences.libraryDisplayMode().set(displayModeSetting)
|
||||
categoryRepository.updateAllFlags(flags)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package eu.kanade.domain.category.interactor
|
||||
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.domain.category.model.CategoryUpdate
|
||||
import eu.kanade.domain.category.repository.CategoryRepository
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
||||
|
||||
class SetSortModeForCategory(
|
||||
private val preferences: PreferencesHelper,
|
||||
private val categoryRepository: CategoryRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(category: Category, sortDirectionSetting: SortDirectionSetting) {
|
||||
val sort = if (preferences.categorizedDisplaySettings().get()) {
|
||||
SortModeSetting.fromFlag(category.flags)
|
||||
} else {
|
||||
preferences.librarySortingMode().get()
|
||||
}
|
||||
await(category, sort, sortDirectionSetting)
|
||||
}
|
||||
|
||||
suspend fun await(category: Category, sortModeSetting: SortModeSetting) {
|
||||
val direction = if (preferences.categorizedDisplaySettings().get()) {
|
||||
SortDirectionSetting.fromFlag(category.flags)
|
||||
} else {
|
||||
preferences.librarySortingAscending().get()
|
||||
}
|
||||
await(category, sortModeSetting, direction)
|
||||
}
|
||||
|
||||
suspend fun await(category: Category, sortModeSetting: SortModeSetting, sortDirectionSetting: SortDirectionSetting) {
|
||||
var flags = category.flags and SortModeSetting.MASK.inv() or (sortModeSetting.flag and SortModeSetting.MASK)
|
||||
flags = flags and SortDirectionSetting.MASK.inv() or (sortDirectionSetting.flag and SortDirectionSetting.MASK)
|
||||
if (preferences.categorizedDisplaySettings().get()) {
|
||||
categoryRepository.updatePartial(
|
||||
CategoryUpdate(
|
||||
id = category.id,
|
||||
flags = flags,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
preferences.librarySortingMode().set(sortModeSetting)
|
||||
preferences.librarySortingAscending().set(sortDirectionSetting)
|
||||
categoryRepository.updateAllFlags(flags)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,9 @@
|
|||
package eu.kanade.domain.category.model
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
||||
import java.io.Serializable
|
||||
import eu.kanade.tachiyomi.data.database.models.Category as DbCategory
|
||||
|
||||
data class Category(
|
||||
val id: Long,
|
||||
|
@ -16,6 +12,8 @@ data class Category(
|
|||
val flags: Long,
|
||||
) : Serializable {
|
||||
|
||||
val isSystemCategory: Boolean = id == UNCATEGORIZED_ID
|
||||
|
||||
val displayMode: Long
|
||||
get() = flags and DisplayModeSetting.MASK
|
||||
|
||||
|
@ -26,24 +24,11 @@ data class Category(
|
|||
get() = flags and SortDirectionSetting.MASK
|
||||
|
||||
companion object {
|
||||
val default = { context: Context ->
|
||||
Category(
|
||||
id = 0,
|
||||
name = context.getString(R.string.label_default),
|
||||
order = 0,
|
||||
flags = 0,
|
||||
)
|
||||
}
|
||||
|
||||
const val UNCATEGORIZED_ID = 0L
|
||||
}
|
||||
}
|
||||
|
||||
internal fun List<Category>.anyWithName(name: String): Boolean {
|
||||
return any { name.equals(it.name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun Category.toDbCategory(): DbCategory = CategoryImpl().also {
|
||||
it.name = name
|
||||
it.id = id.toInt()
|
||||
it.order = order.toInt()
|
||||
it.flags = flags.toInt()
|
||||
}
|
||||
|
|
|
@ -20,5 +20,7 @@ interface CategoryRepository {
|
|||
|
||||
suspend fun updatePartial(updates: List<CategoryUpdate>)
|
||||
|
||||
suspend fun updateAllFlags(flags: Long?)
|
||||
|
||||
suspend fun delete(categoryId: Long)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package eu.kanade.presentation.category
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
val Category.visualName: String
|
||||
@Composable
|
||||
get() = when (id) {
|
||||
Category.UNCATEGORIZED_ID -> stringResource(id = R.string.label_default)
|
||||
else -> name
|
||||
}
|
||||
|
||||
fun Category.visualName(context: Context): String =
|
||||
when (id) {
|
||||
Category.UNCATEGORIZED_ID -> context.getString(R.string.label_default)
|
||||
else -> name
|
||||
}
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import com.google.accompanist.pager.PagerState
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.presentation.category.visualName
|
||||
import eu.kanade.presentation.components.DownloadedOnlyModeBanner
|
||||
import eu.kanade.presentation.components.IncognitoModeBanner
|
||||
import eu.kanade.presentation.components.Pill
|
||||
|
@ -67,7 +68,7 @@ fun LibraryTabs(
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = category.name,
|
||||
text = category.visualName,
|
||||
color = if (state.currentPage == index) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
if (count != null) {
|
||||
|
|
|
@ -5,6 +5,8 @@ import android.net.Uri
|
|||
import com.hippo.unifile.UniFile
|
||||
import data.Manga_sync
|
||||
import data.Mangas
|
||||
import eu.kanade.data.category.categoryMapper
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.domain.history.model.HistoryUpdate
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
|
||||
|
@ -138,7 +140,9 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
|||
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
||||
// Check if user wants category information in backup
|
||||
return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
||||
handler.awaitList { categoriesQueries.getCategories(backupCategoryMapper) }
|
||||
handler.awaitList { categoriesQueries.getCategories(categoryMapper) }
|
||||
.filterNot(Category::isSystemCategory)
|
||||
.map(backupCategoryMapper)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
@ -224,34 +228,37 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
|||
*/
|
||||
internal suspend fun restoreCategories(backupCategories: List<BackupCategory>) {
|
||||
// Get categories from file and from db
|
||||
val dbCategories = handler.awaitList { categoriesQueries.getCategories() }
|
||||
val dbCategories = handler.awaitList { categoriesQueries.getCategories(categoryMapper) }
|
||||
|
||||
// Iterate over them
|
||||
backupCategories
|
||||
.map { it.getCategoryImpl() }
|
||||
.forEach { category ->
|
||||
// Used to know if the category is already in the db
|
||||
var found = false
|
||||
for (dbCategory in dbCategories) {
|
||||
// If the category is already in the db, assign the id to the file's category
|
||||
// and do nothing
|
||||
if (category.name == dbCategory.name) {
|
||||
category.id = dbCategory.id.toInt()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// If the category isn't in the db, remove the id and insert a new category
|
||||
// Store the inserted id in the category
|
||||
if (!found) {
|
||||
// Let the db assign the id
|
||||
category.id = null
|
||||
category.id = handler.awaitOne {
|
||||
categoriesQueries.insert(category.name, category.order.toLong(), category.flags.toLong())
|
||||
categoriesQueries.selectLastInsertedRowId()
|
||||
}.toInt()
|
||||
val categories = backupCategories.map {
|
||||
var category = it.getCategory()
|
||||
var found = false
|
||||
for (dbCategory in dbCategories) {
|
||||
// If the category is already in the db, assign the id to the file's category
|
||||
// and do nothing
|
||||
if (category.name == dbCategory.name) {
|
||||
category = category.copy(id = dbCategory.id)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Let the db assign the id
|
||||
val id = handler.awaitOne {
|
||||
categoriesQueries.insert(category.name, category.order, category.flags)
|
||||
categoriesQueries.selectLastInsertedRowId()
|
||||
}
|
||||
category = category.copy(id = id)
|
||||
}
|
||||
|
||||
category
|
||||
}
|
||||
|
||||
preferences.categorizedDisplaySettings().set(
|
||||
(dbCategories + categories)
|
||||
.distinctBy { it.flags }
|
||||
.size > 1,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.kanade.tachiyomi.data.backup.full.models
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
|
@ -12,19 +12,20 @@ class BackupCategory(
|
|||
// Bump by 100 to specify this is a 0.x value
|
||||
@ProtoNumber(100) var flags: Long = 0,
|
||||
) {
|
||||
fun getCategoryImpl(): CategoryImpl {
|
||||
return CategoryImpl().apply {
|
||||
name = this@BackupCategory.name
|
||||
flags = this@BackupCategory.flags.toInt()
|
||||
order = this@BackupCategory.order.toInt()
|
||||
}
|
||||
fun getCategory(): Category {
|
||||
return Category(
|
||||
id = 0,
|
||||
name = this@BackupCategory.name,
|
||||
flags = this@BackupCategory.flags,
|
||||
order = this@BackupCategory.order,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val backupCategoryMapper = { _: Long, name: String, order: Long, flags: Long ->
|
||||
val backupCategoryMapper = { category: Category ->
|
||||
BackupCategory(
|
||||
name = name,
|
||||
order = order,
|
||||
flags = flags,
|
||||
name = category.name,
|
||||
order = category.order,
|
||||
flags = category.flags,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
|
||||
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
||||
import java.io.Serializable
|
||||
import eu.kanade.domain.category.model.Category as DomainCategory
|
||||
|
||||
interface Category : Serializable {
|
||||
|
||||
var id: Int?
|
||||
|
||||
var name: String
|
||||
|
||||
var order: Int
|
||||
|
||||
var flags: Int
|
||||
|
||||
private fun setFlags(flag: Int, mask: Int) {
|
||||
flags = flags and mask.inv() or (flag and mask)
|
||||
}
|
||||
|
||||
var displayMode: Int
|
||||
get() = flags and DisplayModeSetting.MASK.toInt()
|
||||
set(mode) = setFlags(mode, DisplayModeSetting.MASK.toInt())
|
||||
|
||||
var sortMode: Int
|
||||
get() = flags and SortModeSetting.MASK.toInt()
|
||||
set(mode) = setFlags(mode, SortModeSetting.MASK.toInt())
|
||||
|
||||
var sortDirection: Int
|
||||
get() = flags and SortDirectionSetting.MASK.toInt()
|
||||
set(mode) = setFlags(mode, SortDirectionSetting.MASK.toInt())
|
||||
}
|
||||
|
||||
fun Category.toDomainCategory(): DomainCategory? {
|
||||
val categoryId = id ?: return null
|
||||
return DomainCategory(
|
||||
id = categoryId.toLong(),
|
||||
name = this.name,
|
||||
order = this.order.toLong(),
|
||||
flags = this.flags.toLong(),
|
||||
)
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
class CategoryImpl : Category {
|
||||
|
||||
override var id: Int? = null
|
||||
|
||||
override lateinit var name: String
|
||||
|
||||
override var order: Int = 0
|
||||
|
||||
override var flags: Int = 0
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
|
||||
val category = other as Category
|
||||
return name == category.name
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return name.hashCode()
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ class CategoryPresenter(
|
|||
getCategories.subscribe()
|
||||
.collectLatest {
|
||||
state.isLoading = false
|
||||
state.categories = it
|
||||
state.categories = it.filterNot(Category::isSystemCategory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.domain.category.model.toDbCategory
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.presentation.library.LibraryScreen
|
||||
|
@ -119,12 +118,8 @@ class LibraryController(
|
|||
}
|
||||
|
||||
fun showSettingsSheet() {
|
||||
if (presenter.categories.isNotEmpty()) {
|
||||
presenter.categories[presenter.activeCategory].let { category ->
|
||||
settingsSheet?.show(category.toDbCategory())
|
||||
}
|
||||
} else {
|
||||
settingsSheet?.show()
|
||||
presenter.categories[presenter.activeCategory].let { category ->
|
||||
settingsSheet?.show(category)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import eu.kanade.domain.manga.model.Manga
|
|||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.model.isLocal
|
||||
import eu.kanade.domain.track.interactor.GetTracks
|
||||
import eu.kanade.presentation.category.visualName
|
||||
import eu.kanade.presentation.library.LibraryState
|
||||
import eu.kanade.presentation.library.LibraryStateImpl
|
||||
import eu.kanade.presentation.library.components.LibraryToolbarTitle
|
||||
|
@ -94,15 +95,9 @@ class LibraryPresenter(
|
|||
private val trackManager: TrackManager = Injekt.get(),
|
||||
) : BasePresenter<LibraryController>(), LibraryState by state {
|
||||
|
||||
private val context = preferences.context
|
||||
|
||||
var loadedManga by mutableStateOf(emptyMap<Long, List<LibraryItem>>())
|
||||
private set
|
||||
|
||||
val isPerCategory by preferences.categorizedDisplaySettings().asState()
|
||||
|
||||
var currentDisplayMode by preferences.libraryDisplayMode().asState()
|
||||
|
||||
val tabVisibility by preferences.categoryTabs().asState()
|
||||
|
||||
val mangaCountVisibility by preferences.categoryNumberOfItems().asState()
|
||||
|
@ -412,8 +407,8 @@ class LibraryPresenter(
|
|||
*/
|
||||
private fun getLibraryObservable(): Observable<Library> {
|
||||
return combine(getCategoriesFlow(), getLibraryMangasFlow()) { dbCategories, libraryManga ->
|
||||
val categories = if (libraryManga.containsKey(0) || libraryManga.isEmpty()) {
|
||||
arrayListOf(Category.default(context)) + dbCategories
|
||||
val categories = if (libraryManga.isNotEmpty() && libraryManga.containsKey(0).not()) {
|
||||
dbCategories.filterNot { it.id == Category.UNCATEGORIZED_ID }
|
||||
} else {
|
||||
dbCategories
|
||||
}
|
||||
|
@ -642,10 +637,12 @@ class LibraryPresenter(
|
|||
val category = categories.getOrNull(activeCategory)
|
||||
|
||||
val defaultTitle = stringResource(id = R.string.label_library)
|
||||
val categoryName = category?.visualName ?: defaultTitle
|
||||
|
||||
val default = remember { LibraryToolbarTitle(defaultTitle) }
|
||||
|
||||
return produceState(initialValue = default, category, loadedManga, mangaCountVisibility, tabVisibility) {
|
||||
val title = if (tabVisibility.not()) category?.name ?: defaultTitle else defaultTitle
|
||||
val title = if (tabVisibility.not()) categoryName else defaultTitle
|
||||
|
||||
value = when {
|
||||
category == null -> default
|
||||
|
@ -681,11 +678,7 @@ class LibraryPresenter(
|
|||
fun getDisplayMode(index: Int): androidx.compose.runtime.State<DisplayModeSetting> {
|
||||
val category = categories[index]
|
||||
return derivedStateOf {
|
||||
if (isPerCategory.not() || category.id == 0L) {
|
||||
currentDisplayMode
|
||||
} else {
|
||||
DisplayModeSetting.fromFlag(category.displayMode)
|
||||
}
|
||||
DisplayModeSetting.fromFlag(category.displayMode)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,10 @@ import android.content.Context
|
|||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import eu.kanade.domain.category.interactor.UpdateCategory
|
||||
import eu.kanade.domain.category.model.CategoryUpdate
|
||||
import eu.kanade.domain.category.interactor.SetDisplayModeForCategory
|
||||
import eu.kanade.domain.category.interactor.SetSortModeForCategory
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainCategory
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
|
@ -29,7 +28,8 @@ import uy.kohesive.injekt.injectLazy
|
|||
class LibrarySettingsSheet(
|
||||
router: Router,
|
||||
private val trackManager: TrackManager = Injekt.get(),
|
||||
private val updateCategory: UpdateCategory = Injekt.get(),
|
||||
private val setDisplayModeForCategory: SetDisplayModeForCategory = Injekt.get(),
|
||||
private val setSortModeForCategory: SetSortModeForCategory = Injekt.get(),
|
||||
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit,
|
||||
) : TabbedBottomSheetDialog(router.activity!!) {
|
||||
|
||||
|
@ -202,8 +202,8 @@ class LibrarySettingsSheet(
|
|||
override val footer = null
|
||||
|
||||
override fun initModels() {
|
||||
val sorting = SortModeSetting.get(preferences, currentCategory?.toDomainCategory())
|
||||
val order = if (SortDirectionSetting.get(preferences, currentCategory?.toDomainCategory()) == SortDirectionSetting.ASCENDING) {
|
||||
val sorting = SortModeSetting.get(preferences, currentCategory)
|
||||
val order = if (SortDirectionSetting.get(preferences, currentCategory) == SortDirectionSetting.ASCENDING) {
|
||||
Item.MultiSort.SORT_ASC
|
||||
} else {
|
||||
Item.MultiSort.SORT_DESC
|
||||
|
@ -256,18 +256,8 @@ class LibrarySettingsSheet(
|
|||
SortDirectionSetting.DESCENDING
|
||||
}
|
||||
|
||||
if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
|
||||
currentCategory?.sortDirection = flag.flag.toInt()
|
||||
sheetScope.launchIO {
|
||||
updateCategory.await(
|
||||
CategoryUpdate(
|
||||
id = currentCategory!!.id?.toLong()!!,
|
||||
flags = currentCategory!!.flags.toLong(),
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
preferences.librarySortingAscending().set(flag)
|
||||
sheetScope.launchIO {
|
||||
setSortModeForCategory.await(currentCategory!!, flag)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,18 +274,8 @@ class LibrarySettingsSheet(
|
|||
else -> throw NotImplementedError("Unknown display mode")
|
||||
}
|
||||
|
||||
if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
|
||||
currentCategory?.sortMode = flag.flag.toInt()
|
||||
sheetScope.launchIO {
|
||||
updateCategory.await(
|
||||
CategoryUpdate(
|
||||
id = currentCategory!!.id?.toLong()!!,
|
||||
flags = currentCategory!!.flags.toLong(),
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
preferences.librarySortingMode().set(flag)
|
||||
sheetScope.launchIO {
|
||||
setSortModeForCategory.await(currentCategory!!, flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,8 +307,8 @@ class LibrarySettingsSheet(
|
|||
|
||||
// Gets user preference of currently selected display mode at current category
|
||||
private fun getDisplayModePreference(): DisplayModeSetting {
|
||||
return if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
|
||||
DisplayModeSetting.fromFlag(currentCategory?.displayMode?.toLong())
|
||||
return if (currentCategory != null && preferences.categorizedDisplaySettings().get()) {
|
||||
DisplayModeSetting.fromFlag(currentCategory!!.displayMode)
|
||||
} else {
|
||||
preferences.libraryDisplayMode().get()
|
||||
}
|
||||
|
@ -379,18 +359,8 @@ class LibrarySettingsSheet(
|
|||
else -> throw NotImplementedError("Unknown display mode")
|
||||
}
|
||||
|
||||
if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
|
||||
currentCategory?.displayMode = flag.flag.toInt()
|
||||
sheetScope.launchIO {
|
||||
updateCategory.await(
|
||||
CategoryUpdate(
|
||||
id = currentCategory!!.id?.toLong()!!,
|
||||
flags = currentCategory!!.flags.toLong(),
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
preferences.libraryDisplayMode().set(flag)
|
||||
sheetScope.launchIO {
|
||||
setDisplayModeForCategory.await(currentCategory!!, flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ enum class SortModeSetting(val flag: Long) {
|
|||
}
|
||||
|
||||
fun get(preferences: PreferencesHelper, category: Category?): SortModeSetting {
|
||||
return if (preferences.categorizedDisplaySettings().get() && category != null && category.id != 0L) {
|
||||
return if (category != null && preferences.categorizedDisplaySettings().get()) {
|
||||
fromFlag(category.sortMode)
|
||||
} else {
|
||||
preferences.librarySortingMode().get()
|
||||
|
|
|
@ -12,7 +12,7 @@ import androidx.preference.PreferenceScreen
|
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.presentation.category.visualName
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -46,8 +46,7 @@ class SettingsDownloadController : SettingsController() {
|
|||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
titleRes = R.string.pref_category_downloads
|
||||
|
||||
val dbCategories = runBlocking { getCategories.await() }
|
||||
val categories = listOf(Category.default(context)) + dbCategories
|
||||
val categories = runBlocking { getCategories.await() }
|
||||
|
||||
preference {
|
||||
bindTo(preferences.downloadsDirectory())
|
||||
|
@ -111,7 +110,7 @@ class SettingsDownloadController : SettingsController() {
|
|||
multiSelectListPreference {
|
||||
bindTo(preferences.removeExcludeCategories())
|
||||
titleRes = R.string.pref_remove_exclude_categories
|
||||
entries = categories.map { it.name }.toTypedArray()
|
||||
entries = categories.map { it.visualName(context) }.toTypedArray()
|
||||
entryValues = categories.map { it.id.toString() }.toTypedArray()
|
||||
|
||||
preferences.removeExcludeCategories().asFlow()
|
||||
|
@ -255,10 +254,9 @@ class SettingsDownloadController : SettingsController() {
|
|||
private val getCategories: GetCategories = Injekt.get()
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val dbCategories = runBlocking { getCategories.await() }
|
||||
val categories = listOf(Category.default(activity!!)) + dbCategories
|
||||
val categories = runBlocking { getCategories.await() }
|
||||
|
||||
val items = categories.map { it.name }
|
||||
val items = categories.map { it.visualName(activity!!) }
|
||||
var selected = categories
|
||||
.map {
|
||||
when (it.id.toString()) {
|
||||
|
|
|
@ -8,7 +8,9 @@ import androidx.core.text.buildSpannedString
|
|||
import androidx.preference.PreferenceScreen
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.ResetCategoryFlags
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.presentation.category.visualName
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_BATTERY_NOT_LOW
|
||||
|
@ -51,12 +53,13 @@ class SettingsLibraryController : SettingsController() {
|
|||
|
||||
private val getCategories: GetCategories by injectLazy()
|
||||
private val trackManager: TrackManager by injectLazy()
|
||||
private val resetCategoryFlags: ResetCategoryFlags by injectLazy()
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
titleRes = R.string.pref_category_library
|
||||
|
||||
val dbCategories = runBlocking { getCategories.await() }
|
||||
val categories = listOf(Category.default(context)) + dbCategories
|
||||
val allCategories = runBlocking { getCategories.await() }
|
||||
val userCategories = allCategories.filterNot(Category::isSystemCategory)
|
||||
|
||||
preferenceCategory {
|
||||
titleRes = R.string.pref_category_display
|
||||
|
@ -94,7 +97,7 @@ class SettingsLibraryController : SettingsController() {
|
|||
key = "pref_action_edit_categories"
|
||||
titleRes = R.string.action_edit_categories
|
||||
|
||||
val catCount = dbCategories.size
|
||||
val catCount = userCategories.size
|
||||
summary = context.resources.getQuantityString(R.plurals.num_categories, catCount, catCount)
|
||||
|
||||
onClick {
|
||||
|
@ -107,15 +110,15 @@ class SettingsLibraryController : SettingsController() {
|
|||
titleRes = R.string.default_category
|
||||
|
||||
entries = arrayOf(context.getString(R.string.default_category_summary)) +
|
||||
categories.map { it.name }.toTypedArray()
|
||||
entryValues = arrayOf("-1") + categories.map { it.id.toString() }.toTypedArray()
|
||||
allCategories.map { it.visualName(context) }.toTypedArray()
|
||||
entryValues = arrayOf("-1") + allCategories.map { it.id.toString() }.toTypedArray()
|
||||
defaultValue = "-1"
|
||||
|
||||
val selectedCategory = categories.find { it.id == preferences.defaultCategory().toLong() }
|
||||
val selectedCategory = allCategories.find { it.id == preferences.defaultCategory().toLong() }
|
||||
summary = selectedCategory?.name
|
||||
?: context.getString(R.string.default_category_summary)
|
||||
onChange { newValue ->
|
||||
summary = categories.find {
|
||||
summary = allCategories.find {
|
||||
it.id == (newValue as String).toLong()
|
||||
}?.name ?: context.getString(R.string.default_category_summary)
|
||||
true
|
||||
|
@ -125,6 +128,14 @@ class SettingsLibraryController : SettingsController() {
|
|||
switchPreference {
|
||||
bindTo(preferences.categorizedDisplaySettings())
|
||||
titleRes = R.string.categorized_display_settings
|
||||
|
||||
preferences.categorizedDisplaySettings().asFlow()
|
||||
.onEach {
|
||||
if (it.not()) {
|
||||
resetCategoryFlags.await()
|
||||
}
|
||||
}
|
||||
.launchIn(viewScope)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,19 +240,19 @@ class SettingsLibraryController : SettingsController() {
|
|||
|
||||
fun updateSummary() {
|
||||
val includedCategories = preferences.libraryUpdateCategories().get()
|
||||
.mapNotNull { id -> categories.find { it.id == id.toLong() } }
|
||||
.mapNotNull { id -> allCategories.find { it.id == id.toLong() } }
|
||||
.sortedBy { it.order }
|
||||
val excludedCategories = preferences.libraryUpdateCategoriesExclude().get()
|
||||
.mapNotNull { id -> categories.find { it.id == id.toLong() } }
|
||||
.mapNotNull { id -> allCategories.find { it.id == id.toLong() } }
|
||||
.sortedBy { it.order }
|
||||
|
||||
val allExcluded = excludedCategories.size == categories.size
|
||||
val allExcluded = excludedCategories.size == allCategories.size
|
||||
|
||||
val includedItemsText = when {
|
||||
// Some selected, but not all
|
||||
includedCategories.isNotEmpty() && includedCategories.size != categories.size -> includedCategories.joinToString { it.name }
|
||||
includedCategories.isNotEmpty() && includedCategories.size != allCategories.size -> includedCategories.joinToString { it.name }
|
||||
// All explicitly selected
|
||||
includedCategories.size == categories.size -> context.getString(R.string.all)
|
||||
includedCategories.size == allCategories.size -> context.getString(R.string.all)
|
||||
allExcluded -> context.getString(R.string.none)
|
||||
else -> context.getString(R.string.all)
|
||||
}
|
||||
|
@ -331,10 +342,9 @@ class SettingsLibraryController : SettingsController() {
|
|||
private val getCategories: GetCategories = Injekt.get()
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val dbCategories = runBlocking { getCategories.await() }
|
||||
val categories = listOf(Category.default(activity!!)) + dbCategories
|
||||
val categories = runBlocking { getCategories.await() }
|
||||
|
||||
val items = categories.map { it.name }
|
||||
val items = categories.map { it.visualName(activity!!) }
|
||||
var selected = categories
|
||||
.map {
|
||||
when (it.id.toString()) {
|
||||
|
|
|
@ -5,6 +5,17 @@ CREATE TABLE categories(
|
|||
flags INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- Insert system category
|
||||
INSERT OR IGNORE INTO categories(_id, name, sort, flags) VALUES (0, "", -1, 0);
|
||||
-- Disallow deletion of default category
|
||||
CREATE TRIGGER IF NOT EXISTS system_category_delete_trigger BEFORE DELETE
|
||||
ON categories
|
||||
BEGIN SELECT CASE
|
||||
WHEN old._id <= 0 THEN
|
||||
RAISE(ABORT, "System category can't be deleted")
|
||||
END;
|
||||
END;
|
||||
|
||||
getCategories:
|
||||
SELECT
|
||||
_id AS id,
|
||||
|
@ -40,5 +51,9 @@ SET name = coalesce(:name, name),
|
|||
flags = coalesce(:flags, flags)
|
||||
WHERE _id = :categoryId;
|
||||
|
||||
updateAllFlags:
|
||||
UPDATE categories SET
|
||||
flags = coalesce(?, flags);
|
||||
|
||||
selectLastInsertedRowId:
|
||||
SELECT last_insert_rowid();
|
10
app/src/main/sqldelight/migrations/19.sqm
Normal file
10
app/src/main/sqldelight/migrations/19.sqm
Normal file
|
@ -0,0 +1,10 @@
|
|||
-- Insert Default category
|
||||
INSERT OR IGNORE INTO categories(_id, name, sort, flags) VALUES (0, "", -1, 0);
|
||||
-- Disallow deletion of default category
|
||||
CREATE TRIGGER IF NOT EXISTS system_category_delete_trigger BEFORE DELETE
|
||||
ON categories
|
||||
BEGIN SELECT CASE
|
||||
WHEN old._id <= 0 THEN
|
||||
RAISE(ABORT, "System category can't be deleted")
|
||||
END;
|
||||
END;
|
Reference in a new issue