feat: redesign message field again and typing indicator
This commit is contained in:
parent
af92c95a82
commit
61bfda37f2
|
|
@ -1,6 +1,7 @@
|
||||||
package chat.revolt.components.chat
|
package chat.revolt.components.chat
|
||||||
|
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
|
@ -54,7 +55,10 @@ fun MessageField(
|
||||||
|
|
||||||
val sendButtonVisible = (messageContent.isNotBlank() || forceSendButton) && !disabled
|
val sendButtonVisible = (messageContent.isNotBlank() || forceSendButton) && !disabled
|
||||||
|
|
||||||
Row(modifier) {
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
||||||
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = messageContent,
|
value = messageContent,
|
||||||
onValueChange = onMessageContentChange,
|
onValueChange = onMessageContentChange,
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@ package chat.revolt.components.screens.chat
|
||||||
|
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
|
@ -14,10 +12,37 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.RevoltTweenFloat
|
import chat.revolt.RevoltTweenFloat
|
||||||
import chat.revolt.RevoltTweenInt
|
import chat.revolt.RevoltTweenInt
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.components.generic.UserAvatar
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StackedUserAvatars(
|
||||||
|
users: List<String>,
|
||||||
|
amount: Int = 3,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(16.dp + (8.dp * minOf(users.size, amount)), 16.dp)
|
||||||
|
) {
|
||||||
|
users.take(amount).forEachIndexed { index, userId ->
|
||||||
|
val user = RevoltAPI.userCache[userId]
|
||||||
|
UserAvatar(
|
||||||
|
avatar = user?.avatar,
|
||||||
|
userId = userId,
|
||||||
|
username = user?.username ?: stringResource(id = R.string.unknown),
|
||||||
|
size = 16.dp,
|
||||||
|
modifier = Modifier
|
||||||
|
.offset(
|
||||||
|
x = (index * 8).dp,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TypingIndicator(
|
fun TypingIndicator(
|
||||||
|
|
@ -53,8 +78,10 @@ fun TypingIndicator(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.background(MaterialTheme.colorScheme.background)
|
.background(MaterialTheme.colorScheme.background)
|
||||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
.padding(top = 4.dp, start = 16.dp, end = 16.dp),
|
||||||
) {
|
) {
|
||||||
|
StackedUserAvatars(users = users)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(
|
text = stringResource(
|
||||||
id = typingMessageResource(),
|
id = typingMessageResource(),
|
||||||
|
|
@ -64,6 +91,7 @@ fun TypingIndicator(
|
||||||
} ?: it
|
} ?: it
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
fontSize = 12.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,7 @@ fun ChannelScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
val scrollDownFABPadding by animateDpAsState(
|
val scrollDownFABPadding by animateDpAsState(
|
||||||
if (viewModel.typingUsers.isNotEmpty()) 40.dp else 0.dp,
|
if (viewModel.typingUsers.isNotEmpty()) 25.dp else 0.dp,
|
||||||
animationSpec = RevoltTweenDp
|
animationSpec = RevoltTweenDp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -513,10 +513,13 @@ fun ChannelScreen(
|
||||||
) {
|
) {
|
||||||
LazyColumn(state = lazyListState, reverseLayout = true) {
|
LazyColumn(state = lazyListState, reverseLayout = true) {
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(40.dp))
|
Spacer(modifier = Modifier.height(25.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
items(viewModel.renderableMessages) { message ->
|
items(
|
||||||
|
items = viewModel.renderableMessages,
|
||||||
|
key = { it.id!! }
|
||||||
|
) { message ->
|
||||||
Message(message) {
|
Message(message) {
|
||||||
navController.navigate("message/${message.id}/menu")
|
navController.navigate("message/${message.id}/menu")
|
||||||
}
|
}
|
||||||
|
|
@ -589,12 +592,14 @@ fun ChannelScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.clip(
|
modifier = Modifier
|
||||||
RoundedCornerShape(
|
.padding(
|
||||||
topStart = 16.dp,
|
start = 16.dp,
|
||||||
topEnd = 16.dp
|
end = 16.dp,
|
||||||
|
bottom = 16.dp,
|
||||||
|
top = 8.dp
|
||||||
)
|
)
|
||||||
)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(visible = viewModel.replies.isNotEmpty()) {
|
AnimatedVisibility(visible = viewModel.replies.isNotEmpty()) {
|
||||||
ReplyManager(
|
ReplyManager(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue