Remade the chat system based on the jetchat example app.

This commit is contained in:
Mathieu 2022-01-05 10:39:19 +01:00
parent 5ef0bf7160
commit 774adb608d
7 changed files with 106 additions and 46 deletions

View File

@ -38,6 +38,8 @@
<entry key="../../../../../layout/compose-model-1641313051635.xml" value="0.3861111111111111" /> <entry key="../../../../../layout/compose-model-1641313051635.xml" value="0.3861111111111111" />
<entry key="../../../../../layout/compose-model-1641313223231.xml" value="0.3861111111111111" /> <entry key="../../../../../layout/compose-model-1641313223231.xml" value="0.3861111111111111" />
<entry key="../../../../../layout/compose-model-1641313346209.xml" value="0.3861111111111111" /> <entry key="../../../../../layout/compose-model-1641313346209.xml" value="0.3861111111111111" />
<entry key="../../../../../layout/compose-model-1641371559019.xml" value="0.33" />
<entry key="../../../../../layout/compose-model-1641372970000.xml" value="0.3861111111111111" />
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.5307291666666667" /> <entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.5307291666666667" />
<entry key="app/src/main/res/drawable/ic_baseline_arrow_back_24.xml" value="0.38981481481481484" /> <entry key="app/src/main/res/drawable/ic_baseline_arrow_back_24.xml" value="0.38981481481481484" />
<entry key="app/src/main/res/drawable/ic_baseline_keyboard_24.xml" value="0.38981481481481484" /> <entry key="app/src/main/res/drawable/ic_baseline_keyboard_24.xml" value="0.38981481481481484" />

View File

@ -9,14 +9,10 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import androidx.navigation.compose.rememberNavController
import ch.mathieubroillet.jarvis.android.nav.Navigation import ch.mathieubroillet.jarvis.android.nav.Navigation
import ch.mathieubroillet.jarvis.android.pages.DisplayMainPage
import ch.mathieubroillet.jarvis.android.ui.theme.JarvisComposeTheme import ch.mathieubroillet.jarvis.android.ui.theme.JarvisComposeTheme
@ -51,13 +47,4 @@ class MainActivity : ComponentActivity() {
} }
} }
} }
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
JarvisComposeTheme {
DisplayMainPage(rememberNavController())
}
} }

View File

@ -0,0 +1,22 @@
package ch.mathieubroillet.jarvis.android.chat
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.mutableStateListOf
class ConversationUiState(
initialMessages: List<Message>
) {
private val _messages: MutableList<Message> =
mutableStateListOf(*initialMessages.toTypedArray())
val messages: List<Message> = _messages
fun addMessage(msg: Message) {
_messages.add(0, msg) // Add to the beginning of the list
}
}
@Immutable
data class Message(
val isJarvis: Boolean,
val content: String,
)

View File

@ -1,9 +1,10 @@
package ch.mathieubroillet.jarvis.android.utils package ch.mathieubroillet.jarvis.android.chat
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
@ -16,6 +17,30 @@ import androidx.compose.ui.unit.dp
import ch.mathieubroillet.jarvis.android.R import ch.mathieubroillet.jarvis.android.R
import ch.mathieubroillet.jarvis.android.ui.theme.productSansFont import ch.mathieubroillet.jarvis.android.ui.theme.productSansFont
@Composable
fun Messages(
messages: List<Message>,
modifier: Modifier = Modifier
) {
Box(modifier = modifier) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
val reverse: List<Message> = messages.reversed()
for (message in reverse) {
item {
if (message.isJarvis) {
MessageFromJarvis(text = message.content)
} else {
MessageFromUser(text = message.content)
}
}
}
}
}
}
@Composable @Composable
fun MessageFromJarvis( fun MessageFromJarvis(
@ -95,7 +120,7 @@ fun MessageFromUser(text: String) {
.fillMaxWidth(fraction = 0.8F) .fillMaxWidth(fraction = 0.8F)
.clip(RoundedCornerShape(15.dp)) .clip(RoundedCornerShape(15.dp))
.background(color = MaterialTheme.colors.secondary) .background(color = MaterialTheme.colors.secondary)
.padding(horizontal = 10.dp, vertical = 5.dp) .padding(horizontal = 10.dp, vertical = 10.dp)
) { ) {
Text( Text(
text = text, text = text,

View File

@ -1,10 +1,14 @@
package ch.mathieubroillet.jarvis.android.nav package ch.mathieubroillet.jarvis.android.nav
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import ch.mathieubroillet.jarvis.android.R
import ch.mathieubroillet.jarvis.android.chat.ConversationUiState
import ch.mathieubroillet.jarvis.android.chat.Message
import ch.mathieubroillet.jarvis.android.pages.DisplayMainPage import ch.mathieubroillet.jarvis.android.pages.DisplayMainPage
import ch.mathieubroillet.jarvis.android.pages.DisplayPermissionsPage import ch.mathieubroillet.jarvis.android.pages.DisplayPermissionsPage
import ch.mathieubroillet.jarvis.android.pages.DisplaySettingsPage import ch.mathieubroillet.jarvis.android.pages.DisplaySettingsPage
@ -39,7 +43,17 @@ fun Navigation() {
@Composable @Composable
fun MainScreen(navController: NavController) { fun MainScreen(navController: NavController) {
DisplayMainPage(navController) DisplayMainPage(
navController,
ConversationUiState(
listOf(
Message(
true,
stringResource(id = R.string.demo_message_1)
)
)
)
)
} }
@Composable @Composable

View File

@ -1,7 +1,6 @@
package ch.mathieubroillet.jarvis.android.pages package ch.mathieubroillet.jarvis.android.pages
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -15,26 +14,35 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import ch.mathieubroillet.jarvis.android.R import ch.mathieubroillet.jarvis.android.R
import ch.mathieubroillet.jarvis.android.chat.ConversationUiState
import ch.mathieubroillet.jarvis.android.chat.Message
import ch.mathieubroillet.jarvis.android.chat.Messages
import ch.mathieubroillet.jarvis.android.nav.Screen import ch.mathieubroillet.jarvis.android.nav.Screen
import ch.mathieubroillet.jarvis.android.ui.theme.JarvisComposeTheme import ch.mathieubroillet.jarvis.android.ui.theme.JarvisComposeTheme
import ch.mathieubroillet.jarvis.android.ui.theme.productSansFont import ch.mathieubroillet.jarvis.android.ui.theme.productSansFont
import ch.mathieubroillet.jarvis.android.utils.DefaultBox import ch.mathieubroillet.jarvis.android.utils.DefaultBox
import ch.mathieubroillet.jarvis.android.utils.IconAlertDialogTextField import ch.mathieubroillet.jarvis.android.utils.IconAlertDialogTextField
import ch.mathieubroillet.jarvis.android.utils.MessageFromJarvis
import ch.mathieubroillet.jarvis.android.utils.MessageFromUser
//Draws the base of the main activity, that includes the 3-dots menu and the "hi text". //Draws the base of the main activity, that includes the 3-dots menu and the "hi text".
@Composable @Composable
fun Base(navController: NavController) { fun Base(navController: NavController, uiState: ConversationUiState) {
Column(Modifier.padding(bottom = 25.dp).fillMaxWidth()) { Column(
Modifier
.padding(bottom = 25.dp)
.fillMaxWidth()
) {
Row(Modifier.align(Alignment.End)) { Row(Modifier.align(Alignment.End)) {
var text by remember { mutableStateOf("") }
IconAlertDialogTextField( IconAlertDialogTextField(
R.drawable.ic_baseline_keyboard_24, buttonIcon = R.drawable.ic_baseline_keyboard_24,
stringResource(id = R.string.main_page_dialog_ask_me_anything), title = stringResource(id = R.string.main_page_dialog_ask_me_anything),
stringResource(id = R.string.main_page_dialog_type_a_sentence) label = stringResource(id = R.string.main_page_dialog_type_a_sentence),
text = text,
textFieldValue = { text = it },
onOKClick = { uiState.addMessage(Message(false, text)); text = "" }
) )
DropDownSettingsMenu(navController) DropDownSettingsMenu(navController)
@ -98,24 +106,21 @@ fun StartRecordingFAB() {
} }
} }
@Composable @Composable
fun DisplayMainPage(navController: NavController) { fun DisplayMainPage(navController: NavController, uiState: ConversationUiState) {
//We create a main box with basic padding to avoid having stuff too close to every side. //We create a main box with basic padding to avoid having stuff too close to every side.
DefaultBox { DefaultBox {
// This column regroup the base and all the conversations (everything except the footer) // This column regroup the base and all the conversations (everything except the footer)
Column(Modifier.padding(bottom = 80.dp)) { Column(Modifier.padding(bottom = 80.dp)) {
Base(navController)
// This column regroup only the conversations and make them scrollable Base(navController, uiState)
LazyColumn(content = {
item { Messages(
// Basic interaction stuff for demo messages = uiState.messages,
MessageFromJarvis(text = stringResource(id = R.string.demo_message_1)) modifier = Modifier.weight(1f)
MessageFromUser(text = stringResource(id = R.string.demo_message_2)) )
MessageFromJarvis(text = stringResource(id = R.string.demo_message_3))
}
})
} }
// Finally we add the footer to the bottom center of the main box // Finally we add the footer to the bottom center of the main box
@ -134,6 +139,10 @@ fun DisplayMainPage(navController: NavController) {
@Composable @Composable
fun MainPagePreview() { fun MainPagePreview() {
JarvisComposeTheme { JarvisComposeTheme {
DisplayMainPage(rememberNavController()) DisplayMainPage(
rememberNavController(), ConversationUiState(
listOf(Message(true, stringResource(id = R.string.demo_message_1)))
)
)
} }
} }

View File

@ -4,13 +4,14 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import ch.mathieubroillet.jarvis.android.R import ch.mathieubroillet.jarvis.android.R
@ -21,7 +22,10 @@ import ch.mathieubroillet.jarvis.android.ui.theme.productSansFont
fun IconAlertDialogTextField( fun IconAlertDialogTextField(
buttonIcon: Int = R.drawable.ic_baseline_error_24, buttonIcon: Int = R.drawable.ic_baseline_error_24,
title: String = "Title", title: String = "Title",
label: String = "Label" label: String = "Label",
text: String,
textFieldValue: (String) -> Unit,
onOKClick: () -> Unit
) { ) {
JarvisComposeTheme { JarvisComposeTheme {
Column { Column {
@ -68,12 +72,9 @@ fun IconAlertDialogTextField(
.fillMaxWidth() .fillMaxWidth()
) { ) {
Column { Column {
var text by remember { mutableStateOf(TextFieldValue("")) }
OutlinedTextField( OutlinedTextField(
value = text, value = text,
onValueChange = { newText -> onValueChange = textFieldValue,
text = newText
},
label = { Text(text = label) }, label = { Text(text = label) },
colors = TextFieldDefaults.outlinedTextFieldColors( colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = MaterialTheme.colors.secondaryVariant, focusedBorderColor = MaterialTheme.colors.secondaryVariant,
@ -93,7 +94,9 @@ fun IconAlertDialogTextField(
color = MaterialTheme.colors.secondary color = MaterialTheme.colors.secondary
) )
} }
TextButton(onClick = { /*TODO*/ }) { TextButton(onClick = {
onOKClick(); openDialog.value = false
}) {
Text( Text(
text = stringResource(id = R.string.ok), text = stringResource(id = R.string.ok),
color = MaterialTheme.colors.secondary color = MaterialTheme.colors.secondary
@ -101,8 +104,6 @@ fun IconAlertDialogTextField(
} }
} }
} }
} }
} }
}, },