diff --git a/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt index 396af3b3a..d62069d1a 100644 --- a/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt @@ -67,6 +67,12 @@ class CategoryRepositoryImpl( ) } + override suspend fun updateAllFlags(flags: Long?) { + handler.await { + categoriesQueries.updateAllFlags(flags) + } + } + override suspend fun delete(categoryId: Long) { handler.await { categoriesQueries.delete( diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 51643d3d6..2c21e63fe 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -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 { 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()) } diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/ReorderCategory.kt b/app/src/main/java/eu/kanade/domain/category/interactor/ReorderCategory.kt index bfaaf174a..a286103a6 100644 --- a/app/src/main/java/eu/kanade/domain/category/interactor/ReorderCategory.kt +++ b/app/src/main/java/eu/kanade/domain/category/interactor/ReorderCategory.kt @@ -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) { diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt b/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt new file mode 100644 index 000000000..21504eddd --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt @@ -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) + } +} diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt b/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt new file mode 100644 index 000000000..37cd115c6 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt @@ -0,0 +1,38 @@ +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.LibraryGroup +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) + // SY --> + val isDefaultGroup = preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT + // SY <-- + if (preferences.categorizedDisplaySettings().get() /* SY --> */ && isDefaultGroup/* SY <-- */) { + categoryRepository.updatePartial( + CategoryUpdate( + id = category.id, + flags = flags, + ), + ) + } else { + preferences.libraryDisplayMode().set(displayModeSetting) + // SY --> + if (isDefaultGroup) { + // SY <-- + categoryRepository.updateAllFlags(flags) + // SY --> + } + // SY <-- + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt b/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt new file mode 100644 index 000000000..4b6120c47 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt @@ -0,0 +1,59 @@ +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.LibraryGroup +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() /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT/* SY <-- */) { + 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() /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT/* SY <-- */) { + 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) + // SY --> + val isDefaultGroup = preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT + // SY <-- + if (preferences.categorizedDisplaySettings().get() /* SY --> */ && isDefaultGroup/* SY <-- */) { + categoryRepository.updatePartial( + CategoryUpdate( + id = category.id, + flags = flags, + ), + ) + } else { + preferences.librarySortingMode().set(sortModeSetting) + preferences.librarySortingAscending().set(sortDirectionSetting) + // SY --> + if (isDefaultGroup) { + // SY <-- + categoryRepository.updateAllFlags(flags) + // SY --> + } + // SY <-- + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/category/model/Category.kt b/app/src/main/java/eu/kanade/domain/category/model/Category.kt index 74666136e..1b8b1d14b 100644 --- a/app/src/main/java/eu/kanade/domain/category/model/Category.kt +++ b/app/src/main/java/eu/kanade/domain/category/model/Category.kt @@ -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.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() -} diff --git a/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt b/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt index e907d411c..917b21d50 100644 --- a/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt +++ b/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt @@ -22,5 +22,7 @@ interface CategoryRepository { suspend fun updatePartial(updates: List) + suspend fun updateAllFlags(flags: Long?) + suspend fun delete(categoryId: Long) } diff --git a/app/src/main/java/eu/kanade/presentation/category/CategoryExtensions.kt b/app/src/main/java/eu/kanade/presentation/category/CategoryExtensions.kt new file mode 100644 index 000000000..a9a5a64e5 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/category/CategoryExtensions.kt @@ -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 + } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt b/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt index bb7790b46..02994e10f 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt @@ -109,6 +109,7 @@ fun LibraryScreen( isDownloadOnly = presenter.isDownloadOnly, // SY --> onOpenReader = onOpenReader, + getCategoryName = presenter::getCategoryName, // SY <-- ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibraryState.kt b/app/src/main/java/eu/kanade/presentation/library/LibraryState.kt index 4fee5adc7..e989fa0aa 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibraryState.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibraryState.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import eu.kanade.domain.category.model.Category import eu.kanade.tachiyomi.data.database.models.LibraryManga +import eu.kanade.tachiyomi.ui.library.LibraryGroup import exh.source.PERV_EDEN_EN_SOURCE_ID import exh.source.PERV_EDEN_IT_SOURCE_ID import exh.source.isEhBasedManga @@ -24,6 +25,7 @@ interface LibraryState { // SY --> val ogCategories: List + val groupType: Int val showSyncExh: Boolean val showCleanTitles: Boolean val showAddToMangadex: Boolean @@ -43,6 +45,8 @@ class LibraryStateImpl : LibraryState { override var hasActiveFilters: Boolean by mutableStateOf(false) // SY --> + override var groupType: Int by mutableStateOf(LibraryGroup.BY_DEFAULT) + override var ogCategories: List by mutableStateOf(emptyList()) override var showSyncExh: Boolean by mutableStateOf(true) diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt index 00791b6a7..7bc4d9237 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt @@ -1,13 +1,16 @@ package eu.kanade.presentation.library.components +import android.content.Context import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import com.google.accompanist.pager.rememberPagerState import com.google.accompanist.swiperefresh.SwipeRefresh @@ -44,6 +47,7 @@ fun LibraryContent( getLibraryForPage: @Composable (Int) -> State>, // SY --> onOpenReader: (LibraryManga) -> Unit, + getCategoryName: (Context, Category, Int, String) -> String, // SY <-- ) { Column( @@ -61,6 +65,14 @@ fun LibraryContent( getNumberOfMangaForCategory = getNumberOfMangaForCategory, isDownloadOnly = isDownloadOnly, isIncognitoMode = isIncognitoMode, + // SY --> + getCategoryName = { category, name -> + val context = LocalContext.current + derivedStateOf { + getCategoryName(context, category, state.groupType, name) + }.value + }, + // SY <-- ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryTabs.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryTabs.kt index c2cd11787..35a43ff4b 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryTabs.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryTabs.kt @@ -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 @@ -36,6 +37,9 @@ fun LibraryTabs( isDownloadOnly: Boolean, isIncognitoMode: Boolean, getNumberOfMangaForCategory: @Composable (Long) -> State, + // SY --> + getCategoryName: @Composable (Category, String) -> String, + // SY <-- ) { val scope = rememberCoroutineScope() @@ -43,12 +47,12 @@ fun LibraryTabs( Column { ScrollableTabRow( - selectedTabIndex = state.currentPage, + selectedTabIndex = state.currentPage.coerceAtMost(categories.lastIndex), edgePadding = 0.dp, indicator = { tabPositions -> TabRowDefaults.Indicator( Modifier - .tabIndicatorOffset(tabPositions[state.currentPage]) + .tabIndicatorOffset(tabPositions[state.currentPage.coerceAtMost(categories.lastIndex)]) .clip(RoundedCornerShape(topStart = 3.dp, topEnd = 3.dp)), ) }, @@ -67,7 +71,9 @@ fun LibraryTabs( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = category.name, + // SY --> + text = getCategoryName(category, category.visualName), + // SY <-- color = if (state.currentPage == index) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground, ) if (count != null) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt index 5234de49a..d854026ab 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt @@ -5,8 +5,10 @@ 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.data.exh.mergedMangaReferenceMapper import eu.kanade.data.manga.mangaMapper +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 @@ -160,7 +162,9 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { private suspend fun backupCategories(options: Int): List { // 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() } @@ -270,34 +274,37 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { */ internal suspend fun restoreCategories(backupCategories: List) { // 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, + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt index 6d6c23aa0..7f87d3dd1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupCategory.kt @@ -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 @@ -14,20 +14,21 @@ class BackupCategory( // SY specific values /*@ProtoNumber(600) var mangaOrder: List = emptyList(),*/ ) { - 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, /*mangaOrder = this@BackupCategory.mangaOrder*/ - } + ) } } -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, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt deleted file mode 100755 index 806a36671..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt +++ /dev/null @@ -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(), - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt deleted file mode 100755 index af40baecb..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt +++ /dev/null @@ -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() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt index 22da4c121..cf26d57e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.data.track.myanimelist import eu.kanade.tachiyomi.network.parseAs -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt index b24c81ec9..f0809a9fe 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt @@ -35,7 +35,7 @@ class CategoryPresenter( getCategories.subscribe() .collectLatest { state.isLoading = false - state.categories = it + state.categories = it.filterNot(Category::isSystemCategory) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 98a5ea794..e2b217a33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -12,7 +12,6 @@ import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType import com.google.android.material.dialog.MaterialAlertDialogBuilder 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 @@ -205,7 +204,7 @@ class LibraryController( fun showSettingsSheet() { if (presenter.categories.isNotEmpty() /* SY --> */ && presenter.groupType == LibraryGroup.BY_DEFAULT /* SY <-- */) { presenter.categories[presenter.activeCategory].let { category -> - settingsSheet?.show(category.toDbCategory()) + settingsSheet?.show(category) } } else { settingsSheet?.show() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 6877c6135..ed650466e 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.ui.library +import android.content.Context import android.os.Bundle import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf @@ -8,6 +9,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.util.fastAny import com.jakewharton.rxrelay.BehaviorRelay @@ -34,6 +36,7 @@ import eu.kanade.domain.manga.model.MangaUpdate import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.track.interactor.GetTracks import eu.kanade.domain.track.model.Track +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 @@ -138,15 +141,9 @@ class LibraryPresenter( // SY <-- ) : BasePresenter(), LibraryState by state { - private val context = preferences.context - var loadedManga by mutableStateOf(emptyMap>()) 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() @@ -175,15 +172,13 @@ class LibraryPresenter( private var librarySubscription: Job? = null // SY --> - val favoritesSync = FavoritesSyncHelper(context) - - val groupType by preferences.groupLibraryBy().asState() + val favoritesSync = FavoritesSyncHelper(preferences.context) private val loggedServices by lazy { trackManager.services.filter { it.isLogged } } private val services by lazy { trackManager.services.associate { service -> - service.id to context.getString(service.nameRes()) + service.id to preferences.context.getString(service.nameRes()) } } @@ -249,6 +244,7 @@ class LibraryPresenter( .asFlow() .collectLatest { // SY --> + state.groupType = preferences.groupLibraryBy().get() state.categories = it.categories // SY <-- state.isLoading = false @@ -578,8 +574,8 @@ class LibraryPresenter( */ private fun getLibraryObservable(): Observable { 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 } @@ -612,7 +608,8 @@ class LibraryPresenter( } else -> { val (items, customCategories) = getGroupedMangaItems( - map.values.flatten().distinctBy { it.manga.id }, + groupType = groupType, + libraryManga = map.values.flatten().distinctBy { it.manga.id }, ) editedCategories = customCategories items @@ -909,13 +906,18 @@ class LibraryPresenter( // TODO: This is good but should we separate title from count or get categories with count from db @Composable fun getToolbarTitle(): androidx.compose.runtime.State { + val context = LocalContext.current 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 + return produceState(initialValue = default, category, loadedManga, mangaCountVisibility, tabVisibility, groupType, context) { + val title = if (tabVisibility.not()) { + getCategoryName(context, category, groupType, categoryName) + } else defaultTitle value = when { category == null -> default @@ -928,6 +930,36 @@ class LibraryPresenter( } } + fun getCategoryName( + context: Context, + category: Category?, + groupType: Int, + categoryName: String, + ): String { + return when (groupType) { + LibraryGroup.BY_STATUS -> when (category?.id) { + SManga.ONGOING.toLong() -> context.getString(R.string.ongoing) + SManga.LICENSED.toLong() -> context.getString(R.string.licensed) + SManga.CANCELLED.toLong() -> context.getString(R.string.cancelled) + SManga.ON_HIATUS.toLong() -> context.getString(R.string.on_hiatus) + SManga.PUBLISHING_FINISHED.toLong() -> context.getString(R.string.publishing_finished) + SManga.COMPLETED.toLong() -> context.getString(R.string.completed) + else -> context.getString(R.string.unknown) + } + LibraryGroup.BY_SOURCE -> if (category?.id == LocalSource.ID) { + context.getString(R.string.local_source) + } else { + categoryName + } + LibraryGroup.BY_TRACK_STATUS -> TrackStatus.values() + .find { it.int.toLong() == category?.id } + .let { it ?: TrackStatus.OTHER } + .let { context.getString(it.res) } + LibraryGroup.UNGROUPED -> context.getString(R.string.ungrouped) + else -> categoryName + } + } + // SY --> @Composable fun getMangaForCategory(page: Int): androidx.compose.runtime.State> { @@ -1063,7 +1095,7 @@ class LibraryPresenter( } } - private fun filterTracks(constraint: String, tracks: List): Boolean { + private fun filterTracks(constraint: String, tracks: List): Boolean { return tracks.any { val trackService = trackManager.getService(it.syncId) if (trackService != null) { @@ -1073,6 +1105,8 @@ class LibraryPresenter( } else false } } + + private val currentCategory by preferences.libraryDisplayMode().asState() // SY <-- @Composable @@ -1080,12 +1114,12 @@ class LibraryPresenter( val category = categories[index] return derivedStateOf { // SY --> - if (groupType != LibraryGroup.BY_DEFAULT || isPerCategory.not() || (category.id == 0L && groupType == LibraryGroup.BY_DEFAULT)) { - // SY <-- - currentDisplayMode + if (groupType != LibraryGroup.BY_DEFAULT) { + currentCategory } else { DisplayModeSetting.fromFlag(category.displayMode) } + // SY <-- } } @@ -1135,41 +1169,8 @@ class LibraryPresenter( } } - private fun getGroupedMangaItems(libraryManga: List): Pair> { - val groupType = preferences.groupLibraryBy().get() - val grouping: MutableMap> = mutableMapOf() - when (groupType) { - LibraryGroup.BY_STATUS -> { - grouping.putAll( - listOf( - SManga.ONGOING.toLong() to context.getString(R.string.ongoing), - SManga.LICENSED.toLong() to context.getString(R.string.licensed), - SManga.CANCELLED.toLong() to context.getString(R.string.cancelled), - SManga.ON_HIATUS.toLong() to context.getString(R.string.on_hiatus), - SManga.PUBLISHING_FINISHED.toLong() to context.getString(R.string.publishing_finished), - SManga.COMPLETED.toLong() to context.getString(R.string.completed), - SManga.UNKNOWN.toLong() to context.getString(R.string.unknown), - ).associateBy(Pair::first), - ) - } - LibraryGroup.BY_SOURCE -> - libraryManga - .map { it.manga.source } - .distinct() - .sorted() - .map { sourceId -> - sourceId to (sourceId to sourceManager.getOrStub(sourceId).name) - } - .let(grouping::putAll) - LibraryGroup.BY_TRACK_STATUS -> { - grouping.putAll( - TrackStatus.values() - .map { it.int.toLong() to context.getString(it.res) } - .associateBy(Pair::first), - ) - } - } - val map: MutableMap> = mutableMapOf() + private fun getGroupedMangaItems(groupType: Int, libraryManga: List): Pair> { + val manga = mutableMapOf>() when (groupType) { LibraryGroup.BY_TRACK_STATUS -> { @@ -1179,46 +1180,39 @@ class LibraryPresenter( TrackStatus.parseTrackerStatus(track.syncId, track.status) } ?: TrackStatus.OTHER - map.getOrPut(status.int.toLong()) { mutableListOf() } += libraryItem + manga.getOrPut(status.int.toLong()) { mutableListOf() } += libraryItem } } LibraryGroup.BY_SOURCE -> { libraryManga.forEach { libraryItem -> - val group = grouping[libraryItem.manga.source] - if (group != null) { - map.getOrPut(group.first) { mutableListOf() } += libraryItem - } else { - grouping.getOrPut(Long.MAX_VALUE) { - Long.MAX_VALUE to context.getString(R.string.unknown) - } - map.getOrPut(Long.MAX_VALUE) { mutableListOf() } += libraryItem - } + manga.getOrPut(libraryItem.manga.source) { mutableListOf() } += libraryItem } } else -> { libraryManga.forEach { libraryItem -> - val group = grouping[libraryItem.manga.status.toLong()] - if (group != null) { - map.getOrPut(group.first) { mutableListOf() } += libraryItem - } else { - grouping.getOrPut(Long.MAX_VALUE) { - Long.MAX_VALUE to context.getString(R.string.unknown) - } - map.getOrPut(Long.MAX_VALUE) { mutableListOf() } += libraryItem - } + manga.getOrPut(libraryItem.manga.status.toLong()) { mutableListOf() } += libraryItem } } } val categories = when (groupType) { - LibraryGroup.BY_SOURCE -> grouping.values.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, Pair<*, String>::second)) - LibraryGroup.BY_TRACK_STATUS, LibraryGroup.BY_STATUS -> grouping.values.filter { it.first in map.keys } - else -> grouping.values - }.map { (id, name) -> - Category(id, name, 0, 0) + LibraryGroup.BY_SOURCE -> manga.keys.map { Category(it, sourceManager.getOrStub(it).name, 0, 0) } + .sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }) + LibraryGroup.BY_TRACK_STATUS -> + manga.keys + .map { id -> + TrackStatus.values().find { id == it.int.toLong() } + ?: TrackStatus.OTHER + } + .sortedBy { it.int } + .map { + Category(it.int.toLong(), "", 0, 0) + } + LibraryGroup.BY_STATUS -> manga.keys.sorted().map { Category(it, "", 0, 0) } + else -> throw IllegalStateException("Invalid group type $groupType") } - return map to categories + return manga to categories } fun runSync() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index 5d5c239b6..398d24149 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -5,11 +5,10 @@ import android.util.AttributeSet import android.view.View import com.bluelinelabs.conductor.Router import eu.kanade.domain.category.interactor.GetCategories -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 @@ -31,7 +30,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!!) { @@ -226,8 +226,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 @@ -292,18 +292,8 @@ class LibrarySettingsSheet( SortDirectionSetting.DESCENDING } - if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0 /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT /* SY <-- */) { - 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) } } @@ -323,18 +313,8 @@ class LibrarySettingsSheet( else -> throw NotImplementedError("Unknown display mode") } - if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0 /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT /* SY <-- */) { - 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) } } } @@ -374,8 +354,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 /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT /* SY <-- */) { - DisplayModeSetting.fromFlag(currentCategory?.displayMode?.toLong()) + return if (currentCategory != null && preferences.categorizedDisplaySettings().get()/* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT /* SY <-- */) { + DisplayModeSetting.fromFlag(currentCategory!!.displayMode) } else { preferences.libraryDisplayMode().get() } @@ -426,18 +406,8 @@ class LibrarySettingsSheet( else -> throw NotImplementedError("Unknown display mode") } - if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0 /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT /* SY <-- */) { - 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) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt index d0bceb57e..2901ad6d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.library.setting import eu.kanade.domain.category.model.Category import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.ui.library.LibraryGroup enum class SortModeSetting(val flag: Long) { ALPHABETICAL(0b00000000), @@ -38,7 +39,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() /* SY --> */ && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT/* SY <-- */) { fromFlag(category.sortMode) } else { preferences.librarySortingMode().get() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index 8b550b9b7..7c89ae6c6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -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()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index b61fb1098..00d2fc647 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -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 @@ -55,6 +57,7 @@ class SettingsLibraryController : SettingsController() { private val getCategories: GetCategories by injectLazy() private val trackManager: TrackManager by injectLazy() + private val resetCategoryFlags: ResetCategoryFlags by injectLazy() // SY --> /** @@ -66,8 +69,8 @@ class SettingsLibraryController : SettingsController() { 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 @@ -120,7 +123,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 { @@ -133,15 +136,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 @@ -151,6 +154,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) } } @@ -255,19 +266,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) } @@ -403,10 +414,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()) { diff --git a/app/src/main/sqldelight/data/categories.sq b/app/src/main/sqldelight/data/categories.sq index e40a4707f..b20b9f1b7 100644 --- a/app/src/main/sqldelight/data/categories.sq +++ b/app/src/main/sqldelight/data/categories.sq @@ -8,6 +8,17 @@ CREATE TABLE categories( manga_order TEXT AS List NOT NULL ); +-- Insert system category +INSERT OR IGNORE INTO categories(_id, name, sort, flags, manga_order) 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, @@ -43,5 +54,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(); diff --git a/app/src/main/sqldelight/migrations/20.sqm b/app/src/main/sqldelight/migrations/20.sqm new file mode 100644 index 000000000..e06c0d80f --- /dev/null +++ b/app/src/main/sqldelight/migrations/20.sqm @@ -0,0 +1,10 @@ +-- Insert Default category +INSERT OR IGNORE INTO categories(_id, name, sort, flags, manga_order) 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; \ No newline at end of file