mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-21 12:17:12 +03:00
parent
564a959bab
commit
f51b36a759
38 changed files with 383 additions and 442 deletions
|
@ -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()) }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<BasePreferences>() }
|
||||
val networkPreferences = remember { Injekt.get<NetworkPreferences>() }
|
||||
|
||||
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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -283,7 +283,6 @@ private fun getLocalizedBreadcrumb(path: String, node: String?): String {
|
|||
}
|
||||
|
||||
private val settingScreens = listOf(
|
||||
SettingsGeneralScreen,
|
||||
SettingsAppearanceScreen,
|
||||
SettingsLibraryScreen,
|
||||
SettingsReaderScreen,
|
||||
|
|
|
@ -32,7 +32,6 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||
val authSupported = remember { context.isAuthenticationSupported() }
|
||||
|
||||
val useAuthPref = securityPreferences.useAuthenticator()
|
||||
|
||||
val useAuth by useAuthPref.collectAsState()
|
||||
|
||||
return listOf(
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue