product gaselsai

This commit is contained in:
Gracia
2025-04-15 02:09:46 +07:00
parent 4389cecc24
commit 5a8ae5e12b
10 changed files with 124 additions and 108 deletions

View File

@ -38,14 +38,14 @@ android {
buildTypes { buildTypes {
release { release {
buildConfigField("String",
"BASE_URL",
"\"${localProperties["BASE_URL"] ?: "http://default-url.com/"}\"")
isMinifyEnabled = false isMinifyEnabled = false
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
buildConfigField("String",
"BASE_URL",
"\"${localProperties["BASE_URL"] ?: "http://default-url.com/"}\"")
} }
debug { debug {
buildConfigField("String", buildConfigField("String",

View File

@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:allowBackup="true" android:allowBackup="true"

View File

@ -29,7 +29,7 @@ data class Product(
val categoryId: Int? = null, val categoryId: Int? = null,
@field:SerializedName("price") @field:SerializedName("price")
val price: String? = null, val price: Int? = null,
@field:SerializedName("name") @field:SerializedName("name")
val name: String? = null, val name: String? = null,

View File

@ -1,6 +1,5 @@
package com.alya.ecommerce_serang.data.api.response package com.alya.ecommerce_serang.data.api.response.product
import com.alya.ecommerce_serang.data.api.response.product.Product
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
data class CreateProductResponse( data class CreateProductResponse(

View File

@ -7,6 +7,7 @@ import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
class ApiConfig { class ApiConfig {
companion object { companion object {

View File

@ -9,6 +9,7 @@ import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy
import com.alya.ecommerce_serang.data.api.dto.OtpRequest import com.alya.ecommerce_serang.data.api.dto.OtpRequest
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
import com.alya.ecommerce_serang.data.api.dto.UpdateCart import com.alya.ecommerce_serang.data.api.dto.UpdateCart
import com.alya.ecommerce_serang.data.api.response.product.CreateProductResponse
import com.alya.ecommerce_serang.data.api.response.ViewStoreProductsResponse import com.alya.ecommerce_serang.data.api.response.ViewStoreProductsResponse
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
@ -34,9 +35,9 @@ import com.alya.ecommerce_serang.data.api.response.profile.ProfileResponse
import retrofit2.Call import retrofit2.Call
import retrofit2.Response import retrofit2.Response
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.HeaderMap
import retrofit2.http.Multipart import retrofit2.http.Multipart
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Part import retrofit2.http.Part
@ -84,6 +85,24 @@ interface ApiService {
@Path("id") storeId: Int @Path("id") storeId: Int
): Response<DetailStoreProductResponse> ): Response<DetailStoreProductResponse>
@POST("order")
suspend fun postOrder(
@Body request: OrderRequest
): Response<CreateOrderResponse>
@POST("order")
suspend fun postOrderBuyNow(
@Body request: OrderRequestBuy
): Response<CreateOrderResponse>
@GET("profile/address")
suspend fun getAddress(
): Response<AddressResponse>
@POST("profile/addaddress")
suspend fun createAddress(
@Body createAddressRequest: CreateAddressRequest
): Response<CreateAddressResponse>
@GET("mystore") @GET("mystore")
suspend fun getStore (): Response<StoreResponse> suspend fun getStore (): Response<StoreResponse>
@ -106,11 +125,11 @@ interface ApiService {
@Part("is_pre_order") isPreOrder: RequestBody, @Part("is_pre_order") isPreOrder: RequestBody,
@Part("duration") duration: RequestBody, @Part("duration") duration: RequestBody,
@Part("category_id") categoryId: RequestBody, @Part("category_id") categoryId: RequestBody,
@Part("is_active") isActive: RequestBody, @Part("status") status: RequestBody,
@Part image: MultipartBody.Part?, @Part image: MultipartBody.Part?,
@Part sppirt: MultipartBody.Part?, @Part sppirt: MultipartBody.Part?,
@Part halal: MultipartBody.Part? @Part halal: MultipartBody.Part?
): Response<Unit> ): Response<CreateProductResponse>
@GET("cart_item") @GET("cart_item")
suspend fun getCart (): Response<ListCartResponse> suspend fun getCart (): Response<ListCartResponse>

View File

@ -4,11 +4,13 @@ import android.util.Log
import com.alya.ecommerce_serang.data.api.dto.CartItem import com.alya.ecommerce_serang.data.api.dto.CartItem
import com.alya.ecommerce_serang.data.api.dto.CategoryItem import com.alya.ecommerce_serang.data.api.dto.CategoryItem
import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.response.product.CreateProductResponse
import com.alya.ecommerce_serang.data.api.response.cart.AddCartResponse import com.alya.ecommerce_serang.data.api.response.cart.AddCartResponse
import com.alya.ecommerce_serang.data.api.response.product.ProductResponse import com.alya.ecommerce_serang.data.api.response.product.ProductResponse
import com.alya.ecommerce_serang.data.api.response.product.ReviewsItem import com.alya.ecommerce_serang.data.api.response.product.ReviewsItem
import com.alya.ecommerce_serang.data.api.response.product.StoreProduct import com.alya.ecommerce_serang.data.api.response.product.StoreProduct
import com.alya.ecommerce_serang.data.api.retrofit.ApiService import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import com.alya.ecommerce_serang.utils.SessionManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@ -158,51 +160,39 @@ class ProductRepository(private val apiService: ApiService) {
isPreOrder: Boolean, isPreOrder: Boolean,
duration: Int, duration: Int,
categoryId: Int, categoryId: Int,
isActive: Boolean, status: String,
image: File?, imagePart: MultipartBody.Part?,
sppirt: File?, sppirtPart: MultipartBody.Part?,
halal: File? halalPart: MultipartBody.Part?
): Result<Unit> = withContext(Dispatchers.IO) { ): Result<CreateProductResponse> {
try { return try {
val namePart = RequestBody.create("text/plain".toMediaTypeOrNull(), name)
val descriptionPart = RequestBody.create("text/plain".toMediaTypeOrNull(), description)
val pricePart = RequestBody.create("text/plain".toMediaTypeOrNull(), price.toString())
val stockPart = RequestBody.create("text/plain".toMediaTypeOrNull(), stock.toString())
val minOrderPart = RequestBody.create("text/plain".toMediaTypeOrNull(), minOrder.toString())
val weightPart = RequestBody.create("text/plain".toMediaTypeOrNull(), weight.toString())
val isPreOrderPart = RequestBody.create("text/plain".toMediaTypeOrNull(), isPreOrder.toString())
val durationPart = RequestBody.create("text/plain".toMediaTypeOrNull(), duration.toString())
val categoryIdPart = RequestBody.create("text/plain".toMediaTypeOrNull(), categoryId.toString())
val isActivePart = RequestBody.create("text/plain".toMediaTypeOrNull(), if (isActive) "1" else "0")
val imagePart = image?.let {
val req = RequestBody.create("image/*".toMediaTypeOrNull(), it)
MultipartBody.Part.createFormData("image", it.name, req)
}
val sppirtPart = sppirt?.let {
val req = RequestBody.create("application/pdf".toMediaTypeOrNull(), it)
MultipartBody.Part.createFormData("sppirt", it.name, req)
}
val halalPart = halal?.let {
val req = RequestBody.create("application/pdf".toMediaTypeOrNull(), it)
MultipartBody.Part.createFormData("halal", it.name, req)
}
val response = apiService.addProduct( val response = apiService.addProduct(
namePart, descriptionPart, pricePart, stockPart, minOrderPart, name = RequestBody.create("text/plain".toMediaTypeOrNull(), name),
weightPart, isPreOrderPart, durationPart, categoryIdPart, isActivePart, description = RequestBody.create("text/plain".toMediaTypeOrNull(), description),
imagePart, sppirtPart, halalPart price = RequestBody.create("text/plain".toMediaTypeOrNull(), price.toString()),
stock = RequestBody.create("text/plain".toMediaTypeOrNull(), stock.toString()),
minOrder = RequestBody.create("text/plain".toMediaTypeOrNull(), minOrder.toString()),
weight = RequestBody.create("text/plain".toMediaTypeOrNull(), weight.toString()),
isPreOrder = RequestBody.create("text/plain".toMediaTypeOrNull(), isPreOrder.toString()),
duration = RequestBody.create("text/plain".toMediaTypeOrNull(), duration.toString()),
categoryId = RequestBody.create("text/plain".toMediaTypeOrNull(), categoryId.toString()),
status = RequestBody.create("text/plain".toMediaTypeOrNull(), status),
image = imagePart,
sppirt = sppirtPart,
halal = halalPart
) )
if (response.isSuccessful) Result.Success(Unit) if (response.isSuccessful) {
else Result.Error(Exception("Failed: ${response.code()}")) Result.Success(response.body()!!)
} else {
Result.Error(Exception("Failed to create product: ${response.code()}"))
}
} catch (e: Exception) { } catch (e: Exception) {
Result.Error(e) Result.Error(e)
} }
} }
companion object { companion object {
private const val TAG = "ProductRepository" private const val TAG = "ProductRepository"
} }

View File

@ -5,8 +5,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.util.Log
import android.text.TextWatcher
import android.view.View import android.view.View
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Toast import android.widget.Toast
@ -23,11 +22,11 @@ import com.alya.ecommerce_serang.databinding.ActivityStoreProductDetailBinding
import com.alya.ecommerce_serang.utils.viewmodel.ProductViewModel import com.alya.ecommerce_serang.utils.viewmodel.ProductViewModel
import com.alya.ecommerce_serang.utils.BaseViewModelFactory import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager import com.alya.ecommerce_serang.utils.SessionManager
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
import java.io.File import java.io.File
import java.io.FileOutputStream
import kotlin.getValue import kotlin.getValue
class StoreProductDetailActivity : AppCompatActivity() { class StoreProductDetailActivity : AppCompatActivity() {
@ -62,7 +61,7 @@ class StoreProductDetailActivity : AppCompatActivity() {
private val sppirtLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> private val sppirtLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null && isValidFile(uri)) { if (uri != null && isValidFile(uri)) {
sppirtUri = uri sppirtUri = uri
binding.tvSppirtName.text = File(uri.path ?: "").name binding.tvSppirtName.text = getFileName(uri)
binding.switcherSppirt.showNext() binding.switcherSppirt.showNext()
} }
} }
@ -70,7 +69,7 @@ class StoreProductDetailActivity : AppCompatActivity() {
private val halalLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> private val halalLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null && isValidFile(uri)) { if (uri != null && isValidFile(uri)) {
halalUri = uri halalUri = uri
binding.tvHalalName.text = File(uri.path ?: "").name binding.tvHalalName.text = getFileName(uri)
binding.switcherHalal.showNext() binding.switcherHalal.showNext()
} }
} }
@ -109,6 +108,12 @@ class StoreProductDetailActivity : AppCompatActivity() {
imagePickerLauncher.launch(intent) imagePickerLauncher.launch(intent)
} }
binding.btnRemoveFoto.setOnClickListener {
imageUri = null
binding.switcherFotoProduk.showPrevious()
validateForm()
}
binding.layoutUploadSppirt.setOnClickListener { sppirtLauncher.launch("*/*") } binding.layoutUploadSppirt.setOnClickListener { sppirtLauncher.launch("*/*") }
binding.btnRemoveSppirt.setOnClickListener { binding.btnRemoveSppirt.setOnClickListener {
sppirtUri = null sppirtUri = null
@ -121,33 +126,10 @@ class StoreProductDetailActivity : AppCompatActivity() {
binding.switcherHalal.showPrevious() binding.switcherHalal.showPrevious()
} }
binding.btnRemoveFoto.setOnClickListener {
imageUri = null
binding.switcherFotoProduk.showPrevious()
validateForm()
}
val watcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) { validateForm() }
}
listOf(
binding.edtNamaProduk,
binding.edtDeskripsiProduk,
binding.edtHargaProduk,
binding.edtStokProduk,
binding.edtMinOrder,
binding.edtBeratProduk,
binding.edtDurasi
).forEach { it.addTextChangedListener(watcher) }
validateForm() validateForm()
binding.btnSaveProduct.setOnClickListener { binding.btnSaveProduct.setOnClickListener {
if (!binding.btnSaveProduct.isEnabled) { if (!binding.btnSaveProduct.isEnabled) {
focusFirstInvalidField()
return@setOnClickListener return@setOnClickListener
} }
submitProduct() submitProduct()
@ -159,6 +141,10 @@ class StoreProductDetailActivity : AppCompatActivity() {
return listOf("application/pdf", "image/jpeg", "image/png", "image/jpg").contains(mimeType) return listOf("application/pdf", "image/jpeg", "image/png", "image/jpg").contains(mimeType)
} }
private fun getFileName(uri: Uri): String {
return uri.lastPathSegment?.split("/")?.last() ?: "unknown_file"
}
private fun validateForm() { private fun validateForm() {
val valid = binding.edtNamaProduk.text.isNotBlank() && val valid = binding.edtNamaProduk.text.isNotBlank() &&
binding.edtDeskripsiProduk.text.isNotBlank() && binding.edtDeskripsiProduk.text.isNotBlank() &&
@ -178,23 +164,15 @@ class StoreProductDetailActivity : AppCompatActivity() {
) )
} }
private fun focusFirstInvalidField() { private fun uriToNamedFile(uri: Uri, context: Context, prefix: String): File {
when { val extension = context.contentResolver.getType(uri)?.substringAfter("/") ?: "jpg"
binding.edtNamaProduk.text.isBlank() -> binding.edtNamaProduk.requestFocus() val filename = "$prefix-${System.currentTimeMillis()}.$extension"
binding.edtDeskripsiProduk.text.isBlank() -> binding.edtDeskripsiProduk.requestFocus() val file = File(context.cacheDir, filename)
binding.edtHargaProduk.text.isBlank() -> binding.edtHargaProduk.requestFocus()
binding.edtStokProduk.text.isBlank() -> binding.edtStokProduk.requestFocus() context.contentResolver.openInputStream(uri)?.use { input ->
binding.edtMinOrder.text.isBlank() -> binding.edtMinOrder.requestFocus() FileOutputStream(file).use { output -> input.copyTo(output) }
binding.edtBeratProduk.text.isBlank() -> binding.edtBeratProduk.requestFocus()
binding.switchIsPreOrder.isChecked && binding.edtDurasi.text.isBlank() -> binding.edtDurasi.requestFocus()
imageUri == null -> Toast.makeText(this, "Silakan unggah foto produk", Toast.LENGTH_SHORT).show()
}
} }
private fun uriToFile(uri: Uri, context: Context): File {
val inputStream = context.contentResolver.openInputStream(uri)
val file = File.createTempFile("upload_", ".tmp", context.cacheDir)
inputStream?.use { input -> file.outputStream().use { input.copyTo(it) } }
return file return file
} }
@ -207,30 +185,47 @@ class StoreProductDetailActivity : AppCompatActivity() {
val weight = binding.edtBeratProduk.text.toString().toInt() val weight = binding.edtBeratProduk.text.toString().toInt()
val isPreOrder = binding.switchIsPreOrder.isChecked val isPreOrder = binding.switchIsPreOrder.isChecked
val duration = if (isPreOrder) binding.edtDurasi.text.toString().toInt() else 0 val duration = if (isPreOrder) binding.edtDurasi.text.toString().toInt() else 0
val isActive = binding.switchIsActive.isChecked val status = if (binding.switchIsActive.isChecked) "active" else "inactive"
val categoryId = categoryList.getOrNull(binding.spinnerKategoriProduk.selectedItemPosition)?.id ?: 0 val categoryId = categoryList.getOrNull(binding.spinnerKategoriProduk.selectedItemPosition)?.id ?: 0
val imageFile = imageUri?.let { uriToFile(it, this) } val imageFile = imageUri?.let { File(it.path) }
val sppirtFile = sppirtUri?.let { uriToFile(it, this) } val sppirtFile = sppirtUri?.let { uriToNamedFile(it, this, "sppirt") }
val halalFile = halalUri?.let { uriToFile(it, this) } val halalFile = halalUri?.let { uriToNamedFile(it, this, "halal") }
Log.d("File URI", "SPPIRT URI: ${sppirtUri.toString()}")
Log.d("File URI", "Halal URI: ${halalUri.toString()}")
val imagePart = imageFile?.let { createPartFromFile("image", it) }
val sppirtPart = sppirtFile?.let { createPartFromFile("sppirt", it) }
val halalPart = halalFile?.let { createPartFromFile("halal", it) }
viewModel.addProduct( viewModel.addProduct(
name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, isActive, imageFile, sppirtFile, halalFile name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, status, imagePart, sppirtPart, halalPart
).observe(this) { result -> )
viewModel.productCreationResult.observe(this) { result ->
when (result) { when (result) {
is Result.Loading -> binding.btnSaveProduct.isEnabled = false is Result.Loading -> binding.btnSaveProduct.isEnabled = false
is Result.Success -> { is Result.Success -> {
Toast.makeText(this, "Produk berhasil ditambahkan!", Toast.LENGTH_SHORT).show() val product = result.data.product
Toast.makeText(this, "Product Created: ${product?.productName}", Toast.LENGTH_SHORT).show()
finish() finish()
} }
is Result.Error -> { is Result.Error -> {
Toast.makeText(this, "Gagal: ${result.exception.message}", Toast.LENGTH_SHORT).show() Log.e("ProductDetailActivity", "Error: ${result.exception.message}")
binding.btnSaveProduct.isEnabled = true binding.btnSaveProduct.isEnabled = true
} }
} }
} }
} }
fun createPartFromFile(field: String, file: File?): MultipartBody.Part? {
return file?.let {
val requestBody = RequestBody.create("application/octet-stream".toMediaTypeOrNull(), it)
MultipartBody.Part.createFormData(field, it.name, requestBody)
}
}
private fun setupHeader() { private fun setupHeader() {
binding.header.headerTitle.text = "Tambah Produk" binding.header.headerTitle.text = "Tambah Produk"
binding.header.headerLeftIcon.setOnClickListener { onBackPressedDispatcher.onBackPressed() } binding.header.headerLeftIcon.setOnClickListener { onBackPressedDispatcher.onBackPressed() }

View File

@ -3,20 +3,23 @@ package com.alya.ecommerce_serang.utils.viewmodel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.dto.CategoryItem import com.alya.ecommerce_serang.data.api.dto.CategoryItem
import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.response.product.CreateProductResponse
import com.alya.ecommerce_serang.data.api.response.product.Product import com.alya.ecommerce_serang.data.api.response.product.Product
import com.alya.ecommerce_serang.data.api.response.product.ReviewsItem import com.alya.ecommerce_serang.data.api.response.product.ReviewsItem
import com.alya.ecommerce_serang.data.api.response.product.StoreProduct import com.alya.ecommerce_serang.data.api.response.product.StoreProduct
import com.alya.ecommerce_serang.data.repository.ProductRepository import com.alya.ecommerce_serang.data.repository.ProductRepository
import com.alya.ecommerce_serang.data.repository.Result import com.alya.ecommerce_serang.data.repository.Result
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import okhttp3.MultipartBody
class ProductViewModel(private val repository: ProductRepository) : ViewModel() { class ProductViewModel(private val repository: ProductRepository) : ViewModel() {
private val _productCreationResult = MutableLiveData<Result<CreateProductResponse>>()
val productCreationResult: LiveData<Result<CreateProductResponse>> get() = _productCreationResult
private val _productDetail = MutableLiveData<Product?>() private val _productDetail = MutableLiveData<Product?>()
val productDetail: LiveData<Product?> get() = _productDetail val productDetail: LiveData<Product?> get() = _productDetail
@ -75,13 +78,18 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel()
isPreOrder: Boolean, isPreOrder: Boolean,
duration: Int, duration: Int,
categoryId: Int, categoryId: Int,
isActive: Boolean, status: String,
image: File?, imagePart: MultipartBody.Part?,
sppirt: File?, sppirtPart: MultipartBody.Part?,
halal: File? halalPart: MultipartBody.Part?
): LiveData<Result<Unit>> = liveData { ) {
emit(Result.Loading) _productCreationResult.value = Result.Loading
emit(repository.addProduct(name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, isActive, image, sppirt, halal)) viewModelScope.launch {
val result = repository.addProduct(
name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, status, imagePart, sppirtPart, halalPart
)
_productCreationResult.value = result
}
} }
// Optional: for store detail if you need it later // Optional: for store detail if you need it later

View File

@ -20,10 +20,12 @@ lifecycleViewmodelKtx = "2.8.7"
fragmentKtx = "1.5.6" fragmentKtx = "1.5.6"
navigationFragmentKtx = "2.8.5" navigationFragmentKtx = "2.8.5"
navigationUiKtx = "2.8.5" navigationUiKtx = "2.8.5"
recyclerview = "1.4.0"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-hilt-lifecycle-viewmodel = { module = "androidx.hilt:hilt-lifecycle-viewmodel", version.ref = "hiltLifecycleViewmodel" } androidx-hilt-lifecycle-viewmodel = { module = "androidx.hilt:hilt-lifecycle-viewmodel", version.ref = "hiltLifecycleViewmodel" }
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
junit = { group = "junit", name = "junit", version.ref = "junit" } junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }