From cbcec8c4d9d6f08ecb6ab50eff9aa51d4a3728a0 Mon Sep 17 00:00:00 2001 From: zaghdaneh <46049558+zaghdaneh@users.noreply.github.com> Date: Sat, 15 Jul 2023 04:49:14 +0200 Subject: [PATCH 01/15] Add filters to Global search (#9691) * add pinned and available filter chips to global search * split filter predicate into seperate function * change the global search available filter to has Results * reordering of imports --- .../presentation/browse/GlobalSearchScreen.kt | 97 +++++++++++++++++-- .../source/globalsearch/GlobalSearchScreen.kt | 3 + .../globalsearch/GlobalSearchScreenModel.kt | 29 ++++++ i18n/src/main/res/values/strings.xml | 1 + 4 files changed, 120 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 790053063..886f9960a 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -1,8 +1,22 @@ package eu.kanade.presentation.browse +import androidx.compose.foundation.background +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.DoneAll +import androidx.compose.material.icons.outlined.FilterList +import androidx.compose.material.icons.outlined.PushPin +import androidx.compose.material3.FilterChip +import androidx.compose.material3.FilterChipDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -16,19 +30,23 @@ import eu.kanade.presentation.browse.components.GlobalSearchResultItem import eu.kanade.presentation.browse.components.GlobalSearchToolbar import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.CatalogueSource +import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchFilter import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchState import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult import eu.kanade.tachiyomi.util.system.LocaleHelper import tachiyomi.domain.manga.model.Manga +import tachiyomi.presentation.core.components.material.Divider import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding @Composable fun GlobalSearchScreen( state: GlobalSearchState, + items: Map, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, + onChangeFilter: (GlobalSearchFilter) -> Unit, getManga: @Composable (Manga) -> State, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, @@ -36,19 +54,78 @@ fun GlobalSearchScreen( ) { Scaffold( topBar = { scrollBehavior -> - GlobalSearchToolbar( - searchQuery = state.searchQuery, - progress = state.progress, - total = state.total, - navigateUp = navigateUp, - onChangeSearchQuery = onChangeSearchQuery, - onSearch = onSearch, - scrollBehavior = scrollBehavior, - ) + Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) { + GlobalSearchToolbar( + searchQuery = state.searchQuery, + progress = state.progress, + total = state.total, + navigateUp = navigateUp, + onChangeSearchQuery = onChangeSearchQuery, + onSearch = onSearch, + scrollBehavior = scrollBehavior, + ) + + Row( + modifier = Modifier + .horizontalScroll(rememberScrollState()) + .padding(horizontal = MaterialTheme.padding.small), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), + ) { + FilterChip( + selected = state.searchFilter == GlobalSearchFilter.All, + onClick = { onChangeFilter(GlobalSearchFilter.All) }, + leadingIcon = { + Icon( + imageVector = Icons.Outlined.DoneAll, + contentDescription = "", + modifier = Modifier + .size(FilterChipDefaults.IconSize), + ) + }, + label = { + Text(text = stringResource(id = R.string.all)) + }, + ) + + FilterChip( + selected = state.searchFilter == GlobalSearchFilter.PinnedOnly, + onClick = { onChangeFilter(GlobalSearchFilter.PinnedOnly) }, + leadingIcon = { + Icon( + imageVector = Icons.Outlined.PushPin, + contentDescription = "", + modifier = Modifier + .size(FilterChipDefaults.IconSize), + ) + }, + label = { + Text(text = stringResource(id = R.string.pinned_sources)) + }, + ) + + FilterChip( + selected = state.searchFilter == GlobalSearchFilter.AvailableOnly, + onClick = { onChangeFilter(GlobalSearchFilter.AvailableOnly) }, + leadingIcon = { + Icon( + imageVector = Icons.Outlined.FilterList, + contentDescription = "", + modifier = Modifier + .size(FilterChipDefaults.IconSize), + ) + }, + label = { + Text(text = stringResource(id = R.string.has_results)) + }, + ) + } + + Divider() + } }, ) { paddingValues -> GlobalSearchContent( - items = state.items, + items = items, contentPadding = paddingValues, getManga = getManga, onClickSource = onClickSource, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt index 82ed21be7..5f1999378 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt @@ -35,6 +35,7 @@ class GlobalSearchScreen( var showSingleLoadingScreen by remember { mutableStateOf(searchQuery.isNotEmpty() && extensionFilter.isNotEmpty() && state.total == 1) } + val filteredSources by screenModel.searchPagerFlow.collectAsState() if (showSingleLoadingScreen) { LoadingScreen() @@ -57,10 +58,12 @@ class GlobalSearchScreen( } else { GlobalSearchScreen( state = state, + items = filteredSources, navigateUp = navigator::pop, onChangeSearchQuery = screenModel::updateSearchQuery, onSearch = screenModel::search, getManga = { screenModel.getManga(it) }, + onChangeFilter = screenModel::setFilter, onClickSource = { if (!screenModel.incognitoMode.get()) { screenModel.lastUsedSourceId.set(it.id) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt index 5c3d2b00b..7190987f6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt @@ -3,7 +3,12 @@ package eu.kanade.tachiyomi.ui.browse.source.globalsearch import androidx.compose.runtime.Immutable import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.source.service.SourcePreferences +import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.source.CatalogueSource +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt @@ -20,6 +25,13 @@ class GlobalSearchScreenModel( val incognitoMode = preferences.incognitoMode() val lastUsedSourceId = sourcePreferences.lastUsedSource() + val searchPagerFlow = state.map { Pair(it.searchFilter, it.items) } + .distinctUntilChanged() + .map { (filter, items) -> + items + .filter { (source, result) -> isSourceVisible(filter, source, result) } + }.stateIn(ioCoroutineScope, SharingStarted.Lazily, state.value.items) + init { extensionFilter = initialExtensionFilter if (initialQuery.isNotBlank() || initialExtensionFilter.isNotBlank()) { @@ -38,6 +50,14 @@ class GlobalSearchScreenModel( .sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" })) } + private fun isSourceVisible(filter: GlobalSearchFilter, source: CatalogueSource, result: SearchItemResult): Boolean { + return when (filter) { + GlobalSearchFilter.AvailableOnly -> result is SearchItemResult.Success && !result.isEmpty + GlobalSearchFilter.PinnedOnly -> "${source.id}" in sourcePreferences.pinnedSources().get() + GlobalSearchFilter.All -> true + } + } + override fun updateSearchQuery(query: String?) { mutableState.update { it.copy(searchQuery = query) @@ -50,14 +70,23 @@ class GlobalSearchScreenModel( } } + fun setFilter(filter: GlobalSearchFilter) { + mutableState.update { it.copy(searchFilter = filter) } + } + override fun getItems(): Map { return mutableState.value.items } } +enum class GlobalSearchFilter { + All, PinnedOnly, AvailableOnly +} + @Immutable data class GlobalSearchState( val searchQuery: String? = null, + val searchFilter: GlobalSearchFilter = GlobalSearchFilter.All, val items: Map = emptyMap(), ) { diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index aed9b32ee..6984ac54a 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -627,6 +627,7 @@ Latest Popular Browse + Has results Local source guide You have no pinned sources Chapter not found From a629db2884c19a0910eacfe0bc5bde33e838e15b Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 14 Jul 2023 23:08:45 -0400 Subject: [PATCH 02/15] Address some build warnings --- .../extension/util/ExtensionLoader.kt | 22 +++++++++---------- .../util/system/ContextExtensions.kt | 1 - .../util/system/DisplayExtensions.kt | 11 ---------- .../tachiyomi/network/JavaScriptEngine.kt | 2 +- .../core/components/material/Tabs.kt | 6 ++--- 5 files changed, 15 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 02246a30d..e8dbe23ec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -41,7 +41,12 @@ internal object ExtensionLoader { const val LIB_VERSION_MIN = 1.3 const val LIB_VERSION_MAX = 1.5 - private const val PACKAGE_FLAGS = PackageManager.GET_CONFIGURATIONS or PackageManager.GET_SIGNATURES + private val PACKAGE_FLAGS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + PackageManager.GET_CONFIGURATIONS or PackageManager.GET_SIGNING_CERTIFICATES + } else { + @Suppress("DEPRECATION") + PackageManager.GET_CONFIGURATIONS or PackageManager.GET_SIGNATURES + } // inorichi's key private const val officialSignature = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" @@ -49,7 +54,7 @@ internal object ExtensionLoader { /** * List of the trusted signatures. */ - var trustedSignatures = mutableSetOf() + preferences.trustedSignatures().get() + officialSignature + var trustedSignatures = mutableSetOf(officialSignature) + preferences.trustedSignatures().get() /** * Return a list of all the installed extensions initialized concurrently. @@ -59,7 +64,6 @@ internal object ExtensionLoader { fun loadExtensions(context: Context): List { val pkgManager = context.packageManager - @Suppress("DEPRECATION") val installedPkgs = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { pkgManager.getInstalledPackages(PackageManager.PackageInfoFlags.of(PACKAGE_FLAGS.toLong())) } else { @@ -135,7 +139,7 @@ internal object ExtensionLoader { return LoadResult.Error } - val signatureHash = getSignatureHash(pkgInfo) + val signatureHash = getSignatureHash(context, pkgInfo) if (signatureHash == null) { logcat(LogPriority.WARN) { "Package $pkgName isn't signed" } return LoadResult.Error @@ -220,12 +224,8 @@ internal object ExtensionLoader { * * @param pkgInfo The package info of the application. */ - private fun getSignatureHash(pkgInfo: PackageInfo): String? { - val signatures = pkgInfo.signatures - return if (signatures != null && signatures.isNotEmpty()) { - Hash.sha256(signatures.first().toByteArray()) - } else { - null - } + private fun getSignatureHash(context: Context, pkgInfo: PackageInfo): String? { + val signatures = PackageInfoCompat.getSignatures(context.packageManager, pkgInfo.packageName) + return signatures.firstOrNull()?.let { Hash.sha256(it.toByteArray()) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt index 9124619f8..8cc74445b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt @@ -134,7 +134,6 @@ private fun Context.defaultBrowserPackageName(): String? { val resolveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { packageManager.resolveActivity(browserIntent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())) } else { - @Suppress("DEPRECATION") packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY) } return resolveInfo diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt index e93905c74..50f45ae85 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt @@ -5,10 +5,7 @@ import android.content.Context import android.content.res.Configuration import android.content.res.Resources import android.os.Build -import android.view.Display import android.view.View -import android.view.WindowManager -import androidx.core.content.getSystemService import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.TabletUiMode import uy.kohesive.injekt.Injekt @@ -67,14 +64,6 @@ fun Context.isNightMode(): Boolean { return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES } -val Context.displayCompat: Display? - get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - display - } else { - @Suppress("DEPRECATION") - getSystemService()?.defaultDisplay - } - val Resources.isLTR get() = configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/JavaScriptEngine.kt b/core/src/main/java/eu/kanade/tachiyomi/network/JavaScriptEngine.kt index 3517d1dc9..4ecf3e09d 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/JavaScriptEngine.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/JavaScriptEngine.kt @@ -7,6 +7,7 @@ import tachiyomi.core.util.lang.withIOContext /** * Util for evaluating JavaScript in sources. */ +@Suppress("UNUSED", "UNCHECKED_CAST") class JavaScriptEngine(context: Context) { /** @@ -17,7 +18,6 @@ class JavaScriptEngine(context: Context) { * @param script JavaScript to execute. * @return Result of JavaScript code as a primitive type. */ - @Suppress("UNUSED", "UNCHECKED_CAST") suspend fun evaluate(script: String): T = withIOContext { QuickJs.create().use { it.evaluate(script) as T diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt index b76407e60..d547ad8d0 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt @@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.TabPosition -import androidx.compose.material3.TabRowDefaults +import androidx.compose.material3.TabRowDefaults.SecondaryIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -50,8 +50,8 @@ fun TabIndicator( currentTabPosition: TabPosition, currentPageOffsetFraction: Float, ) { - TabRowDefaults.Indicator( - Modifier + SecondaryIndicator( + modifier = Modifier .tabIndicatorOffset(currentTabPosition, currentPageOffsetFraction) .padding(horizontal = 8.dp) .clip(RoundedCornerShape(topStart = 3.dp, topEnd = 3.dp)), From 22e8050fff273a189d2fdfae6e66ec622f04f1dd Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 09:34:20 -0400 Subject: [PATCH 03/15] Handle Cloudflare in default network client and deprecate cloudflareClient --- .../eu/kanade/tachiyomi/network/NetworkHelper.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index efbdacb9d..54d185883 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -44,6 +44,8 @@ class NetworkHelper( builder.addNetworkInterceptor(httpLoggingInterceptor) } + builder.addInterceptor(cloudflareInterceptor) + when (preferences.dohProvider().get()) { PREF_DOH_CLOUDFLARE -> builder.dohCloudflare() PREF_DOH_GOOGLE -> builder.dohGoogle() @@ -64,12 +66,12 @@ class NetworkHelper( val client by lazy { baseClientBuilder.cache(Cache(cacheDir, cacheSize)).build() } + /** + * @deprecated Since extension-lib 1.5 + */ + @Deprecated("The regular client handles Cloudflare by default") @Suppress("UNUSED") - val cloudflareClient by lazy { - client.newBuilder() - .addInterceptor(cloudflareInterceptor) - .build() - } + val cloudflareClient = client fun defaultUserAgentProvider() = preferences.defaultUserAgent().get().trim() } From 54733e6ceb541d314687f46f5a01cf2f08dec89e Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 09:54:29 -0400 Subject: [PATCH 04/15] Mark some state data classes as immutable --- .../ui/browse/migration/search/MigrateDialog.kt | 2 ++ .../tachiyomi/ui/manga/track/TrackInfoDialog.kt | 6 ++++++ .../eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt | 12 +++++------- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt index 496a40c58..137af5eff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt @@ -16,6 +16,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf @@ -313,6 +314,7 @@ internal class MigrateDialogScreenModel( ) } + @Immutable data class State( val isMigrating: Boolean = false, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 1ed1895a9..04c5cd40d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -20,6 +20,7 @@ import androidx.compose.material3.SelectableDates import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -265,6 +266,7 @@ data class TrackInfoDialogHomeScreen( .filter { (it.service as? EnhancedTrackService)?.accept(source) ?: true } } + @Immutable data class State( val trackItems: List = emptyList(), ) @@ -314,6 +316,7 @@ private data class TrackStatusSelectorScreen( } } + @Immutable data class State( val selection: Int, ) @@ -369,6 +372,7 @@ private data class TrackChapterSelectorScreen( } } + @Immutable data class State( val selection: Int, ) @@ -419,6 +423,7 @@ private data class TrackScoreSelectorScreen( } } + @Immutable data class State( val selection: String, ) @@ -724,6 +729,7 @@ data class TrackServiceSearchScreen( mutableState.update { it.copy(selected = selected) } } + @Immutable data class State( val queryResult: Result>? = null, val selected: TrackSearch? = null, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index 7a7a313a6..0fa5423c3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader import android.app.Application import android.net.Uri +import androidx.compose.runtime.Immutable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -790,16 +791,12 @@ class ReaderViewModel( } } - /** - * Results of the set as cover feature. - */ enum class SetAsCoverResult { - Success, AddToLibraryFirst, Error + Success, + AddToLibraryFirst, + Error, } - /** - * Results of the save image feature. - */ sealed class SaveImageResult { class Success(val uri: Uri) : SaveImageResult() class Error(val error: Throwable) : SaveImageResult() @@ -844,6 +841,7 @@ class ReaderViewModel( } } + @Immutable data class State( val manga: Manga? = null, val viewerChapters: ViewerChapters? = null, From 12e7ee9d0caaa56d551908d179788fa637768397 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 10:09:46 -0400 Subject: [PATCH 05/15] Tweak global search source filtering Pinned only setting is removed in favor of the UI in the global search screen itself, which defaults to pinned only. This needs more UX improvements, but I'm not really sure what it should be like right now. --- .../source/service/SourcePreferences.kt | 2 - .../presentation/browse/GlobalSearchScreen.kt | 54 ++++++++------- .../settings/screen/SettingsBrowseScreen.kt | 4 -- .../migration/search/MigrateSearchScreen.kt | 1 + .../source/globalsearch/GlobalSearchScreen.kt | 3 +- .../globalsearch/GlobalSearchScreenModel.kt | 66 +++++++++---------- .../source/globalsearch/SearchScreenModel.kt | 16 ++--- i18n/src/main/res/values/strings.xml | 1 - 8 files changed, 70 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index c81fa1632..582dd61d7 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -30,7 +30,5 @@ class SourcePreferences( fun trustedSignatures() = preferenceStore.getStringSet("trusted_signatures", emptySet()) - fun searchPinnedSourcesOnly() = preferenceStore.getBoolean("search_pinned_sources_only", false) - fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false) } diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 886f9960a..4a80724f0 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -30,23 +30,25 @@ import eu.kanade.presentation.browse.components.GlobalSearchResultItem import eu.kanade.presentation.browse.components.GlobalSearchToolbar import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.CatalogueSource -import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchFilter -import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchState +import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreenModel import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult +import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter import eu.kanade.tachiyomi.util.system.LocaleHelper import tachiyomi.domain.manga.model.Manga import tachiyomi.presentation.core.components.material.Divider import tachiyomi.presentation.core.components.material.Scaffold +import tachiyomi.presentation.core.components.material.VerticalDivider import tachiyomi.presentation.core.components.material.padding @Composable fun GlobalSearchScreen( - state: GlobalSearchState, + state: GlobalSearchScreenModel.State, items: Map, navigateUp: () -> Unit, onChangeSearchQuery: (String?) -> Unit, onSearch: (String) -> Unit, - onChangeFilter: (GlobalSearchFilter) -> Unit, + onChangeSearchFilter: (SourceFilter) -> Unit, + onToggleResults: () -> Unit, getManga: @Composable (Manga) -> State, onClickSource: (CatalogueSource) -> Unit, onClickItem: (Manga) -> Unit, @@ -71,13 +73,29 @@ fun GlobalSearchScreen( .padding(horizontal = MaterialTheme.padding.small), horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), ) { + // TODO: make this UX better; it only applies when triggering a new search FilterChip( - selected = state.searchFilter == GlobalSearchFilter.All, - onClick = { onChangeFilter(GlobalSearchFilter.All) }, + selected = state.sourceFilter == SourceFilter.PinnedOnly, + onClick = { onChangeSearchFilter(SourceFilter.PinnedOnly) }, + leadingIcon = { + Icon( + imageVector = Icons.Outlined.PushPin, + contentDescription = null, + modifier = Modifier + .size(FilterChipDefaults.IconSize), + ) + }, + label = { + Text(text = stringResource(id = R.string.pinned_sources)) + }, + ) + FilterChip( + selected = state.sourceFilter == SourceFilter.All, + onClick = { onChangeSearchFilter(SourceFilter.All) }, leadingIcon = { Icon( imageVector = Icons.Outlined.DoneAll, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) @@ -87,29 +105,15 @@ fun GlobalSearchScreen( }, ) - FilterChip( - selected = state.searchFilter == GlobalSearchFilter.PinnedOnly, - onClick = { onChangeFilter(GlobalSearchFilter.PinnedOnly) }, - leadingIcon = { - Icon( - imageVector = Icons.Outlined.PushPin, - contentDescription = "", - modifier = Modifier - .size(FilterChipDefaults.IconSize), - ) - }, - label = { - Text(text = stringResource(id = R.string.pinned_sources)) - }, - ) + VerticalDivider() FilterChip( - selected = state.searchFilter == GlobalSearchFilter.AvailableOnly, - onClick = { onChangeFilter(GlobalSearchFilter.AvailableOnly) }, + selected = state.onlyShowHasResults, + onClick = { onToggleResults() }, leadingIcon = { Icon( imageVector = Icons.Outlined.FilterList, - contentDescription = "", + contentDescription = null, modifier = Modifier .size(FilterChipDefaults.IconSize), ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt index 01fb87e7e..5b3ab28cf 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt @@ -29,10 +29,6 @@ object SettingsBrowseScreen : SearchableSettings { Preference.PreferenceGroup( title = stringResource(R.string.label_sources), preferenceItems = listOf( - Preference.PreferenceItem.SwitchPreference( - pref = sourcePreferences.searchPinnedSourcesOnly(), - title = stringResource(R.string.pref_search_pinned_sources_only), - ), Preference.PreferenceItem.SwitchPreference( pref = sourcePreferences.hideInLibraryItems(), title = stringResource(R.string.pref_hide_in_library_items), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt index 73ad96780..ae89d9cb0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt @@ -10,6 +10,7 @@ import eu.kanade.presentation.browse.MigrateSearchScreen import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.ui.manga.MangaScreen +// TODO: this should probably be merged with GlobalSearchScreen somehow to dedupe logic class MigrateSearchScreen(private val mangaId: Long) : Screen() { @Composable diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt index 5f1999378..78c449fd0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt @@ -63,7 +63,8 @@ class GlobalSearchScreen( onChangeSearchQuery = screenModel::updateSearchQuery, onSearch = screenModel::search, getManga = { screenModel.getManga(it) }, - onChangeFilter = screenModel::setFilter, + onChangeSearchFilter = screenModel::setSourceFilter, + onToggleResults = screenModel::toggleFilterResults, onClickSource = { if (!screenModel.incognitoMode.get()) { screenModel.lastUsedSourceId.set(it.id) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt index 7190987f6..13ac00468 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt @@ -20,17 +20,17 @@ class GlobalSearchScreenModel( preferences: BasePreferences = Injekt.get(), private val sourcePreferences: SourcePreferences = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(), -) : SearchScreenModel(GlobalSearchState(searchQuery = initialQuery)) { +) : SearchScreenModel(State(searchQuery = initialQuery)) { val incognitoMode = preferences.incognitoMode() val lastUsedSourceId = sourcePreferences.lastUsedSource() - val searchPagerFlow = state.map { Pair(it.searchFilter, it.items) } + val searchPagerFlow = state.map { Pair(it.onlyShowHasResults, it.items) } .distinctUntilChanged() - .map { (filter, items) -> - items - .filter { (source, result) -> isSourceVisible(filter, source, result) } - }.stateIn(ioCoroutineScope, SharingStarted.Lazily, state.value.items) + .map { (onlyShowHasResults, items) -> + items.filter { (_, result) -> result.isVisible(onlyShowHasResults) } + } + .stateIn(ioCoroutineScope, SharingStarted.Lazily, state.value.items) init { extensionFilter = initialExtensionFilter @@ -45,19 +45,12 @@ class GlobalSearchScreenModel( val pinnedSources = sourcePreferences.pinnedSources().get() return sourceManager.getCatalogueSources() + .filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources } .filter { it.lang in enabledLanguages } .filterNot { "${it.id}" in disabledSources } .sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" })) } - private fun isSourceVisible(filter: GlobalSearchFilter, source: CatalogueSource, result: SearchItemResult): Boolean { - return when (filter) { - GlobalSearchFilter.AvailableOnly -> result is SearchItemResult.Success && !result.isEmpty - GlobalSearchFilter.PinnedOnly -> "${source.id}" in sourcePreferences.pinnedSources().get() - GlobalSearchFilter.All -> true - } - } - override fun updateSearchQuery(query: String?) { mutableState.update { it.copy(searchQuery = query) @@ -70,27 +63,32 @@ class GlobalSearchScreenModel( } } - fun setFilter(filter: GlobalSearchFilter) { - mutableState.update { it.copy(searchFilter = filter) } - } - override fun getItems(): Map { return mutableState.value.items } -} - -enum class GlobalSearchFilter { - All, PinnedOnly, AvailableOnly -} - -@Immutable -data class GlobalSearchState( - val searchQuery: String? = null, - val searchFilter: GlobalSearchFilter = GlobalSearchFilter.All, - val items: Map = emptyMap(), -) { - - val progress: Int = items.count { it.value !is SearchItemResult.Loading } - - val total: Int = items.size + + fun setSourceFilter(filter: SourceFilter) { + mutableState.update { it.copy(sourceFilter = filter) } + } + + fun toggleFilterResults() { + mutableState.update { + it.copy(onlyShowHasResults = !it.onlyShowHasResults) + } + } + + private fun SearchItemResult.isVisible(onlyShowHasResults: Boolean): Boolean { + return !onlyShowHasResults || (this is SearchItemResult.Success && !this.isEmpty) + } + + @Immutable + data class State( + val searchQuery: String? = null, + val sourceFilter: SourceFilter = SourceFilter.PinnedOnly, + val onlyShowHasResults: Boolean = false, + val items: Map = emptyMap(), + ) { + val progress: Int = items.count { it.value !is SearchItemResult.Loading } + val total: Int = items.size + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 78238b21b..26ab767c5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -68,16 +68,7 @@ abstract class SearchScreenModel( val enabledSources = getEnabledSources() if (filter.isEmpty()) { - val shouldSearchPinnedOnly = sourcePreferences.searchPinnedSourcesOnly().get() - val pinnedSources = sourcePreferences.pinnedSources().get() - - return enabledSources.filter { - if (shouldSearchPinnedOnly) { - "${it.id}" in pinnedSources - } else { - true - } - } + return enabledSources } return extensionManager.installedExtensionsFlow.value @@ -137,6 +128,11 @@ abstract class SearchScreenModel( } } +enum class SourceFilter { + All, + PinnedOnly, +} + sealed class SearchItemResult { object Loading : SearchItemResult() diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 6984ac54a..3df318c7e 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -480,7 +480,6 @@ Track - Only search pinned sources in global search Hide entries already in library From e40b8d537c2727a9867fedf8971afd01237a661f Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 10:47:56 -0400 Subject: [PATCH 06/15] Move all pager/webtoon reader setting to Compose sheet --- .../eu/kanade/domain/base/BasePreferences.kt | 3 +- .../settings/screen/SettingsReaderScreen.kt | 34 +++----- .../reader/settings/ReadingModePage.kt | 80 ++++++++++++++++--- .../ui/reader/setting/ReaderPreferences.kt | 41 ++++++++-- .../ui/reader/setting/ReaderSettingsSheet.kt | 52 ------------ .../tachiyomi/widget/MaterialSpinnerView.kt | 37 --------- .../main/res/layout/reader_pager_settings.xml | 46 ----------- .../layout/reader_reading_mode_settings.xml | 27 ------- .../res/layout/reader_webtoon_settings.xml | 32 -------- app/src/main/res/values/arrays.xml | 41 ---------- 10 files changed, 121 insertions(+), 272 deletions(-) delete mode 100644 app/src/main/res/layout/reader_pager_settings.xml delete mode 100644 app/src/main/res/layout/reader_webtoon_settings.xml diff --git a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt index ba3cebc86..eb69664f7 100644 --- a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt @@ -1,6 +1,7 @@ package eu.kanade.domain.base import android.content.Context +import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.isPreviewBuildType import eu.kanade.tachiyomi.util.system.isReleaseBuildType @@ -19,7 +20,7 @@ class BasePreferences( fun acraEnabled() = preferenceStore.getBoolean("acra.enable", isPreviewBuildType || isReleaseBuildType) - enum class ExtensionInstaller(val titleResId: Int) { + enum class ExtensionInstaller(@StringRes val titleResId: Int) { LEGACY(R.string.ext_installer_legacy), PACKAGEINSTALLER(R.string.ext_installer_packageinstaller), SHIZUKU(R.string.ext_installer_shizuku), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index 31f60acfd..0a19a72c2 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -7,7 +7,6 @@ import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.util.collectAsState @@ -164,9 +163,9 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = navModePref, title = stringResource(R.string.pref_viewer_nav), - entries = stringArrayResource(id = R.array.pager_nav).let { - it.indices.zip(it).toMap() - }, + entries = ReaderPreferences.TapZones + .mapIndexed { index, it -> index to stringResource(it) } + .toMap(), ), Preference.PreferenceItem.ListPreference( pref = readerPreferences.pagerNavInverted(), @@ -182,25 +181,16 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = imageScaleTypePref, title = stringResource(R.string.pref_image_scale_type), - entries = mapOf( - 1 to stringResource(R.string.scale_type_fit_screen), - 2 to stringResource(R.string.scale_type_stretch), - 3 to stringResource(R.string.scale_type_fit_width), - 4 to stringResource(R.string.scale_type_fit_height), - 5 to stringResource(R.string.scale_type_original_size), - 6 to stringResource(R.string.scale_type_smart_fit), - ), + entries = ReaderPreferences.ImageScaleType + .mapIndexed { index, it -> index + 1 to stringResource(it) } + .toMap(), ), Preference.PreferenceItem.ListPreference( pref = readerPreferences.zoomStart(), title = stringResource(R.string.pref_zoom_start), - entries = mapOf( - 1 to stringResource(R.string.zoom_start_automatic), - 2 to stringResource(R.string.zoom_start_left), - 3 to stringResource(R.string.zoom_start_right), - 4 to stringResource(R.string.zoom_start_center), - ), - + entries = ReaderPreferences.ZoomStart + .mapIndexed { index, it -> index + 1 to stringResource(it) } + .toMap(), ), Preference.PreferenceItem.SwitchPreference( pref = readerPreferences.cropBorders(), @@ -265,9 +255,9 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = navModePref, title = stringResource(R.string.pref_viewer_nav), - entries = stringArrayResource(id = R.array.webtoon_nav).let { - it.indices.zip(it).toMap() - }, + entries = ReaderPreferences.TapZones + .mapIndexed { index, it -> index to stringResource(it) } + .toMap(), ), Preference.PreferenceItem.ListPreference( pref = readerPreferences.webtoonNavInverted(), diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index ff710a76d..48d002a1b 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -12,17 +12,23 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem +import tachiyomi.presentation.core.components.RadioItem import tachiyomi.presentation.core.components.SliderItem import java.text.NumberFormat @Composable internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) { + HeadingItem("This is still a WIP, the UI will be improved soon") + HeadingItem(R.string.pref_category_for_this_series) - // Reading mode - // Rotation type + // TODO: Reading mode + HeadingItem(R.string.pref_category_reading_mode) - // if (pager) + // TODO: Rotation type + HeadingItem(R.string.rotation_type) + + // TODO: if (pager) PagerViewerSettings(screenModel) WebtoonViewerSettings(screenModel) @@ -32,10 +38,47 @@ internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenModel) { HeadingItem(R.string.pager_viewer) - // Tap zones - // Invert tap zones - // Scale type - // Zoom start position + val navigationModePager by screenModel.preferences.navigationModePager().collectAsState() + HeadingItem(R.string.pref_viewer_nav) + ReaderPreferences.TapZones.mapIndexed { index, titleResId -> + RadioItem( + label = stringResource(titleResId), + selected = navigationModePager == index, + onClick = { screenModel.preferences.navigationModePager().set(index) }, + ) + } + + if (navigationModePager != 5) { + val pagerNavInverted by screenModel.preferences.pagerNavInverted().collectAsState() + HeadingItem(R.string.pref_read_with_tapping_inverted) + ReaderPreferences.TappingInvertMode.values().map { + RadioItem( + label = stringResource(it.titleResId), + selected = pagerNavInverted == it, + onClick = { screenModel.preferences.pagerNavInverted().set(it) }, + ) + } + } + + val imageScaleType by screenModel.preferences.imageScaleType().collectAsState() + HeadingItem(R.string.pref_image_scale_type) + ReaderPreferences.ImageScaleType.mapIndexed { index, it -> + RadioItem( + label = stringResource(it), + selected = imageScaleType == index + 1, + onClick = { screenModel.preferences.imageScaleType().set(index + 1) }, + ) + } + + val zoomStart by screenModel.preferences.zoomStart().collectAsState() + HeadingItem(R.string.pref_zoom_start) + ReaderPreferences.ZoomStart.mapIndexed { index, it -> + RadioItem( + label = stringResource(it), + selected = zoomStart == index + 1, + onClick = { screenModel.preferences.zoomStart().set(index + 1) }, + ) + } val cropBorders by screenModel.preferences.cropBorders().collectAsState() CheckboxItem( @@ -111,8 +154,27 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM HeadingItem(R.string.webtoon_viewer) - // TODO: Tap zones - // TODO: Invert tap zones + val navigationModeWebtoon by screenModel.preferences.navigationModeWebtoon().collectAsState() + HeadingItem(R.string.pref_viewer_nav) + ReaderPreferences.TapZones.mapIndexed { index, titleResId -> + RadioItem( + label = stringResource(titleResId), + selected = navigationModeWebtoon == index, + onClick = { screenModel.preferences.navigationModeWebtoon().set(index) }, + ) + } + + if (navigationModeWebtoon != 5) { + val webtoonNavInverted by screenModel.preferences.webtoonNavInverted().collectAsState() + HeadingItem(R.string.pref_read_with_tapping_inverted) + ReaderPreferences.TappingInvertMode.values().map { + RadioItem( + label = stringResource(it.titleResId), + selected = webtoonNavInverted == it, + onClick = { screenModel.preferences.webtoonNavInverted().set(it) }, + ) + } + } val webtoonSidePadding by screenModel.preferences.webtoonSidePadding().collectAsState() SliderItem( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt index b18a5682e..23a5beb13 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.ui.reader.setting +import androidx.annotation.StringRes +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.getEnum @@ -122,11 +124,15 @@ class ReaderPreferences( // endregion - enum class TappingInvertMode(val shouldInvertHorizontal: Boolean = false, val shouldInvertVertical: Boolean = false) { - NONE, - HORIZONTAL(shouldInvertHorizontal = true), - VERTICAL(shouldInvertVertical = true), - BOTH(shouldInvertHorizontal = true, shouldInvertVertical = true), + enum class TappingInvertMode( + @StringRes val titleResId: Int, + val shouldInvertHorizontal: Boolean = false, + val shouldInvertVertical: Boolean = false, + ) { + NONE(R.string.tapping_inverted_none), + HORIZONTAL(R.string.tapping_inverted_horizontal, shouldInvertHorizontal = true), + VERTICAL(R.string.tapping_inverted_vertical, shouldInvertVertical = true), + BOTH(R.string.tapping_inverted_both, shouldInvertHorizontal = true, shouldInvertVertical = true), } enum class ReaderHideThreshold(val threshold: Int) { @@ -139,5 +145,30 @@ class ReaderPreferences( companion object { const val WEBTOON_PADDING_MIN = 0 const val WEBTOON_PADDING_MAX = 25 + + val TapZones = listOf( + R.string.label_default, + R.string.l_nav, + R.string.kindlish_nav, + R.string.edge_nav, + R.string.right_and_left_nav, + R.string.disabled_nav, + ) + + val ImageScaleType = listOf( + R.string.scale_type_fit_screen, + R.string.scale_type_stretch, + R.string.scale_type_fit_width, + R.string.scale_type_fit_height, + R.string.scale_type_original_size, + R.string.scale_type_smart_fit, + ) + + val ZoomStart = listOf( + R.string.zoom_start_automatic, + R.string.zoom_start_left, + R.string.zoom_start_right, + R.string.zoom_start_center, + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt index 50529e4cb..a54aa233b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt @@ -1,26 +1,16 @@ package eu.kanade.tachiyomi.ui.reader.setting import android.os.Bundle -import androidx.core.view.isVisible -import androidx.lifecycle.lifecycleScope import com.google.android.material.bottomsheet.BottomSheetDialog import eu.kanade.domain.manga.model.orientationType import eu.kanade.domain.manga.model.readingModeType import eu.kanade.tachiyomi.databinding.ReaderReadingModeSettingsBinding import eu.kanade.tachiyomi.ui.reader.ReaderActivity -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer -import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer -import eu.kanade.tachiyomi.util.preference.bindToPreference -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import uy.kohesive.injekt.injectLazy class ReaderSettingsSheet( private val activity: ReaderActivity, ) : BottomSheetDialog(activity) { - private val readerPreferences: ReaderPreferences by injectLazy() - private lateinit var binding: ReaderReadingModeSettingsBinding override fun onCreate(savedInstanceState: Bundle?) { @@ -30,24 +20,12 @@ class ReaderSettingsSheet( setContentView(binding.root) initGeneralPreferences() - - when (activity.viewModel.state.value.viewer) { - is PagerViewer -> initPagerPreferences() - is WebtoonViewer -> initWebtoonPreferences() - } } private fun initGeneralPreferences() { binding.viewer.onItemSelectedListener = { position -> val readingModeType = ReadingModeType.fromSpinner(position) activity.viewModel.setMangaReadingMode(readingModeType.flagValue) - - val mangaViewer = activity.viewModel.getMangaReadingMode() - if (mangaViewer == ReadingModeType.WEBTOON.flagValue || mangaViewer == ReadingModeType.CONTINUOUS_VERTICAL.flagValue) { - initWebtoonPreferences() - } else { - initPagerPreferences() - } } binding.viewer.setSelection(activity.viewModel.manga?.readingModeType?.let { ReadingModeType.fromPreference(it.toInt()).prefValue } ?: ReadingModeType.DEFAULT.prefValue) @@ -57,34 +35,4 @@ class ReaderSettingsSheet( } binding.rotationMode.setSelection(activity.viewModel.manga?.orientationType?.let { OrientationType.fromPreference(it.toInt()).prefValue } ?: OrientationType.DEFAULT.prefValue) } - - private fun initPagerPreferences() { - binding.webtoonPrefsGroup.root.isVisible = false - binding.pagerPrefsGroup.root.isVisible = true - - binding.pagerPrefsGroup.tappingInverted.bindToPreference(readerPreferences.pagerNavInverted(), ReaderPreferences.TappingInvertMode::class.java) - - binding.pagerPrefsGroup.pagerNav.bindToPreference(readerPreferences.navigationModePager()) - readerPreferences.navigationModePager().changes() - .onEach { - val isTappingEnabled = it != 5 - binding.pagerPrefsGroup.tappingInverted.isVisible = isTappingEnabled - } - .launchIn(activity.lifecycleScope) - binding.pagerPrefsGroup.scaleType.bindToPreference(readerPreferences.imageScaleType(), 1) - - binding.pagerPrefsGroup.zoomStart.bindToPreference(readerPreferences.zoomStart(), 1) - } - - private fun initWebtoonPreferences() { - binding.pagerPrefsGroup.root.isVisible = false - binding.webtoonPrefsGroup.root.isVisible = true - - binding.webtoonPrefsGroup.tappingInverted.bindToPreference(readerPreferences.webtoonNavInverted(), ReaderPreferences.TappingInvertMode::class.java) - - binding.webtoonPrefsGroup.webtoonNav.bindToPreference(readerPreferences.navigationModeWebtoon()) - readerPreferences.navigationModeWebtoon().changes() - .onEach { binding.webtoonPrefsGroup.tappingInverted.isVisible = it != 5 } - .launchIn(activity.lifecycleScope) - } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt index 57289daf1..54160cf71 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt @@ -77,43 +77,6 @@ class MaterialSpinnerView @JvmOverloads constructor(context: Context, attrs: Att binding.details.text = entries.getOrNull(selection).orEmpty() } - fun bindToPreference(pref: Preference, offset: Int = 0, block: ((Int) -> Unit)? = null) { - setSelection(pref.get() - offset) - - popup = makeSettingsPopup(pref, offset, block) - setOnTouchListener(popup?.dragToOpenListener) - setOnClickListener { - popup?.show() - } - } - - fun > bindToPreference(pref: Preference, clazz: Class) { - val enumConstants = clazz.enumConstants - enumConstants?.indexOf(pref.get())?.let { setSelection(it) } - - popup = makeSettingsPopup(pref, clazz) - setOnTouchListener(popup?.dragToOpenListener) - setOnClickListener { - popup?.show() - } - } - - private fun > makeSettingsPopup(preference: Preference, clazz: Class): PopupMenu { - return createPopupMenu { pos -> - onItemSelectedListener?.invoke(pos) - - val enumConstants = clazz.enumConstants - enumConstants?.get(pos)?.let { enumValue -> preference.set(enumValue) } - } - } - - private fun makeSettingsPopup(preference: Preference, intValues: List, block: ((Int) -> Unit)? = null): PopupMenu { - return createPopupMenu { pos -> - preference.set(intValues[pos] ?: 0) - block?.invoke(pos) - } - } - private fun makeSettingsPopup(preference: Preference, offset: Int = 0, block: ((Int) -> Unit)? = null): PopupMenu { return createPopupMenu { pos -> preference.set(pos + offset) diff --git a/app/src/main/res/layout/reader_pager_settings.xml b/app/src/main/res/layout/reader_pager_settings.xml deleted file mode 100644 index f79bcfa11..000000000 --- a/app/src/main/res/layout/reader_pager_settings.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/reader_reading_mode_settings.xml b/app/src/main/res/layout/reader_reading_mode_settings.xml index e825c229a..39b824939 100644 --- a/app/src/main/res/layout/reader_reading_mode_settings.xml +++ b/app/src/main/res/layout/reader_reading_mode_settings.xml @@ -1,7 +1,6 @@ @@ -10,17 +9,6 @@ android:layout_height="wrap_content" android:orientation="vertical"> - - - - - - diff --git a/app/src/main/res/layout/reader_webtoon_settings.xml b/app/src/main/res/layout/reader_webtoon_settings.xml deleted file mode 100644 index 00e970665..000000000 --- a/app/src/main/res/layout/reader_webtoon_settings.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index d9403c687..11d827db9 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -9,22 +9,6 @@ @string/vertical_plus_viewer - - @string/scale_type_fit_screen - @string/scale_type_stretch - @string/scale_type_fit_width - @string/scale_type_fit_height - @string/scale_type_original_size - @string/scale_type_smart_fit - - - - @string/zoom_start_automatic - @string/zoom_start_left - @string/zoom_start_right - @string/zoom_start_center - - @string/label_default @string/rotation_free @@ -34,29 +18,4 @@ @string/rotation_force_landscape @string/rotation_reverse_portrait - - - @string/tapping_inverted_none - @string/tapping_inverted_horizontal - @string/tapping_inverted_vertical - @string/tapping_inverted_both - - - - @string/label_default - @string/l_nav - @string/kindlish_nav - @string/edge_nav - @string/right_and_left_nav - @string/disabled_nav - - - - @string/label_default - @string/l_nav - @string/kindlish_nav - @string/edge_nav - @string/right_and_left_nav - @string/disabled_nav - From 28131ac1357e1134d75c02e2a3bb5e3161a3ecfe Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 11:10:01 -0400 Subject: [PATCH 07/15] Remove legacy settings sheet The per-series settings aren't quite functional yet, but they're also accessible outside of the sheet. --- .../reader/settings/ReadingModePage.kt | 32 ++++- .../tachiyomi/ui/reader/ReaderActivity.kt | 23 ++-- .../tachiyomi/ui/reader/ReaderViewModel.kt | 8 +- .../setting/ReaderSettingsScreenModel.kt | 15 +++ .../ui/reader/setting/ReaderSettingsSheet.kt | 38 ------ .../util/preference/PreferenceExtensions.kt | 9 -- .../view/BottomSheetBehaviorExtensions.kt | 12 -- .../tachiyomi/util/view/WindowExtensions.kt | 23 ---- .../tachiyomi/widget/MaterialSpinnerView.kt | 117 ------------------ .../main/res/anim/bottom_sheet_slide_in.xml | 10 -- .../main/res/anim/bottom_sheet_slide_out.xml | 10 -- .../main/res/drawable/ic_expand_more_24dp.xml | 9 -- app/src/main/res/layout/pref_spinner.xml | 58 --------- app/src/main/res/layout/reader_activity.xml | 15 +-- .../layout/reader_reading_mode_settings.xml | 29 ----- app/src/main/res/values/attrs.xml | 10 -- app/src/main/res/values/dimens.xml | 2 - app/src/main/res/values/styles.xml | 49 -------- app/src/main/res/values/themes.xml | 4 - 19 files changed, 55 insertions(+), 418 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/view/BottomSheetBehaviorExtensions.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt delete mode 100644 app/src/main/res/anim/bottom_sheet_slide_in.xml delete mode 100644 app/src/main/res/anim/bottom_sheet_slide_out.xml delete mode 100644 app/src/main/res/drawable/ic_expand_more_24dp.xml delete mode 100644 app/src/main/res/layout/pref_spinner.xml delete mode 100644 app/src/main/res/layout/reader_reading_mode_settings.xml delete mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index 48d002a1b..425d7bbff 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -2,13 +2,17 @@ package eu.kanade.presentation.reader.settings import androidx.compose.foundation.layout.ColumnScope import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource import eu.kanade.presentation.util.collectAsState import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel +import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem @@ -22,16 +26,32 @@ internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) HeadingItem(R.string.pref_category_for_this_series) - // TODO: Reading mode HeadingItem(R.string.pref_category_reading_mode) + ReadingModeType.values().map { + RadioItem( + label = stringResource(it.stringRes), + // TODO: Reading mode + selected = false, + onClick = { screenModel.onChangeReadingMode(it) }, + ) + } - // TODO: Rotation type HeadingItem(R.string.rotation_type) + OrientationType.values().map { + RadioItem( + label = stringResource(it.stringRes), + // TODO: Rotation type + selected = false, + onClick = { screenModel.onChangeOrientation(it) }, + ) + } - // TODO: if (pager) - PagerViewerSettings(screenModel) - - WebtoonViewerSettings(screenModel) + val viewer by screenModel.viewerFlow.collectAsState() + if (viewer is WebtoonViewer) { + WebtoonViewerSettings(screenModel) + } else { + PagerViewerSettings(screenModel) + } } @Composable diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index a8acff615..f7afede9e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -69,7 +69,6 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel -import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer @@ -391,7 +390,13 @@ class ReaderActivity : BaseActivity() { binding.dialogRoot.setComposeContent { val state by viewModel.state.collectAsState() - val settingsScreenModel = remember { ReaderSettingsScreenModel() } + val settingsScreenModel = remember { + ReaderSettingsScreenModel( + readerState = viewModel.state, + onChangeReadingMode = viewModel::setMangaReadingMode, + onChangeOrientation = viewModel::setMangaOrientationType, + ) + } val onDismissRequest = viewModel::closeDialog when (state.dialog) { @@ -485,7 +490,7 @@ class ReaderActivity : BaseActivity() { ) { val newReadingMode = ReadingModeType.fromPreference(itemId) - viewModel.setMangaReadingMode(newReadingMode.flagValue) + viewModel.setMangaReadingMode(newReadingMode) menuToggleToast?.cancel() if (!readerPreferences.showReadingMode().get()) { @@ -539,7 +544,7 @@ class ReaderActivity : BaseActivity() { ) { val newOrientation = OrientationType.fromPreference(itemId) - viewModel.setMangaOrientationType(newOrientation.flagValue) + viewModel.setMangaOrientationType(newOrientation) menuToggleToast?.cancel() menuToggleToast = toast(newOrientation.stringRes) @@ -548,16 +553,6 @@ class ReaderActivity : BaseActivity() { } // Settings sheet - with(binding.actionSettingsLegacy) { - setTooltip(R.string.action_settings) - - var readerSettingSheet: ReaderSettingsSheet? = null - - setOnClickListener { - if (readerSettingSheet?.isShowing == true) return@setOnClickListener - readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity).apply { show() } - } - } with(binding.actionSettings) { setTooltip(R.string.action_settings) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index 0fa5423c3..797096738 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -602,10 +602,10 @@ class ReaderViewModel( /** * Updates the viewer position for the open manga. */ - fun setMangaReadingMode(readingModeType: Int) { + fun setMangaReadingMode(readingModeType: ReadingModeType) { val manga = manga ?: return runBlocking(Dispatchers.IO) { - setMangaViewerFlags.awaitSetMangaReadingMode(manga.id, readingModeType.toLong()) + setMangaViewerFlags.awaitSetMangaReadingMode(manga.id, readingModeType.flagValue.toLong()) val currChapters = state.value.viewerChapters if (currChapters != null) { // Save current page @@ -638,10 +638,10 @@ class ReaderViewModel( /** * Updates the orientation type for the open manga. */ - fun setMangaOrientationType(rotationType: Int) { + fun setMangaOrientationType(rotationType: OrientationType) { val manga = manga ?: return viewModelScope.launchIO { - setMangaViewerFlags.awaitSetOrientationType(manga.id, rotationType.toLong()) + setMangaViewerFlags.awaitSetOrientationType(manga.id, rotationType.flagValue.toLong()) val currChapters = state.value.viewerChapters if (currChapters != null) { // Save current page diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt index 6a9ad2936..87068fa61 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt @@ -1,15 +1,30 @@ package eu.kanade.tachiyomi.ui.reader.setting import cafe.adriel.voyager.core.model.ScreenModel +import eu.kanade.presentation.util.ioCoroutineScope +import eu.kanade.tachiyomi.ui.reader.ReaderViewModel import eu.kanade.tachiyomi.util.preference.toggle +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import tachiyomi.core.preference.Preference import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class ReaderSettingsScreenModel( + readerState: StateFlow, + val onChangeReadingMode: (ReadingModeType) -> Unit, + val onChangeOrientation: (OrientationType) -> Unit, val preferences: ReaderPreferences = Injekt.get(), ) : ScreenModel { + val viewerFlow = readerState + .map { it.viewer } + .distinctUntilChanged() + .stateIn(ioCoroutineScope, SharingStarted.Lazily, null) + fun togglePreference(preference: (ReaderPreferences) -> Preference) { preference(preferences).toggle() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt deleted file mode 100644 index a54aa233b..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt +++ /dev/null @@ -1,38 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.setting - -import android.os.Bundle -import com.google.android.material.bottomsheet.BottomSheetDialog -import eu.kanade.domain.manga.model.orientationType -import eu.kanade.domain.manga.model.readingModeType -import eu.kanade.tachiyomi.databinding.ReaderReadingModeSettingsBinding -import eu.kanade.tachiyomi.ui.reader.ReaderActivity - -class ReaderSettingsSheet( - private val activity: ReaderActivity, -) : BottomSheetDialog(activity) { - - private lateinit var binding: ReaderReadingModeSettingsBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = ReaderReadingModeSettingsBinding.inflate(activity.layoutInflater) - setContentView(binding.root) - - initGeneralPreferences() - } - - private fun initGeneralPreferences() { - binding.viewer.onItemSelectedListener = { position -> - val readingModeType = ReadingModeType.fromSpinner(position) - activity.viewModel.setMangaReadingMode(readingModeType.flagValue) - } - binding.viewer.setSelection(activity.viewModel.manga?.readingModeType?.let { ReadingModeType.fromPreference(it.toInt()).prefValue } ?: ReadingModeType.DEFAULT.prefValue) - - binding.rotationMode.onItemSelectedListener = { position -> - val rotationType = OrientationType.fromSpinner(position) - activity.viewModel.setMangaOrientationType(rotationType.flagValue) - } - binding.rotationMode.setSelection(activity.viewModel.manga?.orientationType?.let { OrientationType.fromPreference(it.toInt()).prefValue } ?: OrientationType.DEFAULT.prefValue) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceExtensions.kt index 7009635c6..887fc7e2e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceExtensions.kt @@ -1,16 +1,7 @@ package eu.kanade.tachiyomi.util.preference -import android.widget.CompoundButton import tachiyomi.core.preference.Preference -/** - * Binds a checkbox or switch view with a boolean preference. - */ -fun CompoundButton.bindToPreference(pref: Preference) { - isChecked = pref.get() - setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) } -} - operator fun Preference>.plusAssign(item: T) { set(get() + item) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/BottomSheetBehaviorExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/BottomSheetBehaviorExtensions.kt deleted file mode 100644 index a5da1a432..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/BottomSheetBehaviorExtensions.kt +++ /dev/null @@ -1,12 +0,0 @@ -@file:Suppress("PackageDirectoryMismatch") - -package com.google.android.material.bottomsheet - -import android.view.View - -/** - * Returns package-private elevation value - */ -fun BottomSheetBehavior.getElevation(): Float { - return elevation.takeIf { it >= 0F } ?: 0F -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt index fc5a2fc1f..1a60b8e1e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt @@ -1,30 +1,7 @@ package eu.kanade.tachiyomi.util.view -import android.content.Context -import android.graphics.Color import android.view.Window import android.view.WindowManager -import com.google.android.material.elevation.ElevationOverlayProvider -import eu.kanade.tachiyomi.util.system.getResourceColor -import eu.kanade.tachiyomi.util.system.isNavigationBarNeedsScrim - -/** - * Sets navigation bar color to transparent if system's config_navBarNeedsScrim is false, - * otherwise it will use the theme navigationBarColor with 70% opacity. - * - * @see isNavigationBarNeedsScrim - */ -fun Window.setNavigationBarTransparentCompat(context: Context, elevation: Float = 0F) { - navigationBarColor = if (context.isNavigationBarNeedsScrim()) { - // Set navbar scrim 70% of navigationBarColor - ElevationOverlayProvider(context).compositeOverlayIfNeeded( - context.getResourceColor(android.R.attr.navigationBarColor, 0.7F), - elevation, - ) - } else { - Color.TRANSPARENT - } -} fun Window.setSecureScreen(enabled: Boolean) { if (enabled) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt deleted file mode 100644 index 54160cf71..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt +++ /dev/null @@ -1,117 +0,0 @@ -package eu.kanade.tachiyomi.widget - -import android.annotation.SuppressLint -import android.content.Context -import android.util.AttributeSet -import android.view.Gravity -import android.view.LayoutInflater -import android.view.MenuItem -import android.widget.FrameLayout -import androidx.appcompat.content.res.AppCompatResources -import androidx.appcompat.view.menu.MenuBuilder -import androidx.appcompat.widget.PopupMenu -import androidx.core.content.withStyledAttributes -import androidx.core.view.forEach -import androidx.core.view.get -import androidx.core.view.size -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.databinding.PrefSpinnerBinding -import eu.kanade.tachiyomi.util.system.getResourceColor -import tachiyomi.core.preference.Preference - -class MaterialSpinnerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - FrameLayout(context, attrs) { - - private var entries = emptyList() - private var selectedPosition = 0 - private var popup: PopupMenu? = null - - var onItemSelectedListener: ((Int) -> Unit)? = null - set(value) { - field = value - if (value != null) { - popup = makeSettingsPopup() - setOnTouchListener(popup?.dragToOpenListener) - setOnClickListener { - popup?.show() - } - } - } - - private val emptyIcon by lazy { - AppCompatResources.getDrawable(context, R.drawable.ic_blank_24dp) - } - private val checkmarkIcon by lazy { - AppCompatResources.getDrawable(context, R.drawable.ic_check_24dp)?.mutate()?.apply { - setTint(context.getResourceColor(android.R.attr.textColorPrimary)) - } - } - - private val binding = PrefSpinnerBinding.inflate(LayoutInflater.from(context), this, false) - - init { - addView(binding.root) - - context.withStyledAttributes(set = attrs, attrs = R.styleable.MaterialSpinnerView) { - val title = getString(R.styleable.MaterialSpinnerView_title).orEmpty() - binding.title.text = title - - val viewEntries = getTextArray(R.styleable.MaterialSpinnerView_android_entries) - .orEmpty() - .map { it.toString() } - entries = viewEntries - binding.details.text = viewEntries.firstOrNull().orEmpty() - } - } - - fun setSelection(selection: Int) { - if (selectedPosition < (popup?.menu?.size ?: 0)) { - popup?.menu?.getItem(selectedPosition)?.let { - it.icon = emptyIcon - } - } - selectedPosition = selection - popup?.menu?.getItem(selectedPosition)?.let { - it.icon = checkmarkIcon - } - binding.details.text = entries.getOrNull(selection).orEmpty() - } - - private fun makeSettingsPopup(preference: Preference, offset: Int = 0, block: ((Int) -> Unit)? = null): PopupMenu { - return createPopupMenu { pos -> - preference.set(pos + offset) - block?.invoke(pos) - } - } - - private fun makeSettingsPopup(): PopupMenu { - return createPopupMenu { pos -> - onItemSelectedListener?.invoke(pos) - } - } - - private fun menuClicked(menuItem: MenuItem): Int { - val pos = menuItem.itemId - setSelection(pos) - return pos - } - - @SuppressLint("RestrictedApi") - fun createPopupMenu(onItemClick: (Int) -> Unit): PopupMenu { - val popup = PopupMenu(context, this, Gravity.END, R.attr.actionOverflowMenuStyle, 0) - entries.forEachIndexed { index, entry -> - popup.menu.add(0, index, 0, entry) - } - (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true) - popup.menu.forEach { - it.icon = emptyIcon - } - popup.menu[selectedPosition].icon = checkmarkIcon - popup.setOnMenuItemClickListener { menuItem -> - val pos = menuClicked(menuItem) - onItemClick(pos) - true - } - return popup - } -} diff --git a/app/src/main/res/anim/bottom_sheet_slide_in.xml b/app/src/main/res/anim/bottom_sheet_slide_in.xml deleted file mode 100644 index 74f052a3f..000000000 --- a/app/src/main/res/anim/bottom_sheet_slide_in.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/app/src/main/res/anim/bottom_sheet_slide_out.xml b/app/src/main/res/anim/bottom_sheet_slide_out.xml deleted file mode 100644 index 553c827a5..000000000 --- a/app/src/main/res/anim/bottom_sheet_slide_out.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_expand_more_24dp.xml b/app/src/main/res/drawable/ic_expand_more_24dp.xml deleted file mode 100644 index 5f5ba4e44..000000000 --- a/app/src/main/res/drawable/ic_expand_more_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/pref_spinner.xml b/app/src/main/res/layout/pref_spinner.xml deleted file mode 100644 index c7335fa1f..000000000 --- a/app/src/main/res/layout/pref_spinner.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index afd40f4c9..b5dd2778b 100644 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -118,19 +118,6 @@ app:srcCompat="@drawable/ic_screen_rotation_24dp" app:tint="?attr/colorOnSurface" /> - - diff --git a/app/src/main/res/layout/reader_reading_mode_settings.xml b/app/src/main/res/layout/reader_reading_mode_settings.xml deleted file mode 100644 index 39b824939..000000000 --- a/app/src/main/res/layout/reader_reading_mode_settings.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml deleted file mode 100644 index d644cdf85..000000000 --- a/app/src/main/res/values/attrs.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f6f722017..e82288767 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,6 +1,4 @@ - 8dp - 16dp 16dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index fdcafe4c4..14dc1a13a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -20,33 +20,6 @@ - - - - - - - - - - - - - @@ -71,18 +44,6 @@ - - - - - - @@ -94,16 +55,6 @@ @bool/elevationOverlayEnabled - - - - - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 50aa51d0e..b61c34eb9 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -64,17 +64,13 @@ 0.32 true @style/Theme.Tachiyomi.ActionButton.Overflow - @drawable/ic_close_24dp @style/PreferenceThemeOverlay.Tachiyomi - @style/ThemeOverlay.Tachiyomi.BottomSheetDialog @style/Widget.Material3.TextInputLayout.OutlinedBox @style/Widget.Material3.AppBarLayout @style/Widget.Material3.Toolbar.Surface - @style/Widget.Tachiyomi.TabLayout @style/Widget.Tachiyomi.Switch @style/Widget.Material3.CompoundButton.MaterialSwitch @style/Widget.Tachiyomi.Switch - @style/Widget.Tachiyomi.Slider @style/Widget.Material3.CardView.Elevated From fb99577836955bde8d13d79492a20d835cf288c0 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 12:39:36 -0400 Subject: [PATCH 08/15] Implement showing selected per-series reader settings --- .../presentation/reader/settings/ReadingModePage.kt | 12 ++++++++---- .../tachiyomi/ui/reader/setting/OrientationType.kt | 4 +--- .../ui/reader/setting/ReaderSettingsScreenModel.kt | 5 +++++ .../tachiyomi/ui/reader/setting/ReadingModeType.kt | 2 -- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index 425d7bbff..6fbd4f5d4 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -6,6 +6,8 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource +import eu.kanade.domain.manga.model.orientationType +import eu.kanade.domain.manga.model.readingModeType import eu.kanade.presentation.util.collectAsState import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.OrientationType @@ -26,12 +28,15 @@ internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) HeadingItem(R.string.pref_category_for_this_series) + val manga by screenModel.mangaFlow.collectAsState() + val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } + val orientation = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } + HeadingItem(R.string.pref_category_reading_mode) ReadingModeType.values().map { RadioItem( label = stringResource(it.stringRes), - // TODO: Reading mode - selected = false, + selected = readingMode == it, onClick = { screenModel.onChangeReadingMode(it) }, ) } @@ -40,8 +45,7 @@ internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) OrientationType.values().map { RadioItem( label = stringResource(it.stringRes), - // TODO: Rotation type - selected = false, + selected = orientation == it, onClick = { screenModel.onChangeOrientation(it) }, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt index fb7df6282..0125a78a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt @@ -18,8 +18,6 @@ enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val str companion object { const val MASK = 0x00000038 - fun fromPreference(preference: Int?): OrientationType = values().find { it.flagValue == preference } ?: FREE - - fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT + fun fromPreference(preference: Int?): OrientationType = values().find { it.flagValue == preference } ?: DEFAULT } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt index 87068fa61..11125ac77 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt @@ -25,6 +25,11 @@ class ReaderSettingsScreenModel( .distinctUntilChanged() .stateIn(ioCoroutineScope, SharingStarted.Lazily, null) + val mangaFlow = readerState + .map { it.manga } + .distinctUntilChanged() + .stateIn(ioCoroutineScope, SharingStarted.Lazily, null) + fun togglePreference(preference: (ReaderPreferences) -> Preference) { preference(preferences).toggle() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt index 88e1a3f02..73975e28f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt @@ -29,8 +29,6 @@ enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @D return mode == LEFT_TO_RIGHT || mode == RIGHT_TO_LEFT || mode == VERTICAL } - fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT - fun toViewer(preference: Int?, activity: ReaderActivity): Viewer { return when (fromPreference(preference)) { LEFT_TO_RIGHT -> L2RPagerViewer(activity) From 1cf7f9be54fda2385953f7b2dd91191bc01b21ba Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 13:05:06 -0400 Subject: [PATCH 09/15] Use segmented buttons for reader background setting in sheet --- .../reader/settings/GeneralSettingsPage.kt | 37 +++++--- i18n/src/main/res/values/strings.xml | 2 +- .../components/material/SegmentedButtons.kt | 90 +++++++++++++++++++ 3 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/components/material/SegmentedButtons.kt diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt index 02738eeda..f04776bf6 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt @@ -1,34 +1,43 @@ package eu.kanade.presentation.reader.settings import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import eu.kanade.presentation.util.collectAsState import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem -import tachiyomi.presentation.core.components.RadioItem +import tachiyomi.presentation.core.components.SettingsItemsPaddings +import tachiyomi.presentation.core.components.material.SegmentedButtons + +private val themes = listOf( + R.string.black_background to 1, + R.string.gray_background to 2, + R.string.white_background to 0, + R.string.automatic_background to 3, +) @Composable internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { - // TODO: show this in a nicer way HeadingItem(R.string.pref_reader_theme) val readerTheme by screenModel.preferences.readerTheme().collectAsState() - listOf( - R.string.black_background to 1, - R.string.gray_background to 2, - R.string.white_background to 0, - R.string.automatic_background to 3, - ).map { (titleRes, theme) -> - RadioItem( - label = stringResource(titleRes), - selected = readerTheme == theme, - onClick = { screenModel.preferences.readerTheme().set(theme) }, - ) - } + SegmentedButtons( + modifier = Modifier.padding( + start = SettingsItemsPaddings.Horizontal, + top = 0.dp, + end = SettingsItemsPaddings.Horizontal, + bottom = SettingsItemsPaddings.Vertical, + ), + entries = themes.map { stringResource(it.first) }, + selectedIndex = themes.indexOfFirst { readerTheme == it.second }, + onClick = { screenModel.preferences.readerTheme().set(themes[it].second) }, + ) val showPageNumber by screenModel.preferences.showPageNumber().collectAsState() CheckboxItem( diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 3df318c7e..3d0d9b9d8 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -383,7 +383,7 @@ White Gray Black - Automatic + Auto Default reading mode L shaped Kindle-ish diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/SegmentedButtons.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/SegmentedButtons.kt new file mode 100644 index 000000000..7656af007 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/SegmentedButtons.kt @@ -0,0 +1,90 @@ +package tachiyomi.presentation.core.components.material + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview + +val StartItemShape = RoundedCornerShape(topStartPercent = 100, bottomStartPercent = 100) +val MiddleItemShape = RoundedCornerShape(0) +val EndItemShape = RoundedCornerShape(topEndPercent = 100, bottomEndPercent = 100) + +@Composable +fun SegmentedButtons( + modifier: Modifier = Modifier, + entries: List, + selectedIndex: Int, + onClick: (Int) -> Unit, +) { + Row( + modifier = modifier, + ) { + entries.mapIndexed { index, label -> + val shape = remember(entries, index) { + when (index) { + 0 -> StartItemShape + entries.lastIndex -> EndItemShape + else -> MiddleItemShape + } + } + + if (index == selectedIndex) { + Button( + modifier = Modifier.weight(1f), + shape = shape, + onClick = { onClick(index) }, + ) { + Text( + text = label, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } else { + OutlinedButton( + modifier = Modifier.weight(1f), + shape = shape, + onClick = { onClick(index) }, + ) { + Text( + text = label, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + } + } +} + +@Preview +@Composable +private fun SegmentedButtonsPreview() { + Column { + SegmentedButtons( + entries = listOf( + "Day", + "Week", + "Month", + "Year", + ), + selectedIndex = 1, + onClick = {}, + ) + + SegmentedButtons( + entries = listOf( + "Foo", + "Bar", + ), + selectedIndex = 1, + onClick = {}, + ) + } +} From e0733c1a4cef28cf413ca79597ba5ad739b5328a Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 13:05:25 -0400 Subject: [PATCH 10/15] Clean up NetworkHelper --- .../kanade/tachiyomi/network/NetworkHelper.kt | 87 +++++++++---------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 54d185883..8af3d45be 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -11,67 +11,60 @@ import java.io.File import java.util.concurrent.TimeUnit class NetworkHelper( - context: Context, + private val context: Context, private val preferences: NetworkPreferences, ) { - private val cacheDir = File(context.cacheDir, "network_cache") - private val cacheSize = 5L * 1024 * 1024 // 5 MiB + val cookieJar by lazy { AndroidCookieJar() } - val cookieJar = AndroidCookieJar() + val client by lazy { + val builder = OkHttpClient.Builder() + .cookieJar(cookieJar) + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .callTimeout(2, TimeUnit.MINUTES) + .cache( + Cache( + directory = File(context.cacheDir, "network_cache"), + maxSize = 5L * 1024 * 1024, // 5 MiB + ), + ) + .addInterceptor(UncaughtExceptionInterceptor()) + .addInterceptor(UserAgentInterceptor(::defaultUserAgentProvider)) - private val userAgentInterceptor by lazy { - UserAgentInterceptor(::defaultUserAgentProvider) - } - private val cloudflareInterceptor by lazy { - CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider) - } - - private val baseClientBuilder: OkHttpClient.Builder - get() { - val builder = OkHttpClient.Builder() - .cookieJar(cookieJar) - .connectTimeout(30, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .callTimeout(2, TimeUnit.MINUTES) - .addInterceptor(UncaughtExceptionInterceptor()) - .addInterceptor(userAgentInterceptor) - - if (preferences.verboseLogging().get()) { - val httpLoggingInterceptor = HttpLoggingInterceptor().apply { - level = HttpLoggingInterceptor.Level.HEADERS - } - builder.addNetworkInterceptor(httpLoggingInterceptor) + if (preferences.verboseLogging().get()) { + val httpLoggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.HEADERS } - - builder.addInterceptor(cloudflareInterceptor) - - when (preferences.dohProvider().get()) { - PREF_DOH_CLOUDFLARE -> builder.dohCloudflare() - PREF_DOH_GOOGLE -> builder.dohGoogle() - PREF_DOH_ADGUARD -> builder.dohAdGuard() - PREF_DOH_QUAD9 -> builder.dohQuad9() - PREF_DOH_ALIDNS -> builder.dohAliDNS() - PREF_DOH_DNSPOD -> builder.dohDNSPod() - PREF_DOH_360 -> builder.doh360() - PREF_DOH_QUAD101 -> builder.dohQuad101() - PREF_DOH_MULLVAD -> builder.dohMullvad() - PREF_DOH_CONTROLD -> builder.dohControlD() - PREF_DOH_NJALLA -> builder.dohNajalla() - PREF_DOH_SHECAN -> builder.dohShecan() - } - - return builder + builder.addNetworkInterceptor(httpLoggingInterceptor) } - val client by lazy { baseClientBuilder.cache(Cache(cacheDir, cacheSize)).build() } + builder.addInterceptor(CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider)) + + when (preferences.dohProvider().get()) { + PREF_DOH_CLOUDFLARE -> builder.dohCloudflare() + PREF_DOH_GOOGLE -> builder.dohGoogle() + PREF_DOH_ADGUARD -> builder.dohAdGuard() + PREF_DOH_QUAD9 -> builder.dohQuad9() + PREF_DOH_ALIDNS -> builder.dohAliDNS() + PREF_DOH_DNSPOD -> builder.dohDNSPod() + PREF_DOH_360 -> builder.doh360() + PREF_DOH_QUAD101 -> builder.dohQuad101() + PREF_DOH_MULLVAD -> builder.dohMullvad() + PREF_DOH_CONTROLD -> builder.dohControlD() + PREF_DOH_NJALLA -> builder.dohNajalla() + PREF_DOH_SHECAN -> builder.dohShecan() + } + + builder.build() + } /** * @deprecated Since extension-lib 1.5 */ @Deprecated("The regular client handles Cloudflare by default") @Suppress("UNUSED") - val cloudflareClient = client + val cloudflareClient by lazy { client } fun defaultUserAgentProvider() = preferences.defaultUserAgent().get().trim() } From 5467104b955fc854285f22f9be56083a1d503144 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 13:23:25 -0400 Subject: [PATCH 11/15] Fix window undimming when reader custom filter settings are open --- .../reader/settings/ReaderSettingsDialog.kt | 25 +++++++++---------- .../kanade/tachiyomi/ui/main/MainActivity.kt | 8 +++--- .../kanade/tachiyomi/network/NetworkHelper.kt | 6 ++--- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt index 44f1bc27f..cf5b08997 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReaderSettingsDialog.kt @@ -23,9 +23,6 @@ fun ReaderSettingsDialog( onHideMenus: () -> Unit, screenModel: ReaderSettingsScreenModel, ) { - // TODO: undimming doesn't seem to work - val window = (LocalView.current.parent as? DialogWindowProvider)?.window - val tabTitles = listOf( stringResource(R.string.pref_category_reading_mode), stringResource(R.string.pref_category_general), @@ -33,16 +30,6 @@ fun ReaderSettingsDialog( ) val pagerState = rememberPagerState { tabTitles.size } - LaunchedEffect(pagerState.currentPage) { - if (pagerState.currentPage == 2) { - window?.setDimAmount(0f) - onHideMenus() - } else { - window?.setDimAmount(0.75f) - onShowMenus() - } - } - TabbedDialog( onDismissRequest = { onDismissRequest() @@ -51,6 +38,18 @@ fun ReaderSettingsDialog( tabTitles = tabTitles, pagerState = pagerState, ) { page -> + val window = (LocalView.current.parent as? DialogWindowProvider)?.window + + LaunchedEffect(pagerState.currentPage) { + if (pagerState.currentPage == 2) { + window?.setDimAmount(0f) + onHideMenus() + } else { + window?.setDimAmount(0.5f) + onShowMenus() + } + } + Column( modifier = Modifier .padding(vertical = TabbedDialogPaddings.Vertical) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 4612eec34..9fd4674fe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -113,6 +113,10 @@ class MainActivity : BaseActivity() { private var navigator: Navigator? = null + init { + registerSecureActivity(this) + } + override fun onCreate(savedInstanceState: Bundle?) { val isLaunch = savedInstanceState == null @@ -429,10 +433,6 @@ class MainActivity : BaseActivity() { return true } - init { - registerSecureActivity(this) - } - companion object { // Splash screen private const val SPLASH_MIN_DURATION = 500 // ms diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 8af3d45be..38ba749d2 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -15,9 +15,9 @@ class NetworkHelper( private val preferences: NetworkPreferences, ) { - val cookieJar by lazy { AndroidCookieJar() } + val cookieJar = AndroidCookieJar() - val client by lazy { + val client: OkHttpClient = run { val builder = OkHttpClient.Builder() .cookieJar(cookieJar) .connectTimeout(30, TimeUnit.SECONDS) @@ -64,7 +64,7 @@ class NetworkHelper( */ @Deprecated("The regular client handles Cloudflare by default") @Suppress("UNUSED") - val cloudflareClient by lazy { client } + val cloudflareClient: OkHttpClient = client fun defaultUserAgentProvider() = preferences.defaultUserAgent().get().trim() } From 09e4b5a9cd753a7a3a64fa8d3a868ac68dfa767f Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 14:27:30 -0400 Subject: [PATCH 12/15] Replace some reader sheet settings with FlowRow of Chips --- .../reader/settings/ColorFilterPage.kt | 18 +++--- .../reader/settings/GeneralSettingsPage.kt | 30 ++++------ .../core/components/SettingsItems.kt | 42 +++++++++++-- .../core/components/material/Chip.kt | 60 +++++++++++++++++++ 4 files changed, 121 insertions(+), 29 deletions(-) create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Chip.kt diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt index 06bbb37b1..78f20cb8f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ColorFilterPage.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.reader.settings import android.os.Build import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.res.stringResource @@ -15,8 +16,9 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.core.preference.getAndSet import tachiyomi.presentation.core.components.CheckboxItem -import tachiyomi.presentation.core.components.SelectItem +import tachiyomi.presentation.core.components.SettingsFlowRow import tachiyomi.presentation.core.components.SliderItem +import tachiyomi.presentation.core.components.material.ChoiceChip @Composable internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) { @@ -122,12 +124,14 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) ) val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState() - SelectItem( - label = stringResource(R.string.pref_color_filter_mode), - options = colorFilterModes.toTypedArray(), - selectedIndex = colorFilterMode, - ) { - screenModel.preferences.colorFilterMode().set(it) + SettingsFlowRow(R.string.pref_color_filter_mode) { + colorFilterModes.mapIndexed { index, it -> + ChoiceChip( + isSelected = colorFilterMode == index, + onClick = { screenModel.preferences.colorFilterMode().set(index) }, + content = { Text(it) }, + ) + } } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt index f04776bf6..990a1423d 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt @@ -1,20 +1,17 @@ package eu.kanade.presentation.reader.settings import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import eu.kanade.presentation.util.collectAsState import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.presentation.core.components.CheckboxItem -import tachiyomi.presentation.core.components.HeadingItem -import tachiyomi.presentation.core.components.SettingsItemsPaddings -import tachiyomi.presentation.core.components.material.SegmentedButtons +import tachiyomi.presentation.core.components.SettingsFlowRow +import tachiyomi.presentation.core.components.material.ChoiceChip private val themes = listOf( R.string.black_background to 1, @@ -25,19 +22,16 @@ private val themes = listOf( @Composable internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { - HeadingItem(R.string.pref_reader_theme) val readerTheme by screenModel.preferences.readerTheme().collectAsState() - SegmentedButtons( - modifier = Modifier.padding( - start = SettingsItemsPaddings.Horizontal, - top = 0.dp, - end = SettingsItemsPaddings.Horizontal, - bottom = SettingsItemsPaddings.Vertical, - ), - entries = themes.map { stringResource(it.first) }, - selectedIndex = themes.indexOfFirst { readerTheme == it.second }, - onClick = { screenModel.preferences.readerTheme().set(themes[it].second) }, - ) + SettingsFlowRow(R.string.pref_reader_theme) { + themes.map { (labelRes, value) -> + ChoiceChip( + isSelected = readerTheme == value, + onClick = { screenModel.preferences.readerTheme().set(value) }, + content = { Text(stringResource(labelRes)) }, + ) + } + } val showPageNumber by screenModel.preferences.showPageNumber().collectAsState() CheckboxItem( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index d5ce4a5d2..d40a7747b 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -4,6 +4,8 @@ import androidx.annotation.StringRes import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.FlowRowScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer @@ -61,7 +63,10 @@ fun HeadingItem( style = MaterialTheme.typography.header, modifier = Modifier .fillMaxWidth() - .padding(horizontal = SettingsItemsPaddings.Horizontal, vertical = SettingsItemsPaddings.Vertical), + .padding( + horizontal = SettingsItemsPaddings.Horizontal, + vertical = SettingsItemsPaddings.Vertical, + ), ) } @@ -203,7 +208,10 @@ fun SelectItem( modifier = Modifier .menuAnchor() .fillMaxWidth() - .padding(horizontal = SettingsItemsPaddings.Horizontal, vertical = SettingsItemsPaddings.Vertical), + .padding( + horizontal = SettingsItemsPaddings.Horizontal, + vertical = SettingsItemsPaddings.Vertical, + ), label = { Text(text = label) }, value = options[selectedIndex].toString(), onValueChange = {}, @@ -259,7 +267,10 @@ fun TriStateItem( }, ) .fillMaxWidth() - .padding(horizontal = SettingsItemsPaddings.Horizontal, vertical = SettingsItemsPaddings.Vertical), + .padding( + horizontal = SettingsItemsPaddings.Horizontal, + vertical = SettingsItemsPaddings.Vertical, + ), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), ) { @@ -306,6 +317,26 @@ fun TextItem( ) } +@Composable +fun SettingsFlowRow( + @StringRes labelRes: Int, + content: @Composable FlowRowScope.() -> Unit, +) { + Column { + HeadingItem(labelRes) + FlowRow( + modifier = Modifier.padding( + start = SettingsItemsPaddings.Horizontal, + top = 0.dp, + end = SettingsItemsPaddings.Horizontal, + bottom = SettingsItemsPaddings.Vertical, + ), + horizontalArrangement = Arrangement.spacedBy(4.dp), + content = content, + ) + } +} + @Composable private fun BaseSettingsItem( label: String, @@ -316,7 +347,10 @@ private fun BaseSettingsItem( modifier = Modifier .clickable(onClick = onClick) .fillMaxWidth() - .padding(horizontal = SettingsItemsPaddings.Horizontal, vertical = SettingsItemsPaddings.Vertical), + .padding( + horizontal = SettingsItemsPaddings.Horizontal, + vertical = SettingsItemsPaddings.Vertical, + ), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), ) { diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Chip.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Chip.kt new file mode 100644 index 000000000..55d988f52 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Chip.kt @@ -0,0 +1,60 @@ +package tachiyomi.presentation.core.components.material + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ProvideTextStyle +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun Chip( + modifier: Modifier = Modifier, + backgroundColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.15f), + contentColor: Color = MaterialTheme.colorScheme.onSurface, + onClick: () -> Unit = {}, + content: @Composable () -> Unit, +) { + Surface( + modifier = Modifier, + shape = CircleShape, + color = backgroundColor, + contentColor = contentColor, + onClick = {}, + ) { + Row( + modifier = modifier.clickable(onClick = onClick) + .widthIn(min = 56.dp) + .requiredHeight(32.dp) + .padding(horizontal = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + ) { + ProvideTextStyle(MaterialTheme.typography.bodySmall, content) + } + } +} + +@Composable +fun ChoiceChip( + modifier: Modifier = Modifier, + isSelected: Boolean, + onClick: () -> Unit = {}, + selectedBackgroundColor: Color = MaterialTheme.colorScheme.primary, + selectedContentColor: Color = MaterialTheme.colorScheme.onPrimary, + content: @Composable () -> Unit, +) { + if (isSelected) { + Chip(modifier, selectedBackgroundColor, selectedContentColor, onClick, content) + } else { + Chip(modifier, onClick = onClick, content = content) + } +} From 30bea8b753fbc40b1c889bdc180cb99f643f89e8 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 15 Jul 2023 14:31:13 -0400 Subject: [PATCH 13/15] Replace library sheet display modes with FlowRow of Chips --- .../library/LibrarySettingsDialog.kt | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index d91f8fc04..1db4c0f18 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -25,10 +26,11 @@ import tachiyomi.domain.library.model.sort import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem -import tachiyomi.presentation.core.components.RadioItem +import tachiyomi.presentation.core.components.SettingsFlowRow import tachiyomi.presentation.core.components.SliderItem import tachiyomi.presentation.core.components.SortItem import tachiyomi.presentation.core.components.TriStateItem +import tachiyomi.presentation.core.components.material.ChoiceChip @Composable fun LibrarySettingsDialog( @@ -167,23 +169,26 @@ private fun ColumnScope.SortPage( } } +private val displayModes = listOf( + R.string.action_display_grid to LibraryDisplayMode.CompactGrid, + R.string.action_display_comfortable_grid to LibraryDisplayMode.ComfortableGrid, + R.string.action_display_cover_only_grid to LibraryDisplayMode.CoverOnlyGrid, + R.string.action_display_list to LibraryDisplayMode.List, +) + @Composable private fun ColumnScope.DisplayPage( screenModel: LibrarySettingsScreenModel, ) { - 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, - R.string.action_display_cover_only_grid to LibraryDisplayMode.CoverOnlyGrid, - R.string.action_display_list to LibraryDisplayMode.List, - ).map { (titleRes, mode) -> - RadioItem( - label = stringResource(titleRes), - selected = displayMode == mode, - onClick = { screenModel.setDisplayMode(mode) }, - ) + SettingsFlowRow(R.string.action_display_mode) { + displayModes.map { (titleRes, mode) -> + ChoiceChip( + isSelected = displayMode == mode, + onClick = { screenModel.setDisplayMode(mode) }, + content = { Text(stringResource(titleRes)) }, + ) + } } if (displayMode != LibraryDisplayMode.List) { From ec08ba05fcc6cb2c77ae64016b9eafc2125733ba Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 16 Jul 2023 01:47:01 +0600 Subject: [PATCH 14/15] Finish up reader reading mode settings compose migration (#9721) --- .../reader/settings/ReadingModePage.kt | 127 ++++++++---------- 1 file changed, 59 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index 6fbd4f5d4..7ada769df 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -18,36 +18,35 @@ import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem -import tachiyomi.presentation.core.components.RadioItem +import tachiyomi.presentation.core.components.SelectItem import tachiyomi.presentation.core.components.SliderItem import java.text.NumberFormat +private val readingModeOptions = ReadingModeType.values().map { it.stringRes to it } +private val orientationTypeOptions = OrientationType.values().map { it.stringRes to it } +private val tappingInvertModeOptions = ReaderPreferences.TappingInvertMode.values().map { it.titleResId to it } + @Composable internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) { - HeadingItem("This is still a WIP, the UI will be improved soon") - HeadingItem(R.string.pref_category_for_this_series) - val manga by screenModel.mangaFlow.collectAsState() - val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } - val orientation = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } - HeadingItem(R.string.pref_category_reading_mode) - ReadingModeType.values().map { - RadioItem( - label = stringResource(it.stringRes), - selected = readingMode == it, - onClick = { screenModel.onChangeReadingMode(it) }, - ) + val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } + SelectItem( + label = stringResource(R.string.pref_category_reading_mode), + options = readingModeOptions.map { stringResource(it.first) }.toTypedArray(), + selectedIndex = readingModeOptions.indexOfFirst { it.second == readingMode }, + ) { + screenModel.onChangeReadingMode(readingModeOptions[it].second) } - HeadingItem(R.string.rotation_type) - OrientationType.values().map { - RadioItem( - label = stringResource(it.stringRes), - selected = orientation == it, - onClick = { screenModel.onChangeOrientation(it) }, - ) + val orientationType = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } + SelectItem( + label = stringResource(R.string.rotation_type), + options = orientationTypeOptions.map { stringResource(it.first) }.toTypedArray(), + selectedIndex = orientationTypeOptions.indexOfFirst { it.second == orientationType }, + ) { + screenModel.onChangeOrientation(orientationTypeOptions[it].second) } val viewer by screenModel.viewerFlow.collectAsState() @@ -63,46 +62,40 @@ private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenMod HeadingItem(R.string.pager_viewer) val navigationModePager by screenModel.preferences.navigationModePager().collectAsState() - HeadingItem(R.string.pref_viewer_nav) - ReaderPreferences.TapZones.mapIndexed { index, titleResId -> - RadioItem( - label = stringResource(titleResId), - selected = navigationModePager == index, - onClick = { screenModel.preferences.navigationModePager().set(index) }, - ) - } + SelectItem( + label = stringResource(R.string.pref_viewer_nav), + options = ReaderPreferences.TapZones.map { stringResource(it) }.toTypedArray(), + selectedIndex = navigationModePager, + onSelect = { screenModel.preferences.navigationModePager().set(it) }, + ) if (navigationModePager != 5) { val pagerNavInverted by screenModel.preferences.pagerNavInverted().collectAsState() - HeadingItem(R.string.pref_read_with_tapping_inverted) - ReaderPreferences.TappingInvertMode.values().map { - RadioItem( - label = stringResource(it.titleResId), - selected = pagerNavInverted == it, - onClick = { screenModel.preferences.pagerNavInverted().set(it) }, - ) - } + SelectItem( + label = stringResource(R.string.pref_read_with_tapping_inverted), + options = tappingInvertModeOptions.map { stringResource(it.first) }.toTypedArray(), + selectedIndex = tappingInvertModeOptions.indexOfFirst { it.second == pagerNavInverted }, + onSelect = { + screenModel.preferences.pagerNavInverted().set(tappingInvertModeOptions[it].second) + }, + ) } val imageScaleType by screenModel.preferences.imageScaleType().collectAsState() - HeadingItem(R.string.pref_image_scale_type) - ReaderPreferences.ImageScaleType.mapIndexed { index, it -> - RadioItem( - label = stringResource(it), - selected = imageScaleType == index + 1, - onClick = { screenModel.preferences.imageScaleType().set(index + 1) }, - ) - } + SelectItem( + label = stringResource(R.string.pref_image_scale_type), + options = ReaderPreferences.ImageScaleType.map { stringResource(it) }.toTypedArray(), + selectedIndex = imageScaleType - 1, + onSelect = { screenModel.preferences.imageScaleType().set(it + 1) }, + ) val zoomStart by screenModel.preferences.zoomStart().collectAsState() - HeadingItem(R.string.pref_zoom_start) - ReaderPreferences.ZoomStart.mapIndexed { index, it -> - RadioItem( - label = stringResource(it), - selected = zoomStart == index + 1, - onClick = { screenModel.preferences.zoomStart().set(index + 1) }, - ) - } + SelectItem( + label = stringResource(R.string.pref_zoom_start), + options = ReaderPreferences.ZoomStart.map { stringResource(it) }.toTypedArray(), + selectedIndex = zoomStart - 1, + onSelect = { screenModel.preferences.zoomStart().set(it + 1) }, + ) val cropBorders by screenModel.preferences.cropBorders().collectAsState() CheckboxItem( @@ -179,25 +172,23 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM HeadingItem(R.string.webtoon_viewer) val navigationModeWebtoon by screenModel.preferences.navigationModeWebtoon().collectAsState() - HeadingItem(R.string.pref_viewer_nav) - ReaderPreferences.TapZones.mapIndexed { index, titleResId -> - RadioItem( - label = stringResource(titleResId), - selected = navigationModeWebtoon == index, - onClick = { screenModel.preferences.navigationModeWebtoon().set(index) }, - ) - } + SelectItem( + label = stringResource(R.string.pref_viewer_nav), + options = ReaderPreferences.TapZones.map { stringResource(it) }.toTypedArray(), + selectedIndex = navigationModeWebtoon, + onSelect = { screenModel.preferences.navigationModeWebtoon().set(it) }, + ) if (navigationModeWebtoon != 5) { val webtoonNavInverted by screenModel.preferences.webtoonNavInverted().collectAsState() - HeadingItem(R.string.pref_read_with_tapping_inverted) - ReaderPreferences.TappingInvertMode.values().map { - RadioItem( - label = stringResource(it.titleResId), - selected = webtoonNavInverted == it, - onClick = { screenModel.preferences.webtoonNavInverted().set(it) }, - ) - } + SelectItem( + label = stringResource(R.string.pref_read_with_tapping_inverted), + options = tappingInvertModeOptions.map { stringResource(it.first) }.toTypedArray(), + selectedIndex = tappingInvertModeOptions.indexOfFirst { it.second == webtoonNavInverted }, + onSelect = { + screenModel.preferences.webtoonNavInverted().set(tappingInvertModeOptions[it].second) + }, + ) } val webtoonSidePadding by screenModel.preferences.webtoonSidePadding().collectAsState() From a24afa9a7676354f2e26a67a366397c3cadb274a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 15 Jul 2023 21:23:42 -0400 Subject: [PATCH 15/15] Update dependency gradle to v8.2.1 (#9723) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 62f495dfe..9f4197d5f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME