mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
Bump Compose M3 to 1.0.0-beta01 (#7867)
This commit is contained in:
parent
aab5f083db
commit
655fa25b51
7 changed files with 520 additions and 49 deletions
|
@ -2,7 +2,8 @@ package eu.kanade.presentation.components
|
|||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
|
@ -15,6 +16,7 @@ import androidx.compose.material3.SmallTopAppBar
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
|
@ -22,12 +24,11 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@Composable
|
||||
|
@ -97,14 +98,10 @@ fun AppBar(
|
|||
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||
) {
|
||||
val scrollFraction = if (isActionMode) 1f else scrollBehavior?.state?.overlappedFraction ?: 0f
|
||||
val backgroundColor by TopAppBarDefaults.smallTopAppBarColors().containerColor(scrollFraction)
|
||||
|
||||
Column(
|
||||
modifier = modifier.drawBehind { drawRect(backgroundColor) },
|
||||
modifier = modifier,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
navigationIcon = {
|
||||
if (isActionMode) {
|
||||
IconButton(onClick = onCancelActionMode) {
|
||||
|
@ -126,10 +123,11 @@ fun AppBar(
|
|||
},
|
||||
title = titleContent,
|
||||
actions = actions,
|
||||
// Background handled by parent
|
||||
windowInsets = WindowInsets.statusBars,
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = Color.Transparent,
|
||||
scrolledContainerColor = Color.Transparent,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
elevation = if (isActionMode) 3.dp else 0.dp,
|
||||
),
|
||||
),
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
|
|
|
@ -1,26 +1,45 @@
|
|||
package eu.kanade.presentation.components
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.VectorConverter
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.interaction.FocusInteraction
|
||||
import androidx.compose.foundation.interaction.HoverInteraction
|
||||
import androidx.compose.foundation.interaction.Interaction
|
||||
import androidx.compose.foundation.interaction.InteractionSource
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ButtonElevation
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.ElevatedButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ProvideTextStyle
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.util.animateElevation
|
||||
import androidx.compose.material3.ButtonDefaults as M3ButtonDefaults
|
||||
|
||||
@Composable
|
||||
fun TextButton(
|
||||
|
@ -30,10 +49,15 @@ fun TextButton(
|
|||
enabled: Boolean = true,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
elevation: ButtonElevation? = null,
|
||||
shape: Shape = ButtonDefaults.textShape,
|
||||
shape: Shape = M3ButtonDefaults.textShape,
|
||||
border: BorderStroke? = null,
|
||||
colors: ButtonColors = ButtonDefaults.textButtonColors(),
|
||||
contentPadding: PaddingValues = ButtonDefaults.TextButtonContentPadding,
|
||||
colors: ButtonColors = ButtonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colorScheme.primary,
|
||||
disabledContainerColor = Color.Transparent,
|
||||
disabledContentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f),
|
||||
),
|
||||
contentPadding: PaddingValues = M3ButtonDefaults.TextButtonContentPadding,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) =
|
||||
Button(
|
||||
|
@ -58,10 +82,10 @@ fun Button(
|
|||
enabled: Boolean = true,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
||||
shape: Shape = ButtonDefaults.textShape,
|
||||
shape: Shape = M3ButtonDefaults.textShape,
|
||||
border: BorderStroke? = null,
|
||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||
contentPadding: PaddingValues = M3ButtonDefaults.ContentPadding,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
val containerColor = colors.containerColor(enabled).value
|
||||
|
@ -86,8 +110,8 @@ fun Button(
|
|||
ProvideTextStyle(value = MaterialTheme.typography.labelLarge) {
|
||||
Row(
|
||||
Modifier.defaultMinSize(
|
||||
minWidth = ButtonDefaults.MinWidth,
|
||||
minHeight = ButtonDefaults.MinHeight,
|
||||
minWidth = M3ButtonDefaults.MinWidth,
|
||||
minHeight = M3ButtonDefaults.MinHeight,
|
||||
)
|
||||
.padding(contentPadding),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
|
@ -98,3 +122,255 @@ fun Button(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ButtonDefaults {
|
||||
/**
|
||||
* Creates a [ButtonColors] that represents the default container and content colors used in a
|
||||
* [Button].
|
||||
*
|
||||
* @param containerColor the container color of this [Button] when enabled.
|
||||
* @param contentColor the content color of this [Button] when enabled.
|
||||
* @param disabledContainerColor the container color of this [Button] when not enabled.
|
||||
* @param disabledContentColor the content color of this [Button] when not enabled.
|
||||
*/
|
||||
@Composable
|
||||
fun buttonColors(
|
||||
containerColor: Color = MaterialTheme.colorScheme.primary,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onPrimary,
|
||||
disabledContainerColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
|
||||
disabledContentColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f),
|
||||
): ButtonColors = ButtonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor,
|
||||
)
|
||||
|
||||
/**
|
||||
* Creates a [ButtonElevation] that will animate between the provided values according to the
|
||||
* Material specification for a [Button].
|
||||
*
|
||||
* @param defaultElevation the elevation used when the [Button] is enabled, and has no other
|
||||
* [Interaction]s.
|
||||
* @param pressedElevation the elevation used when this [Button] is enabled and pressed.
|
||||
* @param focusedElevation the elevation used when the [Button] is enabled and focused.
|
||||
* @param hoveredElevation the elevation used when the [Button] is enabled and hovered.
|
||||
* @param disabledElevation the elevation used when the [Button] is not enabled.
|
||||
*/
|
||||
@Composable
|
||||
fun buttonElevation(
|
||||
defaultElevation: Dp = 0.dp,
|
||||
pressedElevation: Dp = 0.dp,
|
||||
focusedElevation: Dp = 0.dp,
|
||||
hoveredElevation: Dp = 1.dp,
|
||||
disabledElevation: Dp = 0.dp,
|
||||
): ButtonElevation = ButtonElevation(
|
||||
defaultElevation = defaultElevation,
|
||||
pressedElevation = pressedElevation,
|
||||
focusedElevation = focusedElevation,
|
||||
hoveredElevation = hoveredElevation,
|
||||
disabledElevation = disabledElevation,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the elevation for a button in different states.
|
||||
*
|
||||
* - See [M3ButtonDefaults.buttonElevation] for the default elevation used in a [Button].
|
||||
* - See [M3ButtonDefaults.elevatedButtonElevation] for the default elevation used in a
|
||||
* [ElevatedButton].
|
||||
*/
|
||||
@Stable
|
||||
class ButtonElevation internal constructor(
|
||||
private val defaultElevation: Dp,
|
||||
private val pressedElevation: Dp,
|
||||
private val focusedElevation: Dp,
|
||||
private val hoveredElevation: Dp,
|
||||
private val disabledElevation: Dp,
|
||||
) {
|
||||
/**
|
||||
* Represents the tonal elevation used in a button, depending on its [enabled] state and
|
||||
* [interactionSource]. This should typically be the same value as the [shadowElevation].
|
||||
*
|
||||
* Tonal elevation is used to apply a color shift to the surface to give the it higher emphasis.
|
||||
* When surface's color is [ColorScheme.surface], a higher elevation will result in a darker
|
||||
* color in light theme and lighter color in dark theme.
|
||||
*
|
||||
* See [shadowElevation] which controls the elevation of the shadow drawn around the button.
|
||||
*
|
||||
* @param enabled whether the button is enabled
|
||||
* @param interactionSource the [InteractionSource] for this button
|
||||
*/
|
||||
@Composable
|
||||
internal fun tonalElevation(enabled: Boolean, interactionSource: InteractionSource): State<Dp> {
|
||||
return animateElevation(enabled = enabled, interactionSource = interactionSource)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the shadow elevation used in a button, depending on its [enabled] state and
|
||||
* [interactionSource]. This should typically be the same value as the [tonalElevation].
|
||||
*
|
||||
* Shadow elevation is used to apply a shadow around the button to give it higher emphasis.
|
||||
*
|
||||
* See [tonalElevation] which controls the elevation with a color shift to the surface.
|
||||
*
|
||||
* @param enabled whether the button is enabled
|
||||
* @param interactionSource the [InteractionSource] for this button
|
||||
*/
|
||||
@Composable
|
||||
internal fun shadowElevation(
|
||||
enabled: Boolean,
|
||||
interactionSource: InteractionSource,
|
||||
): State<Dp> {
|
||||
return animateElevation(enabled = enabled, interactionSource = interactionSource)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun animateElevation(
|
||||
enabled: Boolean,
|
||||
interactionSource: InteractionSource,
|
||||
): State<Dp> {
|
||||
val interactions = remember { mutableStateListOf<Interaction>() }
|
||||
LaunchedEffect(interactionSource) {
|
||||
interactionSource.interactions.collect { interaction ->
|
||||
when (interaction) {
|
||||
is HoverInteraction.Enter -> {
|
||||
interactions.add(interaction)
|
||||
}
|
||||
is HoverInteraction.Exit -> {
|
||||
interactions.remove(interaction.enter)
|
||||
}
|
||||
is FocusInteraction.Focus -> {
|
||||
interactions.add(interaction)
|
||||
}
|
||||
is FocusInteraction.Unfocus -> {
|
||||
interactions.remove(interaction.focus)
|
||||
}
|
||||
is PressInteraction.Press -> {
|
||||
interactions.add(interaction)
|
||||
}
|
||||
is PressInteraction.Release -> {
|
||||
interactions.remove(interaction.press)
|
||||
}
|
||||
is PressInteraction.Cancel -> {
|
||||
interactions.remove(interaction.press)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val interaction = interactions.lastOrNull()
|
||||
|
||||
val target =
|
||||
if (!enabled) {
|
||||
disabledElevation
|
||||
} else {
|
||||
when (interaction) {
|
||||
is PressInteraction.Press -> pressedElevation
|
||||
is HoverInteraction.Enter -> hoveredElevation
|
||||
is FocusInteraction.Focus -> focusedElevation
|
||||
else -> defaultElevation
|
||||
}
|
||||
}
|
||||
|
||||
val animatable = remember { Animatable(target, Dp.VectorConverter) }
|
||||
|
||||
if (!enabled) {
|
||||
// No transition when moving to a disabled state
|
||||
LaunchedEffect(target) { animatable.snapTo(target) }
|
||||
} else {
|
||||
LaunchedEffect(target) {
|
||||
val lastInteraction = when (animatable.targetValue) {
|
||||
pressedElevation -> PressInteraction.Press(Offset.Zero)
|
||||
hoveredElevation -> HoverInteraction.Enter()
|
||||
focusedElevation -> FocusInteraction.Focus()
|
||||
else -> null
|
||||
}
|
||||
animatable.animateElevation(
|
||||
from = lastInteraction,
|
||||
to = interaction,
|
||||
target = target,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return animatable.asState()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || other !is ButtonElevation) return false
|
||||
|
||||
if (defaultElevation != other.defaultElevation) return false
|
||||
if (pressedElevation != other.pressedElevation) return false
|
||||
if (focusedElevation != other.focusedElevation) return false
|
||||
if (hoveredElevation != other.hoveredElevation) return false
|
||||
if (disabledElevation != other.disabledElevation) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = defaultElevation.hashCode()
|
||||
result = 31 * result + pressedElevation.hashCode()
|
||||
result = 31 * result + focusedElevation.hashCode()
|
||||
result = 31 * result + hoveredElevation.hashCode()
|
||||
result = 31 * result + disabledElevation.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the container and content colors used in a button in different states.
|
||||
*
|
||||
* - See [M3ButtonDefaults.buttonColors] for the default colors used in a [Button].
|
||||
* - See [M3ButtonDefaults.elevatedButtonColors] for the default colors used in a [ElevatedButton].
|
||||
* - See [M3ButtonDefaults.textButtonColors] for the default colors used in a [TextButton].
|
||||
*/
|
||||
@Immutable
|
||||
class ButtonColors internal constructor(
|
||||
private val containerColor: Color,
|
||||
private val contentColor: Color,
|
||||
private val disabledContainerColor: Color,
|
||||
private val disabledContentColor: Color,
|
||||
) {
|
||||
/**
|
||||
* Represents the container color for this button, depending on [enabled].
|
||||
*
|
||||
* @param enabled whether the button is enabled
|
||||
*/
|
||||
@Composable
|
||||
internal fun containerColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (enabled) containerColor else disabledContainerColor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the content color for this button, depending on [enabled].
|
||||
*
|
||||
* @param enabled whether the button is enabled
|
||||
*/
|
||||
@Composable
|
||||
internal fun contentColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (enabled) contentColor else disabledContentColor)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || other !is ButtonColors) return false
|
||||
|
||||
if (containerColor != other.containerColor) return false
|
||||
if (contentColor != other.contentColor) return false
|
||||
if (disabledContainerColor != other.disabledContainerColor) return false
|
||||
if (disabledContentColor != other.disabledContentColor) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = containerColor.hashCode()
|
||||
result = 31 * result + contentColor.hashCode()
|
||||
result = 31 * result + disabledContainerColor.hashCode()
|
||||
result = 31 * result + disabledContentColor.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,15 +23,20 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButtonColors
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.OutlinedIconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.util.minimumTouchTargetSize
|
||||
|
@ -100,6 +105,88 @@ fun IconButton(
|
|||
}
|
||||
}
|
||||
|
||||
object IconButtonDefaults {
|
||||
/**
|
||||
* Creates a [IconButtonColors] that represents the default colors used in a [IconButton].
|
||||
*
|
||||
* @param containerColor the container color of this icon button when enabled.
|
||||
* @param contentColor the content color of this icon button when enabled.
|
||||
* @param disabledContainerColor the container color of this icon button when not enabled.
|
||||
* @param disabledContentColor the content color of this icon button when not enabled.
|
||||
*/
|
||||
@Composable
|
||||
fun iconButtonColors(
|
||||
containerColor: Color = Color.Transparent,
|
||||
contentColor: Color = LocalContentColor.current,
|
||||
disabledContainerColor: Color = Color.Transparent,
|
||||
disabledContentColor: Color = contentColor.copy(alpha = 0.38f),
|
||||
): IconButtonColors =
|
||||
IconButtonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor,
|
||||
)
|
||||
}
|
||||
|
||||
object IconButtonTokens {
|
||||
val StateLayerSize = 40.0.dp
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the container and content colors used in an icon button in different states.
|
||||
*
|
||||
* - See [IconButtonDefaults.filledIconButtonColors] and
|
||||
* [IconButtonDefaults.filledTonalIconButtonColors] for the default colors used in a
|
||||
* [FilledIconButton].
|
||||
* - See [IconButtonDefaults.outlinedIconButtonColors] for the default colors used in an
|
||||
* [OutlinedIconButton].
|
||||
*/
|
||||
@Immutable
|
||||
class IconButtonColors internal constructor(
|
||||
private val containerColor: Color,
|
||||
private val contentColor: Color,
|
||||
private val disabledContainerColor: Color,
|
||||
private val disabledContentColor: Color,
|
||||
) {
|
||||
/**
|
||||
* Represents the container color for this icon button, depending on [enabled].
|
||||
*
|
||||
* @param enabled whether the icon button is enabled
|
||||
*/
|
||||
@Composable
|
||||
internal fun containerColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (enabled) containerColor else disabledContainerColor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the content color for this icon button, depending on [enabled].
|
||||
*
|
||||
* @param enabled whether the icon button is enabled
|
||||
*/
|
||||
@Composable
|
||||
internal fun contentColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (enabled) contentColor else disabledContentColor)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || other !is IconButtonColors) return false
|
||||
|
||||
if (containerColor != other.containerColor) return false
|
||||
if (contentColor != other.contentColor) return false
|
||||
if (disabledContainerColor != other.disabledContainerColor) return false
|
||||
if (disabledContentColor != other.disabledContentColor) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = containerColor.hashCode()
|
||||
result = 31 * result + contentColor.hashCode()
|
||||
result = 31 * result + disabledContainerColor.hashCode()
|
||||
result = 31 * result + disabledContentColor.hashCode()
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,12 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
|
@ -138,12 +135,7 @@ fun LibrarySelectionToolbar(
|
|||
onClickSelectAll: () -> Unit,
|
||||
onClickInvertSelection: () -> Unit,
|
||||
) {
|
||||
val backgroundColor by TopAppBarDefaults.smallTopAppBarColors().containerColor(1f)
|
||||
AppBar(
|
||||
modifier = Modifier
|
||||
.drawBehind {
|
||||
drawRect(backgroundColor.copy(alpha = 1f))
|
||||
},
|
||||
titleContent = { Text(text = "${state.selection.size}") },
|
||||
actions = {
|
||||
IconButton(onClick = onClickSelectAll) {
|
||||
|
|
|
@ -3,10 +3,7 @@ package eu.kanade.presentation.manga.components
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
|
@ -18,19 +15,19 @@ import androidx.compose.material.icons.outlined.Share
|
|||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.components.DownloadedOnlyModeBanner
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
import eu.kanade.presentation.components.IncognitoModeBanner
|
||||
|
@ -55,16 +52,11 @@ fun MangaAppBar(
|
|||
onSelectAll: () -> Unit,
|
||||
onInvertSelection: () -> Unit,
|
||||
) {
|
||||
val isActionMode = actionModeCounter > 0
|
||||
val backgroundAlpha = if (isActionMode) 1f else backgroundAlphaProvider()
|
||||
val backgroundColor by TopAppBarDefaults.smallTopAppBarColors().containerColor(1f)
|
||||
Column(
|
||||
modifier = modifier.drawBehind {
|
||||
drawRect(backgroundColor.copy(alpha = backgroundAlpha))
|
||||
},
|
||||
modifier = modifier,
|
||||
) {
|
||||
val isActionMode = actionModeCounter > 0
|
||||
SmallTopAppBar(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top)),
|
||||
title = {
|
||||
Text(
|
||||
text = if (isActionMode) actionModeCounter.toString() else title,
|
||||
|
@ -198,10 +190,11 @@ fun MangaAppBar(
|
|||
}
|
||||
}
|
||||
},
|
||||
// Background handled by parent
|
||||
windowInsets = WindowInsets.statusBars,
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = Color.Transparent,
|
||||
scrolledContainerColor = Color.Transparent,
|
||||
containerColor = MaterialTheme.colorScheme
|
||||
.surfaceColorAtElevation(3.dp)
|
||||
.copy(alpha = if (isActionMode) 1f else backgroundAlphaProvider()),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
125
app/src/main/java/eu/kanade/presentation/util/Elevation.kt
Normal file
125
app/src/main/java/eu/kanade/presentation/util/Elevation.kt
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Straight copy from Compose M3 for Button fork
|
||||
*/
|
||||
|
||||
package eu.kanade.presentation.util
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.AnimationSpec
|
||||
import androidx.compose.animation.core.CubicBezierEasing
|
||||
import androidx.compose.animation.core.Easing
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.TweenSpec
|
||||
import androidx.compose.foundation.interaction.DragInteraction
|
||||
import androidx.compose.foundation.interaction.FocusInteraction
|
||||
import androidx.compose.foundation.interaction.HoverInteraction
|
||||
import androidx.compose.foundation.interaction.Interaction
|
||||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
/**
|
||||
* Animates the [Dp] value of [this] between [from] and [to] [Interaction]s, to [target]. The
|
||||
* [AnimationSpec] used depends on the values for [from] and [to], see
|
||||
* [ElevationDefaults.incomingAnimationSpecForInteraction] and
|
||||
* [ElevationDefaults.outgoingAnimationSpecForInteraction] for more details.
|
||||
*
|
||||
* @param target the [Dp] target elevation for this component, corresponding to the elevation
|
||||
* desired for the [to] state.
|
||||
* @param from the previous [Interaction] that was used to calculate elevation. `null` if there
|
||||
* was no previous [Interaction], such as when the component is in its default state.
|
||||
* @param to the [Interaction] that this component is moving to, such as [PressInteraction.Press]
|
||||
* when this component is being pressed. `null` if this component is moving back to its default
|
||||
* state.
|
||||
*/
|
||||
internal suspend fun Animatable<Dp, *>.animateElevation(
|
||||
target: Dp,
|
||||
from: Interaction? = null,
|
||||
to: Interaction? = null,
|
||||
) {
|
||||
val spec = when {
|
||||
// Moving to a new state
|
||||
to != null -> ElevationDefaults.incomingAnimationSpecForInteraction(to)
|
||||
// Moving to default, from a previous state
|
||||
from != null -> ElevationDefaults.outgoingAnimationSpecForInteraction(from)
|
||||
// Loading the initial state, or moving back to the baseline state from a disabled /
|
||||
// unknown state, so just snap to the final value.
|
||||
else -> null
|
||||
}
|
||||
if (spec != null) animateTo(target, spec) else snapTo(target)
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains default [AnimationSpec]s used for animating elevation between different [Interaction]s.
|
||||
*
|
||||
* Typically you should use [animateElevation] instead, which uses these [AnimationSpec]s
|
||||
* internally. [animateElevation] in turn is used by the defaults for cards and buttons.
|
||||
*
|
||||
* @see animateElevation
|
||||
*/
|
||||
private object ElevationDefaults {
|
||||
/**
|
||||
* Returns the [AnimationSpec]s used when animating elevation to [interaction], either from a
|
||||
* previous [Interaction], or from the default state. If [interaction] is unknown, then
|
||||
* returns `null`.
|
||||
*
|
||||
* @param interaction the [Interaction] that is being animated to
|
||||
*/
|
||||
fun incomingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? {
|
||||
return when (interaction) {
|
||||
is PressInteraction.Press -> DefaultIncomingSpec
|
||||
is DragInteraction.Start -> DefaultIncomingSpec
|
||||
is HoverInteraction.Enter -> DefaultIncomingSpec
|
||||
is FocusInteraction.Focus -> DefaultIncomingSpec
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [AnimationSpec]s used when animating elevation away from [interaction], to the
|
||||
* default state. If [interaction] is unknown, then returns `null`.
|
||||
*
|
||||
* @param interaction the [Interaction] that is being animated away from
|
||||
*/
|
||||
fun outgoingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? {
|
||||
return when (interaction) {
|
||||
is PressInteraction.Press -> DefaultOutgoingSpec
|
||||
is DragInteraction.Start -> DefaultOutgoingSpec
|
||||
is HoverInteraction.Enter -> HoveredOutgoingSpec
|
||||
is FocusInteraction.Focus -> DefaultOutgoingSpec
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val OutgoingSpecEasing: Easing = CubicBezierEasing(0.40f, 0.00f, 0.60f, 1.00f)
|
||||
|
||||
private val DefaultIncomingSpec = TweenSpec<Dp>(
|
||||
durationMillis = 120,
|
||||
easing = FastOutSlowInEasing,
|
||||
)
|
||||
|
||||
private val DefaultOutgoingSpec = TweenSpec<Dp>(
|
||||
durationMillis = 150,
|
||||
easing = OutgoingSpecEasing,
|
||||
)
|
||||
|
||||
private val HoveredOutgoingSpec = TweenSpec<Dp>(
|
||||
durationMillis = 120,
|
||||
easing = OutgoingSpecEasing,
|
||||
)
|
|
@ -2,7 +2,7 @@
|
|||
compiler = "1.3.0-rc02"
|
||||
compose = "1.2.1"
|
||||
accompanist = "0.25.1"
|
||||
material3 = "1.0.0-alpha16"
|
||||
material3 = "1.0.0-beta01"
|
||||
|
||||
[libraries]
|
||||
activity = "androidx.activity:activity-compose:1.6.0-beta01"
|
||||
|
|
Loading…
Reference in a new issue