mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-13 10:42:21 +00:00
product gaselsai
This commit is contained in:
@ -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",
|
||||||
|
@ -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"
|
||||||
|
@ -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,
|
||||||
|
@ -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(
|
@ -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 {
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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() }
|
||||||
|
@ -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
|
||||||
|
@ -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" }
|
||||||
|
Reference in New Issue
Block a user