package eu.kanade.presentation.more.settings.screen import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.util.fastMap import androidx.core.content.ContextCompat import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.category.visualName import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.widget.TriStateListDialog import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.ui.category.CategoryScreen import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.ResetCategoryFlags import tachiyomi.domain.category.model.Category import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_CHARGING import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_NETWORK_NOT_METERED import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_ONLY_ON_WIFI import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_HAS_UNREAD import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD import tachiyomi.i18n.MR import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get object SettingsLibraryScreen : SearchableSettings { @Composable @ReadOnlyComposable override fun getTitleRes() = MR.strings.pref_category_library @Composable override fun getPreferences(): List { val getCategories = remember { Injekt.get() } val libraryPreferences = remember { Injekt.get() } val allCategories by getCategories.subscribe().collectAsState(initial = runBlocking { getCategories.await() }) return listOf( getCategoriesGroup(LocalNavigator.currentOrThrow, allCategories, libraryPreferences), getGlobalUpdateGroup(allCategories, libraryPreferences), getChapterSwipeActionsGroup(libraryPreferences), ) } @Composable private fun getCategoriesGroup( navigator: Navigator, allCategories: List, libraryPreferences: LibraryPreferences, ): Preference.PreferenceGroup { val scope = rememberCoroutineScope() val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size val defaultCategory by libraryPreferences.defaultCategory().collectAsState() val selectedCategory = allCategories.find { it.id == defaultCategory.toLong() } // For default category val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) + allCategories.fastMap { it.id.toInt() } val labels = listOf(stringResource(MR.strings.default_category_summary)) + allCategories.fastMap { it.visualName } return Preference.PreferenceGroup( title = stringResource(MR.strings.categories), preferenceItems = persistentListOf( Preference.PreferenceItem.TextPreference( title = stringResource(MR.strings.action_edit_categories), subtitle = pluralStringResource( MR.plurals.num_categories, count = userCategoriesCount, userCategoriesCount, ), onClick = { navigator.push(CategoryScreen()) }, ), Preference.PreferenceItem.ListPreference( pref = libraryPreferences.defaultCategory(), title = stringResource(MR.strings.default_category), subtitle = selectedCategory?.visualName ?: stringResource(MR.strings.default_category_summary), entries = ids.zip(labels).toMap().toImmutableMap(), ), Preference.PreferenceItem.SwitchPreference( pref = libraryPreferences.categorizedDisplaySettings(), title = stringResource(MR.strings.categorized_display_settings), onValueChanged = { if (!it) { scope.launch { Injekt.get().await() } } true }, ), ), ) } @Composable private fun getGlobalUpdateGroup( allCategories: List, libraryPreferences: LibraryPreferences, ): Preference.PreferenceGroup { val context = LocalContext.current val autoUpdateIntervalPref = libraryPreferences.autoUpdateInterval() val autoUpdateCategoriesPref = libraryPreferences.updateCategories() val autoUpdateCategoriesExcludePref = libraryPreferences.updateCategoriesExclude() val autoUpdateInterval by autoUpdateIntervalPref.collectAsState() val included by autoUpdateCategoriesPref.collectAsState() val excluded by autoUpdateCategoriesExcludePref.collectAsState() var showCategoriesDialog by rememberSaveable { mutableStateOf(false) } if (showCategoriesDialog) { TriStateListDialog( title = stringResource(MR.strings.categories), message = stringResource(MR.strings.pref_library_update_categories_details), items = allCategories, initialChecked = included.mapNotNull { id -> allCategories.find { it.id.toString() == id } }, initialInversed = excluded.mapNotNull { id -> allCategories.find { it.id.toString() == id } }, itemLabel = { it.visualName }, onDismissRequest = { showCategoriesDialog = false }, onValueChanged = { newIncluded, newExcluded -> autoUpdateCategoriesPref.set(newIncluded.map { it.id.toString() }.toSet()) autoUpdateCategoriesExcludePref.set(newExcluded.map { it.id.toString() }.toSet()) showCategoriesDialog = false }, ) } return Preference.PreferenceGroup( title = stringResource(MR.strings.pref_category_library_update), preferenceItems = persistentListOf( Preference.PreferenceItem.ListPreference( pref = autoUpdateIntervalPref, title = stringResource(MR.strings.pref_library_update_interval), entries = persistentMapOf( 0 to stringResource(MR.strings.update_never), 12 to stringResource(MR.strings.update_12hour), 24 to stringResource(MR.strings.update_24hour), 48 to stringResource(MR.strings.update_48hour), 72 to stringResource(MR.strings.update_72hour), 168 to stringResource(MR.strings.update_weekly), ), onValueChanged = { LibraryUpdateJob.setupTask(context, it) true }, ), Preference.PreferenceItem.MultiSelectListPreference( pref = libraryPreferences.autoUpdateDeviceRestrictions(), enabled = autoUpdateInterval > 0, title = stringResource(MR.strings.pref_library_update_restriction), subtitle = stringResource(MR.strings.restrictions), entries = persistentMapOf( DEVICE_ONLY_ON_WIFI to stringResource(MR.strings.connected_to_wifi), DEVICE_NETWORK_NOT_METERED to stringResource(MR.strings.network_not_metered), DEVICE_CHARGING to stringResource(MR.strings.charging), ), onValueChanged = { // Post to event looper to allow the preference to be updated. ContextCompat.getMainExecutor(context).execute { LibraryUpdateJob.setupTask(context) } true }, ), Preference.PreferenceItem.TextPreference( title = stringResource(MR.strings.categories), subtitle = getCategoriesLabel( allCategories = allCategories, included = included, excluded = excluded, ), onClick = { showCategoriesDialog = true }, ), Preference.PreferenceItem.SwitchPreference( pref = libraryPreferences.autoUpdateMetadata(), title = stringResource(MR.strings.pref_library_update_refresh_metadata), subtitle = stringResource(MR.strings.pref_library_update_refresh_metadata_summary), ), Preference.PreferenceItem.MultiSelectListPreference( pref = libraryPreferences.autoUpdateMangaRestrictions(), title = stringResource(MR.strings.pref_library_update_smart_update), entries = persistentMapOf( MANGA_HAS_UNREAD to stringResource(MR.strings.pref_update_only_completely_read), MANGA_NON_READ to stringResource(MR.strings.pref_update_only_started), MANGA_NON_COMPLETED to stringResource(MR.strings.pref_update_only_non_completed), MANGA_OUTSIDE_RELEASE_PERIOD to stringResource(MR.strings.pref_update_only_in_release_period), ), ), Preference.PreferenceItem.SwitchPreference( pref = libraryPreferences.newShowUpdatesCount(), title = stringResource(MR.strings.pref_library_update_show_tab_badge), ), ), ) } @Composable private fun getChapterSwipeActionsGroup( libraryPreferences: LibraryPreferences, ): Preference.PreferenceGroup { return Preference.PreferenceGroup( title = stringResource(MR.strings.pref_chapter_swipe), preferenceItems = persistentListOf( Preference.PreferenceItem.ListPreference( pref = libraryPreferences.swipeToStartAction(), title = stringResource(MR.strings.pref_chapter_swipe_start), entries = persistentMapOf( LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(MR.strings.disabled), LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(MR.strings.action_bookmark), LibraryPreferences.ChapterSwipeAction.ToggleRead to stringResource(MR.strings.action_mark_as_read), LibraryPreferences.ChapterSwipeAction.Download to stringResource(MR.strings.action_download), ), ), Preference.PreferenceItem.ListPreference( pref = libraryPreferences.swipeToEndAction(), title = stringResource(MR.strings.pref_chapter_swipe_end), entries = persistentMapOf( LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(MR.strings.disabled), LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(MR.strings.action_bookmark), LibraryPreferences.ChapterSwipeAction.ToggleRead to stringResource(MR.strings.action_mark_as_read), LibraryPreferences.ChapterSwipeAction.Download to stringResource(MR.strings.action_download), ), ), ), ) } }