11package dev.johnoreilly.vertexai.ui
22
3- import androidx.compose.foundation.border
43import androidx.compose.foundation.layout.Box
54import androidx.compose.foundation.layout.Column
65import androidx.compose.foundation.layout.Row
76import androidx.compose.foundation.layout.Spacer
87import androidx.compose.foundation.layout.fillMaxSize
98import androidx.compose.foundation.layout.fillMaxWidth
9+ import androidx.compose.foundation.layout.height
1010import androidx.compose.foundation.layout.padding
1111import androidx.compose.foundation.layout.width
1212import androidx.compose.foundation.lazy.LazyColumn
1313import androidx.compose.foundation.lazy.items
1414import androidx.compose.foundation.rememberScrollState
1515import androidx.compose.foundation.shape.RoundedCornerShape
16- import androidx.compose.foundation.text.BasicTextField
1716import androidx.compose.foundation.verticalScroll
18- import androidx.compose.material3.Checkbox
17+ import androidx.compose.material3.Button
18+ import androidx.compose.material3.Card
19+ import androidx.compose.material3.CardDefaults
1920import androidx.compose.material3.CircularProgressIndicator
21+ import androidx.compose.material3.ElevatedCard
2022import androidx.compose.material3.ListItem
21- import androidx.compose.material3.OutlinedButton
23+ import androidx.compose.material3.MaterialTheme
24+ import androidx.compose.material3.OutlinedTextField
25+ import androidx.compose.material3.Switch
2226import androidx.compose.material3.Text
2327import androidx.compose.runtime.Composable
2428import androidx.compose.runtime.LaunchedEffect
@@ -31,13 +35,11 @@ import androidx.compose.ui.Alignment
3135import androidx.compose.ui.Modifier
3236import androidx.compose.ui.focus.FocusRequester
3337import androidx.compose.ui.focus.focusRequester
34- import androidx.compose.ui.graphics.Color
3538import androidx.compose.ui.layout.ContentScale
3639import androidx.compose.ui.platform.LocalSoftwareKeyboardController
37- import androidx.compose.ui.text.TextStyle
40+ import androidx.compose.ui.text.font.FontWeight
3841import androidx.compose.ui.text.input.TextFieldValue
3942import androidx.compose.ui.unit.dp
40- import androidx.compose.ui.unit.sp
4143import androidx.lifecycle.compose.collectAsStateWithLifecycle
4244import coil3.compose.AsyncImage
4345import coil3.compose.LocalPlatformContext
@@ -67,50 +69,73 @@ fun HomeScreen() {
6769 focusRequester.requestFocus()
6870 }
6971
70- Column (modifier = Modifier .padding(8 .dp)) {
71- BasicTextField (
72+ Column (modifier = Modifier .padding(16 .dp)) {
73+ Text (
74+ text = " Enter your prompt" ,
75+ style = MaterialTheme .typography.labelLarge,
76+ color = MaterialTheme .colorScheme.primary,
77+ modifier = Modifier .padding(bottom = 4 .dp)
78+ )
79+
80+ OutlinedTextField (
7281 value = prompt,
7382 onValueChange = { prompt = it },
74- textStyle = TextStyle (fontSize = 24 .sp) ,
83+ placeholder = { Text ( " What would you like to generate? " ) } ,
7584 modifier = Modifier
76- .border(1 .dp, Color .Black , RoundedCornerShape (8 .dp))
77- .padding(8 .dp)
7885 .focusRequester(focusRequester)
7986 .fillMaxWidth()
87+ .height(120 .dp),
88+ shape = RoundedCornerShape (12 .dp)
8089 )
81-
82- Row (verticalAlignment = Alignment .CenterVertically ) {
83- Text (" Generate JSON" )
84- Checkbox (checked = generateJson.value, onCheckedChange = { generateJson.value = it })
90+
91+ Spacer (modifier = Modifier .height(12 .dp))
92+
93+ Row (
94+ verticalAlignment = Alignment .CenterVertically ,
95+ modifier = Modifier .padding(vertical = 8 .dp)
96+ ) {
97+ Text (
98+ " Generate JSON" ,
99+ style = MaterialTheme .typography.bodyLarge,
100+ fontWeight = FontWeight .Medium
101+ )
102+ Spacer (modifier = Modifier .width(8 .dp))
103+ Switch (checked = generateJson.value, onCheckedChange = { generateJson.value = it })
85104 }
86105
87- Row {
88- OutlinedButton (
106+ Row (
107+ modifier = Modifier .padding(vertical = 8 .dp)
108+ ) {
109+ Button (
89110 onClick = {
90111 if (prompt.text.isNotBlank()) {
91112 keyboardController?.hide()
92113 viewModel.generateContent(prompt.text, generateJson = generateJson.value)
93114 }
94115 },
95- modifier = Modifier .padding(vertical = 8 .dp)
116+ modifier = Modifier .weight(1f ),
117+ shape = RoundedCornerShape (8 .dp)
96118 ) {
97119 Text (stringResource(Res .string.generate_content))
98120 }
99121
100122 Spacer (Modifier .width(16 .dp))
101- OutlinedButton (
123+
124+ Button (
102125 onClick = {
103126 if (prompt.text.isNotBlank()) {
104127 keyboardController?.hide()
105128 viewModel.generateImage(prompt.text)
106129 }
107130 },
108- modifier = Modifier .padding(vertical = 8 .dp)
131+ modifier = Modifier .weight(1f ),
132+ shape = RoundedCornerShape (8 .dp)
109133 ) {
110134 Text (stringResource(Res .string.generate_image))
111135 }
112-
113136 }
137+
138+ Spacer (modifier = Modifier .height(16 .dp))
114139
115140 ResponseView (uiState, prompt.text)
116141 }
@@ -133,34 +158,96 @@ fun ResponseView(uiState: GenerativeModelUIState, prompt: String) {
133158 }
134159
135160 is GenerativeModelUIState .Success -> {
136- if (uiState.entityContent != null ) {
137- LazyColumn {
138- items(uiState.entityContent) { item ->
139- ListItem (
140- headlineContent = { Text (item.name) },
141- supportingContent = { Text (item.country) }
161+ ElevatedCard (
162+ modifier = Modifier .fillMaxWidth(),
163+ shape = RoundedCornerShape (12 .dp),
164+ elevation = CardDefaults .elevatedCardElevation(defaultElevation = 4 .dp)
165+ ) {
166+ Column (modifier = Modifier .padding(16 .dp)) {
167+ Text (
168+ text = " Generated Result" ,
169+ style = MaterialTheme .typography.titleMedium,
170+ color = MaterialTheme .colorScheme.primary,
171+ fontWeight = FontWeight .Bold ,
172+ modifier = Modifier .padding(bottom = 8 .dp)
173+ )
174+
175+ if (uiState.entityContent != null ) {
176+ LazyColumn {
177+ items(uiState.entityContent) { item ->
178+ Card (
179+ modifier = Modifier
180+ .fillMaxWidth()
181+ .padding(vertical = 4 .dp),
182+ shape = RoundedCornerShape (8 .dp)
183+ ) {
184+ ListItem (
185+ headlineContent = {
186+ Text (
187+ text = item.name,
188+ fontWeight = FontWeight .Medium
189+ )
190+ },
191+ supportingContent = {
192+ Text (
193+ text = item.country,
194+ style = MaterialTheme .typography.bodyMedium
195+ )
196+ }
197+ )
198+ }
199+ }
200+ }
201+ } else if (uiState.textContent != null ) {
202+ Column (modifier = Modifier .verticalScroll(scrollState)) {
203+ Markdown (uiState.textContent)
204+ }
205+ } else if (uiState.imageData != null ) {
206+ Text (
207+ text = " Generated Image" ,
208+ style = MaterialTheme .typography.labelLarge,
209+ modifier = Modifier .padding(bottom = 8 .dp)
142210 )
211+ Card (
212+ shape = RoundedCornerShape (8 .dp),
213+ modifier = Modifier .fillMaxWidth()
214+ ) {
215+ AsyncImage (
216+ model = ImageRequest
217+ .Builder (LocalPlatformContext .current)
218+ .data(uiState.imageData)
219+ .build(),
220+ contentDescription = prompt,
221+ contentScale = ContentScale .Fit ,
222+ modifier = Modifier
223+ .fillMaxWidth()
224+ .padding(8 .dp)
225+ )
226+ }
143227 }
144228 }
145- } else if (uiState.textContent != null ) {
146- Column (modifier = Modifier .verticalScroll(scrollState)) {
147- Markdown (uiState.textContent)
148- }
149- } else if (uiState.imageData != null ) {
150- AsyncImage (
151- model = ImageRequest
152- .Builder (LocalPlatformContext .current)
153- .data(uiState.imageData)
154- .build(),
155- contentDescription = prompt,
156- contentScale = ContentScale .Fit ,
157- modifier = Modifier .fillMaxWidth()
158- )
159229 }
160230 }
161231
162232 is GenerativeModelUIState .Error -> {
163- Text (uiState.message)
233+ Card (
234+ modifier = Modifier .fillMaxWidth(),
235+ colors = CardDefaults .cardColors(
236+ containerColor = MaterialTheme .colorScheme.errorContainer
237+ ),
238+ shape = RoundedCornerShape (8 .dp)
239+ ) {
240+ Row (
241+ verticalAlignment = Alignment .CenterVertically ,
242+ modifier = Modifier .padding(16 .dp)
243+ ) {
244+ Text (
245+ text = uiState.message,
246+ color = MaterialTheme .colorScheme.onErrorContainer,
247+ style = MaterialTheme .typography.bodyLarge
248+ )
249+ }
250+ }
164251 }
165252 }
166253}
0 commit comments