Reader app bars improvements (#2337)
* Flatten reader app bars layout * Fix reader app bars contract on grey background * Fix unexpected reader app bars visibility changes
This commit is contained in:
1 parent
fe371f1d66
commit
f2dbb31951
5 files changed
+53
-78
No files matched your search
@@ -232,9 +232,6 @@ fun AnimatedVisibilityScope.ReaderScreen(pageLoader: PageLoader, info: BaseGalle
|
||||
}
|
||||
val bgColor by collectBackgroundColorAsState()
|
||||
syncState.Sync(isWebtoon) { appbarVisible = false }
|
||||
LaunchedEffect(isWebtoon) {
|
||||
appbarVisible = false
|
||||
}
|
||||
if (fullscreen) {
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { appbarVisible }.collect {
|
||||
@@ -372,6 +369,7 @@ fun AnimatedVisibilityScope.ReaderScreen(pageLoader: PageLoader, info: BaseGalle
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import com.hippo.ehviewer.gallery.PageLoader
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
|
||||
@Stable
|
||||
@@ -59,7 +60,7 @@ class SliderPagerDoubleSync(
|
||||
}
|
||||
if (sliderFollowPager) {
|
||||
LaunchedEffect(currentIndexFlow) {
|
||||
currentIndexFlow.collect { index ->
|
||||
currentIndexFlow.drop(1).collect { index ->
|
||||
sliderValue = index + 1
|
||||
pageLoader.startPage = index
|
||||
onPageSelected()
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExposedDropdownMenuAnchorType
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
@@ -16,6 +15,7 @@ import androidx.compose.material3.FlexibleBottomAppBar
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -77,8 +77,9 @@ fun BottomReaderBar(onClickSettings: () -> Unit) = FlexibleBottomAppBar(
|
||||
)
|
||||
}
|
||||
|
||||
// Use surface container highest to have a higher contract on grey background
|
||||
val toolbarColor
|
||||
@Composable get() = BottomAppBarDefaults.containerColor.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
|
||||
@Composable get() = MaterialTheme.colorScheme.surfaceContainerHighest.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
|
||||
|
||||
@Composable
|
||||
private fun DropdownIconButton(
|
||||
|
||||
@@ -4,9 +4,8 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsDraggedAsState
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.material3.Text
|
||||
@@ -35,61 +34,45 @@ fun ChapterNavigator(
|
||||
currentPage: Int,
|
||||
totalPages: Int,
|
||||
onSliderValueChange: (Int) -> Unit,
|
||||
) {
|
||||
) = CompositionLocalProvider(LocalLayoutDirection provides if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr) {
|
||||
val windowSizeClass = LocalWindowSizeClass.current
|
||||
val horizontalPadding = if (windowSizeClass.isExpanded) 24.dp else 16.dp
|
||||
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
|
||||
val configuration = LocalConfiguration.current
|
||||
val maxTickCount = configuration.screenWidthDp / (SliderDefaults.TickSize.value * 2.5f).roundToInt()
|
||||
val showTicks = totalPages < maxTickCount
|
||||
|
||||
// We explicitly handle direction based on the reader viewer rather than the system direction
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (totalPages > 1) {
|
||||
CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
|
||||
Row(
|
||||
modifier = Modifier.weight(1f).clip(RoundedCornerShape(24.dp)).background(toolbarColor).padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(text = currentPage.toString())
|
||||
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
if (showTicks) {
|
||||
val sliderDragged by interactionSource.collectIsDraggedAsState()
|
||||
val hapticFeedback = rememberHapticFeedback()
|
||||
LaunchedEffect(currentPage) {
|
||||
if (sliderDragged) {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.MOVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
Slider(
|
||||
modifier = Modifier.weight(1f).padding(horizontal = 8.dp),
|
||||
value = currentPage.toFloat(),
|
||||
valueRange = 1f..totalPages.toFloat(),
|
||||
steps = totalPages - 2,
|
||||
onValueChange = {
|
||||
onSliderValueChange(it.roundToInt() - 1)
|
||||
},
|
||||
interactionSource = interactionSource,
|
||||
colors = if (showTicks) {
|
||||
SliderDefaults.colors()
|
||||
} else {
|
||||
SliderDefaults.colors(
|
||||
activeTickColor = Color.Transparent,
|
||||
inactiveTickColor = Color.Transparent,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
Text(text = totalPages.toString())
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = horizontalPadding).clip(CircleShape).background(toolbarColor).padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(text = "$currentPage")
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
if (showTicks) {
|
||||
val sliderDragged by interactionSource.collectIsDraggedAsState()
|
||||
val hapticFeedback = rememberHapticFeedback()
|
||||
LaunchedEffect(currentPage) {
|
||||
if (sliderDragged) {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.MOVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
Slider(
|
||||
modifier = Modifier.weight(1f).padding(horizontal = 8.dp),
|
||||
value = currentPage.toFloat(),
|
||||
valueRange = 1f..totalPages.toFloat(),
|
||||
steps = totalPages - 2,
|
||||
onValueChange = {
|
||||
onSliderValueChange(it.roundToInt() - 1)
|
||||
},
|
||||
interactionSource = interactionSource,
|
||||
colors = if (showTicks) {
|
||||
SliderDefaults.colors()
|
||||
} else {
|
||||
SliderDefaults.colors(
|
||||
activeTickColor = Color.Transparent,
|
||||
inactiveTickColor = Color.Transparent,
|
||||
)
|
||||
},
|
||||
)
|
||||
Text(text = "$totalPages")
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,8 @@ import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
@@ -30,27 +28,21 @@ fun ReaderAppBars(
|
||||
onSliderValueChange: (Int) -> Unit,
|
||||
onClickSettings: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) = Column(
|
||||
modifier = modifier.fillMaxHeight().windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal)),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
) = AnimatedVisibility(
|
||||
visible = visible,
|
||||
modifier = modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal)),
|
||||
enter = slideInVertically(initialOffsetY = { it }, animationSpec = animationSpec),
|
||||
exit = slideOutVertically(targetOffsetY = { it }, animationSpec = animationSpec),
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
enter = slideInVertically(initialOffsetY = { it }, animationSpec = animationSpec),
|
||||
exit = slideOutVertically(targetOffsetY = { it }, animationSpec = animationSpec),
|
||||
) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
if (showSeekBar) {
|
||||
ChapterNavigator(
|
||||
isRtl = isRtl,
|
||||
currentPage = currentPage,
|
||||
totalPages = totalPages,
|
||||
onSliderValueChange = onSliderValueChange,
|
||||
)
|
||||
}
|
||||
BottomReaderBar(onClickSettings = onClickSettings)
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
if (showSeekBar && totalPages > 1) {
|
||||
ChapterNavigator(
|
||||
isRtl = isRtl,
|
||||
currentPage = currentPage,
|
||||
totalPages = totalPages,
|
||||
onSliderValueChange = onSliderValueChange,
|
||||
)
|
||||
}
|
||||
BottomReaderBar(onClickSettings = onClickSettings)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user