Abstract ChapterSettingsDialog for reuse elsewhere
This commit is contained in:
parent
1009e15aa6
commit
a61e2799db
2 changed files with 173 additions and 178 deletions
|
@ -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<String>,
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,22 +2,18 @@ package eu.kanade.presentation.manga
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.heightIn
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowDownward
|
import androidx.compose.material.icons.filled.ArrowDownward
|
||||||
import androidx.compose.material.icons.filled.ArrowUpward
|
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.CheckBox
|
||||||
import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank
|
import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank
|
||||||
import androidx.compose.material.icons.rounded.DisabledByDefault
|
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.Checkbox
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.RadioButton
|
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.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
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
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
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.graphics.vector.ImageVector
|
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.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
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.Manga
|
||||||
import eu.kanade.domain.manga.model.TriStateFilter
|
import eu.kanade.domain.manga.model.TriStateFilter
|
||||||
import eu.kanade.presentation.components.AdaptiveSheet
|
import eu.kanade.presentation.components.TabbedDialog
|
||||||
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.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChapterSettingsDialog(
|
fun ChapterSettingsDialog(
|
||||||
|
@ -72,41 +51,6 @@ fun ChapterSettingsDialog(
|
||||||
onDisplayModeChanged: (Long) -> Unit,
|
onDisplayModeChanged: (Long) -> Unit,
|
||||||
onSetAsDefault: (applyToExistingManga: Boolean) -> 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) }
|
var showSetAsDefaultDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
if (showSetAsDefaultDialog) {
|
if (showSetAsDefaultDialog) {
|
||||||
SetAsDefaultDialog(
|
SetAsDefaultDialog(
|
||||||
|
@ -115,56 +59,23 @@ private fun ChapterSettingsDialogImpl(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
TabbedDialog(
|
||||||
Row {
|
onDismissRequest = onDismissRequest,
|
||||||
TabRow(
|
tabTitles = listOf(
|
||||||
modifier = Modifier.weight(1f),
|
stringResource(R.string.action_filter),
|
||||||
selectedTabIndex = pagerState.currentPage,
|
stringResource(R.string.action_sort),
|
||||||
indicator = { TabIndicator(it[pagerState.currentPage]) },
|
stringResource(R.string.action_display),
|
||||||
divider = {},
|
),
|
||||||
) {
|
tabOverflowMenuContent = { closeMenu ->
|
||||||
tabTitles.fastForEachIndexed { i, s ->
|
DropdownMenuItem(
|
||||||
val selected = pagerState.currentPage == i
|
text = { Text(stringResource(R.string.set_chapter_settings_as_default)) },
|
||||||
Tab(
|
onClick = {
|
||||||
selected = selected,
|
showSetAsDefaultDialog = true
|
||||||
onClick = { scope.launch { pagerState.animateScrollToPage(i) } },
|
closeMenu()
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
text = s,
|
|
||||||
color = if (selected) {
|
|
||||||
MaterialTheme.colorScheme.primary
|
|
||||||
} else {
|
|
||||||
MaterialTheme.colorScheme.onSurfaceVariant
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
) { contentPadding, page ->
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
when (page) {
|
when (page) {
|
||||||
0 -> {
|
0 -> {
|
||||||
val forceDownloaded = manga?.forceDownloaded() == true
|
val forceDownloaded = manga?.forceDownloaded() == true
|
||||||
|
@ -182,13 +93,16 @@ private fun ChapterSettingsDialogImpl(
|
||||||
onBookmarkedFilterChanged = onBookmarkedFilterChanged,
|
onBookmarkedFilterChanged = onBookmarkedFilterChanged,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
1 -> SortPage(
|
1 -> {
|
||||||
|
SortPage(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
sortingMode = manga?.sorting ?: 0,
|
sortingMode = manga?.sorting ?: 0,
|
||||||
sortDescending = manga?.sortDescending() ?: false,
|
sortDescending = manga?.sortDescending() ?: false,
|
||||||
onItemSelected = onSortModeChanged,
|
onItemSelected = onSortModeChanged,
|
||||||
)
|
)
|
||||||
2 -> DisplayPage(
|
}
|
||||||
|
2 -> {
|
||||||
|
DisplayPage(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
displayMode = manga?.displayMode ?: 0,
|
displayMode = manga?.displayMode ?: 0,
|
||||||
onItemSelected = onDisplayModeChanged,
|
onItemSelected = onDisplayModeChanged,
|
||||||
|
@ -196,7 +110,6 @@ private fun ChapterSettingsDialogImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -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
|
@Composable
|
||||||
private fun FilterPage(
|
private fun FilterPage(
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
|
@ -470,19 +356,3 @@ private fun DisplayPageItem(
|
||||||
|
|
||||||
private val HorizontalPadding = 24.dp
|
private val HorizontalPadding = 24.dp
|
||||||
private val VerticalPadding = 8.dp
|
private val VerticalPadding = 8.dp
|
||||||
|
|
||||||
@ThemePreviews
|
|
||||||
@Composable
|
|
||||||
private fun ChapterSettingsDialogPreview() {
|
|
||||||
TachiyomiTheme {
|
|
||||||
Surface {
|
|
||||||
ChapterSettingsDialogImpl(
|
|
||||||
onDownloadFilterChanged = {},
|
|
||||||
onUnreadFilterChanged = {},
|
|
||||||
onBookmarkedFilterChanged = {},
|
|
||||||
onSortModeChanged = {},
|
|
||||||
onDisplayModeChanged = {},
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in a new issue