diff --git a/agrilinkvocpro/app/build.gradle.kts b/agrilinkvocpro/app/build.gradle.kts index 94444cc..3416d93 100644 --- a/agrilinkvocpro/app/build.gradle.kts +++ b/agrilinkvocpro/app/build.gradle.kts @@ -102,7 +102,7 @@ dependencies { // pull to refresh implementation(libs.accompanist.swiperefresh) - //graphic chat by Ycharts - implementation(libs.ycharts) + // placeholder or shimmer loading + implementation(libs.accompanist.placeholder.material) } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt index 364bf5d..ffe0477 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt @@ -8,8 +8,8 @@ import androidx.activity.enableEdgeToEdge import com.syaroful.agrilinkvocpro.core.components.DownloadModuleConfirmationDialog import com.syaroful.agrilinkvocpro.data.UserPreferences import com.syaroful.agrilinkvocpro.navigation.SetupNavigation -import com.syaroful.agrilinkvocpro.ui.screen.home.DynamicModuleViewModel -import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme +import com.syaroful.agrilinkvocpro.presentation.screen.home.DynamicModuleViewModel +import com.syaroful.agrilinkvocpro.presentation.theme.AgrilinkVocproTheme import org.koin.android.ext.android.get import org.koin.androidx.viewmodel.ext.android.viewModel diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt index 4e1cb96..f4941f3 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt index 93b1677..4a6ea6a 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt @@ -26,9 +26,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.syaroful.agrilinkvocpro.R -import com.syaroful.agrilinkvocpro.ui.theme.DarkGrey -import com.syaroful.agrilinkvocpro.ui.theme.LightGrey -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.DarkGrey +import com.syaroful.agrilinkvocpro.presentation.theme.LightGrey +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt index 4d3e058..2ea5028 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt @@ -21,8 +21,8 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.syaroful.agrilinkvocpro.R -import com.syaroful.agrilinkvocpro.ui.theme.LightGrey -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.LightGrey +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @OptIn(ExperimentalFoundationApi::class) diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/DownloadProgressDialog.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/DownloadProgressDialog.kt index 470f186..deac935 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/DownloadProgressDialog.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/DownloadProgressDialog.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable fun DownloadProgressDialog( diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt index 98ee994..f2e91ff 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.syaroful.agrilinkvocpro.R -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable fun MenuItemButton( diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt index 92d2e11..7696efd 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt @@ -4,7 +4,7 @@ import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -import com.syaroful.agrilinkvocpro.ui.theme.LightGrey +import com.syaroful.agrilinkvocpro.presentation.theme.LightGrey val textTheme = Typography( displayLarge = TextStyle( diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/placeholder/ShimmerEffect.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/placeholder/ShimmerEffect.kt new file mode 100644 index 0000000..9fba379 --- /dev/null +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/placeholder/ShimmerEffect.kt @@ -0,0 +1,61 @@ +package com.syaroful.agrilinkvocpro.core.placeholder + +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp + + +fun Modifier.shimmerEffect( + shimmerColors: List = listOf( + Color.LightGray.copy(alpha = 0.6f), + Color.LightGray.copy(alpha = 0.2f), + Color.LightGray.copy(alpha = 0.6f) + ), + shimmerDuration: Int = 1000, + cornerRadius: Dp = 16.dp +): Modifier = composed { + var size by remember { mutableStateOf(IntSize.Zero) } + val transition = rememberInfiniteTransition() + + val xShimmer by transition.animateFloat( + initialValue = 0f, + targetValue = 1f, + animationSpec = infiniteRepeatable( + animation = tween(durationMillis = shimmerDuration, easing = LinearEasing) + ) + ) + + val brush = Brush.linearGradient( + colors = shimmerColors, + start = Offset.Zero, + end = Offset( + x = size.width * xShimmer, + y = size.height * xShimmer + ) + ) + + this + .onGloballyPositioned { coordinates -> + size = coordinates.size + } + .clip(RoundedCornerShape(cornerRadius)) + .background(brush) +} diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/utils/extention/DateExtention.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/utils/extention/DateExtention.kt new file mode 100644 index 0000000..5935743 --- /dev/null +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/utils/extention/DateExtention.kt @@ -0,0 +1,10 @@ +package com.syaroful.agrilinkvocpro.core.utils.extention + +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +fun Date.toFormattedString(): String { + val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + return sdf.format(this) +} \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/utils/extention/ErrorMessageExtention.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/utils/extention/ErrorMessageExtention.kt new file mode 100644 index 0000000..d4ab3bc --- /dev/null +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/utils/extention/ErrorMessageExtention.kt @@ -0,0 +1,19 @@ +package com.syaroful.agrilinkvocpro.core.utils.extention + +fun mapToUserFriendlyError(e: Exception): String { + return when (e) { + is java.net.UnknownHostException -> "Tidak dapat terhubung ke server. Periksa koneksi internet Anda." + is java.net.SocketTimeoutException -> "Waktu koneksi habis. Mohon coba lagi." + is java.io.IOException -> "Terjadi kesalahan jaringan. Silakan cek koneksi Anda." + is retrofit2.HttpException -> { + when (e.code()) { + 401 -> "Akses ditolak. Silakan logout dan login kembali." + 403 -> "Anda tidak memiliki izin untuk mengakses ini." + 404 -> "Data tidak ditemukan." + 500 -> "Terjadi kesalahan pada server. Silakan coba lagi nanti." + else -> "Terjadi kesalahan. Kode: ${e.code()}" + } + } + else -> "Terjadi kesalahan. Silakan coba lagi." + } +} \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/model/NpkGraphicDataResponse.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/model/NpkGraphicDataResponse.kt index b8ab3ca..b00caf8 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/model/NpkGraphicDataResponse.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/model/NpkGraphicDataResponse.kt @@ -1,25 +1,11 @@ package com.syaroful.agrilinkvocpro.data.model -data class Npk1GraphicDataResponse( - val data: ListDataNpk1?, +data class NpkGraphicDataResponse( + val data: Map>?, val statusCode: Int?, val message: String?, ) -data class ListDataNpk1( - val npk1: List?, -) - -data class Npk2GraphicDataResponse( - val data: ListDataNpk2?, - val statusCode: Int?, - val message: String?, -) - -data class ListDataNpk2( - val npk1: List?, -) - data class NpkWithHour( val hour: Int?, val date: String?, diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/network/ApiService.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/network/ApiService.kt index 4e1c0d7..886b737 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/network/ApiService.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/network/ApiService.kt @@ -1,12 +1,14 @@ package com.syaroful.agrilinkvocpro.data.network import com.syaroful.agrilinkvocpro.data.model.LoginResponse +import com.syaroful.agrilinkvocpro.data.model.NpkGraphicDataResponse import com.syaroful.agrilinkvocpro.data.model.SensorDataResponse import retrofit2.Response import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.POST +import retrofit2.http.Query data class LoginRequest( @@ -25,4 +27,14 @@ interface ApiService { suspend fun getLatestSensorData( @Header("Authorization") authHeader: String ): Response + + @GET("api/sensor/getData") + suspend fun getNpk1DataSensor( + @Header("Authorization") authHeader: String, + @Query("range[start]") startDate: String, + @Query("range[end]") endDate: String, + @Query("range[time_range]") timeRange: String = "HOURLY", + @Query("sensor") sensor: String + ): Response + } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/repository/SensorDataRepository.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/repository/SensorDataRepository.kt index 0e32fac..f480bdd 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/repository/SensorDataRepository.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/data/repository/SensorDataRepository.kt @@ -1,12 +1,30 @@ package com.syaroful.agrilinkvocpro.data.repository +import com.syaroful.agrilinkvocpro.data.model.NpkGraphicDataResponse import com.syaroful.agrilinkvocpro.data.model.SensorDataResponse import com.syaroful.agrilinkvocpro.data.network.ApiService import retrofit2.Response class SensorDataRepository(private val apiService: ApiService) { + private var _latestSensorData: SensorDataResponse? = null + val latestSensorData: SensorDataResponse? + get() = _latestSensorData suspend fun getLatestSensorData(authHeader: String): Response { - return apiService.getLatestSensorData(authHeader) + val response = apiService.getLatestSensorData(authHeader) + if (response.isSuccessful) { + _latestSensorData = response.body() + } + return response + } + + suspend fun getNpkDataSensor( + authHeader: String, + startDate: String, + endDate: String, + timeRange: String = "HOURLY", + sensor: String + ): Response { + return apiService.getNpk1DataSensor(authHeader, startDate, endDate, timeRange, sensor) } } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/di/ViewModelModule.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/di/ViewModelModule.kt index c3f0ac6..0ad1154 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/di/ViewModelModule.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/di/ViewModelModule.kt @@ -1,9 +1,10 @@ package com.syaroful.agrilinkvocpro.di -import com.syaroful.agrilinkvocpro.ui.screen.home.DynamicModuleViewModel -import com.syaroful.agrilinkvocpro.ui.screen.home.HomeViewModel -import com.syaroful.agrilinkvocpro.ui.screen.login.LoginViewModel -import com.syaroful.agrilinkvocpro.ui.screen.profile.ProfileViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.detail.DetailViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.home.DynamicModuleViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.home.HomeViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.login.LoginViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.profile.ProfileViewModel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module @@ -12,4 +13,5 @@ val viewModelModule = module { viewModel { LoginViewModel(get(), get()) } viewModel { ProfileViewModel(get()) } viewModel { HomeViewModel(get(), get()) } + viewModel { DetailViewModel(get(), get()) } } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/navigation/NavGraph.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/navigation/NavGraph.kt index 4f24dde..9167300 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/navigation/NavGraph.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/navigation/NavGraph.kt @@ -1,18 +1,20 @@ package com.syaroful.agrilinkvocpro.navigation import androidx.compose.runtime.Composable +import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import com.syaroful.agrilinkvocpro.data.UserPreferences -import com.syaroful.agrilinkvocpro.ui.screen.detail.DetailScreen -import com.syaroful.agrilinkvocpro.ui.screen.home.DynamicModuleViewModel -import com.syaroful.agrilinkvocpro.ui.screen.home.HomeScreen -import com.syaroful.agrilinkvocpro.ui.screen.login.LoginScreen -import com.syaroful.agrilinkvocpro.ui.screen.login.LoginViewModel -import com.syaroful.agrilinkvocpro.ui.screen.profile.ProfileScreen -import com.syaroful.agrilinkvocpro.ui.screen.register.RegisterScreen -import com.syaroful.agrilinkvocpro.ui.screen.splash.SplashScreen +import com.syaroful.agrilinkvocpro.presentation.screen.detail.DetailScreen +import com.syaroful.agrilinkvocpro.presentation.screen.home.DynamicModuleViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.home.HomeScreen +import com.syaroful.agrilinkvocpro.presentation.screen.login.LoginScreen +import com.syaroful.agrilinkvocpro.presentation.screen.login.LoginViewModel +import com.syaroful.agrilinkvocpro.presentation.screen.profile.ProfileScreen +import com.syaroful.agrilinkvocpro.presentation.screen.register.RegisterScreen +import com.syaroful.agrilinkvocpro.presentation.screen.splash.SplashScreen import org.koin.androidx.compose.koinViewModel @Composable @@ -83,8 +85,12 @@ fun SetupNavigation( } ) } - composable("detail-screen") { - DetailScreen() + composable( + route = "detail-screen/{sensorId}", + arguments = listOf(navArgument("sensorId") { type = NavType.StringType }) + ) { backStackEntry -> + val sensorId = backStackEntry.arguments?.getString("sensorId") ?: "npk1" + DetailScreen(sensorId = sensorId) } } } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DataSensorBar.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DataSensorBar.kt similarity index 95% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DataSensorBar.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DataSensorBar.kt index eba0eb0..57657e2 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DataSensorBar.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DataSensorBar.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.detail +package com.syaroful.agrilinkvocpro.presentation.screen.detail import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -25,7 +25,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.syaroful.agrilinkvocpro.R -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable fun DataSensorBar( @@ -95,7 +95,7 @@ private fun CustomLinearProgressIndicator( fun DataSensorBarPreview() { DataSensorBar( label = "Nitrogen", - percentage = 0.5f, + percentage = 20f, painter = painterResource(id = R.drawable.npk), ) diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DetailScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DetailScreen.kt new file mode 100644 index 0000000..fc68be2 --- /dev/null +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DetailScreen.kt @@ -0,0 +1,229 @@ +package com.syaroful.agrilinkvocpro.presentation.screen.detail + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.CenterHorizontally +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.syaroful.agrilinkvocpro.R +import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent +import com.syaroful.agrilinkvocpro.core.placeholder.shimmerEffect +import com.syaroful.agrilinkvocpro.core.utils.ResultState +import org.koin.androidx.compose.koinViewModel +import java.text.SimpleDateFormat +import java.util.Date + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailScreen( + sensorId: String, + modifier: Modifier = Modifier, + detailViewModel: DetailViewModel = koinViewModel(), +) { + LaunchedEffect(sensorId) { + detailViewModel.fetchNpkData(sensorId) + } + val currentData = detailViewModel.currentSensorData + val sdf = SimpleDateFormat("dd MMMM yyyy", java.util.Locale.getDefault()) + val currentDate = sdf.format(Date()) + val options = listOf( + "Nitrogen", + "Pospor", + "Kalium", + "Suhu Tanah", + "PH Tanah", + "Kelembapan", + "Konduktivitas" + ) + Scaffold( + topBar = { + TopAppBar( + title = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxWidth() + ) { + Text( + "Detail Grafik", + style = MaterialTheme.typography.titleMedium + ) + } + }, + ) + }, + ) { innerPadding -> + val npkDataState by detailViewModel.npkDataState.collectAsState() + val isRefreshing = remember { mutableStateOf(false) } + PullToRefreshBox( + isRefreshing = isRefreshing.value, + onRefresh = { + isRefreshing.value = true + detailViewModel.fetchNpkData(sensorId) + }, + ) { + Column( + modifier = Modifier + .padding(innerPadding) + .padding(top = 16.dp) + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()) + ) { + + when (npkDataState) { + is ResultState.Loading -> { + Box( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + + .shimmerEffect() + ) + } + + is ResultState.Error -> { + isRefreshing.value = false + DefaultErrorComponent( + modifier = Modifier.padding(vertical = 20.dp), + label = "Oops!", + message = (npkDataState as ResultState.Error).message, + painter = painterResource(id = R.drawable.mascot_confused) + ) + } + + ResultState.Idle -> { + + } + + is ResultState.Success -> { + isRefreshing.value = false + val selectedSensor = remember { mutableStateOf(options[0]) } + val result = (npkDataState as ResultState.Success).data + val npkData = result?.data?.get(sensorId) + val hours = npkData?.filter { it.hour != null }?.map { it.hour!!.toInt() } + ?: emptyList() + val values = when (selectedSensor.value) { + "Nitrogen" -> npkData?.mapNotNull { it.soilnitrogen?.toDouble() } ?: emptyList() + "Pospor" -> npkData?.mapNotNull { it.soilphosphorus?.toDouble() } ?: emptyList() + "Kalium" -> npkData?.mapNotNull { it.soilpotassium?.toDouble() } ?: emptyList() + "Suhu Tanah" -> npkData?.mapNotNull { it.soiltemperature?.toDouble() } ?: emptyList() + "PH Tanah" -> npkData?.mapNotNull { it.soilph?.toDouble() } ?: emptyList() + "Kelembapan" -> npkData?.mapNotNull { it.soilhumidity?.toDouble() } ?: emptyList() + "Konduktivitas" -> npkData?.mapNotNull { it.soilconductivity?.toDouble() } ?: emptyList() + else -> emptyList() + } + + DynamicBottomSheet( + options = options + ) { selected -> + selectedSensor.value = selected + } + Spacer(modifier = Modifier.height(16.dp)) + LineChart( + hours = hours, + values = values, + modifier = Modifier + .fillMaxWidth() + .height(180.dp) + .align(CenterHorizontally) + ) + } + } + + Text( + "Grafik ini adalah grafik per hari ini tanggal $currentDate", + style = MaterialTheme.typography.bodySmall, + textAlign = TextAlign.Center, + fontStyle = FontStyle.Italic, + modifier = Modifier + .fillMaxWidth() + .alpha(0.5f) + .padding(vertical = 8.dp) + ) + if (currentData != null) { + val dataSensor = when (sensorId) { + "npk1" -> currentData.data?.npk1 + "npk2" -> currentData.data?.npk2 + else -> null + } + Column( + verticalArrangement = Arrangement.spacedBy( + 8.dp, + Alignment.Top + ) + ) { + DataSensorBar( + label = "Nitrogen", + value = dataSensor?.soilnitrogen ?: 0, + painter = painterResource(id = R.drawable.npk), // Assuming the max value is 255 + percentage = (dataSensor?.soilnitrogen?.toFloat() ?: 0f) / 50f + ) + DataSensorBar( + label = "Pospor", + value = dataSensor?.soilphosphorus ?: 0, + painter = painterResource(id = R.drawable.npk), // Assuming the max value is 255 + percentage = (dataSensor?.soilphosphorus?.toFloat() ?: 0f) / 255f + ) + DataSensorBar( + label = "Kalium", + value = dataSensor?.soilpotassium ?: 0, + painter = painterResource(id = R.drawable.npk), // Assuming the max value is 255 + percentage = (dataSensor?.soilpotassium?.toFloat() ?: 0f) / 255f + ) + DataSensorBar( + label = "Kelembaban", + value = dataSensor?.soilhumidity ?: 0, + painter = painterResource(id = R.drawable.soil_humidity), // Assuming the max value is 100 + percentage = (dataSensor?.soilhumidity?.toFloat() ?: 0f) / 100f + ) + DataSensorBar( + label = "Suhu Tanah", + value = dataSensor?.soiltemperature ?: 0, + painter = painterResource(id = R.drawable.soil_temperature), // Assuming the max value is 50 (adjust as needed) + percentage = (dataSensor?.soiltemperature?.toFloat() ?: 0f) / 50f + ) + DataSensorBar( + label = "PH Tanah", + value = dataSensor?.soilph ?: 0, + painter = painterResource(id = R.drawable.meters), // Assuming the max value is 14 + percentage = (dataSensor?.soilph?.toFloat() ?: 0f) / 14f + ) + DataSensorBar( + label = "Konduktivitas", + value = dataSensor?.soilconductivity ?: 0, + painter = painterResource(id = R.drawable.electricity), + percentage = (dataSensor?.soilconductivity?.toFloat() ?: 0f) / 200f + ) + } + } else { + Text("data Sesnor kosong") + } + + } + } + } +} \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DetailViewModel.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DetailViewModel.kt new file mode 100644 index 0000000..b6de5b5 --- /dev/null +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DetailViewModel.kt @@ -0,0 +1,70 @@ +package com.syaroful.agrilinkvocpro.presentation.screen.detail + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.syaroful.agrilinkvocpro.core.utils.ResultState +import com.syaroful.agrilinkvocpro.core.utils.extention.mapToUserFriendlyError +import com.syaroful.agrilinkvocpro.core.utils.extention.toFormattedString +import com.syaroful.agrilinkvocpro.data.UserPreferences +import com.syaroful.agrilinkvocpro.data.model.NpkGraphicDataResponse +import com.syaroful.agrilinkvocpro.data.model.SensorDataResponse +import com.syaroful.agrilinkvocpro.data.repository.SensorDataRepository +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import java.util.Date + + +private const val TAG = "DetailViewModel" + +class DetailViewModel( + private val sensorDataRepository: SensorDataRepository, + private val userPreferences: UserPreferences +) : ViewModel() { + + val currentSensorData: SensorDataResponse? + get() = sensorDataRepository.latestSensorData + + private val _npkDataState = MutableStateFlow>(ResultState.Idle) + val npkDataState: StateFlow> = _npkDataState.asStateFlow() + + private val today = Date() + + fun fetchNpkData( + sensor: String, + ) { + viewModelScope.launch { + _npkDataState.value = ResultState.Loading + val token = userPreferences.tokenFlow.first() + val authHeader = "Bearer $token" + val formattedToday = today.toFormattedString() + try { + delay(2000L) + val response = sensorDataRepository.getNpkDataSensor( + authHeader = authHeader, + startDate = formattedToday, + endDate = formattedToday, + timeRange = "HOURLY", + sensor = sensor + ) + if (response.isSuccessful) { + response.body()?.let { body -> + _npkDataState.value = ResultState.Success(body) + } ?: run { + _npkDataState.value = ResultState.Error("Data tidak ditemukan") + } + } else { + _npkDataState.value = ResultState.Error("Error: ${response.code()} - ${response.message()}") + } + } catch (e: Exception) { + val errorMessage = mapToUserFriendlyError(e) + _npkDataState.value = ResultState.Error(errorMessage) + Log.d(TAG, "Failed to fetch data: ${e.message}") + } + } + } +} \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DynamicBottomSheet.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DynamicBottomSheet.kt similarity index 97% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DynamicBottomSheet.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DynamicBottomSheet.kt index 808d7ca..2452a49 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DynamicBottomSheet.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/DynamicBottomSheet.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.detail +package com.syaroful.agrilinkvocpro.presentation.screen.detail import androidx.compose.foundation.border import androidx.compose.foundation.clickable diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/LineChart.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/LineChart.kt similarity index 89% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/LineChart.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/LineChart.kt index 2ca9d8c..2a40579 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/LineChart.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/detail/LineChart.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.detail +package com.syaroful.agrilinkvocpro.presentation.screen.detail import android.graphics.Paint import androidx.compose.foundation.Canvas @@ -22,7 +22,7 @@ import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen import kotlin.math.round import kotlin.math.roundToInt @@ -36,7 +36,7 @@ fun LineChart( Box( modifier = Modifier .background(color = MaterialTheme.colorScheme.surfaceContainer, shape = RoundedCornerShape(8.dp)) - .padding(top = 20.dp) + .padding(top = 24.dp) .padding(8.dp) ) { val spacing = 100f @@ -130,6 +130,21 @@ fun LineChart( cap = StrokeCap.Round ) ) + val labelPadding = 12.dp.toPx() + + drawContext.canvas.nativeCanvas.drawText( + "Jumlah", + spacing / 2f, + labelPadding - 80, + textPaint + ) + + drawContext.canvas.nativeCanvas.drawText( + "Jam", + size.width - labelPadding, + size.height - 4, + textPaint + ) } } } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/DynamicModuleViewModel.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/DynamicModuleViewModel.kt similarity index 99% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/DynamicModuleViewModel.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/DynamicModuleViewModel.kt index 0196c7b..2438801 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/DynamicModuleViewModel.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/DynamicModuleViewModel.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.home +package com.syaroful.agrilinkvocpro.presentation.screen.home import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/HomeScreen.kt similarity index 68% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/HomeScreen.kt index 6d3c7d8..eb82bc4 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/HomeScreen.kt @@ -1,7 +1,5 @@ -package com.syaroful.agrilinkvocpro.ui.screen.home +package com.syaroful.agrilinkvocpro.presentation.screen.home -import android.content.res.Configuration.UI_MODE_NIGHT_YES -import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -21,8 +19,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Person -import androidx.compose.material3.Button -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -31,12 +27,11 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -44,22 +39,19 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavController -import androidx.navigation.compose.rememberNavController import com.syaroful.agrilinkvocpro.R import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent import com.syaroful.agrilinkvocpro.core.components.DownloadProgressDialog import com.syaroful.agrilinkvocpro.core.components.MenuItemButton import com.syaroful.agrilinkvocpro.core.components.textTheme +import com.syaroful.agrilinkvocpro.core.placeholder.shimmerEffect import com.syaroful.agrilinkvocpro.core.utils.ResultState -import com.syaroful.agrilinkvocpro.data.model.SensorDataResponse -import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme -import com.syaroful.agrilinkvocpro.ui.theme.LightGrey -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.AgrilinkVocproTheme +import com.syaroful.agrilinkvocpro.presentation.theme.LightGrey +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen import org.koin.androidx.compose.koinViewModel -import kotlin.math.log @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -76,6 +68,10 @@ fun HomeScreen( val homeState by homeViewModel.homeState.collectAsState() val isRefreshing = remember { mutableStateOf(false) } + + val sensors = listOf("NPK", "DHT") + var selectedSensor by remember { mutableStateOf("NPK") } + AgrilinkVocproTheme { Scaffold { padding -> PullToRefreshBox( @@ -98,20 +94,26 @@ fun HomeScreen( onFeatureClick = onFeatureClick ) Spacer(modifier = Modifier.height(32.dp)) - Text( - modifier = Modifier - .padding(horizontal = 20.dp) - .fillMaxWidth(), - text = "Data Sensor Green House", - textAlign = TextAlign.Center, - style = textTheme.bodyMedium + SensorTabBar( + sensors = sensors, + selectedSensor = selectedSensor, + onSensorSelected = { selectedSensor = it } ) when (homeState) { is ResultState.Loading -> { - CircularProgressIndicator( + Box( modifier = Modifier .padding(16.dp) - .align(Alignment.CenterHorizontally) + .fillMaxWidth() + .height(100.dp) + .shimmerEffect() + ) + Box( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + .height(100.dp) + .shimmerEffect() ) } @@ -119,28 +121,44 @@ fun HomeScreen( isRefreshing.value = false val data = (homeState as ResultState.Success).data data?.data?.let { sensorData -> - BetDataComponent( - onClick = { - navController.navigate("detail-screen") - }, - betNUmber = 1, - commodity = "Kabocha", - nitrogenValue = sensorData.npk1?.soilnitrogen.toString(), - phosphorValue = sensorData.npk1?.soilphosphorus.toString(), - potassiumValue = sensorData.npk1?.soilpotassium.toString(), - commodityImage = painterResource(id = R.drawable.kabocha) - ) - BetDataComponent( - onClick = { - navController.navigate("detail-screen") - }, - betNUmber = 2, - commodity = "Melon", - nitrogenValue = sensorData.npk2?.soilnitrogen.toString(), - phosphorValue = sensorData.npk2?.soilphosphorus.toString(), - potassiumValue = sensorData.npk2?.soilpotassium.toString(), - commodityImage = painterResource(id = R.drawable.melon) - ) + when (selectedSensor) { + "NPK" -> { + BetDataComponent( + onClick = { + navController.navigate("detail-screen/npk1") + }, + betNUmber = 1, + commodity = "Kabocha", + nitrogenValue = sensorData.npk1?.soilnitrogen.toString(), + phosphorValue = sensorData.npk1?.soilphosphorus.toString(), + potassiumValue = sensorData.npk1?.soilpotassium.toString(), + commodityImage = painterResource(id = R.drawable.kabocha) + ) + BetDataComponent( + onClick = { + navController.navigate("detail-screen/npk2") + }, + betNUmber = 2, + commodity = "Melon", + nitrogenValue = sensorData.npk2?.soilnitrogen.toString(), + phosphorValue = sensorData.npk2?.soilphosphorus.toString(), + potassiumValue = sensorData.npk2?.soilpotassium.toString(), + commodityImage = painterResource(id = R.drawable.melon) + ) + } + + "DHT" -> { + DhtDataComponent( + onClick = { + + }, + temperatureValue = sensorData.dht?.vicitemperature.toString(), + humidityValue = sensorData.dht?.vicihumidity.toString(), + luminosityValue = sensorData.dht?.viciluminosity.toString(), + ) + } + + } } } @@ -237,6 +255,50 @@ private fun BetDataComponent( } } +@Composable +private fun DhtDataComponent( + onClick: () -> Unit, + temperatureValue: String, + humidityValue: String, + luminosityValue: String, +) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(horizontal = 20.dp, vertical = 8.dp) + .clip(shape = RoundedCornerShape(16.dp)) + .fillMaxWidth() + .background( + color = MaterialTheme.colorScheme.surfaceContainer, + ) + .border( + width = 1.dp, + color = MainGreen.copy(alpha = 0.4f), + shape = RoundedCornerShape(16.dp) + ) + .clickable { onClick() } + .padding(horizontal = 16.dp, vertical = 8.dp) + ) + { + SensorDataItem( + icon = "Temp", + label = "Suhu\nGreen House", + value = temperatureValue + ) + SensorDataItem( + icon = "Hum", + label = "Kelembaban\nUdara", + value = humidityValue + ) + SensorDataItem( + icon = "Lux", + label = "Intensitas\ncahaya", + value = luminosityValue + ) + } +} + @Composable private fun SensorDataItem( icon: String = "-", @@ -245,7 +307,7 @@ private fun SensorDataItem( ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(text = icon, color = MainGreen, style = textTheme.headlineMedium) - Text(text = label, color = LightGrey, style = textTheme.bodySmall) + Text(text = label, color = LightGrey, style = textTheme.bodySmall, textAlign = TextAlign.Center) Spacer(modifier = Modifier.height(8.dp)) Text(text = value, style = textTheme.headlineSmall) } diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeViewModel.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/HomeViewModel.kt similarity index 69% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeViewModel.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/HomeViewModel.kt index d72dd04..5ce0550 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeViewModel.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/HomeViewModel.kt @@ -1,12 +1,14 @@ -package com.syaroful.agrilinkvocpro.ui.screen.home +package com.syaroful.agrilinkvocpro.presentation.screen.home import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.syaroful.agrilinkvocpro.core.utils.ResultState +import com.syaroful.agrilinkvocpro.core.utils.extention.mapToUserFriendlyError import com.syaroful.agrilinkvocpro.data.UserPreferences import com.syaroful.agrilinkvocpro.data.model.SensorDataResponse import com.syaroful.agrilinkvocpro.data.repository.SensorDataRepository +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first @@ -22,6 +24,9 @@ class HomeViewModel( private val _homeState = MutableStateFlow>(ResultState.Idle) val homeState: StateFlow> = _homeState +// var currentDataSensor: SensorDataResponse? = null +// private set + init { getGreenHouseData() } @@ -38,9 +43,12 @@ class HomeViewModel( val token = userPreferences.tokenFlow.first() val authHeader = "Bearer $token" try { + delay(1000L) val response = sensorDataRepository.getLatestSensorData(authHeader) if (response.isSuccessful) { - _homeState.value = ResultState.Success(response.body()) + val responseBody = response.body() + _homeState.value = ResultState.Success(responseBody) +// currentDataSensor = responseBody Log.d(TAG, "Success to fetch data: ${response.body()} \nCurl response: ${response.raw()}") } else { val errorBody = response.errorBody()?.string() @@ -50,7 +58,6 @@ class HomeViewModel( .optString("message", "Failed to fetch data: ${response.code()}") } ?: "Failed to fetch data: ${response.code()}" _homeState.value = ResultState.Error(errorMessage) - // Log.d(TAG, errorMessage) // Sudah di-log di atas } } catch (e: Exception){ val errorMessage = mapToUserFriendlyError(e) @@ -59,21 +66,4 @@ class HomeViewModel( } } } - private fun mapToUserFriendlyError(e: Exception): String { - return when (e) { - is java.net.UnknownHostException -> "Tidak dapat terhubung ke server. Periksa koneksi internet Anda." - is java.net.SocketTimeoutException -> "Waktu koneksi habis. Mohon coba lagi." - is java.io.IOException -> "Terjadi kesalahan jaringan. Silakan cek koneksi Anda." - is retrofit2.HttpException -> { - when (e.code()) { - 401 -> "Akses ditolak. Silakan logout dan login kembali." - 403 -> "Anda tidak memiliki izin untuk mengakses ini." - 404 -> "Data tidak ditemukan." - 500 -> "Terjadi kesalahan pada server. Silakan coba lagi nanti." - else -> "Terjadi kesalahan. Kode: ${e.code()}" - } - } - else -> "Terjadi kesalahan. Silakan coba lagi." - } - } } \ No newline at end of file diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/SensorTabBar.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/SensorTabBar.kt new file mode 100644 index 0000000..28b4f3b --- /dev/null +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/home/SensorTabBar.kt @@ -0,0 +1,52 @@ +package com.syaroful.agrilinkvocpro.presentation.screen.home + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +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.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen + +@Composable +fun SensorTabBar( + sensors: List, + selectedSensor: String, + onSensorSelected: (String) -> Unit, + modifier: Modifier = Modifier +) { + Row( + horizontalArrangement = Arrangement.Center, + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = 8.dp) + ) { + sensors.forEach { sensor -> + val isSelected = sensor == selectedSensor + Box( + modifier = Modifier + .padding(horizontal = 4.dp) + .clip(RoundedCornerShape(50)) + .background(if (isSelected) MainGreen else MaterialTheme.colorScheme.surfaceContainer) + .clickable { onSensorSelected(sensor) } + .padding(horizontal = 24.dp, vertical = 8.dp) + ) { + Text( + text = sensor, + color = if (isSelected) Color.White else MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.labelMedium + ) + } + } + } +} diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/login/LoginScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/login/LoginScreen.kt similarity index 95% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/login/LoginScreen.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/login/LoginScreen.kt index 3b1317b..0c9766b 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/login/LoginScreen.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/login/LoginScreen.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.login +package com.syaroful.agrilinkvocpro.presentation.screen.login import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.Image @@ -36,9 +36,9 @@ import com.syaroful.agrilinkvocpro.core.components.AppPasswordField import com.syaroful.agrilinkvocpro.core.components.AppTextField import com.syaroful.agrilinkvocpro.core.components.textTheme import com.syaroful.agrilinkvocpro.core.utils.ResultState -import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme -import com.syaroful.agrilinkvocpro.ui.theme.DarkGrey -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.AgrilinkVocproTheme +import com.syaroful.agrilinkvocpro.presentation.theme.DarkGrey +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen import org.koin.androidx.compose.koinViewModel diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/login/LoginViewModel.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/login/LoginViewModel.kt similarity index 98% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/login/LoginViewModel.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/login/LoginViewModel.kt index 2972b72..b92d327 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/login/LoginViewModel.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/login/LoginViewModel.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.login +package com.syaroful.agrilinkvocpro.presentation.screen.login import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/profile/ProfileScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/profile/ProfileScreen.kt similarity index 97% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/profile/ProfileScreen.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/profile/ProfileScreen.kt index 85fe82b..cf4ffb6 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/profile/ProfileScreen.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/profile/ProfileScreen.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.profile +package com.syaroful.agrilinkvocpro.presentation.screen.profile import androidx.compose.foundation.Image import androidx.compose.foundation.border @@ -38,8 +38,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.syaroful.agrilinkvocpro.R import com.syaroful.agrilinkvocpro.core.components.textTheme -import com.syaroful.agrilinkvocpro.ui.theme.LightGrey -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.LightGrey +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/profile/ProfileViewModel.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/profile/ProfileViewModel.kt similarity index 97% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/profile/ProfileViewModel.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/profile/ProfileViewModel.kt index 3ddb142..1c981f2 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/profile/ProfileViewModel.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/profile/ProfileViewModel.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.profile +package com.syaroful.agrilinkvocpro.presentation.screen.profile import android.util.Log import androidx.lifecycle.ViewModel diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/register/RegisterScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/register/RegisterScreen.kt similarity index 96% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/register/RegisterScreen.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/register/RegisterScreen.kt index 2a50b60..3ece4db 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/register/RegisterScreen.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/register/RegisterScreen.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.register +package com.syaroful.agrilinkvocpro.presentation.screen.register import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -29,8 +29,8 @@ import com.syaroful.agrilinkvocpro.core.components.AppButton import com.syaroful.agrilinkvocpro.core.components.AppPasswordField import com.syaroful.agrilinkvocpro.core.components.AppTextField import com.syaroful.agrilinkvocpro.core.components.textTheme -import com.syaroful.agrilinkvocpro.ui.theme.DarkGrey -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.DarkGrey +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable fun RegisterScreen( diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/splash/SplashScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/splash/SplashScreen.kt similarity index 92% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/splash/SplashScreen.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/splash/SplashScreen.kt index 6e7a826..16b4bc3 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/splash/SplashScreen.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/screen/splash/SplashScreen.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.screen.splash +package com.syaroful.agrilinkvocpro.presentation.screen.splash import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -20,8 +20,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.syaroful.agrilinkvocpro.R import com.syaroful.agrilinkvocpro.data.UserPreferences -import com.syaroful.agrilinkvocpro.ui.theme.DarkGreen -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.DarkGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen import kotlinx.coroutines.delay @Composable diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Color.kt similarity index 90% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Color.kt index ffe73ac..45caa4c 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Color.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.theme +package com.syaroful.agrilinkvocpro.presentation.theme import androidx.compose.ui.graphics.Color diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Theme.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Theme.kt similarity index 96% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Theme.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Theme.kt index 2b1e1e1..4b760b5 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Theme.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Theme.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.theme +package com.syaroful.agrilinkvocpro.presentation.theme import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Type.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Type.kt similarity index 94% rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Type.kt rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Type.kt index 659e52d..5ffe9db 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Type.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/presentation/theme/Type.kt @@ -1,4 +1,4 @@ -package com.syaroful.agrilinkvocpro.ui.theme +package com.syaroful.agrilinkvocpro.presentation.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DetailScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DetailScreen.kt deleted file mode 100644 index 3fccdd4..0000000 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/detail/DetailScreen.kt +++ /dev/null @@ -1,155 +0,0 @@ -package com.syaroful.agrilinkvocpro.ui.screen.detail - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Alignment.Companion.CenterHorizontally -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontStyle -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.syaroful.agrilinkvocpro.R -import java.text.SimpleDateFormat -import java.util.Date -import kotlin.random.Random - - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun DetailScreen( - modifier: Modifier = Modifier -) { - val sdf = SimpleDateFormat("dd MMMM yyyy", java.util.Locale.getDefault()) - val currentDate = sdf.format(Date()) - val options = listOf( - "Nitrogen", - "Pospor", - "Kalium", - "Suhu Tanah", - "PH Tanah", - "Kelembapan", - "Konduktivitas" - ) - Scaffold( - topBar = { - TopAppBar( - title = { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxWidth() - ) { - Text( - "Detail Grafik", - style = MaterialTheme.typography.titleMedium - ) - } - - }, - ) - }, - ) { innerPadding -> - Column( - modifier = Modifier - .padding(innerPadding) - .padding(top = 16.dp) - .padding(horizontal = 16.dp) - .verticalScroll(rememberScrollState()) - ) { - DynamicBottomSheet( - options = options - ) { - - } - Spacer(modifier = Modifier.height(16.dp)) - LineChart( - hours = listOf(0, 1, 2, 3, 5, 6, 8, 10), - values = listOf(20.0, 22.0, 25.0, 23.0, 28.0, 30.0, 20.0, 22.0), - modifier = Modifier - .fillMaxWidth() - .height(180.dp) - .align(CenterHorizontally) - ) - - Text( - "Grafik ini adalah grafik per hari ini tanggal $currentDate", - style = MaterialTheme.typography.bodySmall, - textAlign = TextAlign.Center, - fontStyle = FontStyle.Italic, - modifier = Modifier - .fillMaxWidth() - .alpha(0.5f) - .padding(vertical = 8.dp) - ) - Column( - verticalArrangement = Arrangement.spacedBy( - 8.dp, - Alignment.Top - ) - ) { - DataSensorBar( - label = "Nitrogen", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.npk), - percentage = 0.5f - ) - DataSensorBar( - label = "Pospor", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.npk), - percentage = 0.43f - ) - DataSensorBar( - label = "Kalium", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.npk), - percentage = 0.3f - ) - DataSensorBar( - label = "Kelembaban", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.soil_humidity), - percentage = 0.2f - ) - DataSensorBar( - label = "Suhu Tanah", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.soil_temperature), - percentage = 0.6f - ) - DataSensorBar( - label = "PH Tanah", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.meters), - percentage = 0.8f - ) - DataSensorBar( - label = "Konduktivitas", - value = Random.nextInt(0, 101), - painter = painterResource(id = R.drawable.electricity), - percentage = 0.6f - ) - } - } - } -} - -@Preview -@Composable -fun PreviewDetailScreen() { - DetailScreen() -} \ No newline at end of file diff --git a/agrilinkvocpro/commodity_price_prediction_feature/src/main/java/com/syaroful/agrilinkvocpro/commodity_price_prediction_feature/PricePredictionActivity.kt b/agrilinkvocpro/commodity_price_prediction_feature/src/main/java/com/syaroful/agrilinkvocpro/commodity_price_prediction_feature/PricePredictionActivity.kt index 519ee8f..4632649 100644 --- a/agrilinkvocpro/commodity_price_prediction_feature/src/main/java/com/syaroful/agrilinkvocpro/commodity_price_prediction_feature/PricePredictionActivity.kt +++ b/agrilinkvocpro/commodity_price_prediction_feature/src/main/java/com/syaroful/agrilinkvocpro/commodity_price_prediction_feature/PricePredictionActivity.kt @@ -11,7 +11,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme +import com.syaroful.agrilinkvocpro.presentation.theme.AgrilinkVocproTheme class PricePredictionActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/agrilinkvocpro/gradle/libs.versions.toml b/agrilinkvocpro/gradle/libs.versions.toml index 6570d7b..c7a2806 100644 --- a/agrilinkvocpro/gradle/libs.versions.toml +++ b/agrilinkvocpro/gradle/libs.versions.toml @@ -37,6 +37,7 @@ runtimeAndroid = "1.8.1" ycharts = "2.1.0" [libraries] +accompanist-placeholder-material = { module = "com.google.accompanist:accompanist-placeholder-material", version.ref = "accompanistSwiperefresh" } accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanistSwiperefresh" } androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraCore" } androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "cameraCore" } diff --git a/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/GrowthRecipeActivity.kt b/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/GrowthRecipeActivity.kt index 1547fa4..01a2184 100644 --- a/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/GrowthRecipeActivity.kt +++ b/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/GrowthRecipeActivity.kt @@ -11,7 +11,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme +import com.syaroful.agrilinkvocpro.presentation.theme.AgrilinkVocproTheme class GrowthRecipeActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/PlantDiseaseDetectionActivity.kt b/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/PlantDiseaseDetectionActivity.kt index b822a72..0437ee8 100644 --- a/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/PlantDiseaseDetectionActivity.kt +++ b/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/PlantDiseaseDetectionActivity.kt @@ -13,7 +13,7 @@ import androidx.navigation.compose.rememberNavController import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.di.cameraModule import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.di.diagnosisModule import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.navigation.NavGraph -import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme +import com.syaroful.agrilinkvocpro.presentation.theme.AgrilinkVocproTheme import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules diff --git a/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/camera/component/CurtomCameraShutter.kt b/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/camera/component/CurtomCameraShutter.kt index 7b9a977..925d6d5 100644 --- a/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/camera/component/CurtomCameraShutter.kt +++ b/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/camera/component/CurtomCameraShutter.kt @@ -19,7 +19,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.syaroful.agrilinkvocpro.plant_disease_detection_feature.R -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen @Composable fun CustomCameraShutter( diff --git a/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/detail/DetailScreen.kt b/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/detail/DetailScreen.kt index e3cce25..69ec858 100644 --- a/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/detail/DetailScreen.kt +++ b/agrilinkvocpro/plant_disease_detection_feature/src/main/java/com/syaroful/agrilinkvocpro/plant_disease_detection_feature/presentation/detail/DetailScreen.kt @@ -40,7 +40,7 @@ import com.syaroful.agrilinkvocpro.R 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.presentation.camera.CameraViewModel -import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class)