Private
Public Access
1
0

Some progress on message list UI

This commit is contained in:
2023-07-07 00:11:13 -07:00
parent 27e3c09228
commit 16148949c8
16 changed files with 283 additions and 48 deletions

View File

@@ -17,6 +17,8 @@
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.KordophoneDroid">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@@ -9,7 +9,8 @@ import androidx.navigation.compose.rememberNavController
import net.buzzert.kordophonedroid.data.AppContainer
import net.buzzert.kordophonedroid.ui.theme.KordophoneTheme
import net.buzzert.kordophonedroid.ui.conversationlist.ConversationListRoute
import net.buzzert.kordophonedroid.ui.conversationlist.ConversationListScreen
import net.buzzert.kordophonedroid.ui.messagelist.MessageListScreen
sealed class Destination(val route: String) {
object ConversationList : Destination("conversations")
@@ -29,14 +30,16 @@ fun KordophoneApp(
startDestination = Destination.ConversationList.route,
) {
composable(route = Destination.ConversationList.route) {
ConversationListRoute(
onNavigateToMessage = { navController.navigate(Destination.MessageList.createRoute(it)) }
)
ConversationListScreen(onMessageSelected = {
navController.navigate(Destination.MessageList.createRoute(it))
})
}
composable(Destination.MessageList.route) {
val conversationID = it.arguments?.getString("id")
Text("Conversation ID: $conversationID")
MessageListScreen(messages = listOf()) {
navController.popBackStack()
}
}
}
}

View File

@@ -1,10 +0,0 @@
package net.buzzert.kordophonedroid.ui.conversationlist
import androidx.compose.runtime.Composable
@Composable
fun ConversationListRoute(
onNavigateToMessage: (conversationID: String) -> Unit
) {
ConversationListScreen(onMessageSelected = onNavigateToMessage)
}

View File

@@ -11,10 +11,12 @@ import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Info
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeCompilerApi
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -33,13 +35,13 @@ fun ConversationListScreen(
Scaffold(
topBar = {
TopAppBar(title = { Text("Conversations") }, actions = {
Button(onClick = { /*TODO*/ }) {
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Rounded.Info, contentDescription = "Info")
}
})
}
) {
LazyColumn(state = listState) {
LazyColumn(state = listState, modifier = Modifier.padding(it)) {
items(convos) { conversation ->
ConversationListItem(
name = "James Magahern",
@@ -61,6 +63,7 @@ fun ConversationListItem(
) {
val unreadSize = 12.dp
val horizontalPadding = 8.dp
val verticalPadding = 12.dp
Row(
Modifier
@@ -81,7 +84,7 @@ fun ConversationListItem(
Spacer(Modifier.width(horizontalPadding))
Column {
Spacer(Modifier.height(horizontalPadding))
Spacer(Modifier.height(verticalPadding))
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
@@ -103,7 +106,7 @@ fun ConversationListItem(
Text("This is a test.")
Spacer(Modifier.height(8.dp))
Spacer(Modifier.height(verticalPadding))
Divider()
}
}
@@ -119,4 +122,20 @@ fun UnreadIndicator(size: Dp, modifier: Modifier = Modifier) {
shape = CircleShape
)
)
}
// -
@Preview
@Composable
fun ConversationListItemPreview() {
Column(modifier = Modifier.background(MaterialTheme.colors.background)) {
ConversationListItem(name = "James Magahern", id = "asdf", isUnread = true) {}
}
}
@Preview
@Composable
fun ConversationListScreenPreview() {
ConversationListScreen(onMessageSelected = {})
}

View File

@@ -0,0 +1,212 @@
package net.buzzert.kordophonedroid.ui.messagelist
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Immutable
data class Message(
val content: String,
)
@Composable
fun MessageListScreen(
messages: List<Message>,
backAction: () -> Unit
) {
val scrollState = rememberLazyListState()
var textState by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue())
}
Scaffold(
topBar = {
TopAppBar(
title = { Text("Messages") },
navigationIcon = {
IconButton(onClick = backAction) {
Icon(Icons.Filled.ArrowBack, null)
}
},
actions = {
})
}
) { paddingValues ->
Column(
Modifier
.fillMaxSize()
.padding(paddingValues)) {
Messages(messages = messages, modifier = Modifier.weight(1f), scrollState = scrollState)
MessageEntry(
onTextChanged = { textState = it },
textFieldValue = textState,
)
}
}
}
@Composable
fun Messages(
messages: List<Message>,
modifier: Modifier = Modifier,
scrollState: LazyListState
) {
val scope = rememberCoroutineScope()
Box(modifier = modifier) {
LazyColumn(
reverseLayout = true,
state = scrollState,
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
) {
for (index in messages.indices) {
val content = messages[index]
item {
MessageBubble(content)
}
}
}
}
}
private val ChatBubbleShape = RoundedCornerShape(4.dp, 20.dp, 20.dp, 20.dp)
@Composable
fun MessageBubble(message: Message) {
val backgroundBubbleColor = MaterialTheme.colors.primary
Column(modifier = Modifier.padding(end = 16.dp)) {
Surface(
color = backgroundBubbleColor,
shape = ChatBubbleShape
) {
Text(
text = message.content,
style = MaterialTheme.typography.body1,
modifier = Modifier
.padding(16.dp)
)
}
Spacer(modifier = Modifier.height(4.dp))
}
}
@Composable
private fun MessageEntry(
keyboardType: KeyboardType = KeyboardType.Text,
onTextChanged: (TextFieldValue) -> Unit,
textFieldValue: TextFieldValue,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(64.dp)
.padding(8.dp)
.background(MaterialTheme.colors.secondary)
) {
Surface {
Row(modifier = Modifier
.padding(8.dp)
.height(64.dp)
.weight(1f)
.align(Alignment.Bottom)
.imePadding()
.navigationBarsPadding()
) {
BasicTextField(
value = textFieldValue,
onValueChange = { onTextChanged(it) },
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.align(Alignment.CenterVertically)
.padding(horizontal = 8.dp),
cursorBrush = SolidColor(MaterialTheme.colors.onBackground),
textStyle = MaterialTheme.typography.body1.copy(MaterialTheme.colors.onBackground),
decorationBox = { textContent ->
if (textFieldValue.text.isEmpty()) {
Text(
text = "Message",
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface)
)
}
textContent()
}
)
Button(onClick = { /*TODO*/ }) {
Text(text = "Send")
}
}
}
}
}
// -
@Preview
@Composable
private fun MessageListScreenPreview() {
val messages = listOf<Message>(
Message(content = "Hello"),
Message(content = "Hi there"),
)
MessageListScreen(messages = messages) {}
}