1616
1717package com.google.firebase.quickstart.vertexai.feature.functioncalling
1818
19- import androidx.compose.foundation.layout.BoxWithConstraints
19+ import androidx.compose.foundation.layout.Box
2020import androidx.compose.foundation.layout.Column
21- import androidx.compose.foundation.layout.Row
2221import androidx.compose.foundation.layout.fillMaxSize
23- import androidx.compose.foundation.layout.fillMaxWidth
24- import androidx.compose.foundation.layout.padding
25- import androidx.compose.foundation.layout.widthIn
26- import androidx.compose.foundation.lazy.LazyColumn
27- import androidx.compose.foundation.lazy.LazyListState
28- import androidx.compose.foundation.lazy.items
2922import androidx.compose.foundation.lazy.rememberLazyListState
30- import androidx.compose.foundation.shape.RoundedCornerShape
31- import androidx.compose.foundation.text.KeyboardOptions
32- import androidx.compose.material.icons.Icons
33- import androidx.compose.material.icons.filled.Send
34- import androidx.compose.material3.Card
35- import androidx.compose.material3.CardDefaults
36- import androidx.compose.material3.CircularProgressIndicator
37- import androidx.compose.material3.ElevatedCard
38- import androidx.compose.material3.Icon
39- import androidx.compose.material3.IconButton
40- import androidx.compose.material3.MaterialTheme
41- import androidx.compose.material3.OutlinedTextField
42- import androidx.compose.material3.Scaffold
43- import androidx.compose.material3.Text
4423import androidx.compose.runtime.Composable
4524import androidx.compose.runtime.collectAsState
4625import androidx.compose.runtime.getValue
47- import androidx.compose.runtime.mutableStateOf
4826import androidx.compose.runtime.rememberCoroutineScope
49- import androidx.compose.runtime.saveable.rememberSaveable
50- import androidx.compose.runtime.setValue
5127import androidx.compose.ui.Alignment
5228import androidx.compose.ui.Modifier
53- import androidx.compose.ui.res.stringResource
54- import androidx.compose.ui.text.input.KeyboardCapitalization
55- import androidx.compose.ui.unit.dp
5629import androidx.lifecycle.viewmodel.compose.viewModel
5730import com.google.firebase.quickstart.vertexai.GenerativeViewModelFactory
58- import com.google.firebase.quickstart.vertexai.R
31+ import com.google.firebase.quickstart.vertexai.feature.chat.ChatList
32+ import com.google.firebase.quickstart.vertexai.feature.chat.MessageInput
5933import kotlinx.coroutines.launch
6034
6135@Composable
@@ -66,9 +40,20 @@ internal fun FunctionsChatRoute(
6640 val listState = rememberLazyListState()
6741 val coroutineScope = rememberCoroutineScope()
6842
69- Scaffold (
70- bottomBar = {
71- FunctionMessageInput (
43+ Column (
44+ modifier = Modifier
45+ .fillMaxSize()
46+ ) {
47+ ChatList (
48+ chatUiState.messages,
49+ listState,
50+ modifier = Modifier .fillMaxSize()
51+ .weight(0.5f )
52+ )
53+ Box (
54+ contentAlignment = Alignment .BottomCenter
55+ ) {
56+ MessageInput (
7257 onSendMessage = { inputText ->
7358 chatViewModel.sendMessage(inputText)
7459 },
@@ -79,141 +64,6 @@ internal fun FunctionsChatRoute(
7964 }
8065 )
8166 }
82- ) { paddingValues ->
83- Column (
84- modifier = Modifier
85- .padding(paddingValues)
86- .fillMaxSize()
87- ) {
88- // Messages List
89- FunctionChatList (chatUiState.messages, listState)
90- }
91- }
92- }
93-
94- @Composable
95- fun FunctionChatList (
96- chatMessages : List <FunctionsChatMessage >,
97- listState : LazyListState
98- ) {
99- LazyColumn (
100- reverseLayout = true ,
101- state = listState
102- ) {
103- items(chatMessages.reversed()) { message ->
104- FunctionChatBubbleItem (message)
105- }
106- }
107- }
108-
109- @Composable
110- fun FunctionChatBubbleItem (
111- chatMessage : FunctionsChatMessage
112- ) {
113- val isModelMessage = chatMessage.participant == Participant .MODEL ||
114- chatMessage.participant == Participant .ERROR
115-
116- val backgroundColor = when (chatMessage.participant) {
117- Participant .MODEL -> MaterialTheme .colorScheme.primaryContainer
118- Participant .USER -> MaterialTheme .colorScheme.tertiaryContainer
119- Participant .ERROR -> MaterialTheme .colorScheme.errorContainer
120- }
121-
122- val bubbleShape = if (isModelMessage) {
123- RoundedCornerShape (4 .dp, 20 .dp, 20 .dp, 20 .dp)
124- } else {
125- RoundedCornerShape (20 .dp, 4 .dp, 20 .dp, 20 .dp)
126- }
127-
128- val horizontalAlignment = if (isModelMessage) {
129- Alignment .Start
130- } else {
131- Alignment .End
132- }
133-
134- Column (
135- horizontalAlignment = horizontalAlignment,
136- modifier = Modifier
137- .padding(horizontal = 8 .dp, vertical = 4 .dp)
138- .fillMaxWidth()
139- ) {
140- Text (
141- text = chatMessage.participant.name,
142- style = MaterialTheme .typography.bodySmall,
143- modifier = Modifier .padding(bottom = 4 .dp)
144- )
145- Row {
146- if (chatMessage.isPending) {
147- CircularProgressIndicator (
148- modifier = Modifier
149- .align(Alignment .CenterVertically )
150- .padding(all = 8 .dp)
151- )
152- }
153- BoxWithConstraints {
154- Card (
155- colors = CardDefaults .cardColors(containerColor = backgroundColor),
156- shape = bubbleShape,
157- modifier = Modifier .widthIn(0 .dp, maxWidth * 0.9f )
158- ) {
159- Text (
160- text = chatMessage.text,
161- modifier = Modifier .padding(16 .dp)
162- )
163- }
164- }
165- }
16667 }
16768}
16869
169- @Composable
170- fun FunctionMessageInput (
171- onSendMessage : (String ) -> Unit ,
172- resetScroll : () -> Unit = {}
173- ) {
174- var userMessage by rememberSaveable { mutableStateOf(" " ) }
175-
176- ElevatedCard (
177- modifier = Modifier
178- .fillMaxWidth()
179- ) {
180- Row (
181- modifier = Modifier
182- .padding(16 .dp)
183- .fillMaxWidth()
184- ) {
185- OutlinedTextField (
186- value = userMessage,
187- label = { Text (stringResource(R .string.chat_label)) },
188- onValueChange = { userMessage = it },
189- keyboardOptions = KeyboardOptions (
190- capitalization = KeyboardCapitalization .Sentences
191- ),
192- modifier = Modifier
193- .align(Alignment .CenterVertically )
194- .fillMaxWidth()
195- .weight(0.85f )
196- )
197- IconButton (
198- onClick = {
199- if (userMessage.isNotBlank()) {
200- onSendMessage(userMessage)
201- userMessage = " "
202- resetScroll()
203- }
204- },
205- modifier = Modifier
206- .padding(start = 16 .dp)
207- .align(Alignment .CenterVertically )
208- .fillMaxWidth()
209- .weight(0.15f )
210- ) {
211- Icon (
212- Icons .Default .Send ,
213- contentDescription = stringResource(R .string.action_send),
214- modifier = Modifier
215- )
216- }
217- }
218- }
219- }
0 commit comments