diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index eba1fe6a28..d4165fcdfd 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -46,6 +46,7 @@ import tachiyomi.data.updates.UpdatesRepositoryImpl import tachiyomi.domain.category.interactor.CreateCategoryWithName import tachiyomi.domain.category.interactor.DeleteCategory import tachiyomi.domain.category.interactor.GetCategories +import tachiyomi.domain.category.interactor.HideCategory import tachiyomi.domain.category.interactor.RenameCategory import tachiyomi.domain.category.interactor.ReorderCategory import tachiyomi.domain.category.interactor.ResetCategoryFlags @@ -110,6 +111,9 @@ class DomainModule : InjektModule { addFactory { ReorderCategory(get()) } addFactory { UpdateCategory(get()) } addFactory { DeleteCategory(get()) } + // KMK --> + addFactory { HideCategory(get()) } + // KMK <-- addSingletonFactory { MangaRepositoryImpl(get()) } addFactory { GetDuplicateLibraryManga(get()) } diff --git a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt index 9bb8c8d538..27f8eca613 100644 --- a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt @@ -37,6 +37,9 @@ fun CategoryScreen( onClickDelete: (Category) -> Unit, onClickMoveUp: (Category) -> Unit, onClickMoveDown: (Category) -> Unit, + // KMK --> + onClickHide: (Category) -> Unit, + // KMK <-- navigateUp: () -> Unit, ) { val lazyListState = rememberLazyListState() @@ -83,6 +86,9 @@ fun CategoryScreen( onClickDelete = onClickDelete, onMoveUp = onClickMoveUp, onMoveDown = onClickMoveDown, + // KMK --> + onClickHide = onClickHide, + // KMK <-- ) } } @@ -96,6 +102,9 @@ private fun CategoryContent( onClickDelete: (Category) -> Unit, onMoveUp: (Category) -> Unit, onMoveDown: (Category) -> Unit, + // KMK --> + onClickHide: (Category) -> Unit, + // KMK <-- ) { LazyColumn( state = lazyListState, @@ -115,6 +124,9 @@ private fun CategoryContent( onMoveDown = onMoveDown, onRename = { onClickRename(category) }, onDelete = { onClickDelete(category) }, + // KMK --> + onHide = { onClickHide(category) }, + // KMK <-- ) } } diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt index 5c387e542c..dc008f5463 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt @@ -11,16 +11,21 @@ import androidx.compose.material.icons.outlined.ArrowDropDown import androidx.compose.material.icons.outlined.ArrowDropUp import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Edit +import androidx.compose.material.icons.outlined.Visibility +import androidx.compose.material.icons.outlined.VisibilityOff import androidx.compose.material3.ElevatedCard import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextDecoration import tachiyomi.domain.category.model.Category import tachiyomi.i18n.MR +import tachiyomi.i18n.kmk.KMR import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource @@ -33,6 +38,9 @@ fun CategoryListItem( onMoveDown: (Category) -> Unit, onRename: () -> Unit, onDelete: () -> Unit, + // KMK --> + onHide: () -> Unit, + // KMK <-- modifier: Modifier = Modifier, ) { ElevatedCard( @@ -49,9 +57,19 @@ fun CategoryListItem( ), verticalAlignment = Alignment.CenterVertically, ) { - Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = null) + Icon( + imageVector = Icons.AutoMirrored.Outlined.Label, + contentDescription = null, + // KMK --> + tint = LocalContentColor.current.let { if (category.hidden) it.copy(alpha = 0.6f) else it }, + // KMK <-- + ) Text( text = category.name, + // KMK --> + color = LocalContentColor.current.let { if (category.hidden) it.copy(alpha = 0.6f) else it }, + textDecoration = TextDecoration.LineThrough.takeIf { category.hidden }, + // KMK <-- modifier = Modifier .padding(start = MaterialTheme.padding.medium), ) @@ -76,6 +94,21 @@ fun CategoryListItem( contentDescription = stringResource(MR.strings.action_rename_category), ) } + // KMK --> + IconButton( + onClick = onHide, + content = { + Icon( + imageVector = if (category.hidden) { + Icons.Outlined.Visibility + } else { + Icons.Outlined.VisibilityOff + }, + contentDescription = stringResource(KMR.strings.action_hide), + ) + }, + ) + // KMK <-- IconButton(onClick = onDelete) { Icon(imageVector = Icons.Outlined.Delete, contentDescription = stringResource(MR.strings.action_delete)) } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index dcdd4b6cec..2dd78a639f 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -335,6 +335,12 @@ private fun ColumnScope.DisplayPage( label = stringResource(MR.strings.action_display_show_tabs), pref = screenModel.libraryPreferences.categoryTabs(), ) + // KMK --> + CheckboxItem( + label = stringResource(KMR.strings.action_hide_hidden_categories), + pref = screenModel.libraryPreferences.hideHiddenCategories(), + ) + // KMK <-- CheckboxItem( label = stringResource(MR.strings.action_display_show_number_of_items), pref = screenModel.libraryPreferences.categoryNumberOfItems(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt index eb5dd08332..b70baad8e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt @@ -10,6 +10,9 @@ class BackupCategory( @ProtoNumber(2) var order: Long = 0, // @ProtoNumber(3) val updateInterval: Int = 0, 1.x value not used in 0.x @ProtoNumber(100) var flags: Long = 0, + // KMK --> + @ProtoNumber(900) var hidden: Boolean = false, + // KMK <-- // SY specific values /*@ProtoNumber(600) var mangaOrder: List = emptyList(),*/ ) { @@ -18,6 +21,9 @@ class BackupCategory( name = this@BackupCategory.name, flags = this@BackupCategory.flags, order = this@BackupCategory.order, + // KMK --> + hidden = this@BackupCategory.hidden, + // KMK <-- /*mangaOrder = this@BackupCategory.mangaOrder*/ ) } @@ -27,5 +33,8 @@ val backupCategoryMapper = { category: Category -> name = category.name, order = category.order, flags = category.flags, + // KMK --> + hidden = category.hidden, + // KMK <-- ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt index 15080f8ee1..2c0eda9cf9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt @@ -26,7 +26,12 @@ class CategoriesRestorer( if (dbCategory != null) return@map dbCategory val order = nextOrder++ handler.awaitOneExecutable { - categoriesQueries.insert(it.name, order, it.flags) + categoriesQueries.insert( + it.name, order, it.flags, + // KMK --> + hidden = if (it.hidden) 1L else 0L, + // KMK <-- + ) categoriesQueries.selectLastInsertedRowId() } .let { id -> it.toCategory(id).copy(order = order) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt index 20ebdba0ff..70368122eb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt @@ -45,6 +45,9 @@ class CategoryScreen : Screen() { onClickDelete = { screenModel.showDialog(CategoryDialog.Delete(it)) }, onClickMoveUp = screenModel::moveUp, onClickMoveDown = screenModel::moveDown, + // KMK --> + onClickHide = screenModel::hideCategory, + // KMK <-- navigateUp = navigator::pop, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt index 2fb78342fd..cf0b029f3d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.launch import tachiyomi.domain.category.interactor.CreateCategoryWithName import tachiyomi.domain.category.interactor.DeleteCategory import tachiyomi.domain.category.interactor.GetCategories +import tachiyomi.domain.category.interactor.HideCategory import tachiyomi.domain.category.interactor.RenameCategory import tachiyomi.domain.category.interactor.ReorderCategory import tachiyomi.domain.category.model.Category @@ -27,6 +28,9 @@ class CategoryScreenModel( private val deleteCategory: DeleteCategory = Injekt.get(), private val reorderCategory: ReorderCategory = Injekt.get(), private val renameCategory: RenameCategory = Injekt.get(), + // KMK --> + private val hideCategory: HideCategory = Injekt.get(), + // KMK <-- ) : StateScreenModel(CategoryScreenState.Loading) { private val _events: Channel = Channel() @@ -56,6 +60,17 @@ class CategoryScreenModel( } } + // KMK --> + fun hideCategory(category: Category) { + screenModelScope.launch { + when (hideCategory.await(category)) { + is HideCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) + else -> {} + } + } + } + // KMK <-- + fun deleteCategory(categoryId: Long) { screenModelScope.launch { when (deleteCategory.await(categoryId = categoryId)) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index baa52bf665..b4c4545304 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -592,7 +592,13 @@ class LibraryScreenModel( .groupBy { it.libraryManga.category } } - return combine(getCategories.subscribe(), libraryMangasFlow) { categories, libraryManga -> + return combine( + // KMK --> + libraryPreferences.hideHiddenCategories().changes(), + // KMK <-- + getCategories.subscribe(), + libraryMangasFlow, + ) { hideHiddenCategories, categories, libraryManga -> val displayCategories = if (libraryManga.isNotEmpty() && !libraryManga.containsKey(0)) { categories.fastFilterNot { it.isSystemCategory } } else { @@ -604,7 +610,11 @@ class LibraryScreenModel( state.copy(ogCategories = displayCategories) } // SY <-- - displayCategories.associateWith { libraryManga[it.id].orEmpty() } + displayCategories + // KMK --> + .filterNot { hideHiddenCategories && it.hidden } + // KMK <-- + .associateWith { libraryManga[it.id].orEmpty() } } } @@ -619,6 +629,9 @@ class LibraryScreenModel( preferences.context.stringResource(SYMR.strings.ungrouped), 0, 0, + // KMK --> + false, + // KMK <-- ) to values.flatten().distinctBy { it.libraryManga.manga.id }, ) @@ -1283,6 +1296,9 @@ class LibraryScreenModel( it.int == id }.takeUnless { it == -1 }?.toLong() ?: TrackStatus.OTHER.ordinal.toLong(), flags = 0, + // KMK --> + hidden = false, + // KMK <-- ) } } @@ -1308,6 +1324,9 @@ class LibraryScreenModel( }, order = sources.indexOf(it.key).takeUnless { it == -1 }?.toLong() ?: Long.MAX_VALUE, flags = 0, + // KMK --> + hidden = false, + // KMK <-- ) } } @@ -1336,6 +1355,9 @@ class LibraryScreenModel( else -> 7 }, flags = 0, + // KMK --> + hidden = false, + // KMK <-- ) } } diff --git a/app/src/main/java/mihon/core/migration/migrations/MoveSortingModeSettingsMigration.kt b/app/src/main/java/mihon/core/migration/migrations/MoveSortingModeSettingsMigration.kt index 0660b0c81b..1f1dfcb70d 100644 --- a/app/src/main/java/mihon/core/migration/migrations/MoveSortingModeSettingsMigration.kt +++ b/app/src/main/java/mihon/core/migration/migrations/MoveSortingModeSettingsMigration.kt @@ -40,6 +40,9 @@ class MoveSortingModeSettingsMigration : Migration { flags = it.flags and 0b00111100L.inv(), name = null, order = null, + // KMK --> + hidden = null, + // KMK <-- ) } } diff --git a/app/src/test/kotlin/Tester.kt b/app/src/test/kotlin/Tester.kt index 56a08af3c6..0933f2c4da 100644 --- a/app/src/test/kotlin/Tester.kt +++ b/app/src/test/kotlin/Tester.kt @@ -81,6 +81,9 @@ class Tester { name = "a", order = 1, flags = 0, + // KMK --> + hidden = false, + // KMK <-- ), ) val favoriteEntries = listOf( diff --git a/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt b/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt index dc91c4535c..30ca855120 100644 --- a/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt +++ b/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt @@ -8,12 +8,18 @@ object CategoryMapper { name: String, order: Long, flags: Long, + // KMK --> + hidden: Long, + // KMK <-- ): Category { return Category( id = id, name = name, order = order, flags = flags, + // KMK --> + hidden = hidden == 1L, + // KMK <-- ) } } diff --git a/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt index 417a04e113..4d3ed4df6c 100644 --- a/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt @@ -42,6 +42,9 @@ class CategoryRepositoryImpl( name = category.name, order = category.order, flags = category.flags, + // KMK --> + hidden = if (category.hidden) 1L else 0L, + // KMK <-- ) categoriesQueries.selectLastInsertedRowId() } @@ -67,6 +70,9 @@ class CategoryRepositoryImpl( name = update.name, order = update.order, flags = update.flags, + // KMK --> + hidden = update.hidden?.let { if (it) 1L else 0L }, + // KMK <-- categoryId = update.id, ) } diff --git a/data/src/main/sqldelight/tachiyomi/data/categories.sq b/data/src/main/sqldelight/tachiyomi/data/categories.sq index c31c65e9cb..7daed167a8 100644 --- a/data/src/main/sqldelight/tachiyomi/data/categories.sq +++ b/data/src/main/sqldelight/tachiyomi/data/categories.sq @@ -6,11 +6,14 @@ CREATE TABLE categories( name TEXT NOT NULL, sort INTEGER NOT NULL, flags INTEGER NOT NULL, - manga_order TEXT AS List NOT NULL + manga_order TEXT AS List NOT NULL, + -- KMK --> + hidden INTEGER NOT NULL DEFAULT 0 + -- KMK <-- ); -- Insert system category -INSERT OR IGNORE INTO categories(_id, name, sort, flags, manga_order) VALUES (0, "", -1, 0, ""); +INSERT OR IGNORE INTO categories(_id, name, sort, flags, manga_order, hidden) VALUES (0, "", -1, 0, "", 0); -- Disallow deletion of default category CREATE TRIGGER IF NOT EXISTS system_category_delete_trigger BEFORE DELETE ON categories @@ -21,7 +24,7 @@ BEGIN SELECT CASE END; getCategory: -SELECT _id,name,sort,flags +SELECT _id,name,sort,flags,hidden FROM categories WHERE _id = :id LIMIT 1; @@ -31,7 +34,10 @@ SELECT _id AS id, name, sort AS `order`, -flags +flags, +-- KMK --> +hidden +-- KMK <-- FROM categories ORDER BY sort; @@ -40,15 +46,18 @@ SELECT C._id AS id, C.name, C.sort AS `order`, -C.flags +C.flags, +-- KMK --> +C.hidden +-- KMK <-- FROM categories C JOIN mangas_categories MC ON C._id = MC.category_id WHERE MC.manga_id = :mangaId; insert: -INSERT INTO categories(name, sort, flags, manga_order) -VALUES (:name, :order, :flags, ""); +INSERT INTO categories(name, sort, flags, manga_order, hidden) +VALUES (:name, :order, :flags, "", :hidden); delete: DELETE FROM categories @@ -58,7 +67,10 @@ update: UPDATE categories SET name = coalesce(:name, name), sort = coalesce(:order, sort), - flags = coalesce(:flags, flags) + flags = coalesce(:flags, flags), + -- KMK --> + hidden = coalesce(:hidden, hidden) + -- KMK <-- WHERE _id = :categoryId; updateAllFlags: @@ -66,4 +78,4 @@ UPDATE categories SET flags = coalesce(?, flags); selectLastInsertedRowId: -SELECT last_insert_rowid(); \ No newline at end of file +SELECT last_insert_rowid(); diff --git a/data/src/main/sqldelight/tachiyomi/migrations/34.sqm b/data/src/main/sqldelight/tachiyomi/migrations/34.sqm new file mode 100644 index 0000000000..86c2ecf1b8 --- /dev/null +++ b/data/src/main/sqldelight/tachiyomi/migrations/34.sqm @@ -0,0 +1 @@ +ALTER TABLE categories ADD COLUMN hidden INTEGER DEFAULT 0 NOT NULL; \ No newline at end of file diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/CreateCategoryWithName.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/CreateCategoryWithName.kt index 535f7103e0..38a5cd84d1 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/CreateCategoryWithName.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/CreateCategoryWithName.kt @@ -26,6 +26,9 @@ class CreateCategoryWithName( name = name, order = nextOrder, flags = initialFlags, + // KMK --> + hidden = false, + // KMK <-- ) try { diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/HideCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/HideCategory.kt new file mode 100644 index 0000000000..d47335a6ae --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/HideCategory.kt @@ -0,0 +1,33 @@ +package tachiyomi.domain.category.interactor + +import logcat.LogPriority +import tachiyomi.core.common.util.lang.withNonCancellableContext +import tachiyomi.core.common.util.system.logcat +import tachiyomi.domain.category.model.Category +import tachiyomi.domain.category.model.CategoryUpdate +import tachiyomi.domain.category.repository.CategoryRepository + +class HideCategory( + private val categoryRepository: CategoryRepository, +) { + + suspend fun await(category: Category) = withNonCancellableContext { + val update = CategoryUpdate( + id = category.id, + hidden = !category.hidden, + ) + + try { + categoryRepository.updatePartial(update) + Result.Success + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + Result.InternalError(e) + } + } + + sealed class Result { + object Success : Result() + data class InternalError(val error: Throwable) : Result() + } +} diff --git a/domain/src/main/java/tachiyomi/domain/category/model/Category.kt b/domain/src/main/java/tachiyomi/domain/category/model/Category.kt index ea901ce80f..800a74aed6 100644 --- a/domain/src/main/java/tachiyomi/domain/category/model/Category.kt +++ b/domain/src/main/java/tachiyomi/domain/category/model/Category.kt @@ -7,6 +7,9 @@ data class Category( val name: String, val order: Long, val flags: Long, + // KMK --> + val hidden: Boolean, + // KMK <-- ) : Serializable { val isSystemCategory: Boolean = id == UNCATEGORIZED_ID diff --git a/domain/src/main/java/tachiyomi/domain/category/model/CategoryUpdate.kt b/domain/src/main/java/tachiyomi/domain/category/model/CategoryUpdate.kt index d3ee8baa97..0071bfa13d 100644 --- a/domain/src/main/java/tachiyomi/domain/category/model/CategoryUpdate.kt +++ b/domain/src/main/java/tachiyomi/domain/category/model/CategoryUpdate.kt @@ -5,4 +5,7 @@ data class CategoryUpdate( val name: String? = null, val order: Long? = null, val flags: Long? = null, + // KMK --> + val hidden: Boolean? = null, + // KMK <-- ) diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index ea6c08f58d..736eb420c9 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -152,6 +152,10 @@ class LibraryPreferences( fun categorizedDisplaySettings() = preferenceStore.getBoolean("categorized_display", false) + // KMK --> + fun hideHiddenCategories() = preferenceStore.getBoolean("hide_hidden_categories", false) + // KMK <-- + fun updateCategories() = preferenceStore.getStringSet("library_update_categories", emptySet()) fun updateCategoriesExclude() = preferenceStore.getStringSet( diff --git a/i18n-kmk/src/commonMain/moko-resources/base/strings.xml b/i18n-kmk/src/commonMain/moko-resources/base/strings.xml index a6cca6516a..6c4c7d2679 100644 --- a/i18n-kmk/src/commonMain/moko-resources/base/strings.xml +++ b/i18n-kmk/src/commonMain/moko-resources/base/strings.xml @@ -12,6 +12,8 @@ Move bottom Confirm Color Remove merged entries? + Hide + Hide hidden categories