Tweak tablet UI mode setting (#8262)

(cherry picked from commit d558f9e1d6bcc8eb8f69359e6e7516f7ea24a408)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
This commit is contained in:
stevenyomi 2022-10-22 22:15:12 +08:00 committed by Jobobby04
parent 2774df208e
commit 46fe5dfd4f
15 changed files with 84 additions and 93 deletions

View File

@ -152,7 +152,6 @@ dependencies {
implementation(compose.activity) implementation(compose.activity)
implementation(compose.foundation) implementation(compose.foundation)
implementation(compose.material3.core) implementation(compose.material3.core)
implementation(compose.material3.windowsizeclass)
implementation(compose.material3.adapter) implementation(compose.material3.adapter)
implementation(compose.material.icons) implementation(compose.material.icons)
implementation(compose.animation) implementation(compose.animation)
@ -334,7 +333,6 @@ tasks {
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi", "-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi", "-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi",
"-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview", "-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.coroutines.InternalCoroutinesApi", "-opt-in=kotlinx.coroutines.InternalCoroutinesApi",

View File

@ -37,7 +37,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
@ -49,13 +48,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import eu.kanade.presentation.util.calculateWindowWidthSizeClass
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.isTabletUi
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
@ -250,7 +250,8 @@ fun LibraryBottomActionMenu(
} }
// SY --> // SY -->
val showOverflow = onClickCleanTitles != null || onClickAddToMangaDex != null val showOverflow = onClickCleanTitles != null || onClickAddToMangaDex != null
val moveMarkPrev = onDeleteClicked != null && calculateWindowWidthSizeClass() == WindowWidthSizeClass.Compact val configuration = LocalConfiguration.current
val moveMarkPrev = onDeleteClicked != null && remember { !configuration.isTabletUi() }
var overFlowOpen by remember { mutableStateOf(false) } var overFlowOpen by remember { mutableStateOf(false) }
// SY <-- // SY <--
Row( Row(

View File

@ -18,7 +18,6 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -26,6 +25,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -38,8 +38,8 @@ import eu.kanade.presentation.components.Pill
import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.presentation.library.LibraryState import eu.kanade.presentation.library.LibraryState
import eu.kanade.presentation.theme.active import eu.kanade.presentation.theme.active
import eu.kanade.presentation.util.calculateWindowWidthSizeClass
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.isTabletUi
@Composable @Composable
fun LibraryToolbar( fun LibraryToolbar(
@ -148,7 +148,8 @@ fun LibraryRegularToolbar(
Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint) Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint)
} }
// SY --> // SY -->
val moveGlobalUpdate = showSyncExh && calculateWindowWidthSizeClass() == WindowWidthSizeClass.Compact val configuration = LocalConfiguration.current
val moveGlobalUpdate = showSyncExh && remember { !configuration.isTabletUi() }
if (!moveGlobalUpdate) { if (!moveGlobalUpdate) {
IconButton(onClick = onClickRefresh) { IconButton(onClick = onClickRefresh) {
Icon(Icons.Outlined.Refresh, contentDescription = stringResource(R.string.pref_category_library_update)) Icon(Icons.Outlined.Refresh, contentDescription = stringResource(R.string.pref_category_library_update))

View File

@ -30,7 +30,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -94,7 +93,7 @@ import exh.ui.metadata.adapters.TsuminoDescription
fun MangaScreen( fun MangaScreen(
state: MangaScreenState.Success, state: MangaScreenState.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
windowWidthSizeClass: WindowWidthSizeClass, isTabletUi: Boolean,
onBackClicked: () -> Unit, onBackClicked: () -> Unit,
onChapterClicked: (Chapter) -> Unit, onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?, onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
@ -136,7 +135,7 @@ fun MangaScreen(
onAllChapterSelected: (Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit, onInvertSelection: () -> Unit,
) { ) {
if (windowWidthSizeClass == WindowWidthSizeClass.Compact) { if (!isTabletUi) {
MangaScreenSmallImpl( MangaScreenSmallImpl(
state = state, state = state,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
@ -176,7 +175,6 @@ fun MangaScreen(
} else { } else {
MangaScreenLargeImpl( MangaScreenLargeImpl(
state = state, state = state,
windowWidthSizeClass = windowWidthSizeClass,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
onBackClicked = onBackClicked, onBackClicked = onBackClicked,
onChapterClicked = onChapterClicked, onChapterClicked = onChapterClicked,
@ -375,7 +373,7 @@ private fun MangaScreenSmallImpl(
contentType = MangaScreenItem.INFO_BOX, contentType = MangaScreenItem.INFO_BOX,
) { ) {
MangaInfoBox( MangaInfoBox(
windowWidthSizeClass = WindowWidthSizeClass.Compact, isTabletUi = false,
appBarPadding = topPadding, appBarPadding = topPadding,
title = state.manga.title, title = state.manga.title,
author = state.manga.author, author = state.manga.author,
@ -489,7 +487,6 @@ private fun MangaScreenSmallImpl(
@Composable @Composable
fun MangaScreenLargeImpl( fun MangaScreenLargeImpl(
state: MangaScreenState.Success, state: MangaScreenState.Success,
windowWidthSizeClass: WindowWidthSizeClass,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
onBackClicked: () -> Unit, onBackClicked: () -> Unit,
onChapterClicked: (Chapter) -> Unit, onChapterClicked: (Chapter) -> Unit,
@ -640,7 +637,7 @@ fun MangaScreenLargeImpl(
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
) { ) {
MangaInfoBox( MangaInfoBox(
windowWidthSizeClass = windowWidthSizeClass, isTabletUi = true,
appBarPadding = contentPadding.calculateTopPadding(), appBarPadding = contentPadding.calculateTopPadding(),
title = state.manga.title, title = state.manga.title,
author = state.manga.author, author = state.manga.author,

View File

@ -41,7 +41,6 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -86,7 +85,7 @@ private val whitespaceLineRegex = Regex("[\\r\\n]{2,}", setOf(RegexOption.MULTIL
@Composable @Composable
fun MangaInfoBox( fun MangaInfoBox(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
windowWidthSizeClass: WindowWidthSizeClass, isTabletUi: Boolean,
appBarPadding: Dp, appBarPadding: Dp,
title: String, title: String,
author: String?, author: String?,
@ -121,7 +120,7 @@ fun MangaInfoBox(
// Manga & source info // Manga & source info
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
if (windowWidthSizeClass == WindowWidthSizeClass.Compact) { if (!isTabletUi) {
MangaAndSourceTitlesSmall( MangaAndSourceTitlesSmall(
appBarPadding = appBarPadding, appBarPadding = appBarPadding,
coverDataProvider = coverDataProvider, coverDataProvider = coverDataProvider,

View File

@ -46,8 +46,6 @@ import eu.kanade.domain.library.service.LibraryPreferences
import eu.kanade.domain.manga.interactor.GetAllManga import eu.kanade.domain.manga.interactor.GetAllManga
import eu.kanade.domain.manga.repository.MangaRepository import eu.kanade.domain.manga.repository.MangaRepository
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.domain.ui.model.TabletUiMode
import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.util.LocalRouter import eu.kanade.presentation.util.LocalRouter
import eu.kanade.presentation.util.collectAsState import eu.kanade.presentation.util.collectAsState
@ -142,7 +140,6 @@ class SettingsAdvancedScreen : SearchableSettings {
getNetworkGroup(networkPreferences = networkPreferences), getNetworkGroup(networkPreferences = networkPreferences),
getLibraryGroup(), getLibraryGroup(),
getExtensionsGroup(basePreferences = basePreferences), getExtensionsGroup(basePreferences = basePreferences),
getDisplayGroup(),
// SY --> // SY -->
getDownloaderGroup(), getDownloaderGroup(),
getDataSaverGroup(), getDataSaverGroup(),
@ -454,26 +451,6 @@ class SettingsAdvancedScreen : SearchableSettings {
) )
} }
@Composable
private fun getDisplayGroup(): Preference.PreferenceGroup {
val context = LocalContext.current
val uiPreferences = remember { Injekt.get<UiPreferences>() }
return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_display),
preferenceItems = listOf(
Preference.PreferenceItem.ListPreference(
pref = uiPreferences.tabletUiMode(),
title = stringResource(R.string.pref_tablet_ui_mode),
entries = TabletUiMode.values().associateWith { stringResource(it.titleResId) },
onValueChanged = {
context.toast(R.string.requires_app_restart)
true
},
),
),
)
}
// SY --> // SY -->
@Composable @Composable
fun CleanupDownloadsDialog( fun CleanupDownloadsDialog(

View File

@ -13,12 +13,14 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.domain.ui.model.TabletUiMode
import eu.kanade.domain.ui.model.ThemeMode import eu.kanade.domain.ui.model.ThemeMode
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.util.collectAsState import eu.kanade.presentation.util.collectAsState
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.isTablet import eu.kanade.tachiyomi.util.system.isAutoTabletUiAvailable
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.merge
@ -40,7 +42,7 @@ class SettingsAppearanceScreen : SearchableSettings {
return listOf( return listOf(
getThemeGroup(context = context, uiPreferences = uiPreferences), getThemeGroup(context = context, uiPreferences = uiPreferences),
getNavigationGroup(context = context, uiPreferences = uiPreferences), getDisplayGroup(context = context, uiPreferences = uiPreferences),
getTimestampGroup(uiPreferences = uiPreferences), getTimestampGroup(uiPreferences = uiPreferences),
// SY --> // SY -->
getNavbarGroup(uiPreferences = uiPreferences), getNavbarGroup(uiPreferences = uiPreferences),
@ -102,18 +104,38 @@ class SettingsAppearanceScreen : SearchableSettings {
} }
@Composable @Composable
private fun getNavigationGroup( private fun getDisplayGroup(
context: Context, context: Context,
uiPreferences: UiPreferences, uiPreferences: UiPreferences,
): Preference.PreferenceGroup { ): Preference.PreferenceGroup {
val tabletUiModePref = uiPreferences.tabletUiMode()
val tabletUiMode by tabletUiModePref.collectAsState()
val isTabletUiAvailable = remember(tabletUiMode) { // won't survive config change
when (tabletUiMode) {
TabletUiMode.AUTOMATIC -> context.resources.configuration.isAutoTabletUiAvailable()
TabletUiMode.NEVER -> false
else -> true
}
}
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_navigation), title = stringResource(R.string.pref_category_display),
enabled = remember(context) { context.isTablet() },
preferenceItems = listOf( preferenceItems = listOf(
Preference.PreferenceItem.ListPreference(
pref = tabletUiModePref,
title = stringResource(R.string.pref_tablet_ui_mode),
entries = TabletUiMode.values().associateWith { stringResource(it.titleResId) },
onValueChanged = {
context.toast(R.string.requires_app_restart)
true
},
),
Preference.PreferenceItem.ListPreference( Preference.PreferenceItem.ListPreference(
pref = uiPreferences.sideNavIconAlignment(), pref = uiPreferences.sideNavIconAlignment(),
title = stringResource(R.string.pref_side_nav_icon_alignment), title = stringResource(R.string.pref_side_nav_icon_alignment),
subtitle = "%s", subtitle = "%s",
enabled = isTabletUiAvailable,
entries = mapOf( entries = mapOf(
0 to stringResource(R.string.alignment_top), 0 to stringResource(R.string.alignment_top),
1 to stringResource(R.string.alignment_center), 1 to stringResource(R.string.alignment_center),

View File

@ -1,24 +0,0 @@
package eu.kanade.presentation.util
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@Composable
@ReadOnlyComposable
fun calculateWindowWidthSizeClass(): WindowWidthSizeClass {
val configuration = LocalConfiguration.current
return fromWidth(configuration.smallestScreenWidthDp.dp)
}
private fun fromWidth(width: Dp): WindowWidthSizeClass {
require(width >= 0.dp) { "Width must not be negative" }
return when {
width < 720.dp -> WindowWidthSizeClass.Compact // Was 600
width < 840.dp -> WindowWidthSizeClass.Medium
else -> WindowWidthSizeClass.Expanded
}
}

View File

@ -67,7 +67,7 @@ import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.preference.asHotFlow import eu.kanade.tachiyomi.util.preference.asHotFlow
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getThemeColor import eu.kanade.tachiyomi.util.system.getThemeColor
import eu.kanade.tachiyomi.util.system.isTablet import eu.kanade.tachiyomi.util.system.isTabletUi
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
@ -669,7 +669,7 @@ class MainActivity : BaseActivity() {
binding.appbar.isVisible = !isComposeController binding.appbar.isVisible = !isComposeController
binding.controllerContainer.enableScrollingBehavior(!isComposeController) binding.controllerContainer.enableScrollingBehavior(!isComposeController)
if (!isTablet()) { if (!isTabletUi()) {
// Save lift state // Save lift state
if (isPush) { if (isPush) {
if (router.backstackSize > 1) { if (router.backstackSize > 1) {

View File

@ -13,6 +13,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalConfiguration
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType import com.bluelinelabs.conductor.ControllerChangeType
@ -27,7 +28,6 @@ import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.presentation.manga.MangaScreen import eu.kanade.presentation.manga.MangaScreen
import eu.kanade.presentation.manga.components.DeleteChaptersDialog import eu.kanade.presentation.manga.components.DeleteChaptersDialog
import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
import eu.kanade.presentation.util.calculateWindowWidthSizeClass
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
@ -63,6 +63,7 @@ import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.getParcelableCompat import eu.kanade.tachiyomi.util.system.getParcelableCompat
import eu.kanade.tachiyomi.util.system.isTabletUi
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import exh.md.similar.MangaDexSimilarController import exh.md.similar.MangaDexSimilarController
@ -159,10 +160,13 @@ class MangaController : FullComposeController<MangaPresenter> {
val isHttpSource = remember { successState.source is HttpSource } val isHttpSource = remember { successState.source is HttpSource }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val configuration = LocalConfiguration.current
val isTabletUi = remember { configuration.isTabletUi() } // won't survive config change
MangaScreen( MangaScreen(
state = successState, state = successState,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
windowWidthSizeClass = calculateWindowWidthSizeClass(), isTabletUi = isTabletUi,
onBackClicked = router::popCurrentController, onBackClicked = router::popCurrentController,
onChapterClicked = this::openChapter, onChapterClicked = this::openChapter,
onDownloadChapter = this::onDownloadChapters.takeIf { !successState.source.isLocalOrStub() }, onDownloadChapter = this::onDownloadChapters.takeIf { !successState.source.isLocalOrStub() },

View File

@ -6,9 +6,10 @@ import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.with import androidx.compose.animation.with
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalConfiguration
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.transitions.ScreenTransition import cafe.adriel.voyager.transitions.ScreenTransition
@ -19,8 +20,8 @@ import eu.kanade.presentation.more.settings.screen.SettingsGeneralScreen
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
import eu.kanade.presentation.util.LocalBackPress import eu.kanade.presentation.util.LocalBackPress
import eu.kanade.presentation.util.LocalRouter import eu.kanade.presentation.util.LocalRouter
import eu.kanade.presentation.util.calculateWindowWidthSizeClass
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
import eu.kanade.tachiyomi.util.system.isTabletUi
class SettingsMainController(bundle: Bundle = bundleOf()) : BasicFullComposeController(bundle) { class SettingsMainController(bundle: Bundle = bundleOf()) : BasicFullComposeController(bundle) {
@ -39,8 +40,9 @@ class SettingsMainController(bundle: Bundle = bundleOf()) : BasicFullComposeCont
@Composable @Composable
override fun ComposeContent() { override fun ComposeContent() {
CompositionLocalProvider(LocalRouter provides router) { CompositionLocalProvider(LocalRouter provides router) {
val widthSizeClass = calculateWindowWidthSizeClass() val configuration = LocalConfiguration.current
if (widthSizeClass == WindowWidthSizeClass.Compact) { val isTabletUi = remember { configuration.isTabletUi() } // won't survive config change
if (!isTabletUi) {
Navigator( Navigator(
screen = if (toBackupScreen) { screen = if (toBackupScreen) {
SettingsBackupScreen() SettingsBackupScreen()

View File

@ -50,8 +50,6 @@ import java.io.File
import kotlin.math.max import kotlin.math.max
import kotlin.math.roundToInt import kotlin.math.roundToInt
private const val TABLET_UI_MIN_SCREEN_WIDTH_DP = 720
/** /**
* Copies a string to clipboard * Copies a string to clipboard
* *
@ -263,28 +261,46 @@ fun Context.createFileInCacheDir(name: String): File {
return file return file
} }
/** private const val TABLET_UI_REQUIRED_SCREEN_WIDTH_DP = 720
* We consider anything with a width of >= 720dp as a tablet, i.e. with layouts in layout-sw720dp.
*/ // some tablets have screen width like 711dp = 1600px / 2.25
fun Context.isTablet(): Boolean { private const val TABLET_UI_MIN_SCREEN_WIDTH_PORTRAIT_DP = 700
return resources.configuration.smallestScreenWidthDp >= TABLET_UI_MIN_SCREEN_WIDTH_DP
// make sure icons on the nav rail fit
private const val TABLET_UI_MIN_SCREEN_WIDTH_LANDSCAPE_DP = 600
fun Context.isTabletUi(): Boolean {
return resources.configuration.isTabletUi()
} }
fun Configuration.isTabletUi(): Boolean {
return smallestScreenWidthDp >= TABLET_UI_REQUIRED_SCREEN_WIDTH_DP
}
fun Configuration.isAutoTabletUiAvailable(): Boolean {
return smallestScreenWidthDp >= TABLET_UI_MIN_SCREEN_WIDTH_LANDSCAPE_DP
}
// TODO: move the logic to `isTabletUi()` when main activity is rewritten in Compose
fun Context.prepareTabletUiContext(): Context { fun Context.prepareTabletUiContext(): Context {
val configuration = resources.configuration val configuration = resources.configuration
val expected = when (Injekt.get<UiPreferences>().tabletUiMode().get()) { val expected = when (Injekt.get<UiPreferences>().tabletUiMode().get()) {
TabletUiMode.AUTOMATIC -> isTablet() TabletUiMode.AUTOMATIC ->
configuration.smallestScreenWidthDp >= when (configuration.orientation) {
Configuration.ORIENTATION_PORTRAIT -> TABLET_UI_MIN_SCREEN_WIDTH_PORTRAIT_DP
else -> TABLET_UI_MIN_SCREEN_WIDTH_LANDSCAPE_DP
}
TabletUiMode.ALWAYS -> true TabletUiMode.ALWAYS -> true
TabletUiMode.LANDSCAPE -> configuration.orientation == Configuration.ORIENTATION_LANDSCAPE TabletUiMode.LANDSCAPE -> configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
TabletUiMode.NEVER -> false TabletUiMode.NEVER -> false
} }
if (configuration.smallestScreenWidthDp >= TABLET_UI_MIN_SCREEN_WIDTH_DP != expected) { if (configuration.isTabletUi() != expected) {
val overrideConf = Configuration() val overrideConf = Configuration()
overrideConf.setTo(configuration) overrideConf.setTo(configuration)
overrideConf.smallestScreenWidthDp = if (expected) { overrideConf.smallestScreenWidthDp = if (expected) {
overrideConf.smallestScreenWidthDp.coerceAtLeast(TABLET_UI_MIN_SCREEN_WIDTH_DP) overrideConf.smallestScreenWidthDp.coerceAtLeast(TABLET_UI_REQUIRED_SCREEN_WIDTH_DP)
} else { } else {
overrideConf.smallestScreenWidthDp.coerceAtMost(TABLET_UI_MIN_SCREEN_WIDTH_DP - 1) overrideConf.smallestScreenWidthDp.coerceAtMost(TABLET_UI_REQUIRED_SCREEN_WIDTH_DP - 1)
} }
return createConfigurationContext(overrideConf) return createConfigurationContext(overrideConf)
} }

View File

@ -14,7 +14,7 @@ import androidx.core.view.isVisible
import androidx.customview.view.AbsSavedState import androidx.customview.view.AbsSavedState
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import eu.kanade.tachiyomi.util.system.isTablet import eu.kanade.tachiyomi.util.system.isTabletUi
import eu.kanade.tachiyomi.util.view.findChild import eu.kanade.tachiyomi.util.view.findChild
/** /**
@ -48,7 +48,7 @@ class TachiyomiCoordinatorLayout @JvmOverloads constructor(
) { ) {
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed) super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed)
// Disable elevation overlay when tabs are visible // Disable elevation overlay when tabs are visible
if (context.isTablet().not()) { if (context.isTabletUi().not()) {
if (target is ComposeView) { if (target is ComposeView) {
val scrollCondition = if (type == ViewCompat.TYPE_NON_TOUCH) { val scrollCondition = if (type == ViewCompat.TYPE_NON_TOUCH) {
dyUnconsumed >= 0 dyUnconsumed >= 0

View File

@ -13,7 +13,6 @@ ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose
ui-util = { module = "androidx.compose.ui:ui-util", version.ref = "compose" } ui-util = { module = "androidx.compose.ui:ui-util", version.ref = "compose" }
material3-core = { module = "androidx.compose.material3:material3", version.ref = "material3" } material3-core = { module = "androidx.compose.material3:material3", version.ref = "material3" }
material3-windowsizeclass = { module = "androidx.compose.material3:material3-window-size-class", version.ref = "material3" }
material3-adapter = "com.google.android.material:compose-theme-adapter-3:1.0.20" material3-adapter = "com.google.android.material:compose-theme-adapter-3:1.0.20"
material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" } material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" }

View File

@ -187,7 +187,6 @@
<string name="theme_yotsuba">Yotsuba</string> <string name="theme_yotsuba">Yotsuba</string>
<string name="theme_tidalwave">Tidal Wave</string> <string name="theme_tidalwave">Tidal Wave</string>
<string name="pref_dark_theme_pure_black">Pure black dark mode</string> <string name="pref_dark_theme_pure_black">Pure black dark mode</string>
<string name="pref_category_navigation">Navigation</string>
<string name="pref_side_nav_icon_alignment">Side navigation icon alignment</string> <string name="pref_side_nav_icon_alignment">Side navigation icon alignment</string>
<string name="alignment_top">Top</string> <string name="alignment_top">Top</string>
<string name="alignment_center">Center</string> <string name="alignment_center">Center</string>