diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index a1fc2257c..e10c1f1cb 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -56,7 +56,7 @@ import tachiyomi.domain.category.anime.interactor.RenameAnimeCategory import tachiyomi.domain.category.anime.interactor.ReorderAnimeCategory import tachiyomi.domain.category.anime.interactor.ResetAnimeCategoryFlags import tachiyomi.domain.category.anime.interactor.SetAnimeCategories -import tachiyomi.domain.category.anime.interactor.SetDisplayModeForAnimeCategory +import tachiyomi.domain.category.anime.interactor.SetAnimeDisplayMode import tachiyomi.domain.category.anime.interactor.SetSortModeForAnimeCategory import tachiyomi.domain.category.anime.interactor.UpdateAnimeCategory import tachiyomi.domain.category.anime.repository.AnimeCategoryRepository @@ -68,8 +68,8 @@ import tachiyomi.domain.category.manga.interactor.HideMangaCategory import tachiyomi.domain.category.manga.interactor.RenameMangaCategory import tachiyomi.domain.category.manga.interactor.ReorderMangaCategory import tachiyomi.domain.category.manga.interactor.ResetMangaCategoryFlags -import tachiyomi.domain.category.manga.interactor.SetDisplayModeForMangaCategory import tachiyomi.domain.category.manga.interactor.SetMangaCategories +import tachiyomi.domain.category.manga.interactor.SetMangaDisplayMode import tachiyomi.domain.category.manga.interactor.SetSortModeForMangaCategory import tachiyomi.domain.category.manga.interactor.UpdateMangaCategory import tachiyomi.domain.category.manga.repository.MangaCategoryRepository @@ -151,7 +151,7 @@ class DomainModule : InjektModule { addFactory { GetAnimeCategories(get()) } addFactory { GetVisibleAnimeCategories(get()) } addFactory { ResetAnimeCategoryFlags(get(), get()) } - addFactory { SetDisplayModeForAnimeCategory(get(), get()) } + addFactory { SetAnimeDisplayMode(get()) } addFactory { SetSortModeForAnimeCategory(get(), get()) } addFactory { CreateAnimeCategoryWithName(get(), get()) } addFactory { RenameAnimeCategory(get()) } @@ -164,7 +164,7 @@ class DomainModule : InjektModule { addFactory { GetMangaCategories(get()) } addFactory { GetVisibleMangaCategories(get()) } addFactory { ResetMangaCategoryFlags(get(), get()) } - addFactory { SetDisplayModeForMangaCategory(get(), get()) } + addFactory { SetMangaDisplayMode(get()) } addFactory { SetSortModeForMangaCategory(get(), get()) } addFactory { CreateMangaCategoryWithName(get(), get()) } addFactory { RenameMangaCategory(get()) } diff --git a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryContent.kt index 2bec27aab..2bd366daf 100644 --- a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryContent.kt @@ -43,7 +43,7 @@ fun AnimeLibraryContent( onRefresh: (Category?) -> Boolean, onGlobalSearchClicked: () -> Unit, getNumberOfAnimeForCategory: (Category) -> Int?, - getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode, + getDisplayMode: (Int) -> PreferenceMutableState, getColumnsForOrientation: (Boolean) -> PreferenceMutableState, getAnimeLibraryForPage: (Int) -> List, ) { @@ -103,7 +103,7 @@ fun AnimeLibraryContent( selectedAnime = selection, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - getDisplayModeForPage = getDisplayModeForPage, + getDisplayMode = getDisplayMode, getColumnsForOrientation = getColumnsForOrientation, getLibraryForPage = getAnimeLibraryForPage, onClickAnime = onClickAnime, diff --git a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryPager.kt b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryPager.kt index c91954a54..4de9cfb65 100644 --- a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryPager.kt +++ b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibraryPager.kt @@ -26,7 +26,7 @@ fun AnimeLibraryPager( selectedAnime: List, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode, + getDisplayMode: (Int) -> PreferenceMutableState, getColumnsForOrientation: (Boolean) -> PreferenceMutableState, getLibraryForPage: (Int) -> List, onClickAnime: (LibraryAnime) -> Unit, @@ -54,7 +54,7 @@ fun AnimeLibraryPager( return@HorizontalPager } - val displayMode = getDisplayModeForPage(page) + val displayMode by getDisplayMode(page) val columns by if (displayMode != LibraryDisplayMode.List) { val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE diff --git a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt index d3187c724..eb3676d63 100644 --- a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt @@ -33,7 +33,6 @@ import tachiyomi.domain.entries.TriStateFilter import tachiyomi.domain.library.anime.model.AnimeLibrarySort import tachiyomi.domain.library.anime.model.sort import tachiyomi.domain.library.model.LibraryDisplayMode -import tachiyomi.domain.library.model.display import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem @@ -45,7 +44,7 @@ import tachiyomi.presentation.core.components.SortItem fun AnimeLibrarySettingsDialog( onDismissRequest: () -> Unit, screenModel: AnimeLibrarySettingsScreenModel, - category: Category, + category: Category?, ) { TabbedDialog( onDismissRequest = onDismissRequest, @@ -69,7 +68,6 @@ fun AnimeLibrarySettingsDialog( screenModel = screenModel, ) 2 -> DisplayPage( - category = category, screenModel = screenModel, ) } @@ -148,7 +146,7 @@ private fun ColumnScope.FilterPage( @Composable private fun ColumnScope.SortPage( - category: Category, + category: Category?, screenModel: AnimeLibrarySettingsScreenModel, ) { val sortingMode = category.sort.type @@ -182,10 +180,10 @@ private fun ColumnScope.SortPage( @Composable private fun ColumnScope.DisplayPage( - category: Category, screenModel: AnimeLibrarySettingsScreenModel, ) { HeadingItem(R.string.action_display_mode) + val displayMode by screenModel.libraryPreferences.libraryDisplayMode().collectAsState() listOf( R.string.action_display_grid to LibraryDisplayMode.CompactGrid, R.string.action_display_comfortable_grid to LibraryDisplayMode.ComfortableGrid, @@ -194,12 +192,12 @@ private fun ColumnScope.DisplayPage( ).map { (titleRes, mode) -> RadioItem( label = stringResource(titleRes), - selected = category.display == mode, - onClick = { screenModel.setDisplayMode(category, mode) }, + selected = displayMode == mode, + onClick = { screenModel.setDisplayMode(mode) }, ) } - if (category.display != LibraryDisplayMode.List) { + if (displayMode != LibraryDisplayMode.List) { Row( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryContent.kt index 7e1af1e42..98d030ffe 100644 --- a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryContent.kt @@ -43,7 +43,7 @@ fun MangaLibraryContent( onRefresh: (Category?) -> Boolean, onGlobalSearchClicked: () -> Unit, getNumberOfMangaForCategory: (Category) -> Int?, - getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode, + getDisplayMode: (Int) -> PreferenceMutableState, getColumnsForOrientation: (Boolean) -> PreferenceMutableState, getLibraryForPage: (Int) -> List, ) { @@ -103,7 +103,7 @@ fun MangaLibraryContent( selectedManga = selection, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - getDisplayModeForPage = getDisplayModeForPage, + getDisplayMode = getDisplayMode, getColumnsForOrientation = getColumnsForOrientation, getLibraryForPage = getLibraryForPage, onClickManga = onClickManga, diff --git a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryPager.kt b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryPager.kt index f3e197d4d..264d27b07 100644 --- a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryPager.kt +++ b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibraryPager.kt @@ -35,7 +35,7 @@ fun MangaLibraryPager( selectedManga: List, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode, + getDisplayMode: (Int) -> PreferenceMutableState, getColumnsForOrientation: (Boolean) -> PreferenceMutableState, getLibraryForPage: (Int) -> List, onClickManga: (LibraryManga) -> Unit, @@ -63,7 +63,7 @@ fun MangaLibraryPager( return@HorizontalPager } - val displayMode = getDisplayModeForPage(page) + val displayMode by getDisplayMode(page) val columns by if (displayMode != LibraryDisplayMode.List) { val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE diff --git a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt index cd4fcd057..94b29f1d6 100644 --- a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt @@ -33,7 +33,6 @@ import tachiyomi.domain.entries.TriStateFilter import tachiyomi.domain.library.manga.model.MangaLibrarySort import tachiyomi.domain.library.manga.model.sort import tachiyomi.domain.library.model.LibraryDisplayMode -import tachiyomi.domain.library.model.display import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem @@ -45,7 +44,7 @@ import tachiyomi.presentation.core.components.SortItem fun MangaLibrarySettingsDialog( onDismissRequest: () -> Unit, screenModel: MangaLibrarySettingsScreenModel, - category: Category, + category: Category?, ) { TabbedDialog( onDismissRequest = onDismissRequest, @@ -69,7 +68,6 @@ fun MangaLibrarySettingsDialog( screenModel = screenModel, ) 2 -> DisplayPage( - category = category, screenModel = screenModel, ) } @@ -148,7 +146,7 @@ private fun ColumnScope.FilterPage( @Composable private fun ColumnScope.SortPage( - category: Category, + category: Category?, screenModel: MangaLibrarySettingsScreenModel, ) { val sortingMode = category.sort.type @@ -181,10 +179,10 @@ private fun ColumnScope.SortPage( @Composable private fun ColumnScope.DisplayPage( - category: Category, screenModel: MangaLibrarySettingsScreenModel, ) { HeadingItem(R.string.action_display_mode) + val displayMode by screenModel.libraryPreferences.libraryDisplayMode().collectAsState() listOf( R.string.action_display_grid to LibraryDisplayMode.CompactGrid, R.string.action_display_comfortable_grid to LibraryDisplayMode.ComfortableGrid, @@ -193,12 +191,12 @@ private fun ColumnScope.DisplayPage( ).map { (titleRes, mode) -> RadioItem( label = stringResource(titleRes), - selected = category.display == mode, - onClick = { screenModel.setDisplayMode(category, mode) }, + selected = displayMode == mode, + onClick = { screenModel.setDisplayMode(mode) }, ) } - if (category.display != LibraryDisplayMode.List) { + if (displayMode != LibraryDisplayMode.List) { Row( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index 89c6b78ef..ef12e6825 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -3,6 +3,7 @@ package eu.kanade.presentation.more.settings.screen import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Intent +import android.os.Build import android.provider.Settings import android.webkit.WebStorage import android.webkit.WebView @@ -73,6 +74,7 @@ import uy.kohesive.injekt.api.get import java.io.File object SettingsAdvancedScreen : SearchableSettings { + @ReadOnlyComposable @Composable @StringRes @@ -87,44 +89,65 @@ object SettingsAdvancedScreen : SearchableSettings { val basePreferences = remember { Injekt.get() } val networkPreferences = remember { Injekt.get() } - return listOf( - Preference.PreferenceItem.SwitchPreference( - pref = basePreferences.acraEnabled(), - title = stringResource(R.string.pref_enable_acra), - subtitle = stringResource(R.string.pref_acra_summary), - enabled = isPreviewBuildType || isReleaseBuildType, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_dump_crash_logs), - subtitle = stringResource(R.string.pref_dump_crash_logs_summary), - onClick = { - scope.launch { - CrashLogUtil(context).dumpLogs() - } - }, - ), - Preference.PreferenceItem.SwitchPreference( - pref = networkPreferences.verboseLogging(), - title = stringResource(R.string.pref_verbose_logging), - subtitle = stringResource(R.string.pref_verbose_logging_summary), - onValueChanged = { - context.toast(R.string.requires_app_restart) - true - }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_debug_info), - onClick = { navigator.push(DebugInfoScreen) }, - ), - getBackgroundActivityGroup(), - getDataGroup(), - getNetworkGroup(networkPreferences = networkPreferences), - getLibraryGroup(), - getExtensionsGroup(basePreferences = basePreferences), - // SY --> - getDataSaverGroup(), - // SY <-- - ) + return buildList { + addAll( + listOf( + Preference.PreferenceItem.SwitchPreference( + pref = basePreferences.acraEnabled(), + title = stringResource(R.string.pref_enable_acra), + subtitle = stringResource(R.string.pref_acra_summary), + enabled = isPreviewBuildType || isReleaseBuildType, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_dump_crash_logs), + subtitle = stringResource(R.string.pref_dump_crash_logs_summary), + onClick = { + scope.launch { + CrashLogUtil(context).dumpLogs() + } + }, + ), + Preference.PreferenceItem.SwitchPreference( + pref = networkPreferences.verboseLogging(), + title = stringResource(R.string.pref_verbose_logging), + subtitle = stringResource(R.string.pref_verbose_logging_summary), + onValueChanged = { + context.toast(R.string.requires_app_restart) + true + }, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_debug_info), + onClick = { navigator.push(DebugInfoScreen) }, + ), + ), + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + add( + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_manage_notifications), + onClick = { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + }, + ), + ) + } + addAll( + listOf( + getBackgroundActivityGroup(), + getDataGroup(), + getNetworkGroup(networkPreferences = networkPreferences), + getLibraryGroup(), + getExtensionsGroup(basePreferences = basePreferences), + // SY --> + getDataSaverGroup(), + // SY <-- + ), + ) + } } @Composable diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt index 2235daed1..c28ad702c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt @@ -4,14 +4,18 @@ import android.app.Activity import android.content.Context import android.os.Build import androidx.annotation.StringRes +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.core.app.ActivityCompat +import androidx.core.os.LocaleListCompat import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.TabletUiMode import eu.kanade.domain.ui.model.ThemeMode @@ -19,10 +23,14 @@ import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.util.collectAsState import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.home.HomeScreen +import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.merge +import org.xmlpull.v1.XmlPullParser +import tachiyomi.domain.library.service.LibraryPreferences import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.Date @@ -103,9 +111,61 @@ object SettingsAppearanceScreen : SearchableSettings { context: Context, uiPreferences: UiPreferences, ): Preference.PreferenceGroup { + val langs = remember { getLangs(context) } + var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") } + + LaunchedEffect(currentLanguage) { + val locale = if (currentLanguage.isEmpty()) { + LocaleListCompat.getEmptyLocaleList() + } else { + LocaleListCompat.forLanguageTags(currentLanguage) + } + AppCompatDelegate.setApplicationLocales(locale) + } + + val libraryPrefs = remember { Injekt.get() } + + LaunchedEffect(Unit) { + libraryPrefs.bottomNavStyle().changes() + .drop(1) + .collectLatest { value -> + HomeScreen.tabs = when (value) { + 0 -> HomeScreen.tabsNoHistory + 1 -> HomeScreen.tabsNoUpdates + else -> HomeScreen.tabsNoManga + } + (context as? Activity)?.let { + ActivityCompat.recreate(it) + } + } + } + return Preference.PreferenceGroup( title = stringResource(R.string.pref_category_display), preferenceItems = listOf( + Preference.PreferenceItem.ListPreference( + pref = libraryPrefs.bottomNavStyle(), + title = stringResource(R.string.pref_bottom_nav_style), + entries = mapOf( + 0 to stringResource(R.string.pref_bottom_nav_no_history), + 1 to stringResource(R.string.pref_bottom_nav_no_updates), + 2 to stringResource(R.string.pref_bottom_nav_no_manga), + ), + ), + Preference.PreferenceItem.SwitchPreference( + pref = libraryPrefs.isDefaultHomeTabLibraryManga(), + title = stringResource(R.string.pref_default_home_tab_library), + enabled = libraryPrefs.bottomNavStyle().get() != 2, + ), + Preference.PreferenceItem.BasicListPreference( + value = currentLanguage, + title = stringResource(R.string.pref_app_language), + entries = langs, + onValueChanged = { newValue -> + currentLanguage = newValue + true + }, + ), Preference.PreferenceItem.ListPreference( pref = uiPreferences.tabletUiMode(), title = stringResource(R.string.pref_tablet_ui_mode), @@ -146,6 +206,31 @@ object SettingsAppearanceScreen : SearchableSettings { ), ) } + + private fun getLangs(context: Context): Map { + val langs = mutableListOf>() + val parser = context.resources.getXml(R.xml.locales_config) + var eventType = parser.eventType + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG && parser.name == "locale") { + for (i in 0 until parser.attributeCount) { + if (parser.getAttributeName(i) == "name") { + val langTag = parser.getAttributeValue(i) + val displayName = LocaleHelper.getDisplayName(langTag) + if (displayName.isNotEmpty()) { + langs.add(Pair(langTag, displayName)) + } + } + } + } + eventType = parser.next() + } + + langs.sortBy { it.second } + langs.add(0, Pair("", context.getString(R.string.label_default))) + + return langs.toMap() + } } private val DateFormats = listOf( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsGeneralScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsGeneralScreen.kt deleted file mode 100644 index b80bafed5..000000000 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsGeneralScreen.kt +++ /dev/null @@ -1,149 +0,0 @@ -package eu.kanade.presentation.more.settings.screen - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.os.Build -import android.provider.Settings -import androidx.annotation.StringRes -import androidx.appcompat.app.AppCompatDelegate -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.core.app.ActivityCompat -import androidx.core.os.LocaleListCompat -import eu.kanade.presentation.more.settings.Preference -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.home.HomeScreen -import eu.kanade.tachiyomi.util.system.LocaleHelper -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.drop -import org.xmlpull.v1.XmlPullParser -import tachiyomi.domain.library.service.LibraryPreferences -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -object SettingsGeneralScreen : SearchableSettings { - - @Composable - @ReadOnlyComposable - @StringRes - override fun getTitleRes() = R.string.pref_category_general - - @Composable - override fun getPreferences(): List { - val libraryPrefs = remember { Injekt.get() } - val context = LocalContext.current - - LaunchedEffect(Unit) { - libraryPrefs.bottomNavStyle().changes() - .drop(1) - .collectLatest { value -> - HomeScreen.tabs = when (value) { - 0 -> HomeScreen.tabsNoHistory - 1 -> HomeScreen.tabsNoUpdates - else -> HomeScreen.tabsNoManga - } - (context as? Activity)?.let { - ActivityCompat.recreate(it) - } - } - } - - val langs = remember { getLangs(context) } - var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") } - - return buildList { - add( - Preference.PreferenceItem.ListPreference( - pref = libraryPrefs.bottomNavStyle(), - title = stringResource(R.string.pref_bottom_nav_style), - entries = mapOf( - 0 to stringResource(R.string.pref_bottom_nav_no_history), - 1 to stringResource(R.string.pref_bottom_nav_no_updates), - 2 to stringResource(R.string.pref_bottom_nav_no_manga), - ), - ), - ) - add( - Preference.PreferenceItem.SwitchPreference( - pref = libraryPrefs.isDefaultHomeTabLibraryManga(), - title = stringResource(R.string.pref_default_home_tab_library), - enabled = libraryPrefs.bottomNavStyle().get() != 2, - ), - ) - add( - Preference.PreferenceItem.SwitchPreference( - pref = libraryPrefs.newShowUpdatesCount(), - title = stringResource(R.string.pref_library_update_show_tab_badge), - ), - ) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - add( - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_manage_notifications), - onClick = { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) - }, - ), - ) - } - - add( - Preference.PreferenceItem.BasicListPreference( - value = currentLanguage, - title = stringResource(R.string.pref_app_language), - entries = langs, - onValueChanged = { newValue -> - currentLanguage = newValue - true - }, - ), - ) - - LaunchedEffect(currentLanguage) { - val locale = if (currentLanguage.isEmpty()) { - LocaleListCompat.getEmptyLocaleList() - } else { - LocaleListCompat.forLanguageTags(currentLanguage) - } - AppCompatDelegate.setApplicationLocales(locale) - } - } - } - - private fun getLangs(context: Context): Map { - val langs = mutableListOf>() - val parser = context.resources.getXml(R.xml.locales_config) - var eventType = parser.eventType - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG && parser.name == "locale") { - for (i in 0 until parser.attributeCount) { - if (parser.getAttributeName(i) == "name") { - val langTag = parser.getAttributeValue(i) - val displayName = LocaleHelper.getDisplayName(langTag) - if (displayName.isNotEmpty()) { - langs.add(Pair(langTag, displayName)) - } - } - } - } - eventType = parser.next() - } - - langs.sortBy { it.second } - langs.add(0, Pair("", context.getString(R.string.label_default))) - - return langs.toMap() - } -} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt index b6367bd7b..9de778e6e 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt @@ -365,7 +365,6 @@ object SettingsLibraryScreen : SearchableSettings { Preference.PreferenceItem.InfoPreference( title = stringResource(R.string.pref_update_release_grace_period_info), ).takeIf { ENTRY_OUTSIDE_RELEASE_PERIOD in libraryUpdateMangaRestriction && isDevFlavor }, - Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_update_anime_release_grace_period), subtitle = listOf( @@ -377,6 +376,11 @@ object SettingsLibraryScreen : SearchableSettings { Preference.PreferenceItem.InfoPreference( title = stringResource(R.string.pref_update_release_grace_period_info), ).takeIf { ENTRY_OUTSIDE_RELEASE_PERIOD in libraryUpdateAnimeRestriction && isDevFlavor }, + + Preference.PreferenceItem.SwitchPreference( + pref = libraryPreferences.newShowUpdatesCount(), + title = stringResource(R.string.pref_library_update_show_tab_badge), + ), ), ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt index 76e5f2c41..484fa293d 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt @@ -21,7 +21,6 @@ import androidx.compose.material.icons.outlined.Search import androidx.compose.material.icons.outlined.Security import androidx.compose.material.icons.outlined.SettingsBackupRestore import androidx.compose.material.icons.outlined.Sync -import androidx.compose.material.icons.outlined.Tune import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor @@ -187,12 +186,6 @@ object SettingsMainScreen : Screen() { ) private val items = listOf( - Item( - titleRes = R.string.pref_category_general, - subtitleRes = R.string.pref_general_summary, - icon = Icons.Outlined.Tune, - screen = SettingsGeneralScreen, - ), Item( titleRes = R.string.pref_category_appearance, subtitleRes = R.string.pref_appearance_summary, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt index 2ae8471e6..21dedc547 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt @@ -283,7 +283,6 @@ private fun getLocalizedBreadcrumb(path: String, node: String?): String { } private val settingScreens = listOf( - SettingsGeneralScreen, SettingsAppearanceScreen, SettingsLibraryScreen, SettingsReaderScreen, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt index c560dff7f..d26c080de 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt @@ -32,7 +32,6 @@ object SettingsSecurityScreen : SearchableSettings { val authSupported = remember { context.isAuthenticationSupported() } val useAuthPref = securityPreferences.useAuthenticator() - val useAuth by useAuthPref.collectAsState() return listOf( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt index aa15792dc..72b1528a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt @@ -58,6 +58,7 @@ import tachiyomi.domain.items.episode.model.Episode import tachiyomi.domain.library.anime.LibraryAnime import tachiyomi.domain.library.anime.model.AnimeLibrarySort import tachiyomi.domain.library.anime.model.sort +import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.source.anime.service.AnimeSourceManager import tachiyomi.domain.track.anime.interactor.GetTracksPerAnime @@ -524,6 +525,10 @@ class AnimeLibraryScreenModel( } } + fun getDisplayMode(): PreferenceMutableState { + return libraryPreferences.libraryDisplayMode().asState(coroutineScope) + } + fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState { return (if (isLandscape) libraryPreferences.animeLandscapeColumns() else libraryPreferences.animePortraitColumns()).asState(coroutineScope) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibrarySettingsScreenModel.kt index a6d4b37a9..a40060979 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibrarySettingsScreenModel.kt @@ -8,8 +8,7 @@ import eu.kanade.tachiyomi.util.preference.toggle import tachiyomi.core.preference.Preference import tachiyomi.core.preference.getAndSet import tachiyomi.core.util.lang.launchIO -import tachiyomi.domain.category.anime.interactor.GetAnimeCategories -import tachiyomi.domain.category.anime.interactor.SetDisplayModeForAnimeCategory +import tachiyomi.domain.category.anime.interactor.SetAnimeDisplayMode import tachiyomi.domain.category.anime.interactor.SetSortModeForAnimeCategory import tachiyomi.domain.category.model.Category import tachiyomi.domain.entries.TriStateFilter @@ -22,8 +21,7 @@ import uy.kohesive.injekt.api.get class AnimeLibrarySettingsScreenModel( val preferences: BasePreferences = Injekt.get(), val libraryPreferences: LibraryPreferences = Injekt.get(), - private val getCategories: GetAnimeCategories = Injekt.get(), - private val setDisplayModeForCategory: SetDisplayModeForAnimeCategory = Injekt.get(), + private val setAnimeDisplayMode: SetAnimeDisplayMode = Injekt.get(), private val setSortModeForCategory: SetSortModeForAnimeCategory = Injekt.get(), private val trackManager: TrackManager = Injekt.get(), ) : ScreenModel { @@ -45,13 +43,11 @@ class AnimeLibrarySettingsScreenModel( toggleFilter { libraryPreferences.filterTrackedAnime(id) } } - fun setDisplayMode(category: Category, mode: LibraryDisplayMode) { - coroutineScope.launchIO { - setDisplayModeForCategory.await(category, mode) - } + fun setDisplayMode(mode: LibraryDisplayMode) { + setAnimeDisplayMode.await(mode) } - fun setSort(category: Category, mode: AnimeLibrarySort.Type, direction: AnimeLibrarySort.Direction) { + fun setSort(category: Category?, mode: AnimeLibrarySort.Type, direction: AnimeLibrarySort.Direction) { coroutineScope.launchIO { setSortModeForCategory.await(category, mode, direction) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt index e784508d0..7df6b1167 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryTab.kt @@ -54,7 +54,6 @@ import tachiyomi.domain.category.model.Category import tachiyomi.domain.entries.anime.model.Anime import tachiyomi.domain.items.episode.model.Episode import tachiyomi.domain.library.anime.LibraryAnime -import tachiyomi.domain.library.model.display import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.screens.EmptyScreen @@ -212,7 +211,7 @@ object AnimeLibraryTab : Tab() { navigator.push(GlobalAnimeSearchScreen(screenModel.state.value.searchQuery ?: "")) }, getNumberOfAnimeForCategory = { state.getAnimeCountForCategory(it) }, - getDisplayModeForPage = { state.categories[it].display }, + getDisplayMode = { screenModel.getDisplayMode() }, getColumnsForOrientation = { screenModel.getColumnsPreferenceForCurrentOrientation(it) }, ) { state.getAnimelibItemsByPage(it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt index b0d3f57a4..ee8e2ae00 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt @@ -58,6 +58,7 @@ import tachiyomi.domain.items.chapter.model.Chapter import tachiyomi.domain.library.manga.LibraryManga import tachiyomi.domain.library.manga.model.MangaLibrarySort import tachiyomi.domain.library.manga.model.sort +import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.source.manga.service.MangaSourceManager import tachiyomi.domain.track.manga.interactor.GetTracksPerManga @@ -518,6 +519,10 @@ class MangaLibraryScreenModel( } } + fun getDisplayMode(): PreferenceMutableState { + return libraryPreferences.libraryDisplayMode().asState(coroutineScope) + } + fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState { return (if (isLandscape) libraryPreferences.mangaLandscapeColumns() else libraryPreferences.mangaPortraitColumns()).asState(coroutineScope) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibrarySettingsScreenModel.kt index cc5ec5a87..e9b364c8f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibrarySettingsScreenModel.kt @@ -8,8 +8,7 @@ import eu.kanade.tachiyomi.util.preference.toggle import tachiyomi.core.preference.Preference import tachiyomi.core.preference.getAndSet import tachiyomi.core.util.lang.launchIO -import tachiyomi.domain.category.manga.interactor.GetMangaCategories -import tachiyomi.domain.category.manga.interactor.SetDisplayModeForMangaCategory +import tachiyomi.domain.category.manga.interactor.SetMangaDisplayMode import tachiyomi.domain.category.manga.interactor.SetSortModeForMangaCategory import tachiyomi.domain.category.model.Category import tachiyomi.domain.entries.TriStateFilter @@ -22,8 +21,7 @@ import uy.kohesive.injekt.api.get class MangaLibrarySettingsScreenModel( val preferences: BasePreferences = Injekt.get(), val libraryPreferences: LibraryPreferences = Injekt.get(), - private val getCategories: GetMangaCategories = Injekt.get(), - private val setDisplayModeForCategory: SetDisplayModeForMangaCategory = Injekt.get(), + private val setMangaDisplayMode: SetMangaDisplayMode = Injekt.get(), private val setSortModeForCategory: SetSortModeForMangaCategory = Injekt.get(), private val trackManager: TrackManager = Injekt.get(), ) : ScreenModel { @@ -45,13 +43,11 @@ class MangaLibrarySettingsScreenModel( toggleFilter { libraryPreferences.filterTrackedManga(id) } } - fun setDisplayMode(category: Category, mode: LibraryDisplayMode) { - coroutineScope.launchIO { - setDisplayModeForCategory.await(category, mode) - } + fun setDisplayMode(mode: LibraryDisplayMode) { + setMangaDisplayMode.await(mode) } - fun setSort(category: Category, mode: MangaLibrarySort.Type, direction: MangaLibrarySort.Direction) { + fun setSort(category: Category?, mode: MangaLibrarySort.Type, direction: MangaLibrarySort.Direction) { coroutineScope.launchIO { setSortModeForCategory.await(category, mode, direction) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt index 203ccc13c..d3573bdeb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryTab.kt @@ -53,7 +53,6 @@ import tachiyomi.core.util.lang.launchIO import tachiyomi.domain.category.model.Category import tachiyomi.domain.entries.manga.model.Manga import tachiyomi.domain.library.manga.LibraryManga -import tachiyomi.domain.library.model.display import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.screens.EmptyScreen @@ -213,7 +212,7 @@ object MangaLibraryTab : Tab() { navigator.push(GlobalMangaSearchScreen(screenModel.state.value.searchQuery ?: "")) }, getNumberOfMangaForCategory = { state.getMangaCountForCategory(it) }, - getDisplayModeForPage = { state.categories[it].display }, + getDisplayMode = { screenModel.getDisplayMode() }, getColumnsForOrientation = { screenModel.getColumnsPreferenceForCurrentOrientation(it) }, ) { state.getLibraryItemsByPage(it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index b9e8ddd95..950fdc0be 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -15,7 +15,6 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.text.TextUtils -import android.view.Gravity import android.view.KeyEvent import android.view.Menu import android.view.MenuItem @@ -24,7 +23,6 @@ import android.view.View.LAYER_TYPE_HARDWARE import android.view.WindowManager import android.view.animation.Animation import android.view.animation.AnimationUtils -import android.widget.FrameLayout import android.widget.Toast import androidx.activity.viewModels import androidx.compose.runtime.collectAsState @@ -36,7 +34,6 @@ import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.isVisible -import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.google.android.material.internal.ToolbarUtils @@ -70,7 +67,6 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.util.preference.toggle import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale -import eu.kanade.tachiyomi.util.system.createReaderThemeContext import eu.kanade.tachiyomi.util.system.hasDisplayCutout import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.toShareIntent @@ -662,12 +658,7 @@ class ReaderActivity : BaseActivity() { supportActionBar?.title = manga.title - val loadingIndicatorContext = createReaderThemeContext() - loadingIndicator = ReaderProgressIndicator(loadingIndicatorContext).apply { - updateLayoutParams { - gravity = Gravity.CENTER - } - } + loadingIndicator = ReaderProgressIndicator(this) binding.readerContainer.addView(loadingIndicator) startPostponedEnterTransition() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt index 75f710686..74aaf7097 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt @@ -2,13 +2,20 @@ package eu.kanade.tachiyomi.ui.reader.viewer import android.content.Context import android.util.AttributeSet +import android.view.Gravity import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -import android.view.animation.Animation -import android.view.animation.LinearInterpolator -import android.view.animation.RotateAnimation import android.widget.FrameLayout import androidx.annotation.IntRange +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.AbstractComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.core.view.isVisible import com.google.android.material.progressindicator.CircularProgressIndicator +import eu.kanade.presentation.theme.TachiyomiTheme +import tachiyomi.presentation.core.components.CombinedCircularProgressIndicator /** * A wrapper for [CircularProgressIndicator] that always rotates. @@ -19,76 +26,31 @@ class ReaderProgressIndicator @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, -) : FrameLayout(context, attrs, defStyleAttr) { - - private val indicator: CircularProgressIndicator - - private val rotateAnimation by lazy { - RotateAnimation( - 0F, - 360F, - Animation.RELATIVE_TO_SELF, - 0.5F, - Animation.RELATIVE_TO_SELF, - 0.5F, - ).apply { - interpolator = LinearInterpolator() - repeatCount = Animation.INFINITE - duration = 4000 - } - } +) : AbstractComposeView(context, attrs, defStyleAttr) { init { - layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT) - indicator = CircularProgressIndicator(context) - indicator.max = 100 - indicator.isIndeterminate = true - addView(indicator) + layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.CENTER) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindowOrReleasedFromPool) } - override fun onAttachedToWindow() { - super.onAttachedToWindow() - updateRotateAnimation() - } + private var progress by mutableFloatStateOf(0f) - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - updateRotateAnimation() + @Composable + override fun Content() { + TachiyomiTheme { + CombinedCircularProgressIndicator(progress = progress) + } } fun show() { - indicator.show() - updateRotateAnimation() + isVisible = true } fun hide() { - indicator.hide() - updateRotateAnimation() + isVisible = false } - /** - * Sets the current indicator progress to the specified value. - * - * @param progress Indicator will be set indeterminate if this value is 0 - */ - fun setProgress(@IntRange(from = 0, to = 100) progress: Int, animated: Boolean = true) { - if (progress > 0) { - indicator.setProgressCompat(progress, animated) - } else if (!indicator.isIndeterminate) { - indicator.hide() - indicator.isIndeterminate = true - indicator.show() - } - updateRotateAnimation() - } - - private fun updateRotateAnimation() { - if (isAttachedToWindow && indicator.isShown && !indicator.isIndeterminate) { - if (animation == null) { - startAnimation(rotateAnimation) - } - } else { - clearAnimation() - } + fun setProgress(@IntRange(from = 0, to = 100) progress: Int) { + this.progress = progress / 100f } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index 76a920c22..e1fd80ff5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -2,10 +2,8 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager import android.annotation.SuppressLint import android.content.Context -import android.view.Gravity import android.view.LayoutInflater import androidx.core.view.isVisible -import androidx.core.view.updateLayoutParams import eu.kanade.tachiyomi.databinding.ReaderErrorBinding import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.InsertPage @@ -46,11 +44,7 @@ class PagerPageHolder( /** * Loading progress bar to indicate the current progress. */ - private val progressIndicator: ReaderProgressIndicator = ReaderProgressIndicator(readerThemedContext).apply { - updateLayoutParams { - gravity = Gravity.CENTER - } - } + private val progressIndicator: ReaderProgressIndicator = ReaderProgressIndicator(readerThemedContext) /** * Error layout to show when the image fails to load. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index d29c2497b..749a48e33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon import android.content.res.Resources -import android.view.Gravity import android.view.LayoutInflater import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT @@ -119,7 +118,7 @@ class WebtoonPageHolder( removeErrorLayout() frame.recycle() - progressIndicator.setProgress(0, animated = false) + progressIndicator.setProgress(0) } /** @@ -288,7 +287,6 @@ class WebtoonPageHolder( val progress = ReaderProgressIndicator(context).apply { updateLayoutParams { - gravity = Gravity.CENTER_HORIZONTAL updateMargins(top = parentHeight / 4) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt index e53427a46..8a18219ad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt @@ -13,8 +13,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.more.settings.screen.AboutScreen +import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen -import eu.kanade.presentation.more.settings.screen.SettingsGeneralScreen import eu.kanade.presentation.more.settings.screen.SettingsMainScreen import eu.kanade.presentation.util.DefaultNavigatorScreenTransition import eu.kanade.presentation.util.LocalBackPress @@ -59,7 +59,7 @@ class SettingsScreen private constructor( } else if (toAbout) { AboutScreen } else { - SettingsGeneralScreen + SettingsAppearanceScreen }, ) { val insets = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal) diff --git a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/CreateAnimeCategoryWithName.kt b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/CreateAnimeCategoryWithName.kt index d705b5a74..090a2b24e 100644 --- a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/CreateAnimeCategoryWithName.kt +++ b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/CreateAnimeCategoryWithName.kt @@ -15,9 +15,7 @@ class CreateAnimeCategoryWithName( private val initialFlags: Long get() { val sort = preferences.libraryAnimeSortingMode().get() - return preferences.libraryDisplayMode().get().flag or - sort.type.flag or - sort.direction.flag + return sort.type.flag or sort.direction.flag } suspend fun await(name: String): Result = withNonCancellableContext { diff --git a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/ResetAnimeCategoryFlags.kt b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/ResetAnimeCategoryFlags.kt index cbaa34b63..210117827 100644 --- a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/ResetAnimeCategoryFlags.kt +++ b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/ResetAnimeCategoryFlags.kt @@ -10,8 +10,7 @@ class ResetAnimeCategoryFlags( ) { suspend fun await() { - val display = preferences.libraryDisplayMode().get() val sort = preferences.libraryAnimeSortingMode().get() - categoryRepository.updateAllAnimeCategoryFlags(display + sort.type + sort.direction) + categoryRepository.updateAllAnimeCategoryFlags(sort.type + sort.direction) } } diff --git a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetAnimeDisplayMode.kt b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetAnimeDisplayMode.kt new file mode 100644 index 000000000..1e041fc03 --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetAnimeDisplayMode.kt @@ -0,0 +1,13 @@ +package tachiyomi.domain.category.anime.interactor + +import tachiyomi.domain.library.model.LibraryDisplayMode +import tachiyomi.domain.library.service.LibraryPreferences + +class SetAnimeDisplayMode( + private val preferences: LibraryPreferences, +) { + + fun await(display: LibraryDisplayMode) { + preferences.libraryDisplayMode().set(display) + } +} diff --git a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetDisplayModeForAnimeCategory.kt b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetDisplayModeForAnimeCategory.kt deleted file mode 100644 index 93221de01..000000000 --- a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetDisplayModeForAnimeCategory.kt +++ /dev/null @@ -1,34 +0,0 @@ -package tachiyomi.domain.category.anime.interactor - -import tachiyomi.domain.category.anime.repository.AnimeCategoryRepository -import tachiyomi.domain.category.model.Category -import tachiyomi.domain.category.model.CategoryUpdate -import tachiyomi.domain.library.model.LibraryDisplayMode -import tachiyomi.domain.library.model.plus -import tachiyomi.domain.library.service.LibraryPreferences - -class SetDisplayModeForAnimeCategory( - private val preferences: LibraryPreferences, - private val categoryRepository: AnimeCategoryRepository, -) { - - suspend fun await(categoryId: Long, display: LibraryDisplayMode) { - val category = categoryRepository.getAnimeCategory(categoryId) ?: return - val flags = category.flags + display - if (preferences.categorizedDisplaySettings().get()) { - categoryRepository.updatePartialAnimeCategory( - CategoryUpdate( - id = category.id, - flags = flags, - ), - ) - } else { - preferences.libraryDisplayMode().set(display) - categoryRepository.updateAllAnimeCategoryFlags(flags) - } - } - - suspend fun await(category: Category, display: LibraryDisplayMode) { - await(category.id, display) - } -} diff --git a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt index 837e13bea..c7f6a7672 100644 --- a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt @@ -12,10 +12,10 @@ class SetSortModeForAnimeCategory( private val categoryRepository: AnimeCategoryRepository, ) { - suspend fun await(categoryId: Long, type: AnimeLibrarySort.Type, direction: AnimeLibrarySort.Direction) { - val category = categoryRepository.getAnimeCategory(categoryId) ?: return - val flags = category.flags + type + direction - if (preferences.categorizedDisplaySettings().get()) { + suspend fun await(categoryId: Long?, type: AnimeLibrarySort.Type, direction: AnimeLibrarySort.Direction) { + val category = categoryId?.let { categoryRepository.getAnimeCategory(it) } + val flags = (category?.flags ?: 0) + type + direction + if (category != null && preferences.categorizedDisplaySettings().get()) { categoryRepository.updatePartialAnimeCategory( CategoryUpdate( id = category.id, @@ -28,7 +28,7 @@ class SetSortModeForAnimeCategory( } } - suspend fun await(category: Category, type: AnimeLibrarySort.Type, direction: AnimeLibrarySort.Direction) { - await(category.id, type, direction) + suspend fun await(category: Category?, type: AnimeLibrarySort.Type, direction: AnimeLibrarySort.Direction) { + await(category?.id, type, direction) } } diff --git a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/CreateMangaCategoryWithName.kt b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/CreateMangaCategoryWithName.kt index c3aedebbc..6b99b49d3 100644 --- a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/CreateMangaCategoryWithName.kt +++ b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/CreateMangaCategoryWithName.kt @@ -15,9 +15,7 @@ class CreateMangaCategoryWithName( private val initialFlags: Long get() { val sort = preferences.libraryMangaSortingMode().get() - return preferences.libraryDisplayMode().get().flag or - sort.type.flag or - sort.direction.flag + return sort.type.flag or sort.direction.flag } suspend fun await(name: String): Result = withNonCancellableContext { diff --git a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/ResetMangaCategoryFlags.kt b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/ResetMangaCategoryFlags.kt index a464fbad8..33152d1ee 100644 --- a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/ResetMangaCategoryFlags.kt +++ b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/ResetMangaCategoryFlags.kt @@ -10,8 +10,7 @@ class ResetMangaCategoryFlags( ) { suspend fun await() { - val display = preferences.libraryDisplayMode().get() val sort = preferences.libraryMangaSortingMode().get() - categoryRepository.updateAllMangaCategoryFlags(display + sort.type + sort.direction) + categoryRepository.updateAllMangaCategoryFlags(sort.type + sort.direction) } } diff --git a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetDisplayModeForMangaCategory.kt b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetDisplayModeForMangaCategory.kt deleted file mode 100644 index 56aab6fba..000000000 --- a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetDisplayModeForMangaCategory.kt +++ /dev/null @@ -1,34 +0,0 @@ -package tachiyomi.domain.category.manga.interactor - -import tachiyomi.domain.category.manga.repository.MangaCategoryRepository -import tachiyomi.domain.category.model.Category -import tachiyomi.domain.category.model.CategoryUpdate -import tachiyomi.domain.library.model.LibraryDisplayMode -import tachiyomi.domain.library.model.plus -import tachiyomi.domain.library.service.LibraryPreferences - -class SetDisplayModeForMangaCategory( - private val preferences: LibraryPreferences, - private val categoryRepository: MangaCategoryRepository, -) { - - suspend fun await(categoryId: Long, display: LibraryDisplayMode) { - val category = categoryRepository.getMangaCategory(categoryId) ?: return - val flags = category.flags + display - if (preferences.categorizedDisplaySettings().get()) { - categoryRepository.updatePartialMangaCategory( - CategoryUpdate( - id = category.id, - flags = flags, - ), - ) - } else { - preferences.libraryDisplayMode().set(display) - categoryRepository.updateAllMangaCategoryFlags(flags) - } - } - - suspend fun await(category: Category, display: LibraryDisplayMode) { - await(category.id, display) - } -} diff --git a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetMangaDisplayMode.kt b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetMangaDisplayMode.kt new file mode 100644 index 000000000..262332839 --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetMangaDisplayMode.kt @@ -0,0 +1,13 @@ +package tachiyomi.domain.category.manga.interactor + +import tachiyomi.domain.library.model.LibraryDisplayMode +import tachiyomi.domain.library.service.LibraryPreferences + +class SetMangaDisplayMode( + private val preferences: LibraryPreferences, +) { + + fun await(display: LibraryDisplayMode) { + preferences.libraryDisplayMode().set(display) + } +} diff --git a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt index 5c3f384e1..90446dde4 100644 --- a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt @@ -12,10 +12,10 @@ class SetSortModeForMangaCategory( private val categoryRepository: MangaCategoryRepository, ) { - suspend fun await(categoryId: Long, type: MangaLibrarySort.Type, direction: MangaLibrarySort.Direction) { - val category = categoryRepository.getMangaCategory(categoryId) ?: return - val flags = category.flags + type + direction - if (preferences.categorizedDisplaySettings().get()) { + suspend fun await(categoryId: Long?, type: MangaLibrarySort.Type, direction: MangaLibrarySort.Direction) { + val category = categoryId?.let { categoryRepository.getMangaCategory(it) } + val flags = (category?.flags ?: 0) + type + direction + if (category != null && preferences.categorizedDisplaySettings().get()) { categoryRepository.updatePartialMangaCategory( CategoryUpdate( id = category.id, @@ -28,7 +28,7 @@ class SetSortModeForMangaCategory( } } - suspend fun await(category: Category, type: MangaLibrarySort.Type, direction: MangaLibrarySort.Direction) { - await(category.id, type, direction) + suspend fun await(category: Category?, type: MangaLibrarySort.Type, direction: MangaLibrarySort.Direction) { + await(category?.id, type, direction) } } diff --git a/domain/src/main/java/tachiyomi/domain/library/model/LibraryDisplayMode.kt b/domain/src/main/java/tachiyomi/domain/library/model/LibraryDisplayMode.kt index f21eb1900..b443ec6c4 100644 --- a/domain/src/main/java/tachiyomi/domain/library/model/LibraryDisplayMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/model/LibraryDisplayMode.kt @@ -1,17 +1,11 @@ package tachiyomi.domain.library.model -import tachiyomi.domain.category.model.Category +sealed class LibraryDisplayMode { -sealed class LibraryDisplayMode( - override val flag: Long, -) : FlagWithMask { - - override val mask: Long = 0b00000011L - - object CompactGrid : LibraryDisplayMode(0b00000000) - object ComfortableGrid : LibraryDisplayMode(0b00000001) - object List : LibraryDisplayMode(0b00000010) - object CoverOnlyGrid : LibraryDisplayMode(0b00000011) + object CompactGrid : LibraryDisplayMode() + object ComfortableGrid : LibraryDisplayMode() + object List : LibraryDisplayMode() + object CoverOnlyGrid : LibraryDisplayMode() object Serializer { fun deserialize(serialized: String): LibraryDisplayMode { @@ -27,13 +21,6 @@ sealed class LibraryDisplayMode( val values by lazy { setOf(CompactGrid, ComfortableGrid, List, CoverOnlyGrid) } val default = CompactGrid - fun valueOf(flag: Long?): LibraryDisplayMode { - if (flag == null) return default - return values - .find { mode -> mode.flag == flag and mode.mask } - ?: default - } - fun deserialize(serialized: String): LibraryDisplayMode { return when (serialized) { "COMFORTABLE_GRID" -> ComfortableGrid @@ -54,6 +41,3 @@ sealed class LibraryDisplayMode( } } } - -val Category?.display: LibraryDisplayMode - get() = LibraryDisplayMode.valueOf(this?.flags) diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 0aac10d03..97016c417 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -280,7 +280,7 @@ Default category Always ask - Per-category settings for sort and display + Per-category settings for sort %d category %d categories diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt new file mode 100644 index 000000000..dafe3237d --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt @@ -0,0 +1,110 @@ +package tachiyomi.presentation.core.components + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ProgressIndicatorDefaults +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.tooling.preview.Preview + +/** + * A combined [CircularProgressIndicator] that always rotates. + * + * By always rotating we give the feedback to the user that the application isn't 'stuck'. + */ +@Composable +fun CombinedCircularProgressIndicator( + progress: Float, +) { + val animatedProgress by animateFloatAsState( + targetValue = progress, + animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, + label = "progress", + ) + AnimatedContent( + targetState = progress == 0f, + transitionSpec = { fadeIn() togetherWith fadeOut() }, + label = "progressState", + ) { indeterminate -> + if (indeterminate) { + // Indeterminate + CircularProgressIndicator() + } else { + // Determinate + val infiniteTransition = rememberInfiniteTransition(label = "infiniteRotation") + val rotation by infiniteTransition.animateFloat( + initialValue = 0f, + targetValue = 360f, + animationSpec = infiniteRepeatable( + animation = tween(2000, easing = LinearEasing), + repeatMode = RepeatMode.Restart, + ), + label = "rotation", + ) + CircularProgressIndicator( + progress = animatedProgress, + modifier = Modifier.rotate(rotation), + ) + } + } +} + +@Preview +@Composable +private fun CombinedCircularProgressIndicatorPreview() { + var progress by remember { mutableFloatStateOf(0f) } + MaterialTheme { + Scaffold( + bottomBar = { + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { + progress = when (progress) { + 0f -> 0.15f + 0.15f -> 0.25f + 0.25f -> 0.5f + 0.5f -> 0.75f + 0.75f -> 0.95f + else -> 0f + } + }, + ) { + Text("change") + } + }, + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxSize() + .padding(it), + ) { + CombinedCircularProgressIndicator(progress = progress) + } + } + } +}