Last commit merged: 34b9c82cd0
This commit is contained in:
LuftVerbot 2023-10-27 20:27:23 +02:00
parent 564a959bab
commit f51b36a759
38 changed files with 383 additions and 442 deletions

View file

@ -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()) }

View file

@ -43,7 +43,7 @@ fun AnimeLibraryContent(
onRefresh: (Category?) -> Boolean,
onGlobalSearchClicked: () -> Unit,
getNumberOfAnimeForCategory: (Category) -> Int?,
getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode,
getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>,
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getAnimeLibraryForPage: (Int) -> List<AnimeLibraryItem>,
) {
@ -103,7 +103,7 @@ fun AnimeLibraryContent(
selectedAnime = selection,
searchQuery = searchQuery,
onGlobalSearchClicked = onGlobalSearchClicked,
getDisplayModeForPage = getDisplayModeForPage,
getDisplayMode = getDisplayMode,
getColumnsForOrientation = getColumnsForOrientation,
getLibraryForPage = getAnimeLibraryForPage,
onClickAnime = onClickAnime,

View file

@ -26,7 +26,7 @@ fun AnimeLibraryPager(
selectedAnime: List<LibraryAnime>,
searchQuery: String?,
onGlobalSearchClicked: () -> Unit,
getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode,
getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>,
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getLibraryForPage: (Int) -> List<AnimeLibraryItem>,
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

View file

@ -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()

View file

@ -43,7 +43,7 @@ fun MangaLibraryContent(
onRefresh: (Category?) -> Boolean,
onGlobalSearchClicked: () -> Unit,
getNumberOfMangaForCategory: (Category) -> Int?,
getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode,
getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>,
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getLibraryForPage: (Int) -> List<MangaLibraryItem>,
) {
@ -103,7 +103,7 @@ fun MangaLibraryContent(
selectedManga = selection,
searchQuery = searchQuery,
onGlobalSearchClicked = onGlobalSearchClicked,
getDisplayModeForPage = getDisplayModeForPage,
getDisplayMode = getDisplayMode,
getColumnsForOrientation = getColumnsForOrientation,
getLibraryForPage = getLibraryForPage,
onClickManga = onClickManga,

View file

@ -35,7 +35,7 @@ fun MangaLibraryPager(
selectedManga: List<LibraryManga>,
searchQuery: String?,
onGlobalSearchClicked: () -> Unit,
getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode,
getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>,
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getLibraryForPage: (Int) -> List<MangaLibraryItem>,
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

View file

@ -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()

View file

@ -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,7 +89,9 @@ object SettingsAdvancedScreen : SearchableSettings {
val basePreferences = remember { Injekt.get<BasePreferences>() }
val networkPreferences = remember { Injekt.get<NetworkPreferences>() }
return listOf(
return buildList {
addAll(
listOf(
Preference.PreferenceItem.SwitchPreference(
pref = basePreferences.acraEnabled(),
title = stringResource(R.string.pref_enable_acra),
@ -116,6 +120,23 @@ object SettingsAdvancedScreen : SearchableSettings {
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),
@ -124,8 +145,10 @@ object SettingsAdvancedScreen : SearchableSettings {
// SY -->
getDataSaverGroup(),
// SY <--
),
)
}
}
@Composable
private fun getBackgroundActivityGroup(): Preference.PreferenceGroup {

View file

@ -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<LibraryPreferences>() }
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<String, String> {
val langs = mutableListOf<Pair<String, String>>()
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(

View file

@ -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<Preference> {
val libraryPrefs = remember { Injekt.get<LibraryPreferences>() }
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<String, String> {
val langs = mutableListOf<Pair<String, String>>()
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()
}
}

View file

@ -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),
),
),
)
}

View file

@ -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,

View file

@ -283,7 +283,6 @@ private fun getLocalizedBreadcrumb(path: String, node: String?): String {
}
private val settingScreens = listOf(
SettingsGeneralScreen,
SettingsAppearanceScreen,
SettingsLibraryScreen,
SettingsReaderScreen,

View file

@ -32,7 +32,6 @@ object SettingsSecurityScreen : SearchableSettings {
val authSupported = remember { context.isAuthenticationSupported() }
val useAuthPref = securityPreferences.useAuthenticator()
val useAuth by useAuthPref.collectAsState()
return listOf(

View file

@ -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<LibraryDisplayMode> {
return libraryPreferences.libraryDisplayMode().asState(coroutineScope)
}
fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState<Int> {
return (if (isLandscape) libraryPreferences.animeLandscapeColumns() else libraryPreferences.animePortraitColumns()).asState(coroutineScope)
}

View file

@ -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)
}

View file

@ -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) }
}

View file

@ -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<LibraryDisplayMode> {
return libraryPreferences.libraryDisplayMode().asState(coroutineScope)
}
fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState<Int> {
return (if (isLandscape) libraryPreferences.mangaLandscapeColumns() else libraryPreferences.mangaPortraitColumns()).asState(coroutineScope)
}

View file

@ -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)
}

View file

@ -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) }
}

View file

@ -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<FrameLayout.LayoutParams> {
gravity = Gravity.CENTER
}
}
loadingIndicator = ReaderProgressIndicator(this)
binding.readerContainer.addView(loadingIndicator)
startPostponedEnterTransition()

View file

@ -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
}
}

View file

@ -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<LayoutParams> {
gravity = Gravity.CENTER
}
}
private val progressIndicator: ReaderProgressIndicator = ReaderProgressIndicator(readerThemedContext)
/**
* Error layout to show when the image fails to load.

View file

@ -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<FrameLayout.LayoutParams> {
gravity = Gravity.CENTER_HORIZONTAL
updateMargins(top = parentHeight / 4)
}
}

View file

@ -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)

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)

View file

@ -280,7 +280,7 @@
<string name="default_category">Default category</string>
<string name="default_category_summary">Always ask</string>
<string name="categorized_display_settings">Per-category settings for sort and display</string>
<string name="categorized_display_settings">Per-category settings for sort</string>
<plurals name="num_categories">
<item quantity="one">%d category</item>
<item quantity="other">%d categories</item>

View file

@ -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)
}
}
}
}