Skip to content

Commit 0a35df6

Browse files
authored
Merge pull request #57 from Coding-Meet/main
Refactor Koin initialization and update UI components
2 parents d8c5bd8 + fecda4f commit 0a35df6

File tree

13 files changed

+104
-78
lines changed

13 files changed

+104
-78
lines changed

.gitignore

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,17 @@
33
**/build/
44
.kotlin
55
.gradle
6-
**/.idea/*
7-
6+
xcuserdata
7+
!src/**/build/
8+
local.properties
9+
.idea
10+
.DS_Store
11+
captures
12+
.externalNativeBuild
13+
.cxx
14+
*.xcodeproj/*
15+
!*.xcodeproj/project.pbxproj
16+
!*.xcodeproj/xcshareddata/
17+
!*.xcodeproj/project.xcworkspace/
18+
!*.xcworkspace/contents.xcworkspacedata
19+
**/xcshareddata/WorkspaceSettings.xcsettings

composeApp/src/androidMain/kotlin/dev/johnoreilly/vertexai/FirebaaseAILogicKMPApp.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@ package dev.johnoreilly.vertexai
22

33
import android.app.Application
44
import com.google.firebase.FirebaseApp
5-
import dev.johnoreilly.vertexai.di.initialiseKoin
5+
import dev.johnoreilly.vertexai.di.initKoin
6+
import org.koin.android.ext.koin.androidContext
7+
import org.koin.dsl.module
68

79

810
class FirebaaseAILogicKMPApp : Application() {
911
override fun onCreate() {
1012
super.onCreate()
1113
FirebaseApp.initializeApp(this)
1214

13-
initialiseKoin()
15+
initKoin(
16+
appDeclaration = {
17+
androidContext(this@FirebaaseAILogicKMPApp)
18+
},
19+
platformModule = module { single<GenerativeModel> { GenerativeModelAndroid() } }
20+
)
1421
}
1522
}

composeApp/src/androidMain/kotlin/dev/johnoreilly/vertexai/GenerativeModel.android.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import com.google.firebase.ai.type.Schema
66
import com.google.firebase.ai.type.generationConfig
77
import com.google.firebase.ai.ai
88
import com.google.firebase.ai.type.GenerativeBackend
9+
import dev.johnoreilly.vertexai.util.GEMINI_MODEL
10+
import dev.johnoreilly.vertexai.util.IMAGE_MODEL
911

1012

1113
class GenerativeModelAndroid : GenerativeModel {
@@ -20,15 +22,15 @@ class GenerativeModelAndroid : GenerativeModel {
2022

2123
override suspend fun generateTextContent(prompt: String): String? {
2224
val generativeModel = Firebase.ai(backend = GenerativeBackend.googleAI()).generativeModel(
23-
modelName = "gemini-2.5-flash"
25+
modelName = GEMINI_MODEL
2426
)
2527

2628
return generativeModel.generateContent(prompt).text
2729
}
2830

2931
override suspend fun generateJsonContent(prompt: String): String? {
3032
val generativeModel = Firebase.ai.generativeModel(
31-
modelName = "gemini-2.5-flash",
33+
modelName = GEMINI_MODEL,
3234
generationConfig = generationConfig {
3335
responseMimeType = "application/json"
3436
responseSchema = jsonSchema
@@ -41,7 +43,7 @@ class GenerativeModelAndroid : GenerativeModel {
4143
@OptIn(PublicPreviewAPI::class)
4244
override suspend fun generateImage(prompt: String): ByteArray? {
4345
val imageModel = Firebase.ai.imagenModel(
44-
modelName = "imagen-4.0-fast-generate-001"
46+
modelName = IMAGE_MODEL
4547
)
4648
val imageResponse = imageModel.generateImages(prompt)
4749
return if (imageResponse.images.isNotEmpty()) {

composeApp/src/androidMain/kotlin/dev/johnoreilly/vertexai/di/Koin.android.kt

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
package dev.johnoreilly.vertexai.di
22

33
import dev.johnoreilly.vertexai.ui.GenerativeModelViewModel
4-
import org.koin.core.module.dsl.factoryOf
4+
import org.koin.core.context.startKoin
5+
import org.koin.core.module.Module
6+
import org.koin.core.module.dsl.viewModelOf
7+
import org.koin.dsl.KoinAppDeclaration
58
import org.koin.dsl.module
69

710

811
val commonModule = module {
9-
factoryOf(::GenerativeModelViewModel)
12+
viewModelOf(::GenerativeModelViewModel)
1013
}
1114

15+
fun initKoin(appDeclaration: KoinAppDeclaration = {}, platformModule: Module = module {}) =
16+
startKoin {
17+
println("🔥 Initializing Koin")
18+
appDeclaration()
19+
modules(
20+
platformModule,
21+
commonModule,
22+
)
23+
println("🔥 Koin initialized")
24+
}

composeApp/src/commonMain/kotlin/dev/johnoreilly/vertexai/ui/GenerativeModelViewModel.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
55
import dev.johnoreilly.vertexai.GenerativeModel
66
import kotlinx.coroutines.flow.MutableStateFlow
7+
import kotlinx.coroutines.flow.update
78
import kotlinx.coroutines.launch
89
import kotlinx.serialization.Serializable
910
import kotlinx.serialization.json.Json
@@ -32,35 +33,51 @@ class GenerativeModelViewModel(private val generativeModel: GenerativeModel) : V
3233
val uiState = MutableStateFlow<GenerativeModelUIState>(GenerativeModelUIState.Initial)
3334

3435
fun generateContent(prompt: String, generateJson: Boolean) {
35-
uiState.value = GenerativeModelUIState.Loading
36+
uiState.update {
37+
GenerativeModelUIState.Loading
38+
}
3639
viewModelScope.launch {
3740
try {
38-
uiState.value = if (generateJson) {
41+
if (generateJson) {
3942
val response = generativeModel.generateJsonContent(prompt)
4043
if (response != null) {
4144
val entities = Json.decodeFromString<List<Entity>>(response)
42-
GenerativeModelUIState.Success(entityContent = entities)
45+
uiState.update { GenerativeModelUIState.Success(entityContent = entities) }
4346
} else {
44-
GenerativeModelUIState.Error("Error generating content")
47+
uiState.update {
48+
GenerativeModelUIState.Error("Error generating content")
49+
}
4550
}
4651
} else {
4752
val response = generativeModel.generateTextContent(prompt)
48-
GenerativeModelUIState.Success(textContent = response)
53+
uiState.update { GenerativeModelUIState.Success(textContent = response) }
4954
}
5055
} catch (e: Exception) {
51-
GenerativeModelUIState.Error(e.message ?: "Error generating content")
56+
uiState.update {
57+
GenerativeModelUIState.Error(
58+
e.message ?: "Error generating content"
59+
)
60+
}
5261
}
5362
}
5463
}
5564

5665
fun generateImage(prompt: String) {
57-
uiState.value = GenerativeModelUIState.Loading
66+
uiState.update {
67+
GenerativeModelUIState.Loading
68+
}
5869
viewModelScope.launch {
59-
uiState.value = try {
70+
try {
6071
val imageData = generativeModel.generateImage(prompt)
61-
GenerativeModelUIState.Success(imageData = imageData)
72+
uiState.update {
73+
GenerativeModelUIState.Success(imageData = imageData)
74+
}
6275
} catch (e: Exception) {
63-
GenerativeModelUIState.Error(e.message ?: "Error generating content")
76+
uiState.update {
77+
GenerativeModelUIState.Error(
78+
e.message ?: "Error generating content"
79+
)
80+
}
6481
}
6582
}
6683
}

composeApp/src/commonMain/kotlin/dev/johnoreilly/vertexai/ui/HomeScreen.kt

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import androidx.compose.material3.ListItem
2323
import androidx.compose.material3.MaterialTheme
2424
import androidx.compose.material3.OutlinedTextField
2525
import androidx.compose.material3.Switch
26+
import androidx.compose.material3.SwitchDefaults
2627
import androidx.compose.material3.Text
2728
import androidx.compose.runtime.Composable
2829
import androidx.compose.runtime.LaunchedEffect
@@ -59,7 +60,7 @@ fun HomeScreen() {
5960
mutableStateOf(TextFieldValue())
6061
}
6162

62-
val generateJson = remember { mutableStateOf(false) }
63+
var generateJson by rememberSaveable { mutableStateOf(false) }
6364

6465
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
6566
val focusRequester = remember { FocusRequester() }
@@ -76,7 +77,7 @@ fun HomeScreen() {
7677
color = MaterialTheme.colorScheme.primary,
7778
modifier = Modifier.padding(bottom = 4.dp)
7879
)
79-
80+
8081
OutlinedTextField(
8182
value = prompt,
8283
onValueChange = { prompt = it },
@@ -87,7 +88,7 @@ fun HomeScreen() {
8788
.height(120.dp),
8889
shape = RoundedCornerShape(12.dp)
8990
)
90-
91+
9192
Spacer(modifier = Modifier.height(12.dp))
9293

9394
Row(
@@ -100,7 +101,16 @@ fun HomeScreen() {
100101
fontWeight = FontWeight.Medium
101102
)
102103
Spacer(modifier = Modifier.width(8.dp))
103-
Switch(checked = generateJson.value, onCheckedChange = { generateJson.value = it })
104+
Switch(checked = generateJson, onCheckedChange = { generateJson = it },
105+
colors = SwitchDefaults.colors(
106+
checkedThumbColor = MaterialTheme.colorScheme.primary,
107+
checkedTrackColor = MaterialTheme.colorScheme.primaryContainer,
108+
uncheckedThumbColor = MaterialTheme.colorScheme.primary,
109+
uncheckedTrackColor = MaterialTheme.colorScheme.primaryContainer,
110+
checkedBorderColor = MaterialTheme.colorScheme.primary,
111+
uncheckedBorderColor = MaterialTheme.colorScheme.primary
112+
)
113+
)
104114
}
105115

106116
Row(
@@ -110,7 +120,7 @@ fun HomeScreen() {
110120
onClick = {
111121
if (prompt.text.isNotBlank()) {
112122
keyboardController?.hide()
113-
viewModel.generateContent(prompt.text, generateJson = generateJson.value)
123+
viewModel.generateContent(prompt.text, generateJson = generateJson)
114124
}
115125
},
116126
modifier = Modifier.weight(1f),
@@ -120,7 +130,7 @@ fun HomeScreen() {
120130
}
121131

122132
Spacer(Modifier.width(16.dp))
123-
133+
124134
Button(
125135
onClick = {
126136
if (prompt.text.isNotBlank()) {
@@ -134,7 +144,7 @@ fun HomeScreen() {
134144
Text(stringResource(Res.string.generate_image))
135145
}
136146
}
137-
147+
138148
Spacer(modifier = Modifier.height(16.dp))
139149

140150
ResponseView(uiState, prompt.text)
@@ -161,7 +171,10 @@ fun ResponseView(uiState: GenerativeModelUIState, prompt: String) {
161171
ElevatedCard(
162172
modifier = Modifier.fillMaxWidth(),
163173
shape = RoundedCornerShape(12.dp),
164-
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 4.dp)
174+
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 4.dp),
175+
colors = CardDefaults.elevatedCardColors(
176+
containerColor = MaterialTheme.colorScheme.surfaceVariant
177+
)
165178
) {
166179
Column(modifier = Modifier.padding(16.dp)) {
167180
Text(
@@ -171,7 +184,7 @@ fun ResponseView(uiState: GenerativeModelUIState, prompt: String) {
171184
fontWeight = FontWeight.Bold,
172185
modifier = Modifier.padding(bottom = 8.dp)
173186
)
174-
187+
175188
if (uiState.entityContent != null) {
176189
LazyColumn {
177190
items(uiState.entityContent) { item ->
@@ -182,17 +195,17 @@ fun ResponseView(uiState: GenerativeModelUIState, prompt: String) {
182195
shape = RoundedCornerShape(8.dp)
183196
) {
184197
ListItem(
185-
headlineContent = {
198+
headlineContent = {
186199
Text(
187200
text = item.name,
188201
fontWeight = FontWeight.Medium
189-
)
202+
)
190203
},
191-
supportingContent = {
204+
supportingContent = {
192205
Text(
193206
text = item.country,
194207
style = MaterialTheme.typography.bodyMedium
195-
)
208+
)
196209
}
197210
)
198211
}

composeApp/src/commonMain/kotlin/dev/johnoreilly/vertexai/ui/theme/FirebaseTheme.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package dev.johnoreilly.vertexai.ui.theme
22

3-
import androidx.compose.material3.ColorScheme
43
import androidx.compose.material3.darkColorScheme
54
import androidx.compose.material3.lightColorScheme
65
import androidx.compose.ui.graphics.Color
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package dev.johnoreilly.vertexai.util
2+
3+
const val GEMINI_MODEL = "gemini-2.5-flash"
4+
const val IMAGE_MODEL = "imagen-4.0-fast-generate-001"

composeApp/src/iosMain/kotlin/dev/johnoreilly/vertexai/di/Koin.ios.kt

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)