mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-22 07:06:05 +00:00
wear: shrink header to dense form on scroll-up instead of hiding it - overlay-only size animation, list geometry untouched
This commit is contained in:
parent
92f60bd02f
commit
2e8f6ffc35
@ -58,7 +58,7 @@ fun ChatScaffold(
|
||||
emptyText: String,
|
||||
voice: VoiceNoteController,
|
||||
onOpenImage: (String) -> Unit,
|
||||
header: @Composable () -> Unit,
|
||||
header: @Composable (expanded: Boolean) -> Unit,
|
||||
actionBar: @Composable () -> Unit
|
||||
) {
|
||||
val haptics = LocalHapticFeedback.current
|
||||
@ -133,7 +133,7 @@ private fun ChatBody(
|
||||
onOpenImage: (String) -> Unit,
|
||||
columnState: TransformingLazyColumnState,
|
||||
controlsVisible: Boolean,
|
||||
header: @Composable () -> Unit,
|
||||
header: @Composable (expanded: Boolean) -> Unit,
|
||||
actionBar: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
@ -181,19 +181,10 @@ private fun ChatBody(
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = controlsVisible,
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
enter = slideInVertically(
|
||||
initialOffsetY = { -it },
|
||||
animationSpec = tween(BitchatMotion.STANDARD_MS)
|
||||
) + fadeIn(animationSpec = tween(BitchatMotion.STANDARD_MS)),
|
||||
exit = slideOutVertically(
|
||||
targetOffsetY = { -it },
|
||||
animationSpec = tween(BitchatMotion.STANDARD_MS)
|
||||
) + fadeOut(animationSpec = tween(BitchatMotion.STANDARD_MS))
|
||||
) {
|
||||
header()
|
||||
// The header stays put and shrinks to its dense form instead of disappearing;
|
||||
// as an overlay its size animation never touches the list's scroll geometry.
|
||||
Box(modifier = Modifier.align(Alignment.TopCenter)) {
|
||||
header(controlsVisible)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
|
||||
@ -75,10 +75,11 @@ fun ChatScreen(onOpenPeople: () -> Unit, onOpenTextInput: () -> Unit) {
|
||||
emptyText = "no messages yet\nsay hi to the mesh",
|
||||
voice = voice,
|
||||
onOpenImage = { viewerPath = it },
|
||||
header = {
|
||||
header = { expanded ->
|
||||
ChatHeader(
|
||||
peerCount = peers.size,
|
||||
unreadDms = unreadDms.values.sum(),
|
||||
expanded = expanded,
|
||||
onOpenPeople = onOpenPeople
|
||||
)
|
||||
},
|
||||
@ -96,16 +97,29 @@ fun ChatScreen(onOpenPeople: () -> Unit, onOpenTextInput: () -> Unit) {
|
||||
private fun ChatHeader(
|
||||
peerCount: Int,
|
||||
unreadDms: Int,
|
||||
expanded: Boolean,
|
||||
onOpenPeople: () -> Unit
|
||||
) {
|
||||
// Floating title row; the scaffold slides/fades it as a unit when the user scrolls.
|
||||
val iconSize = 16.dp
|
||||
val titleSize = 15.dp
|
||||
// Floating title row: full-size at the newest messages, shrinks to its dense form
|
||||
// while scrolling up into history. Rendered as an overlay, so the animation only
|
||||
// relayouts this row, never the message list.
|
||||
val spec = androidx.compose.animation.core.tween<androidx.compose.ui.unit.Dp>(
|
||||
BitchatMotion.STANDARD_MS
|
||||
)
|
||||
val iconSize by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (expanded) 16.dp else 11.dp, animationSpec = spec, label = "hdrIcon"
|
||||
)
|
||||
val titleSize by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (expanded) 15.dp else 11.dp, animationSpec = spec, label = "hdrTitle"
|
||||
)
|
||||
val vPadding by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (expanded) 6.dp else 1.dp, animationSpec = spec, label = "hdrPad"
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp, vertical = 6.dp),
|
||||
.padding(horizontal = 8.dp, vertical = vPadding),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
||||
@ -78,11 +78,12 @@ fun DmScreen(peerID: String, onOpenTextInput: () -> Unit) {
|
||||
else "setting up encryption…",
|
||||
voice = voice,
|
||||
onOpenImage = { viewerPath = it },
|
||||
header = {
|
||||
header = { expanded ->
|
||||
DmHeader(
|
||||
nickname = nickname,
|
||||
peerID = peerID,
|
||||
sessionEstablished = sessionEstablished
|
||||
sessionEstablished = sessionEstablished,
|
||||
expanded = expanded
|
||||
)
|
||||
},
|
||||
actionBar = {
|
||||
@ -99,17 +100,30 @@ fun DmScreen(peerID: String, onOpenTextInput: () -> Unit) {
|
||||
private fun DmHeader(
|
||||
nickname: String,
|
||||
peerID: String,
|
||||
sessionEstablished: Boolean
|
||||
sessionEstablished: Boolean,
|
||||
expanded: Boolean
|
||||
) {
|
||||
val palette = LocalBitchatPalette.current
|
||||
// Floating title row; the scaffold slides/fades it as a unit when the user scrolls.
|
||||
val headerIconSize = 16.dp
|
||||
val headerTitleSize = 15.dp
|
||||
// Floating title row: full-size at the newest messages, shrinks to its dense form
|
||||
// while scrolling up into history. Rendered as an overlay, so the animation only
|
||||
// relayouts this row, never the message list.
|
||||
val spec = androidx.compose.animation.core.tween<androidx.compose.ui.unit.Dp>(
|
||||
BitchatMotion.STANDARD_MS
|
||||
)
|
||||
val headerIconSize by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (expanded) 16.dp else 11.dp, animationSpec = spec, label = "dmHdrIcon"
|
||||
)
|
||||
val headerTitleSize by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (expanded) 15.dp else 11.dp, animationSpec = spec, label = "dmHdrTitle"
|
||||
)
|
||||
val headerVPadding by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (expanded) 6.dp else 1.dp, animationSpec = spec, label = "dmHdrPad"
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp, vertical = 6.dp),
|
||||
.padding(horizontal = 8.dp, vertical = headerVPadding),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user