mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-08 06:46:11 +00:00
wear: M7 code - message appear animations, screen transitions, auto-scroll, unread DM badge
This commit is contained in:
parent
43a88808a5
commit
ecad00c854
@ -13,6 +13,11 @@ import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -135,10 +140,19 @@ fun WearNavHost() {
|
||||
|
||||
BackHandler(enabled = backStack.isNotEmpty()) { goBack() }
|
||||
|
||||
when (val current = screen) {
|
||||
is WearScreen.Chat -> ChatScreen(onOpenPeople = { navigate(WearScreen.People) })
|
||||
is WearScreen.People -> PeopleScreen(onOpenDm = { navigate(WearScreen.Dm(it)) })
|
||||
is WearScreen.Dm -> DmScreen(peerID = current.peerID)
|
||||
AnimatedContent(
|
||||
targetState = screen,
|
||||
transitionSpec = {
|
||||
fadeIn(tween(com.bitchat.watch.ui.theme.BitchatMotion.EMPHASIZED_MS)) togetherWith
|
||||
fadeOut(tween(com.bitchat.watch.ui.theme.BitchatMotion.QUICK_MS))
|
||||
},
|
||||
label = "screenTransition"
|
||||
) { current ->
|
||||
when (current) {
|
||||
is WearScreen.Chat -> ChatScreen(onOpenPeople = { navigate(WearScreen.People) })
|
||||
is WearScreen.People -> PeopleScreen(onOpenDm = { navigate(WearScreen.Dm(it)) })
|
||||
is WearScreen.Dm -> DmScreen(peerID = current.peerID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
@ -32,6 +33,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
@ -65,6 +67,7 @@ import java.util.Locale
|
||||
fun ChatScreen(onOpenPeople: () -> Unit) {
|
||||
val messages by AppStateStore.publicMessages.collectAsState()
|
||||
val peers by AppStateStore.peers.collectAsState()
|
||||
val unreadDms by WearChatState.unreadDms.collectAsState()
|
||||
val mesh = WearMeshService.peek()
|
||||
val myPeerID = mesh?.myPeerID ?: ""
|
||||
val listState = rememberScalingLazyListState()
|
||||
@ -78,6 +81,10 @@ fun ChatScreen(onOpenPeople: () -> Unit) {
|
||||
if (last != null && last.senderPeerID != myPeerID) {
|
||||
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
}
|
||||
// Keep the newest message visible (header + messages + composer indices)
|
||||
if (messages.isNotEmpty()) {
|
||||
listState.animateScrollToItem(messages.size + 1)
|
||||
}
|
||||
}
|
||||
previousCount = messages.size
|
||||
}
|
||||
@ -90,6 +97,7 @@ fun ChatScreen(onOpenPeople: () -> Unit) {
|
||||
item {
|
||||
ChatHeader(
|
||||
peerCount = peers.size,
|
||||
unreadDms = unreadDms.values.sum(),
|
||||
onOpenPeople = onOpenPeople
|
||||
)
|
||||
}
|
||||
@ -121,7 +129,7 @@ fun ChatScreen(onOpenPeople: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChatHeader(peerCount: Int, onOpenPeople: () -> Unit) {
|
||||
private fun ChatHeader(peerCount: Int, unreadDms: Int, onOpenPeople: () -> Unit) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -141,6 +149,14 @@ private fun ChatHeader(peerCount: Int, onOpenPeople: () -> Unit) {
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.clickable { onOpenPeople() }
|
||||
)
|
||||
if (unreadDms > 0) {
|
||||
Text(
|
||||
text = " · $unreadDms new",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = LocalBitchatPalette.current.accentOrange,
|
||||
modifier = Modifier.clickable { onOpenPeople() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,10 +169,30 @@ fun MessageItem(message: BitchatMessage, myPeerID: String) {
|
||||
else -> colorForPeer(message.sender + (message.senderPeerID ?: ""), palette)
|
||||
}
|
||||
|
||||
// Snappy appear animation for incoming messages (BitchatMotion.EMPHASIZED_MS)
|
||||
var appeared by remember { mutableStateOf(false) }
|
||||
LaunchedEffect(message.id) { appeared = true }
|
||||
val alpha by androidx.compose.animation.core.animateFloatAsState(
|
||||
targetValue = if (appeared) 1f else 0f,
|
||||
animationSpec = androidx.compose.animation.core.tween(
|
||||
com.bitchat.watch.ui.theme.BitchatMotion.EMPHASIZED_MS
|
||||
),
|
||||
label = "msgAlpha"
|
||||
)
|
||||
val offset by androidx.compose.animation.core.animateDpAsState(
|
||||
targetValue = if (appeared) 0.dp else 6.dp,
|
||||
animationSpec = androidx.compose.animation.core.tween(
|
||||
com.bitchat.watch.ui.theme.BitchatMotion.EMPHASIZED_MS
|
||||
),
|
||||
label = "msgOffset"
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 14.dp, vertical = 3.dp)
|
||||
.offset(y = offset)
|
||||
.alpha(alpha)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user