diff --git a/app/src/main/java/eu/kanade/presentation/components/Scaffold.kt b/app/src/main/java/eu/kanade/presentation/components/Scaffold.kt index 800405c3b..156f87f00 100644 --- a/app/src/main/java/eu/kanade/presentation/components/Scaffold.kt +++ b/app/src/main/java/eu/kanade/presentation/components/Scaffold.kt @@ -56,6 +56,7 @@ import androidx.compose.ui.unit.dp * @sample androidx.compose.material3.samples.ScaffoldWithSimpleSnackbar * * Tachiyomi changes: + * * Pass scroll behavior to top bar by default * * Remove height constraint for expanded app bar * * Also take account of fab height when providing inner padding * @@ -80,6 +81,7 @@ import androidx.compose.ui.unit.dp @Composable fun Scaffold( modifier: Modifier = Modifier, + topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()), topBar: @Composable (TopAppBarScrollBehavior) -> Unit = {}, bottomBar: @Composable () -> Unit = {}, snackbarHost: @Composable () -> Unit = {}, @@ -89,21 +91,16 @@ fun Scaffold( contentColor: Color = contentColorFor(containerColor), content: @Composable (PaddingValues) -> Unit, ) { - /** - * Tachiyomi: Pass scroll behavior to topBar - */ - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) - androidx.compose.material3.Surface( modifier = Modifier - .nestedScroll(scrollBehavior.nestedScrollConnection) + .nestedScroll(topBarScrollBehavior.nestedScrollConnection) .then(modifier), color = containerColor, contentColor = contentColor, ) { ScaffoldLayout( fabPosition = floatingActionButtonPosition, - topBar = { topBar(scrollBehavior) }, + topBar = { topBar(topBarScrollBehavior) }, bottomBar = bottomBar, content = content, snackbar = snackbarHost, diff --git a/app/src/main/java/eu/kanade/presentation/components/TwoPanelBox.kt b/app/src/main/java/eu/kanade/presentation/components/TwoPanelBox.kt new file mode 100644 index 000000000..37d5a1f83 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/components/TwoPanelBox.kt @@ -0,0 +1,35 @@ +package eu.kanade.presentation.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun TwoPanelBox( + modifier: Modifier = Modifier, + startContent: @Composable BoxScope.() -> Unit, + endContent: @Composable BoxScope.() -> Unit, +) { + BoxWithConstraints(modifier = modifier.fillMaxSize()) { + val firstWidth = (maxWidth / 2).coerceAtMost(450.dp) + val secondWidth = maxWidth - firstWidth + Box( + modifier = Modifier + .align(Alignment.TopStart) + .width(firstWidth), + content = startContent, + ) + Box( + modifier = Modifier + .align(Alignment.TopEnd) + .width(secondWidth), + content = endContent, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index 1797cba78..90c24d469 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -6,7 +6,6 @@ import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets @@ -15,13 +14,11 @@ import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState @@ -47,7 +44,6 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import eu.kanade.domain.chapter.model.Chapter import eu.kanade.presentation.components.ChapterDownloadAction import eu.kanade.presentation.components.ExtendedFloatingActionButton @@ -55,6 +51,7 @@ import eu.kanade.presentation.components.LazyColumn import eu.kanade.presentation.components.MangaBottomActionMenu import eu.kanade.presentation.components.Scaffold import eu.kanade.presentation.components.SwipeRefresh +import eu.kanade.presentation.components.TwoPanelBox import eu.kanade.presentation.components.VerticalFastScroller import eu.kanade.presentation.manga.components.ChapterHeader import eu.kanade.presentation.manga.components.ExpandableMangaDescription @@ -636,108 +633,103 @@ fun MangaScreenLargeImpl( } }, ) { contentPadding -> - BoxWithConstraints(modifier = Modifier.fillMaxSize()) { - val firstWidth = (maxWidth / 2).coerceAtMost(450.dp) - val secondWidth = maxWidth - firstWidth - - Column( - modifier = Modifier - .align(Alignment.TopStart) - .width(firstWidth) - .verticalScroll(rememberScrollState()), - ) { - MangaInfoBox( - windowWidthSizeClass = windowWidthSizeClass, - appBarPadding = contentPadding.calculateTopPadding(), - title = state.manga.title, - author = state.manga.author, - artist = state.manga.artist, - sourceName = remember { state.source.getNameForMangaInfo(state.mergedData?.sources) }, - isStubSource = remember { state.source is SourceManager.StubSource }, - coverDataProvider = { state.manga }, - status = state.manga.status, - onCoverClick = onCoverClicked, - doSearch = onSearch, - ) - MangaActionRow( - favorite = state.manga.favorite, - trackingCount = state.trackingCount, - onAddToLibraryClicked = onAddToLibraryClicked, - onWebViewClicked = onWebViewClicked, - onTrackingClicked = onTrackingClicked, - onEditCategory = onEditCategoryClicked, - // SY --> - onMergeClicked = onMergeClicked.takeUnless { state.showMergeInOverflow }, - // SY <-- - ) - // SY --> - metadataDescription?.invoke( - state = state, - openMetadataViewer = onMetadataViewerClicked, - search = { onSearch(it, false) }, - ) - // SY <-- - ExpandableMangaDescription( - defaultExpandState = true, - description = state.manga.description, - tagsProvider = { state.manga.genre }, - onTagClicked = onTagClicked, - // SY --> - doSearch = onSearch, - searchMetadataChips = remember(state.meta, state.source.id, state.manga.genre) { - SearchMetadataChips(state.meta, state.source, state.manga.genre) - }, - // SY <-- - ) - // SY --> - if (!state.showRecommendationsInOverflow || state.showMergeWithAnother) { - MangaInfoButtons( - showRecommendsButton = !state.showRecommendationsInOverflow, - showMergeWithAnotherButton = state.showMergeWithAnother, - onRecommendClicked = onRecommendClicked, - onMergeWithAnotherClicked = onMergeWithAnotherClicked, - ) - } - if (state.pagePreviewsState !is PagePreviewState.Unused) { - PagePreviews(state.pagePreviewsState, onMorePreviewsClicked) - } - // SY <-- - } - - VerticalFastScroller( - listState = chapterListState, - modifier = Modifier - .align(Alignment.TopEnd) - .width(secondWidth), - topContentPadding = contentPadding.calculateTopPadding(), - ) { - LazyColumn( - modifier = Modifier.fillMaxHeight(), - state = chapterListState, - contentPadding = PaddingValues( - top = contentPadding.calculateTopPadding(), - bottom = contentPadding.calculateBottomPadding(), - ), + TwoPanelBox( + startContent = { + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()), ) { - item( - key = MangaScreenItem.CHAPTER_HEADER, - contentType = MangaScreenItem.CHAPTER_HEADER, - ) { - ChapterHeader( - chapterCount = chapters.size, - onClick = onFilterButtonClicked, + MangaInfoBox( + windowWidthSizeClass = windowWidthSizeClass, + appBarPadding = contentPadding.calculateTopPadding(), + title = state.manga.title, + author = state.manga.author, + artist = state.manga.artist, + sourceName = remember { state.source.getNameForMangaInfo(state.mergedData?.sources) }, + isStubSource = remember { state.source is SourceManager.StubSource }, + coverDataProvider = { state.manga }, + status = state.manga.status, + onCoverClick = onCoverClicked, + doSearch = onSearch, + ) + MangaActionRow( + favorite = state.manga.favorite, + trackingCount = state.trackingCount, + onAddToLibraryClicked = onAddToLibraryClicked, + onWebViewClicked = onWebViewClicked, + onTrackingClicked = onTrackingClicked, + onEditCategory = onEditCategoryClicked, + // SY --> + onMergeClicked = onMergeClicked.takeUnless { state.showMergeInOverflow }, + // SY <-- + ) + // SY --> + metadataDescription?.invoke( + state = state, + openMetadataViewer = onMetadataViewerClicked, + search = { onSearch(it, false) }, + ) + // SY <-- + ExpandableMangaDescription( + defaultExpandState = true, + description = state.manga.description, + tagsProvider = { state.manga.genre }, + onTagClicked = onTagClicked, + // SY --> + doSearch = onSearch, + searchMetadataChips = remember(state.meta, state.source.id, state.manga.genre) { + SearchMetadataChips(state.meta, state.source, state.manga.genre) + }, + // SY <-- + ) + // SY --> + if (!state.showRecommendationsInOverflow || state.showMergeWithAnother) { + MangaInfoButtons( + showRecommendsButton = !state.showRecommendationsInOverflow, + showMergeWithAnotherButton = state.showMergeWithAnother, + onRecommendClicked = onRecommendClicked, + onMergeWithAnotherClicked = onMergeWithAnotherClicked, ) } - - sharedChapterItems( - chapters = chapters, - onChapterClicked = onChapterClicked, - onDownloadChapter = onDownloadChapter, - onChapterSelected = onChapterSelected, - ) + if (state.pagePreviewsState !is PagePreviewState.Unused) { + PagePreviews(state.pagePreviewsState, onMorePreviewsClicked) + } + // SY <-- } - } - } + }, + endContent = { + VerticalFastScroller( + listState = chapterListState, + topContentPadding = contentPadding.calculateTopPadding(), + ) { + LazyColumn( + modifier = Modifier.fillMaxHeight(), + state = chapterListState, + contentPadding = PaddingValues( + top = contentPadding.calculateTopPadding(), + bottom = contentPadding.calculateBottomPadding(), + ), + ) { + item( + key = MangaScreenItem.CHAPTER_HEADER, + contentType = MangaScreenItem.CHAPTER_HEADER, + ) { + ChapterHeader( + chapterCount = chapters.size, + onClick = onFilterButtonClicked, + ) + } + + sharedChapterItems( + chapters = chapters, + onChapterClicked = onChapterClicked, + onDownloadChapter = onDownloadChapter, + onChapterSelected = onChapterSelected, + ) + } + } + }, + ) } } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt index 079c169f3..10fa1984f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt @@ -2,25 +2,48 @@ package eu.kanade.presentation.more.settings import androidx.annotation.StringRes import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import eu.kanade.presentation.components.AppBar +import androidx.compose.ui.unit.dp import eu.kanade.presentation.components.Scaffold +import eu.kanade.tachiyomi.R @Composable fun PreferenceScaffold( @StringRes titleRes: Int, actions: @Composable RowScope.() -> Unit = {}, - onBackPressed: () -> Unit = {}, + onBackPressed: (() -> Unit)? = null, itemsProvider: @Composable () -> List, ) { Scaffold( - topBar = { scrollBehavior -> - AppBar( - title = stringResource(titleRes), - navigateUp = onBackPressed, + topBar = { + TopAppBar( + title = { + Text( + text = stringResource(id = titleRes), + modifier = Modifier.padding(start = 8.dp), + ) + }, + navigationIcon = { + if (onBackPressed != null) { + IconButton(onClick = onBackPressed) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = stringResource(R.string.abc_action_bar_up_description), + ) + } + } + }, actions = actions, - scrollBehavior = scrollBehavior, + scrollBehavior = it, ) }, content = { contentPadding -> diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt index 629c062bf..0cce2ed91 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable @@ -12,7 +11,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEachIndexed -import eu.kanade.presentation.components.Divider import eu.kanade.presentation.components.ScrollbarLazyColumn import eu.kanade.presentation.more.settings.screen.SearchableSettings import eu.kanade.presentation.more.settings.widget.PreferenceGroupHeader @@ -55,9 +53,6 @@ fun PreferenceScreen( item { Column { - if (i != 0) { - Divider(modifier = Modifier.padding(bottom = 8.dp)) - } PreferenceGroupHeader(title = preference.title) } } @@ -68,7 +63,9 @@ fun PreferenceScreen( ) } item { - Spacer(modifier = Modifier.height(12.dp)) + if (i < items.lastIndex) { + Spacer(modifier = Modifier.height(12.dp)) + } } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SearchableSettings.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SearchableSettings.kt index 180e09e63..b7714a3f0 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SearchableSettings.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SearchableSettings.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import cafe.adriel.voyager.core.screen.Screen -import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.PreferenceScaffold import eu.kanade.presentation.util.LocalBackPress @@ -26,10 +25,10 @@ interface SearchableSettings : Screen { @Composable override fun Content() { - val handleBack = LocalBackPress.currentOrThrow + val handleBack = LocalBackPress.current PreferenceScaffold( titleRes = getTitleRes(), - onBackPressed = handleBack::invoke, + onBackPressed = if (handleBack != null) handleBack::invoke else null, actions = { AppBarAction() }, itemsProvider = { getPreferences() }, ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt index 4d935c875..62cef5494 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt @@ -1,7 +1,13 @@ package eu.kanade.presentation.more.settings.screen import androidx.annotation.StringRes +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.outlined.ChromeReaderMode import androidx.compose.material.icons.outlined.Code import androidx.compose.material.icons.outlined.CollectionsBookmark @@ -13,130 +19,227 @@ import androidx.compose.material.icons.outlined.Security import androidx.compose.material.icons.outlined.SettingsBackupRestore import androidx.compose.material.icons.outlined.Sync import androidx.compose.material.icons.outlined.Tune +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable -import androidx.compose.runtime.NonRestartableComposable -import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastFirstOrNull +import androidx.core.graphics.ColorUtils +import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow -import eu.kanade.domain.UnsortedPreferences import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions -import eu.kanade.presentation.more.settings.Preference -import eu.kanade.presentation.more.settings.PreferenceScaffold +import eu.kanade.presentation.components.LazyColumn +import eu.kanade.presentation.components.Scaffold +import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.presentation.util.LocalBackPress -import eu.kanade.presentation.util.collectAsState import eu.kanade.tachiyomi.R import exh.assets.EhAssets import exh.assets.ehassets.EhLogo import exh.assets.ehassets.MangadexLogo -import exh.md.utils.MdUtil -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -object SettingsMainScreen : SearchableSettings { - - @Composable - @ReadOnlyComposable - @StringRes - override fun getTitleRes() = R.string.label_settings - - @Composable - @NonRestartableComposable - override fun getPreferences(): List { - val navigator = LocalNavigator.currentOrThrow - // SY --> - val isHentaiEnabled by remember { Injekt.get() }.isHentaiEnabled().collectAsState() - // SY <-- - return listOf( - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_general), - icon = Icons.Outlined.Tune, - onClick = { navigator.push(SettingsGeneralScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_appearance), - icon = Icons.Outlined.Palette, - onClick = { navigator.push(SettingsAppearanceScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_library), - icon = Icons.Outlined.CollectionsBookmark, - onClick = { navigator.push(SettingsLibraryScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_reader), - icon = Icons.Outlined.ChromeReaderMode, - onClick = { navigator.push(SettingsReaderScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_downloads), - icon = Icons.Outlined.GetApp, - onClick = { navigator.push(SettingsDownloadScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_tracking), - icon = Icons.Outlined.Sync, - onClick = { navigator.push(SettingsTrackingScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.browse), - icon = Icons.Outlined.Explore, - onClick = { navigator.push(SettingsBrowseScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.label_backup), - icon = Icons.Outlined.SettingsBackupRestore, - onClick = { navigator.push(SettingsBackupScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_security), - icon = Icons.Outlined.Security, - onClick = { navigator.push(SettingsSecurityScreen()) }, - ), - // SY --> - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_eh), - icon = EhAssets.EhLogo, - onClick = { navigator.push(SettingsEhScreen()) }, - enabled = isHentaiEnabled, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_mangadex), - icon = EhAssets.MangadexLogo, - onClick = { navigator.push(SettingsMangadexScreen()) }, - enabled = remember { MdUtil.getEnabledMangaDexs(Injekt.get()).isNotEmpty() }, - ), - // SY <-- - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_category_advanced), - icon = Icons.Outlined.Code, - onClick = { navigator.push(SettingsAdvancedScreen()) }, - ), - ) - } +object SettingsMainScreen : Screen { @Composable override fun Content() { + Content(twoPane = false) + } + + @Composable + private fun getPalerSurface(): Color { + val surface = MaterialTheme.colorScheme.surface + val dark = isSystemInDarkTheme() + return remember(surface, dark) { + val arr = FloatArray(3) + ColorUtils.colorToHSL(surface.toArgb(), arr) + arr[2] = if (dark) { + arr[2] - 0.05f + } else { + arr[2] + 0.02f + }.coerceIn(0f, 1f) + Color.hsl(arr[0], arr[1], arr[2]) + } + } + + @Composable + fun Content(twoPane: Boolean) { val navigator = LocalNavigator.currentOrThrow val backPress = LocalBackPress.currentOrThrow - PreferenceScaffold( - titleRes = getTitleRes(), - actions = { - AppBarActions( - listOf( - AppBar.Action( - title = stringResource(R.string.action_search), - icon = Icons.Outlined.Search, - onClick = { navigator.push(SettingsSearchScreen()) }, - ), - ), - ) + val containerColor = if (twoPane) getPalerSurface() else MaterialTheme.colorScheme.surface + Scaffold( + topBar = { scrollBehavior -> + // https://issuetracker.google.com/issues/249688556 + MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy(surface = containerColor), + ) { + TopAppBar( + title = { + Text( + text = stringResource(R.string.label_settings), + modifier = Modifier.padding(start = 8.dp), + ) + }, + navigationIcon = { + IconButton(onClick = backPress::invoke) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = stringResource(R.string.abc_action_bar_up_description), + ) + } + }, + actions = { + AppBarActions( + listOf( + AppBar.Action( + title = stringResource(R.string.action_search), + icon = Icons.Outlined.Search, + onClick = { navigator.navigate(SettingsSearchScreen(), twoPane) }, + ), + ), + ) + }, + scrollBehavior = scrollBehavior, + ) + } + }, + containerColor = containerColor, + content = { contentPadding -> + LazyColumn(contentPadding = contentPadding) { + items( + items = items.filter { it.screen.isEnabled() }, + key = { it.hashCode() }, + ) { item -> + var modifier: Modifier = Modifier + var contentColor = LocalContentColor.current + if (twoPane) { + val selected = navigator.items.fastFirstOrNull { it::class == item.screen::class } != null + modifier = Modifier + .padding(horizontal = 8.dp) + .clip(RoundedCornerShape(24.dp)) + .then( + if (selected) { + Modifier.background(MaterialTheme.colorScheme.surfaceVariant) + } else { + Modifier + }, + ) + if (selected) { + contentColor = MaterialTheme.colorScheme.onSurfaceVariant + } + } + CompositionLocalProvider(LocalContentColor provides contentColor) { + TextPreferenceWidget( + modifier = modifier, + title = stringResource(item.titleRes), + subtitle = stringResource(item.subtitleRes), + icon = item.icon, + onPreferenceClick = { navigator.navigate(item.screen, twoPane) }, + ) + } + } + } }, - onBackPressed = backPress::invoke, - itemsProvider = { getPreferences() }, ) } + + private fun Navigator.navigate(screen: Screen, twoPane: Boolean) { + if (twoPane) replaceAll(screen) else push(screen) + } } + +private data class Item( + @StringRes val titleRes: Int, + @StringRes val subtitleRes: Int, + val icon: ImageVector, + val screen: /* SY --> */SearchableSettings /* SY <-- */, +) + +private val items = listOf( + Item( + titleRes = R.string.pref_category_general, + subtitleRes = R.string.pref_general_summary, + icon = Icons.Outlined.Tune, + screen = SettingsGeneralScreen(), + ), + Item( + titleRes = R.string.pref_category_appearance, + subtitleRes = R.string.pref_appearance_summary, + icon = Icons.Outlined.Palette, + screen = SettingsAppearanceScreen(), + ), + Item( + titleRes = R.string.pref_category_library, + subtitleRes = R.string.pref_library_summary, + icon = Icons.Outlined.CollectionsBookmark, + screen = SettingsLibraryScreen(), + ), + Item( + titleRes = R.string.pref_category_reader, + subtitleRes = R.string.pref_reader_summary, + icon = Icons.Outlined.ChromeReaderMode, + screen = SettingsReaderScreen(), + ), + Item( + titleRes = R.string.pref_category_downloads, + subtitleRes = R.string.pref_downloads_summary, + icon = Icons.Outlined.GetApp, + screen = SettingsDownloadScreen(), + ), + Item( + titleRes = R.string.pref_category_tracking, + subtitleRes = R.string.pref_tracking_summary, + icon = Icons.Outlined.Sync, + screen = SettingsTrackingScreen(), + ), + Item( + titleRes = R.string.browse, + subtitleRes = R.string.pref_browse_summary, + icon = Icons.Outlined.Explore, + screen = SettingsBrowseScreen(), + ), + Item( + titleRes = R.string.label_backup, + subtitleRes = R.string.pref_backup_summary, + icon = Icons.Outlined.SettingsBackupRestore, + screen = SettingsBackupScreen(), + ), + Item( + titleRes = R.string.pref_category_security, + subtitleRes = R.string.pref_security_summary, + icon = Icons.Outlined.Security, + screen = SettingsSecurityScreen(), + ), + // SY --> + Item( + titleRes = R.string.pref_category_eh, + subtitleRes = R.string.pref_ehentai_summary, + icon = EhAssets.EhLogo, + screen = SettingsEhScreen(), + ), + Item( + titleRes = R.string.pref_category_mangadex, + subtitleRes = R.string.pref_mangadex_summary, + icon = EhAssets.MangadexLogo, + screen = SettingsMangadexScreen(), + ), + // SY <-- + Item( + titleRes = R.string.pref_category_advanced, + subtitleRes = R.string.pref_advanced_summary, + icon = Icons.Outlined.Code, + screen = SettingsAdvancedScreen(), + ), +) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMangadexScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMangadexScreen.kt index cc73955bb..8b4dcafef 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMangadexScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMangadexScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.AlertDialog @@ -95,7 +96,20 @@ class SettingsMangadexScreen : SearchableSettings { AlertDialog( onDismissRequest = onDismissRequest, - title = { Text(text = stringResource(R.string.login_title, mdex.name)) }, + title = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(R.string.login_title, mdex.name), + modifier = Modifier.weight(1f), + ) + IconButton(onClick = onDismissRequest) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = stringResource(R.string.action_close), + ) + } + } + }, text = { Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { OutlinedTextField( @@ -138,51 +152,43 @@ class SettingsMangadexScreen : SearchableSettings { } }, confirmButton = { - Column { - Button( - modifier = Modifier.fillMaxWidth(), - enabled = !processing, - onClick = { - if (username.text.isEmpty() || password.text.isEmpty()) { - inputError = true - return@Button - } - scope.launchIO { - try { - inputError = false - processing = true - val result = mdex.login( - username = username.text, - password = password.text, - twoFactorCode = null, - ) - if (result) { - onDismissRequest() - onLoginSuccess() - withUIContext { - context.toast(R.string.login_success) - } - } - } catch (e: Exception) { - xLogW("Login to Mangadex error", e) + Button( + modifier = Modifier.fillMaxWidth(), + enabled = !processing, + onClick = { + if (username.text.isEmpty() || password.text.isEmpty()) { + inputError = true + return@Button + } + scope.launchIO { + try { + inputError = false + processing = true + val result = mdex.login( + username = username.text, + password = password.text, + twoFactorCode = null, + ) + if (result) { + onDismissRequest() + onLoginSuccess() withUIContext { - e.message?.let { context.toast(it) } + context.toast(R.string.login_success) } - } finally { - processing = false } + } catch (e: Exception) { + xLogW("Login to Mangadex error", e) + withUIContext { + e.message?.let { context.toast(it) } + } + } finally { + processing = false } - }, - ) { - val id = if (processing) R.string.loading else R.string.login - Text(text = stringResource(id)) - } - TextButton( - modifier = Modifier.fillMaxWidth(), - onClick = onDismissRequest, - ) { - Text(text = stringResource(android.R.string.cancel)) - } + } + }, + ) { + val id = if (processing) R.string.loading else R.string.login + Text(text = stringResource(id)) } }, properties = DialogProperties( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt index 4e8f865bf..5738b8f88 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt @@ -146,8 +146,7 @@ class SettingsSearchScreen : Screen { contentPadding = contentPadding, ) { result -> SearchableSettings.highlightKey = result.highlightKey - navigator.popUntil { it is SettingsMainScreen } - navigator.push(result.route) + navigator.replace(result.route) } } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt index 85a7527c5..8eeb4054b 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.HelpOutline import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff @@ -22,7 +23,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue @@ -30,6 +30,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler @@ -189,7 +190,20 @@ class SettingsTrackingScreen : SearchableSettings { AlertDialog( onDismissRequest = onDismissRequest, - title = { Text(text = stringResource(R.string.login_title, stringResource(service.nameRes()))) }, + title = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(R.string.login_title, stringResource(service.nameRes())), + modifier = Modifier.weight(1f), + ) + IconButton(onClick = onDismissRequest) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = stringResource(R.string.action_close), + ) + } + } + }, text = { Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { OutlinedTextField( @@ -232,38 +246,30 @@ class SettingsTrackingScreen : SearchableSettings { } }, confirmButton = { - Column { - Button( - modifier = Modifier.fillMaxWidth(), - enabled = !processing, - onClick = { - if (username.text.isEmpty() || password.text.isEmpty()) { - inputError = true - return@Button - } - scope.launchIO { - inputError = false - processing = true - val result = checkLogin( - context = context, - service = service, - username = username.text, - password = password.text, - ) - if (result) onDismissRequest() - processing = false - } - }, - ) { - val id = if (processing) R.string.loading else R.string.login - Text(text = stringResource(id)) - } - TextButton( - modifier = Modifier.fillMaxWidth(), - onClick = onDismissRequest, - ) { - Text(text = stringResource(android.R.string.cancel)) - } + Button( + modifier = Modifier.fillMaxWidth(), + enabled = !processing, + onClick = { + if (username.text.isEmpty() || password.text.isEmpty()) { + inputError = true + return@Button + } + scope.launchIO { + inputError = false + processing = true + val result = checkLogin( + context = context, + service = service, + username = username.text, + password = password.text, + ) + if (result) onDismissRequest() + processing = false + } + }, + ) { + val id = if (processing) R.string.loading else R.string.login + Text(text = stringResource(id)) } }, ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt index fecc94ae8..9c20d670b 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt @@ -109,7 +109,7 @@ private fun AppThemesList( color = MaterialTheme.colorScheme.onSurface, textAlign = TextAlign.Center, maxLines = 2, - style = MaterialTheme.typography.bodySmall, + style = MaterialTheme.typography.bodyMedium, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/BasePreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/BasePreferenceWidget.kt index b27246d6d..3685813d7 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/BasePreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/BasePreferenceWidget.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted import eu.kanade.presentation.util.secondaryItemAlpha import kotlinx.coroutines.delay @@ -54,12 +55,12 @@ internal fun BasePreferenceWidget( modifier = Modifier .padding( start = HorizontalPadding, - top = 4.dp, + top = 0.dp, end = HorizontalPadding, ) .secondaryItemAlpha(), - color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.bodySmall, + style = MaterialTheme.typography.bodyMedium, + maxLines = 10, ) } } else { @@ -106,15 +107,13 @@ private fun BasePreferenceWidgetImpl( imageVector = icon, contentDescription = null, modifier = Modifier - .padding(start = HorizontalPadding, end = 12.dp) - .secondaryItemAlpha(), - tint = MaterialTheme.colorScheme.onSurface, + .padding(start = HorizontalPadding, end = 0.dp), ) } Column( modifier = Modifier .weight(1f) - .padding(vertical = 14.dp), + .padding(vertical = 16.dp), ) { if (title.isNotBlank()) { Row( @@ -125,7 +124,8 @@ private fun BasePreferenceWidgetImpl( text = title, overflow = TextOverflow.Ellipsis, maxLines = 2, - style = MaterialTheme.typography.bodyLarge, + style = MaterialTheme.typography.titleLarge, + fontSize = 20.sp, ) } } @@ -173,4 +173,4 @@ internal fun Modifier.highlightBackground(highlighted: Boolean): Modifier = comp } internal val TrailingWidgetBuffer = 16.dp -internal val HorizontalPadding = 16.dp +internal val HorizontalPadding = 24.dp diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/ListPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/ListPreferenceWidget.kt index 8c1d76770..261de06f3 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/ListPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/ListPreferenceWidget.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton @@ -16,6 +17,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -23,6 +25,7 @@ import eu.kanade.presentation.components.Divider import eu.kanade.presentation.components.ScrollbarLazyColumn import eu.kanade.presentation.util.isScrolledToEnd import eu.kanade.presentation.util.isScrolledToStart +import eu.kanade.presentation.util.minimumTouchTargetSize @Composable fun ListPreferenceWidget( @@ -86,20 +89,22 @@ private fun DialogRow( Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) .selectable( selected = isSelected, onClick = { if (!isSelected) onSelected() }, - ), + ) + .fillMaxWidth() + .minimumTouchTargetSize(), ) { RadioButton( selected = isSelected, - onClick = { if (!isSelected) onSelected() }, + onClick = null, ) Text( text = label, style = MaterialTheme.typography.bodyLarge.merge(), - modifier = Modifier.padding(start = 12.dp), + modifier = Modifier.padding(start = 24.dp), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt index 5131ec1b2..12074093f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt @@ -1,10 +1,11 @@ package eu.kanade.presentation.more.settings.widget -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.Checkbox import androidx.compose.material3.MaterialTheme @@ -16,10 +17,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import eu.kanade.presentation.more.settings.Preference +import eu.kanade.presentation.util.minimumTouchTargetSize @Composable fun MultiSelectListPreferenceWidget( @@ -59,17 +62,22 @@ fun MultiSelectListPreferenceWidget( Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .fillMaxWidth() - .clickable { onSelectionChanged() }, + .clip(RoundedCornerShape(8.dp)) + .selectable( + selected = isSelected, + onClick = { onSelectionChanged() }, + ) + .minimumTouchTargetSize() + .fillMaxWidth(), ) { Checkbox( checked = isSelected, - onCheckedChange = { onSelectionChanged() }, + onCheckedChange = null, ) Text( text = current.value, style = MaterialTheme.typography.bodyMedium, - modifier = Modifier.padding(start = 12.dp), + modifier = Modifier.padding(start = 24.dp), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/PreferenceGroupHeader.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/PreferenceGroupHeader.kt index f825df342..faa57ca36 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/PreferenceGroupHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/PreferenceGroupHeader.kt @@ -21,7 +21,7 @@ fun PreferenceGroupHeader(title: String) { Text( text = title, color = MaterialTheme.colorScheme.secondary, - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier.padding(horizontal = 24.dp), style = MaterialTheme.typography.bodyMedium, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt index a5198ac7b..7172551ee 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt @@ -6,18 +6,20 @@ import androidx.compose.material.icons.filled.Preview import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.Preview @Composable fun TextPreferenceWidget( + modifier: Modifier = Modifier, title: String, subtitle: String? = null, icon: ImageVector? = null, onPreferenceClick: (() -> Unit)? = null, ) { - // TODO: Handle auth requirement here? BasePreferenceWidget( + modifier = modifier, title = title, subtitle = subtitle, icon = icon, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt index 2af0497bf..582453e1a 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted @Composable @@ -39,7 +40,7 @@ fun TrackingPreferenceWidget( modifier = modifier .clickable(enabled = onClick != null, onClick = { onClick?.invoke() }) .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp), + .padding(horizontal = HorizontalPadding, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { Box( @@ -60,7 +61,8 @@ fun TrackingPreferenceWidget( .weight(1f) .padding(horizontal = 16.dp), maxLines = 1, - style = MaterialTheme.typography.titleMedium, + style = MaterialTheme.typography.titleLarge, + fontSize = 20.sp, ) if (checked) { Icon( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt index c169fdd9c..d18654a42 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt @@ -78,7 +78,7 @@ fun TriStateListDialog( val state = selected[index] Row( modifier = Modifier - .clip(RoundedCornerShape(25)) + .clip(RoundedCornerShape(8.dp)) .clickable { selected[index] = when (state) { State.UNCHECKED -> State.CHECKED diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt index 14d2f97eb..53580fc1e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt @@ -1,18 +1,23 @@ package eu.kanade.tachiyomi.ui.setting import android.os.Bundle +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.core.os.bundleOf import cafe.adriel.voyager.core.stack.StackEvent import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.transitions.ScreenTransition +import eu.kanade.presentation.components.TwoPanelBox import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen +import eu.kanade.presentation.more.settings.screen.SettingsGeneralScreen import eu.kanade.presentation.more.settings.screen.SettingsMainScreen import eu.kanade.presentation.util.LocalBackPress import eu.kanade.presentation.util.LocalRouter +import eu.kanade.presentation.util.calculateWindowWidthSizeClass import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController -import soup.compose.material.motion.animation.materialSharedAxisZ +import soup.compose.material.motion.animation.materialSharedAxisX +import soup.compose.material.motion.animation.rememberSlideDistance class SettingsMainController : BasicFullComposeController { @@ -25,20 +30,52 @@ class SettingsMainController : BasicFullComposeController { @Composable override fun ComposeContent() { - Navigator( - screen = if (toBackupScreen) SettingsBackupScreen() else SettingsMainScreen, - content = { - CompositionLocalProvider( - LocalRouter provides router, - LocalBackPress provides this::back, + CompositionLocalProvider(LocalRouter provides router) { + val widthSizeClass = calculateWindowWidthSizeClass() + if (widthSizeClass == WindowWidthSizeClass.Compact) { + Navigator( + screen = if (toBackupScreen) SettingsBackupScreen() else SettingsMainScreen, + content = { + CompositionLocalProvider(LocalBackPress provides this::back) { + val slideDistance = rememberSlideDistance() + ScreenTransition( + navigator = it, + transition = { + materialSharedAxisX( + forward = it.lastEvent != StackEvent.Pop, + slideDistance = slideDistance, + ) + }, + ) + } + }, + ) + } else { + Navigator( + screen = if (toBackupScreen) SettingsBackupScreen() else SettingsGeneralScreen(), ) { - ScreenTransition( - navigator = it, - transition = { materialSharedAxisZ(forward = it.lastEvent != StackEvent.Pop) }, + TwoPanelBox( + startContent = { + CompositionLocalProvider(LocalBackPress provides this@SettingsMainController::back) { + SettingsMainScreen.Content(twoPane = true) + } + }, + endContent = { + val slideDistance = rememberSlideDistance() + ScreenTransition( + navigator = it, + transition = { + materialSharedAxisX( + forward = it.lastEvent != StackEvent.Pop, + slideDistance = slideDistance, + ) + }, + ) + }, ) } - }, - ) + } + } } private fun back() { diff --git a/i18n/src/main/res/values-fr/strings_sy.xml b/i18n/src/main/res/values-fr/strings_sy.xml index a3d5b01a7..2ce40a5b1 100644 --- a/i18n/src/main/res/values-fr/strings_sy.xml +++ b/i18n/src/main/res/values-fr/strings_sy.xml @@ -513,10 +513,10 @@ Désabonné Paramètres de MangaDex - Sync Mangadex manga dans Neko + Sync MangaDex manga dans Neko Extrait le manga de lecture/relecture de Mangadex dans votre bibliothèque Neko Source MangaDex préférée - Définissez votre source mangadex choisie, cela sera utilisé pour les suivis et un tas d\'autres fonctionnalités autour de l\'application + Définissez votre source MangaDex choisie, cela sera utilisé pour les suivis et un tas d\'autres fonctionnalités autour de l\'application Code de double identification Les champs ne peut pas être vide Ajouter au suivie MangaDex @@ -525,8 +525,8 @@ - - + + Manga similaire %1$s diff --git a/i18n/src/main/res/values-pt-rBR/strings_sy.xml b/i18n/src/main/res/values-pt-rBR/strings_sy.xml index a6d4d3189..5d65dc619 100644 --- a/i18n/src/main/res/values-pt-rBR/strings_sy.xml +++ b/i18n/src/main/res/values-pt-rBR/strings_sy.xml @@ -601,7 +601,7 @@ Sincronizar mangá do MangaDex a sua bilioteca Move mangás do MangaDex a sua biblioteca, se ainda não adicionados. Fonte do MangaDex preferida - Define sua fonte do mangadex escolhida, ela será usada para os follows e muitas outras funções ao redor do app + Define sua fonte do MangaDex escolhida, ela será usada para os follows e muitas outras funções ao redor do app Código 2FA Campos não podem estar vazios Adicionar aos follows do MangaDex diff --git a/i18n/src/main/res/values-ru/strings_sy.xml b/i18n/src/main/res/values-ru/strings_sy.xml index 051a6f25f..9560473c8 100644 --- a/i18n/src/main/res/values-ru/strings_sy.xml +++ b/i18n/src/main/res/values-ru/strings_sy.xml @@ -678,7 +678,7 @@ Без отслеживания Настройки (MangaDex) - Синхронизировать серии (Mangadex) + Синхронизировать серии (MangaDex) Добавляет серии из MangaDex в библиотеку, если они ещё не добавлены. Предпочитаемый источник (MangaDex) Установить языковой источник MangaDex. Этот источник будет использовать приложение для некоторых функций. diff --git a/i18n/src/main/res/values-zh-rCN/strings_sy.xml b/i18n/src/main/res/values-zh-rCN/strings_sy.xml index 4fce89627..2e3a8d30a 100644 --- a/i18n/src/main/res/values-zh-rCN/strings_sy.xml +++ b/i18n/src/main/res/values-zh-rCN/strings_sy.xml @@ -635,10 +635,10 @@ 取消关注 MangaDex 设置 - 同步 Mangadex 中的漫画到书架 + 同步 MangaDex 中的漫画到书架 如果未被添加则从 MangaDex 拉取漫画到你的书架 首选 MangaDex 来源 - 设置你所选择的 mangadex 来源,这将用于关注和应用中一系列其他功能。 + 设置你所选择的 MangaDex 来源,这将用于关注和应用中一系列其他功能。 2FA 验证码 字段不能为空 添加到 MangaDex 关注 diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index d88a7aaa9..df53afe11 100755 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -159,6 +159,17 @@ Advanced About + App language, notifications + Theme, date & time format + Categories, global update + Reading mode, display, navigation + Automatic download, download ahead + One-way progress sync, enhanced sync + Sources, extensions, global search + Manual & automatic backups + App lock, secure screen + Dump crash logs, battery optimizations + Theme Dark mode diff --git a/i18n/src/main/res/values/strings_sy.xml b/i18n/src/main/res/values/strings_sy.xml index a981a3282..7658b43bc 100644 --- a/i18n/src/main/res/values/strings_sy.xml +++ b/i18n/src/main/res/values/strings_sy.xml @@ -34,6 +34,9 @@ Fork Settings MangaDex + E-Hentai, ExHentai login, gallery sync + MangaDex, login, follows sync + E-Hentai Website Account Settings Enable ExHentai @@ -664,10 +667,10 @@ MDList Unfollowed MangaDex settings - Sync Mangadex manga to your library + Sync MangaDex manga to your library Pulls manga from MangaDex into your library if they are not already added. Preferred MangaDex source - Set your chosen mangadex source, this will be used for follows and a bunch more features around the app + Set your chosen MangaDex source, this will be used for follows and a bunch more features around the app 2FA Code Fields cannot be blank Add to MangaDex follows @@ -685,7 +688,7 @@ Similar to %1$s No Similar Manga found - + Similar Monochrome Main story