From a61e2799dbfd60039b577d7fffc8b6494ba74aba Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 8 Dec 2022 23:13:09 -0500 Subject: [PATCH] Abstract ChapterSettingsDialog for reuse elsewhere --- .../presentation/components/TabbedDialog.kt | 125 ++++++++++ ...ingsDialog.kt => ChapterSettingsDialog.kt} | 226 ++++-------------- 2 files changed, 173 insertions(+), 178 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt rename app/src/main/java/eu/kanade/presentation/manga/{MangaSettingsDialog.kt => ChapterSettingsDialog.kt} (61%) diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt new file mode 100644 index 000000000..dd2cffe5e --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt @@ -0,0 +1,125 @@ +package eu.kanade.presentation.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastForEachIndexed +import eu.kanade.tachiyomi.R +import kotlinx.coroutines.launch + +@Composable +fun TabbedDialog( + onDismissRequest: () -> Unit, + tabTitles: List, + tabOverflowMenuContent: (@Composable ColumnScope.(() -> Unit) -> Unit)? = null, + content: @Composable (PaddingValues, Int) -> Unit, +) { + AdaptiveSheet( + onDismissRequest = onDismissRequest, + ) { contentPadding -> + val scope = rememberCoroutineScope() + val pagerState = rememberPagerState() + + Column { + Row { + TabRow( + modifier = Modifier.weight(1f), + selectedTabIndex = pagerState.currentPage, + indicator = { TabIndicator(it[pagerState.currentPage]) }, + divider = {}, + ) { + tabTitles.fastForEachIndexed { i, tab -> + val selected = pagerState.currentPage == i + Tab( + selected = selected, + onClick = { scope.launch { pagerState.animateScrollToPage(i) } }, + text = { + Text( + text = tab, + color = if (selected) { + MaterialTheme.colorScheme.primary + } else { + MaterialTheme.colorScheme.onSurfaceVariant + }, + ) + }, + ) + } + } + + tabOverflowMenuContent?.let { + MoreMenu(tabOverflowMenuContent) + } + } + Divider() + + val density = LocalDensity.current + var largestHeight by rememberSaveable { mutableStateOf(0f) } + HorizontalPager( + modifier = Modifier.heightIn(min = largestHeight.dp), + count = tabTitles.size, + state = pagerState, + verticalAlignment = Alignment.Top, + ) { page -> + Box( + modifier = Modifier.onSizeChanged { + with(density) { + val heightDp = it.height.toDp() + if (heightDp.value > largestHeight) { + largestHeight = heightDp.value + } + } + }, + ) { + content(contentPadding, page) + } + } + } + } +} + +@Composable +private fun MoreMenu( + content: @Composable ColumnScope.(() -> Unit) -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { + IconButton(onClick = { expanded = true }) { + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = stringResource(R.string.label_more), + ) + } + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + ) { + content { expanded = false } + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt similarity index 61% rename from app/src/main/java/eu/kanade/presentation/manga/MangaSettingsDialog.kt rename to app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt index 7d43549fb..66ca9e375 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -2,22 +2,18 @@ package eu.kanade.presentation.manga import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowUpward -import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.rounded.CheckBox import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank import androidx.compose.material.icons.rounded.DisabledByDefault @@ -25,41 +21,24 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton -import androidx.compose.material3.Surface -import androidx.compose.material3.Tab -import androidx.compose.material3.TabRow import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.onSizeChanged -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastForEachIndexed import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.TriStateFilter -import eu.kanade.presentation.components.AdaptiveSheet -import eu.kanade.presentation.components.Divider -import eu.kanade.presentation.components.DropdownMenu -import eu.kanade.presentation.components.HorizontalPager -import eu.kanade.presentation.components.TabIndicator -import eu.kanade.presentation.components.rememberPagerState -import eu.kanade.presentation.theme.TachiyomiTheme -import eu.kanade.presentation.util.ThemePreviews +import eu.kanade.presentation.components.TabbedDialog import eu.kanade.tachiyomi.R -import kotlinx.coroutines.launch @Composable fun ChapterSettingsDialog( @@ -72,41 +51,6 @@ fun ChapterSettingsDialog( onDisplayModeChanged: (Long) -> Unit, onSetAsDefault: (applyToExistingManga: Boolean) -> Unit, ) { - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { contentPadding -> - ChapterSettingsDialogImpl( - manga = manga, - contentPadding = contentPadding, - onDownloadFilterChanged = onDownloadFilterChanged, - onUnreadFilterChanged = onUnreadFilterChanged, - onBookmarkedFilterChanged = onBookmarkedFilterChanged, - onSortModeChanged = onSortModeChanged, - onDisplayModeChanged = onDisplayModeChanged, - onSetAsDefault = onSetAsDefault, - ) - } -} - -@Composable -private fun ChapterSettingsDialogImpl( - manga: Manga? = null, - contentPadding: PaddingValues = PaddingValues(), - onDownloadFilterChanged: (TriStateFilter) -> Unit, - onUnreadFilterChanged: (TriStateFilter) -> Unit, - onBookmarkedFilterChanged: (TriStateFilter) -> Unit, - onSortModeChanged: (Long) -> Unit, - onDisplayModeChanged: (Long) -> Unit, - onSetAsDefault: (applyToExistingManga: Boolean) -> Unit, -) { - val scope = rememberCoroutineScope() - val tabTitles = listOf( - stringResource(R.string.action_filter), - stringResource(R.string.action_sort), - stringResource(R.string.action_display), - ) - val pagerState = rememberPagerState() - var showSetAsDefaultDialog by rememberSaveable { mutableStateOf(false) } if (showSetAsDefaultDialog) { SetAsDefaultDialog( @@ -115,85 +59,54 @@ private fun ChapterSettingsDialogImpl( ) } - Column { - Row { - TabRow( - modifier = Modifier.weight(1f), - selectedTabIndex = pagerState.currentPage, - indicator = { TabIndicator(it[pagerState.currentPage]) }, - divider = {}, - ) { - tabTitles.fastForEachIndexed { i, s -> - val selected = pagerState.currentPage == i - Tab( - selected = selected, - onClick = { scope.launch { pagerState.animateScrollToPage(i) } }, - text = { - Text( - text = s, - color = if (selected) { - MaterialTheme.colorScheme.primary - } else { - MaterialTheme.colorScheme.onSurfaceVariant - }, - ) - }, - ) - } - } - - MoreMenu(onSetAsDefault = { showSetAsDefaultDialog = true }) - } - - Divider() - - val density = LocalDensity.current - var largestHeight by rememberSaveable { mutableStateOf(0f) } - HorizontalPager( - modifier = Modifier.heightIn(min = largestHeight.dp), - count = tabTitles.size, - state = pagerState, - verticalAlignment = Alignment.Top, - ) { page -> - Box( - modifier = Modifier.onSizeChanged { - with(density) { - val heightDp = it.height.toDp() - if (heightDp.value > largestHeight) { - largestHeight = heightDp.value - } - } + TabbedDialog( + onDismissRequest = onDismissRequest, + tabTitles = listOf( + stringResource(R.string.action_filter), + stringResource(R.string.action_sort), + stringResource(R.string.action_display), + ), + tabOverflowMenuContent = { closeMenu -> + DropdownMenuItem( + text = { Text(stringResource(R.string.set_chapter_settings_as_default)) }, + onClick = { + showSetAsDefaultDialog = true + closeMenu() }, - ) { - when (page) { - 0 -> { - val forceDownloaded = manga?.forceDownloaded() == true - FilterPage( - contentPadding = contentPadding, - downloadFilter = if (forceDownloaded) { - TriStateFilter.ENABLED_NOT - } else { - manga?.downloadedFilter - } ?: TriStateFilter.DISABLED, - onDownloadFilterChanged = onDownloadFilterChanged.takeUnless { forceDownloaded }, - unreadFilter = manga?.unreadFilter ?: TriStateFilter.DISABLED, - onUnreadFilterChanged = onUnreadFilterChanged, - bookmarkedFilter = manga?.bookmarkedFilter ?: TriStateFilter.DISABLED, - onBookmarkedFilterChanged = onBookmarkedFilterChanged, - ) - } - 1 -> SortPage( - contentPadding = contentPadding, - sortingMode = manga?.sorting ?: 0, - sortDescending = manga?.sortDescending() ?: false, - onItemSelected = onSortModeChanged, - ) - 2 -> DisplayPage( - contentPadding = contentPadding, - displayMode = manga?.displayMode ?: 0, - onItemSelected = onDisplayModeChanged, - ) - } + ) + }, + ) { contentPadding, page -> + when (page) { + 0 -> { + val forceDownloaded = manga?.forceDownloaded() == true + FilterPage( + contentPadding = contentPadding, + downloadFilter = if (forceDownloaded) { + TriStateFilter.ENABLED_NOT + } else { + manga?.downloadedFilter + } ?: TriStateFilter.DISABLED, + onDownloadFilterChanged = onDownloadFilterChanged.takeUnless { forceDownloaded }, + unreadFilter = manga?.unreadFilter ?: TriStateFilter.DISABLED, + onUnreadFilterChanged = onUnreadFilterChanged, + bookmarkedFilter = manga?.bookmarkedFilter ?: TriStateFilter.DISABLED, + onBookmarkedFilterChanged = onBookmarkedFilterChanged, + ) + } + 1 -> { + SortPage( + contentPadding = contentPadding, + sortingMode = manga?.sorting ?: 0, + sortDescending = manga?.sortDescending() ?: false, + onItemSelected = onSortModeChanged, + ) + } + 2 -> { + DisplayPage( + contentPadding = contentPadding, + displayMode = manga?.displayMode ?: 0, + onItemSelected = onDisplayModeChanged, + ) } } } @@ -247,33 +160,6 @@ private fun SetAsDefaultDialog( ) } -@Composable -private fun MoreMenu( - onSetAsDefault: () -> Unit, -) { - var expanded by remember { mutableStateOf(false) } - Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { - IconButton(onClick = { expanded = true }) { - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(R.string.label_more), - ) - } - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - ) { - DropdownMenuItem( - text = { Text(stringResource(R.string.set_chapter_settings_as_default)) }, - onClick = { - onSetAsDefault() - expanded = false - }, - ) - } - } -} - @Composable private fun FilterPage( contentPadding: PaddingValues, @@ -470,19 +356,3 @@ private fun DisplayPageItem( private val HorizontalPadding = 24.dp private val VerticalPadding = 8.dp - -@ThemePreviews -@Composable -private fun ChapterSettingsDialogPreview() { - TachiyomiTheme { - Surface { - ChapterSettingsDialogImpl( - onDownloadFilterChanged = {}, - onUnreadFilterChanged = {}, - onBookmarkedFilterChanged = {}, - onSortModeChanged = {}, - onDisplayModeChanged = {}, - ) {} - } - } -}