1+ package com.google.firebase.quickstart.ai.feature.svg
2+
3+ import androidx.compose.foundation.layout.Box
4+ import androidx.compose.foundation.layout.Column
5+ import androidx.compose.foundation.layout.fillMaxSize
6+ import androidx.compose.foundation.layout.fillMaxWidth
7+ import androidx.compose.foundation.layout.padding
8+ import androidx.compose.foundation.lazy.LazyColumn
9+ import androidx.compose.foundation.lazy.items
10+ import androidx.compose.material3.Card
11+ import androidx.compose.material3.CardDefaults
12+ import androidx.compose.material3.CircularProgressIndicator
13+ import androidx.compose.material3.ElevatedCard
14+ import androidx.compose.material3.MaterialTheme
15+ import androidx.compose.material3.OutlinedTextField
16+ import androidx.compose.material3.Text
17+ import androidx.compose.material3.TextButton
18+ import androidx.compose.runtime.Composable
19+ import androidx.compose.runtime.getValue
20+ import androidx.compose.runtime.mutableStateOf
21+ import androidx.compose.runtime.saveable.rememberSaveable
22+ import androidx.compose.runtime.setValue
23+ import androidx.compose.ui.Alignment
24+ import androidx.compose.ui.Modifier
25+ import androidx.compose.ui.platform.LocalContext
26+ import androidx.compose.ui.unit.dp
27+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
28+ import androidx.lifecycle.viewmodel.compose.viewModel
29+ import coil3.compose.SubcomposeAsyncImage
30+ import coil3.request.ImageRequest
31+ import coil3.request.crossfade
32+ import coil3.svg.SvgDecoder
33+ import kotlinx.coroutines.Dispatchers
34+ import kotlinx.serialization.Serializable
35+ import java.nio.ByteBuffer
36+
37+ @Serializable
38+ class SvgRoute (val sampleId : String )
39+
40+ @Composable
41+ fun SvgScreen (
42+ svgViewModel : SvgViewModel = viewModel<SvgViewModel >()
43+ ) {
44+ var prompt by rememberSaveable { mutableStateOf(svgViewModel.initialPrompt) }
45+ val errorMessage by svgViewModel.errorMessage.collectAsStateWithLifecycle()
46+ val isLoading by svgViewModel.isLoading.collectAsStateWithLifecycle()
47+ val generatedSvgs by svgViewModel.generatedSvgs.collectAsStateWithLifecycle()
48+
49+ Column {
50+ ElevatedCard (
51+ modifier = Modifier
52+ .padding(all = 16 .dp)
53+ .fillMaxWidth(),
54+ shape = MaterialTheme .shapes.large
55+ ) {
56+ OutlinedTextField (
57+ value = prompt,
58+ label = { Text (" Generate a SVG of" ) },
59+ placeholder = { Text (" Enter text to generate image" ) },
60+ onValueChange = { prompt = it },
61+ modifier = Modifier
62+ .padding(16 .dp)
63+ .fillMaxWidth()
64+ )
65+ TextButton (
66+ onClick = {
67+ svgViewModel.generateSVG(prompt)
68+ },
69+ modifier = Modifier
70+ .padding(horizontal = 16 .dp, vertical = 16 .dp)
71+ .align(Alignment .End )
72+ ) {
73+ Text (" Generate" )
74+ }
75+ }
76+ if (isLoading) {
77+ Box (
78+ contentAlignment = Alignment .Center ,
79+ modifier = Modifier
80+ .padding(all = 8 .dp)
81+ .align(Alignment .CenterHorizontally )
82+ ) {
83+ CircularProgressIndicator ()
84+ }
85+ }
86+ LazyColumn (
87+ modifier = Modifier .fillMaxSize()
88+ ) {
89+ items(generatedSvgs) { svg ->
90+ Card (
91+ modifier = Modifier
92+ .padding(horizontal = 16 .dp, vertical = 8 .dp)
93+ .fillMaxWidth(),
94+ shape = MaterialTheme .shapes.large,
95+ colors = CardDefaults .cardColors(
96+ containerColor = MaterialTheme .colorScheme.onSecondaryContainer
97+ )
98+ ) {
99+ SubcomposeAsyncImage (
100+ model = ImageRequest .Builder (LocalContext .current)
101+ .data(ByteBuffer .wrap(svg.toByteArray()))
102+ .decoderFactory(SvgDecoder .Factory ())
103+ .decoderCoroutineContext(Dispatchers .Main )
104+ .crossfade(true )
105+ .build(),
106+ contentDescription = " Generated SVG" ,
107+ modifier = Modifier
108+ .fillMaxWidth()
109+ )
110+ }
111+ }
112+ }
113+ errorMessage?.let {
114+ Card (
115+ modifier = Modifier
116+ .padding(horizontal = 16 .dp)
117+ .fillMaxWidth(),
118+ shape = MaterialTheme .shapes.large,
119+ colors = CardDefaults .cardColors(
120+ containerColor = MaterialTheme .colorScheme.errorContainer
121+ )
122+ ) {
123+ Text (
124+ text = it,
125+ color = MaterialTheme .colorScheme.error,
126+ modifier = Modifier .padding(all = 16 .dp)
127+ )
128+ }
129+ }
130+ }
131+ }
0 commit comments