refactor: merge ClusterNetwotkModule into NetworkModule
This commit is contained in:
parent
3a096f342c
commit
c2969d8c28
|
|
@ -6,9 +6,6 @@ converterGson = "2.9.0"
|
|||
datastorePreferences = "1.1.7"
|
||||
featureDelivery = "2.1.0"
|
||||
firebaseBom = "33.13.0"
|
||||
hiltAndroid = "2.56.2"
|
||||
hiltAndroidCompiler = "2.56.2"
|
||||
hiltNavigationCompose = "1.2.0"
|
||||
javaJwt = "4.4.0"
|
||||
koinAndroid = "3.5.3"
|
||||
koinAndroidxCompose = "3.5.3"
|
||||
|
|
@ -17,17 +14,13 @@ coreKtx = "1.16.0"
|
|||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
kotlinxSerializationJson = "1.6.3"
|
||||
kotlinxSerializationJsonVersion = "1.6.0"
|
||||
ktorClientCio = "2.3.3"
|
||||
ktorClientContentNegotiation = "2.3.3"
|
||||
ktorClientCore = "2.3.3"
|
||||
ktorSerializationKotlinxJson = "2.3.3"
|
||||
lifecycleRuntimeKtx = "2.9.0"
|
||||
activityCompose = "1.10.1"
|
||||
composeBom = "2025.05.00"
|
||||
lifecycleViewmodelCompose = "2.9.0"
|
||||
loggingInterceptor = "4.11.0"
|
||||
lottieCompose = "6.6.6"
|
||||
navigationCompose = "2.9.0"
|
||||
okhttp = "4.12.0"
|
||||
retrofit = "2.9.0"
|
||||
|
|
@ -35,7 +28,6 @@ retrofit2KotlinxSerializationConverter = "0.8.0"
|
|||
roomRuntime = "2.7.1"
|
||||
runtime = "1.8.2"
|
||||
runtimeAndroid = "1.8.1"
|
||||
ycharts = "2.1.0"
|
||||
|
||||
[libraries]
|
||||
accompanist-placeholder-material = { module = "com.google.accompanist:accompanist-placeholder-material", version.ref = "accompanistSwiperefresh" }
|
||||
|
|
@ -46,7 +38,6 @@ androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", versi
|
|||
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraCore" }
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
||||
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
|
||||
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
|
||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomRuntime" }
|
||||
|
|
@ -75,17 +66,12 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
|
|||
androidx-runtime-android = { group = "androidx.compose.runtime", name = "runtime-android", version.ref = "runtimeAndroid" }
|
||||
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koinAndroid" }
|
||||
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koinAndroidxCompose" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
kotlinx-serialization-json-v160 = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJsonVersion" }
|
||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktorClientCio" }
|
||||
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktorClientContentNegotiation" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktorClientCore" }
|
||||
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktorSerializationKotlinxJson" }
|
||||
logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "loggingInterceptor" }
|
||||
lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottieCompose" }
|
||||
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||
retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofit2KotlinxSerializationConverter" }
|
||||
ycharts = { module = "co.yml:ycharts", version.ref = "ycharts" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.component
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.R
|
||||
import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen
|
||||
|
||||
@Composable
|
||||
fun DiseaseDetectionBanner() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = MainGreen, shape = RoundedCornerShape(8.dp))
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth(0.6f)) {
|
||||
Text(
|
||||
"Lindungi Tanamanmu dari Hama dan Penyakit",
|
||||
style = MaterialTheme.typography.titleMedium.copy(color = Color.White)
|
||||
)
|
||||
Text(
|
||||
"Deteksi, lihat hasil dan lakukan perawatan",
|
||||
style = MaterialTheme.typography.bodySmall.copy(Color.White.copy(alpha = 0.5f))
|
||||
)
|
||||
}
|
||||
Image(
|
||||
modifier = Modifier.fillMaxWidth(0.8f),
|
||||
painter = painterResource(id = R.drawable.plant_in_pot),
|
||||
contentDescription = "Plant Image",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.R
|
||||
|
||||
@Composable
|
||||
fun Loader() {
|
||||
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.loading))
|
||||
LottieAnimation(composition)
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention
|
||||
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model.PlantDiseaseDetectionResponse
|
||||
|
||||
sealed class DiagnosisResult {
|
||||
data class Success(val data: PlantDiseaseDetectionResponse) : DiagnosisResult()
|
||||
data class Error(val errorMessage: String) : DiagnosisResult()
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
data class ErrorResponse(
|
||||
val error: String? = null
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.repository
|
||||
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model.PlantDiseaseDetectionResponse
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.DiagnosisResult
|
||||
|
||||
interface PlantDiagnosisRepository {
|
||||
suspend fun detectDisease(base64Image: String, prompt: String): PlantDiseaseDetectionResponse
|
||||
suspend fun detectDisease(base64Image: String, prompt: String): DiagnosisResult
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.repository
|
||||
|
||||
import android.util.Log
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.DiagnosisResult
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model.ErrorResponse
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model.GeminiContent
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model.GeminiPart
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.model.GeminiRequest
|
||||
|
|
@ -10,32 +11,44 @@ import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.network.
|
|||
import kotlinx.serialization.json.Json
|
||||
|
||||
class PlantDiagnosisRepositoryImpl(private val api: GeminiApiService) : PlantDiagnosisRepository {
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
override suspend fun detectDisease(
|
||||
base64Image: String,
|
||||
prompt: String
|
||||
): PlantDiseaseDetectionResponse {
|
||||
val request = GeminiRequest(
|
||||
contents = listOf(
|
||||
GeminiContent(
|
||||
parts = listOf(
|
||||
GeminiPart(text = prompt),
|
||||
GeminiPart(inline_data = InlineData("image/jpeg", base64Image))
|
||||
): DiagnosisResult {
|
||||
return try {
|
||||
val request = GeminiRequest(
|
||||
contents = listOf(
|
||||
GeminiContent(
|
||||
parts = listOf(
|
||||
GeminiPart(text = prompt),
|
||||
GeminiPart(inline_data = InlineData("image/jpeg", base64Image))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
val response = api.detectDisease(
|
||||
apiKey = "AIzaSyDYZHlMfOdFAcTFptWHqhPwIO734VdNUWE",
|
||||
request = request
|
||||
)
|
||||
|
||||
val response = api.detectDisease(
|
||||
apiKey = "AIzaSyDYZHlMfOdFAcTFptWHqhPwIO734VdNUWE", // Ideally use BuildConfig or secure storage
|
||||
request = request
|
||||
)
|
||||
Log.d("PlantDiagnosisRepository", "Response: $response")
|
||||
|
||||
val rawJson = response.candidates.first().content.parts.first().text
|
||||
val cleanedJson = rawJson
|
||||
.replace("```json", "")
|
||||
.replace("```", "")
|
||||
.trim()
|
||||
return Json.decodeFromString(cleanedJson)
|
||||
val rawJson = response.candidates.first().content.parts.first().text
|
||||
val cleanedJson = rawJson
|
||||
.replace("```json", "")
|
||||
.replace("```", "")
|
||||
.trim()
|
||||
try {
|
||||
val parsedSuccess =
|
||||
json.decodeFromString<PlantDiseaseDetectionResponse>(cleanedJson)
|
||||
DiagnosisResult.Success(parsedSuccess)
|
||||
} catch (e: Exception) {
|
||||
val parsedError = json.decodeFromString<ErrorResponse>(cleanedJson)
|
||||
DiagnosisResult.Error(parsedError.error.toString())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
DiagnosisResult.Error("Terjadi kesalahan: ${e.localizedMessage ?: "tidak diketahui"}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
|
|
@ -42,8 +41,8 @@ import com.syaroful.agrilinkvocpro.R
|
|||
import com.syaroful.agrilinkvocpro.core.components.AppButton
|
||||
import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.AppConstant
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.component.Loader
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.presentation.camera.CameraViewModel
|
||||
import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
|
@ -119,7 +118,7 @@ fun DetailScreen(
|
|||
Box(
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
CircularProgressIndicator(color = MainGreen)
|
||||
Loader()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +220,11 @@ fun DetailScreen(
|
|||
}
|
||||
Spacer(modifier = Modifier.height(56.dp))
|
||||
} else {
|
||||
Text("Gagal parsing response")
|
||||
DefaultErrorComponent(
|
||||
painter = painterResource(id = R.drawable.mascot_surprised),
|
||||
label = "Keknya bukan gambar daun",
|
||||
message = "Gambar tidak menunjukkan daun tanaman, mohon unggah gambar daun yang jelas"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.graphics.Bitmap
|
|||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.DiagnosisResult
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.toBase64
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.toByteArray
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.local.entity.PlantDiagnosisEntity
|
||||
|
|
@ -30,9 +31,18 @@ class PlantDiagnosisViewModel(
|
|||
viewModelScope.launch {
|
||||
try {
|
||||
val base64 = bitmap.toBase64()
|
||||
val result = repository.detectDisease(prompt = prompt, base64Image = base64)
|
||||
_state.value = Result.success(result)
|
||||
Log.d("PlantDiagnosisViewModel", "Diagnosis result: $result")
|
||||
when (val result =
|
||||
repository.detectDisease(prompt = prompt, base64Image = base64)) {
|
||||
is DiagnosisResult.Success -> {
|
||||
_state.value = Result.success(result.data)
|
||||
Log.d("PlantDiagnosisViewModel", "Diagnosis result: ${result.data}")
|
||||
}
|
||||
|
||||
is DiagnosisResult.Error -> {
|
||||
_state.value = Result.failure(Exception(result.errorMessage))
|
||||
Log.e("PlantDiagnosisViewModel", "Diagnosis error: ${result.errorMessage}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_state.value = Result.failure(e)
|
||||
Log.e("PlantDiagnosisViewModel", "Error during diagnosis", e)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import androidx.compose.material3.TopAppBar
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -40,6 +39,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.navigation.NavHostController
|
||||
import com.syaroful.agrilinkvocpro.R
|
||||
import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.component.DiseaseDetectionBanner
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.toBitmap
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.core.extention.toFormattedDate
|
||||
import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.data.local.entity.PlantDiagnosisEntity
|
||||
|
|
@ -185,34 +185,4 @@ private fun DiagnosisListItem(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DiseaseDetectionBanner() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = MainGreen, shape = RoundedCornerShape(8.dp))
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth(0.6f)) {
|
||||
Text(
|
||||
"Lindungi Tanamanmu dari Hama dan Penyakit",
|
||||
style = MaterialTheme.typography.titleMedium.copy(color = Color.White)
|
||||
)
|
||||
Text(
|
||||
"Deteksi, lihat hasil dan lakukan perawatan",
|
||||
style = MaterialTheme.typography.bodySmall.copy(Color.White.copy(alpha = 0.5f))
|
||||
)
|
||||
}
|
||||
Image(
|
||||
modifier = Modifier.fillMaxWidth(0.8f),
|
||||
painter = painterResource(id = R.drawable.plant_in_pot),
|
||||
contentDescription = "Plant Image",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user