mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-13 10:42:21 +00:00
Merge branch 'master' into screen-features
# Conflicts: # app/src/main/AndroidManifest.xml # app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt
This commit is contained in:
@ -18,7 +18,7 @@ val localProperties = Properties().apply {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.alya.ecommerce_serang"
|
namespace = "com.alya.ecommerce_serang"
|
||||||
compileSdk = 34
|
compileSdk = 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.alya.ecommerce_serang"
|
applicationId = "com.alya.ecommerce_serang"
|
||||||
@ -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",
|
||||||
@ -79,6 +79,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.fragment.ktx)
|
implementation(libs.androidx.fragment.ktx)
|
||||||
implementation(libs.androidx.navigation.fragment.ktx)
|
implementation(libs.androidx.navigation.fragment.ktx)
|
||||||
implementation(libs.androidx.navigation.ui.ktx)
|
implementation(libs.androidx.navigation.ui.ktx)
|
||||||
|
implementation(libs.androidx.recyclerview)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
@ -94,7 +95,6 @@ dependencies {
|
|||||||
implementation("de.hdodenhof:circleimageview:3.1.0")
|
implementation("de.hdodenhof:circleimageview:3.1.0")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// implementation(libs.hilt.android)
|
// implementation(libs.hilt.android)
|
||||||
// kapt("com.google.dagger:hilt-compiler:2.48")
|
// kapt("com.google.dagger:hilt-compiler:2.48")
|
||||||
//
|
//
|
||||||
@ -103,3 +103,4 @@ dependencies {
|
|||||||
// kapt("androidx.hilt:hilt-compiler:1.0.0")
|
// kapt("androidx.hilt:hilt-compiler:1.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -11,7 +11,10 @@ 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.RequestBody
|
||||||
import com.alya.ecommerce_serang.data.api.response.auth.LoginResponse
|
import com.alya.ecommerce_serang.data.api.response.auth.LoginResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.auth.OtpResponse
|
import com.alya.ecommerce_serang.data.api.response.auth.OtpResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.auth.RegisterResponse
|
import com.alya.ecommerce_serang.data.api.response.auth.RegisterResponse
|
||||||
@ -36,14 +39,14 @@ import com.alya.ecommerce_serang.data.api.response.product.StoreResponse
|
|||||||
import com.alya.ecommerce_serang.data.api.response.profile.AddressResponse
|
import com.alya.ecommerce_serang.data.api.response.profile.AddressResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.profile.CreateAddressResponse
|
import com.alya.ecommerce_serang.data.api.response.profile.CreateAddressResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.profile.ProfileResponse
|
import com.alya.ecommerce_serang.data.api.response.profile.ProfileResponse
|
||||||
import okhttp3.MultipartBody
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
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.Field
|
||||||
import retrofit2.http.FormUrlEncoded
|
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.PUT
|
import retrofit2.http.PUT
|
||||||
@ -142,20 +145,23 @@ interface ApiService {
|
|||||||
@GET("category")
|
@GET("category")
|
||||||
fun getCategories(): Call<CategoryResponse>
|
fun getCategories(): Call<CategoryResponse>
|
||||||
|
|
||||||
|
@Multipart
|
||||||
@POST("store/createproduct")
|
@POST("store/createproduct")
|
||||||
@FormUrlEncoded
|
|
||||||
suspend fun addProduct(
|
suspend fun addProduct(
|
||||||
@Field("name") name: String,
|
@Part("name") name: RequestBody,
|
||||||
@Field("description") description: String,
|
@Part("description") description: RequestBody,
|
||||||
@Field("price") price: Int,
|
@Part("price") price: RequestBody,
|
||||||
@Field("stock") stock: Int,
|
@Part("stock") stock: RequestBody,
|
||||||
@Field("min_order") minOrder: Int,
|
@Part("min_order") minOrder: RequestBody,
|
||||||
@Field("weight") weight: Int,
|
@Part("weight") weight: RequestBody,
|
||||||
@Field("is_pre_order") isPreOrder: Boolean,
|
@Part("is_pre_order") isPreOrder: RequestBody,
|
||||||
@Field("duration") duration: Int,
|
@Part("duration") duration: RequestBody,
|
||||||
@Field("category_id") categoryId: Int,
|
@Part("category_id") categoryId: RequestBody,
|
||||||
@Field("is_active") isActive: String
|
@Part("status") status: RequestBody,
|
||||||
): Response<Unit>
|
@Part image: MultipartBody.Part?,
|
||||||
|
@Part sppirt: MultipartBody.Part?,
|
||||||
|
@Part halal: MultipartBody.Part?
|
||||||
|
): Response<CreateProductResponse>
|
||||||
|
|
||||||
@GET("cart_item")
|
@GET("cart_item")
|
||||||
suspend fun getCart (): Response<ListCartResponse>
|
suspend fun getCart (): Response<ListCartResponse>
|
||||||
|
@ -4,13 +4,19 @@ 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.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class ProductRepository(private val apiService: ApiService) {
|
class ProductRepository(private val apiService: ApiService) {
|
||||||
suspend fun getAllProducts(): Result<List<ProductsItem>> =
|
suspend fun getAllProducts(): Result<List<ProductsItem>> =
|
||||||
@ -131,13 +137,17 @@ class ProductRepository(private val apiService: ApiService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchMyStoreProducts(): List<ProductsItem> {
|
suspend fun fetchMyStoreProducts(): List<ProductsItem> {
|
||||||
|
return try {
|
||||||
val response = apiService.getStoreProduct()
|
val response = apiService.getStoreProduct()
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
val responseBody = response.body()
|
response.body()?.products?.filterNotNull() ?: emptyList()
|
||||||
return responseBody?.products?.filterNotNull() ?: emptyList()
|
|
||||||
} else {
|
} else {
|
||||||
throw Exception("Failed to fetch store products: ${response.message()}")
|
throw Exception("Failed to fetch store products: ${response.message()}")
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("ProductRepository", "Error fetching store products", e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addProduct(
|
suspend fun addProduct(
|
||||||
@ -150,33 +160,39 @@ class ProductRepository(private val apiService: ApiService) {
|
|||||||
isPreOrder: Boolean,
|
isPreOrder: Boolean,
|
||||||
duration: Int,
|
duration: Int,
|
||||||
categoryId: Int,
|
categoryId: Int,
|
||||||
isActive: Boolean
|
status: String,
|
||||||
): Result<Unit> = withContext(Dispatchers.IO) {
|
imagePart: MultipartBody.Part?,
|
||||||
try {
|
sppirtPart: MultipartBody.Part?,
|
||||||
val status = if (isActive) "active" else "inactive"
|
halalPart: MultipartBody.Part?
|
||||||
|
): Result<CreateProductResponse> {
|
||||||
|
return try {
|
||||||
val response = apiService.addProduct(
|
val response = apiService.addProduct(
|
||||||
name = name,
|
name = RequestBody.create("text/plain".toMediaTypeOrNull(), name),
|
||||||
description = description,
|
description = RequestBody.create("text/plain".toMediaTypeOrNull(), description),
|
||||||
price = price,
|
price = RequestBody.create("text/plain".toMediaTypeOrNull(), price.toString()),
|
||||||
stock = stock,
|
stock = RequestBody.create("text/plain".toMediaTypeOrNull(), stock.toString()),
|
||||||
minOrder = minOrder,
|
minOrder = RequestBody.create("text/plain".toMediaTypeOrNull(), minOrder.toString()),
|
||||||
weight = weight,
|
weight = RequestBody.create("text/plain".toMediaTypeOrNull(), weight.toString()),
|
||||||
isPreOrder = isPreOrder,
|
isPreOrder = RequestBody.create("text/plain".toMediaTypeOrNull(), isPreOrder.toString()),
|
||||||
duration = duration,
|
duration = RequestBody.create("text/plain".toMediaTypeOrNull(), duration.toString()),
|
||||||
categoryId = categoryId,
|
categoryId = RequestBody.create("text/plain".toMediaTypeOrNull(), categoryId.toString()),
|
||||||
isActive = status
|
status = RequestBody.create("text/plain".toMediaTypeOrNull(), status),
|
||||||
|
image = imagePart,
|
||||||
|
sppirt = sppirtPart,
|
||||||
|
halal = halalPart
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
Result.Success(Unit)
|
Result.Success(response.body()!!)
|
||||||
} else {
|
} else {
|
||||||
Result.Error(Exception("Failed to add product. Code: ${response.code()}"))
|
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"
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,14 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import android.widget.PopupMenu
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.alya.ecommerce_serang.R
|
import com.alya.ecommerce_serang.R
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.Product
|
||||||
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
|
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
|
||||||
@ -22,27 +26,37 @@ class ProductAdapter(
|
|||||||
private val tvProductPrice: TextView = itemView.findViewById(R.id.tv_product_price)
|
private val tvProductPrice: TextView = itemView.findViewById(R.id.tv_product_price)
|
||||||
private val tvProductStock: TextView = itemView.findViewById(R.id.tv_product_stock)
|
private val tvProductStock: TextView = itemView.findViewById(R.id.tv_product_stock)
|
||||||
private val tvProductStatus: TextView = itemView.findViewById(R.id.tv_product_status)
|
private val tvProductStatus: TextView = itemView.findViewById(R.id.tv_product_status)
|
||||||
|
private val ivMenu: ImageView = itemView.findViewById(R.id.iv_menu)
|
||||||
|
|
||||||
fun bind(product: ProductsItem) {
|
fun bind(product: ProductsItem) {
|
||||||
tvProductName.text = product.name
|
tvProductName.text = product.name
|
||||||
tvProductPrice.text = "Rp${product.price}"
|
tvProductPrice.text = "Rp${product.price}"
|
||||||
tvProductStock.text = "Stok: ${product.stock}"
|
tvProductStock.text = "Stok: ${product.stock}"
|
||||||
tvProductStatus.text = product.status
|
|
||||||
|
|
||||||
// Change color depending on status
|
if (product.status.equals("active",true)) {
|
||||||
tvProductStatus.setTextColor(
|
tvProductStatus.text = "Aktif"
|
||||||
ContextCompat.getColor(
|
tvProductStatus.setTextColor(ContextCompat.getColor(itemView.context, R.color.darkblue_500))
|
||||||
itemView.context,
|
tvProductStatus.background = ContextCompat.getDrawable(itemView.context, R.drawable.bg_product_active)
|
||||||
if (product.status.equals("active", true))
|
} else {
|
||||||
R.color.darkblue_500 else R.color.black_500
|
tvProductStatus.text = "Nonaktif"
|
||||||
)
|
tvProductStatus.setTextColor(ContextCompat.getColor(itemView.context, R.color.black_500))
|
||||||
)
|
tvProductStatus.background = ContextCompat.getDrawable(itemView.context, R.drawable.bg_product_inactive)
|
||||||
|
}
|
||||||
|
|
||||||
Glide.with(itemView.context)
|
Glide.with(itemView.context)
|
||||||
.load(product.image)
|
.load(product.image)
|
||||||
.placeholder(R.drawable.placeholder_image)
|
.placeholder(R.drawable.placeholder_image)
|
||||||
.into(ivProduct)
|
.into(ivProduct)
|
||||||
|
|
||||||
|
ivMenu.setOnClickListener {
|
||||||
|
// Show Bottom Sheet when menu is clicked
|
||||||
|
val bottomSheetFragment = ProductOptionsBottomSheetFragment(product)
|
||||||
|
bottomSheetFragment.show(
|
||||||
|
(itemView.context as FragmentActivity).supportFragmentManager,
|
||||||
|
bottomSheetFragment.tag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
onItemClick(product)
|
onItemClick(product)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.profile.mystore.product
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.alya.ecommerce_serang.R
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
|
||||||
|
import com.alya.ecommerce_serang.databinding.FragmentProductOptionsBottomSheetBinding
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
|
||||||
|
class ProductOptionsBottomSheetFragment(private val product: ProductsItem) : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private var _binding: FragmentProductOptionsBottomSheetBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
_binding = FragmentProductOptionsBottomSheetBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
binding.btnEditProduct.setOnClickListener {
|
||||||
|
// Handle editing product
|
||||||
|
// Example: Open the edit activity or fragment
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnDeleteProduct.setOnClickListener {
|
||||||
|
// Handle deleting product
|
||||||
|
// Example: Show confirmation dialog
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,15 @@
|
|||||||
package com.alya.ecommerce_serang.ui.profile.mystore.product
|
package com.alya.ecommerce_serang.ui.profile.mystore.product
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
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
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import com.alya.ecommerce_serang.R
|
import com.alya.ecommerce_serang.R
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@ -18,6 +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.Companion.toMediaTypeOrNull
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
import kotlin.getValue
|
import kotlin.getValue
|
||||||
|
|
||||||
class StoreProductDetailActivity : AppCompatActivity() {
|
class StoreProductDetailActivity : AppCompatActivity() {
|
||||||
@ -25,6 +34,9 @@ class StoreProductDetailActivity : AppCompatActivity() {
|
|||||||
private lateinit var binding: ActivityStoreProductDetailBinding
|
private lateinit var binding: ActivityStoreProductDetailBinding
|
||||||
private lateinit var sessionManager: SessionManager
|
private lateinit var sessionManager: SessionManager
|
||||||
private lateinit var categoryList: List<CategoryItem>
|
private lateinit var categoryList: List<CategoryItem>
|
||||||
|
private var imageUri: Uri? = null
|
||||||
|
private var sppirtUri: Uri? = null
|
||||||
|
private var halalUri: Uri? = null
|
||||||
|
|
||||||
private val viewModel: ProductViewModel by viewModels {
|
private val viewModel: ProductViewModel by viewModels {
|
||||||
BaseViewModelFactory {
|
BaseViewModelFactory {
|
||||||
@ -35,14 +47,50 @@ class StoreProductDetailActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val imagePickerLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
imageUri = result.data?.data
|
||||||
|
imageUri?.let {
|
||||||
|
binding.ivPreviewFoto.setImageURI(it)
|
||||||
|
binding.switcherFotoProduk.showNext()
|
||||||
|
}
|
||||||
|
validateForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val sppirtLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||||
|
if (uri != null && isValidFile(uri)) {
|
||||||
|
sppirtUri = uri
|
||||||
|
binding.tvSppirtName.text = getFileName(uri)
|
||||||
|
binding.switcherSppirt.showNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val halalLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||||
|
if (uri != null && isValidFile(uri)) {
|
||||||
|
halalUri = uri
|
||||||
|
binding.tvHalalName.text = getFileName(uri)
|
||||||
|
binding.switcherHalal.showNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityStoreProductDetailBinding.inflate(layoutInflater)
|
binding = ActivityStoreProductDetailBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
setupHeader()
|
setupHeader()
|
||||||
observeCategories()
|
|
||||||
|
// Fetch categories
|
||||||
viewModel.loadCategories()
|
viewModel.loadCategories()
|
||||||
|
viewModel.categoryList.observe(this) { result ->
|
||||||
|
if (result is Result.Success) {
|
||||||
|
categoryList = result.data
|
||||||
|
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, categoryList.map { it.name })
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
binding.spinnerKategoriProduk.adapter = adapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setup Pre-Order visibility
|
// Setup Pre-Order visibility
|
||||||
binding.switchIsPreOrder.setOnCheckedChangeListener { _, isChecked ->
|
binding.switchIsPreOrder.setOnCheckedChangeListener { _, isChecked ->
|
||||||
@ -50,126 +98,147 @@ class StoreProductDetailActivity : AppCompatActivity() {
|
|||||||
validateForm()
|
validateForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
setupFormValidation()
|
binding.tvTambahFoto.setOnClickListener {
|
||||||
|
val intent = Intent(Intent.ACTION_PICK).apply { type = "image/*" }
|
||||||
|
imagePickerLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutUploadFoto.setOnClickListener {
|
||||||
|
val intent = Intent(Intent.ACTION_PICK).apply { type = "image/*" }
|
||||||
|
imagePickerLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnRemoveFoto.setOnClickListener {
|
||||||
|
imageUri = null
|
||||||
|
binding.switcherFotoProduk.showPrevious()
|
||||||
|
validateForm()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutUploadSppirt.setOnClickListener { sppirtLauncher.launch("*/*") }
|
||||||
|
binding.btnRemoveSppirt.setOnClickListener {
|
||||||
|
sppirtUri = null
|
||||||
|
binding.switcherSppirt.showPrevious()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutUploadHalal.setOnClickListener { halalLauncher.launch("*/*") }
|
||||||
|
binding.btnRemoveHalal.setOnClickListener {
|
||||||
|
halalUri = null
|
||||||
|
binding.switcherHalal.showPrevious()
|
||||||
|
}
|
||||||
|
|
||||||
validateForm()
|
validateForm()
|
||||||
|
|
||||||
binding.btnSaveProduct.setOnClickListener {
|
binding.btnSaveProduct.setOnClickListener {
|
||||||
if (binding.btnSaveProduct.isEnabled) addProduct()
|
if (!binding.btnSaveProduct.isEnabled) {
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
submitProduct()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isValidFile(uri: Uri): Boolean {
|
||||||
|
val mimeType = contentResolver.getType(uri) ?: return false
|
||||||
|
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() {
|
||||||
|
val valid = binding.edtNamaProduk.text.isNotBlank() &&
|
||||||
|
binding.edtDeskripsiProduk.text.isNotBlank() &&
|
||||||
|
binding.edtHargaProduk.text.isNotBlank() &&
|
||||||
|
binding.edtStokProduk.text.isNotBlank() &&
|
||||||
|
binding.edtMinOrder.text.isNotBlank() &&
|
||||||
|
binding.edtBeratProduk.text.isNotBlank() &&
|
||||||
|
(!binding.switchIsPreOrder.isChecked || binding.edtDurasi.text.isNotBlank()) &&
|
||||||
|
imageUri != null
|
||||||
|
|
||||||
|
binding.btnSaveProduct.isEnabled = valid
|
||||||
|
binding.btnSaveProduct.setTextColor(
|
||||||
|
if (valid) ContextCompat.getColor(this, R.color.white) else ContextCompat.getColor(this, R.color.black_300)
|
||||||
|
)
|
||||||
|
binding.btnSaveProduct.setBackgroundResource(
|
||||||
|
if (valid) R.drawable.bg_button_active else R.drawable.bg_button_disabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uriToNamedFile(uri: Uri, context: Context, prefix: String): File {
|
||||||
|
val extension = context.contentResolver.getType(uri)?.substringAfter("/") ?: "jpg"
|
||||||
|
val filename = "$prefix-${System.currentTimeMillis()}.$extension"
|
||||||
|
val file = File(context.cacheDir, filename)
|
||||||
|
|
||||||
|
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||||
|
FileOutputStream(file).use { output -> input.copyTo(output) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun submitProduct() {
|
||||||
|
val name = binding.edtNamaProduk.text.toString()
|
||||||
|
val description = binding.edtDeskripsiProduk.text.toString()
|
||||||
|
val price = binding.edtHargaProduk.text.toString().toInt()
|
||||||
|
val stock = binding.edtStokProduk.text.toString().toInt()
|
||||||
|
val minOrder = binding.edtMinOrder.text.toString().toInt()
|
||||||
|
val weight = binding.edtBeratProduk.text.toString().toInt()
|
||||||
|
val isPreOrder = binding.switchIsPreOrder.isChecked
|
||||||
|
val duration = if (isPreOrder) binding.edtDurasi.text.toString().toInt() else 0
|
||||||
|
val status = if (binding.switchIsActive.isChecked) "active" else "inactive"
|
||||||
|
val categoryId = categoryList.getOrNull(binding.spinnerKategoriProduk.selectedItemPosition)?.id ?: 0
|
||||||
|
|
||||||
|
val imageFile = imageUri?.let { uriToNamedFile(it, this, "productimg") }
|
||||||
|
val sppirtFile = sppirtUri?.let { uriToNamedFile(it, this, "sppirt") }
|
||||||
|
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("productimg", it) }
|
||||||
|
val sppirtPart = sppirtFile?.let { createPartFromFile("sppirt", it) }
|
||||||
|
val halalPart = halalFile?.let { createPartFromFile("halal", it) }
|
||||||
|
|
||||||
|
viewModel.addProduct(
|
||||||
|
name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, status, imagePart, sppirtPart, halalPart
|
||||||
|
)
|
||||||
|
|
||||||
|
viewModel.productCreationResult.observe(this) { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> binding.btnSaveProduct.isEnabled = false
|
||||||
|
is Result.Success -> {
|
||||||
|
val product = result.data.product
|
||||||
|
Toast.makeText(this, "Product Created: ${product?.productName}", Toast.LENGTH_SHORT).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
Log.e("ProductDetailActivity", "Error: ${result.exception.message}")
|
||||||
|
binding.btnSaveProduct.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMimeType(file: File): String {
|
||||||
|
val extension = file.extension
|
||||||
|
return when (extension.lowercase()) {
|
||||||
|
"jpg", "jpeg" -> "image/jpeg"
|
||||||
|
"png" -> "image/png"
|
||||||
|
"pdf" -> "application/pdf"
|
||||||
|
else -> "application/octet-stream"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPartFromFile(field: String, file: File?): MultipartBody.Part? {
|
||||||
|
return file?.let {
|
||||||
|
val mimeType = getMimeType(it).toMediaTypeOrNull()
|
||||||
|
val requestBody = RequestBody.create(mimeType, 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeCategories() {
|
|
||||||
viewModel.categoryList.observe(this) { result ->
|
|
||||||
when (result) {
|
|
||||||
is Result.Loading -> {
|
|
||||||
// Optionally show loading spinner
|
|
||||||
}
|
|
||||||
is Result.Success -> {
|
|
||||||
categoryList = result.data
|
|
||||||
setupCategorySpinner(categoryList)
|
|
||||||
}
|
|
||||||
is Result.Error -> {
|
|
||||||
Toast.makeText(
|
|
||||||
this,
|
|
||||||
"Failed to load categories: ${result.exception.message}",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupCategorySpinner(categories: List<CategoryItem>) {
|
|
||||||
val categoryNames = categories.map { it.name }
|
|
||||||
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, categoryNames)
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
|
||||||
|
|
||||||
binding.spinnerKategoriProduk.adapter = adapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addProduct() {
|
|
||||||
val name = binding.edtNamaProduk.text.toString()
|
|
||||||
val description = binding.edtDeskripsiProduk.text.toString()
|
|
||||||
val price = binding.edtHargaProduk.text.toString().toIntOrNull() ?: 0
|
|
||||||
val stock = binding.edtStokProduk.text.toString().toIntOrNull() ?: 0
|
|
||||||
val minOrder = binding.edtMinOrder.text.toString().toIntOrNull() ?: 1
|
|
||||||
val weight = binding.edtBeratProduk.text.toString().toIntOrNull() ?: 0
|
|
||||||
val isPreOrder = binding.switchIsPreOrder.isChecked
|
|
||||||
val duration = binding.edtDurasi.text.toString().toIntOrNull() ?: 0
|
|
||||||
val isActive = binding.switchIsActive.isChecked
|
|
||||||
val categoryPosition = binding.spinnerKategoriProduk.selectedItemPosition
|
|
||||||
val categoryId = categoryList.getOrNull(categoryPosition)?.id ?: 0
|
|
||||||
|
|
||||||
if (isPreOrder && duration == 0) {
|
|
||||||
Toast.makeText(this, "Durasi wajib diisi jika pre-order diaktifkan.", Toast.LENGTH_SHORT).show()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.addProduct(
|
|
||||||
name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, isActive
|
|
||||||
).observe(this) { result ->
|
|
||||||
when (result) {
|
|
||||||
is Result.Loading -> binding.btnSaveProduct.isEnabled = false
|
|
||||||
is Result.Success -> {
|
|
||||||
Toast.makeText(this, "Produk berhasil ditambahkan!", Toast.LENGTH_SHORT).show()
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
is Result.Error -> {
|
|
||||||
binding.btnSaveProduct.isEnabled = true
|
|
||||||
Toast.makeText(this, "Gagal: ${result.exception.message}", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupFormValidation() {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch all fields
|
|
||||||
binding.edtNamaProduk.addTextChangedListener(watcher)
|
|
||||||
binding.edtDeskripsiProduk.addTextChangedListener(watcher)
|
|
||||||
binding.edtHargaProduk.addTextChangedListener(watcher)
|
|
||||||
binding.edtStokProduk.addTextChangedListener(watcher)
|
|
||||||
binding.edtMinOrder.addTextChangedListener(watcher)
|
|
||||||
binding.edtBeratProduk.addTextChangedListener(watcher)
|
|
||||||
binding.edtDurasi.addTextChangedListener(watcher)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun validateForm() {
|
|
||||||
val isNameValid = binding.edtNamaProduk.text.toString().isNotBlank()
|
|
||||||
val isDescriptionValid = binding.edtDeskripsiProduk.text.toString().isNotBlank()
|
|
||||||
val isPriceValid = binding.edtHargaProduk.text.toString().isNotBlank()
|
|
||||||
val isStockValid = binding.edtStokProduk.text.toString().isNotBlank()
|
|
||||||
val isMinOrderValid = binding.edtMinOrder.text.toString().isNotBlank()
|
|
||||||
val isWeightValid = binding.edtBeratProduk.text.toString().isNotBlank()
|
|
||||||
val isPreOrderChecked = binding.switchIsPreOrder.isChecked
|
|
||||||
val isDurationValid = !isPreOrderChecked || binding.edtDurasi.text.toString().isNotBlank()
|
|
||||||
|
|
||||||
val isFormValid = isNameValid && isDescriptionValid && isPriceValid &&
|
|
||||||
isStockValid && isMinOrderValid && isWeightValid && isDurationValid
|
|
||||||
|
|
||||||
if (isFormValid) {
|
|
||||||
binding.btnSaveProduct.isEnabled = true
|
|
||||||
binding.btnSaveProduct.setBackgroundResource(R.drawable.bg_button_active)
|
|
||||||
binding.btnSaveProduct.setTextColor(ContextCompat.getColor(this, R.color.white))
|
|
||||||
} else {
|
|
||||||
binding.btnSaveProduct.isEnabled = false
|
|
||||||
binding.btnSaveProduct.setBackgroundResource(R.drawable.bg_button_disabled)
|
|
||||||
binding.btnSaveProduct.setTextColor(ContextCompat.getColor(this, R.color.black_300))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,19 +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 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
|
||||||
|
|
||||||
@ -74,16 +78,19 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel()
|
|||||||
isPreOrder: Boolean,
|
isPreOrder: Boolean,
|
||||||
duration: Int,
|
duration: Int,
|
||||||
categoryId: Int,
|
categoryId: Int,
|
||||||
isActive: Boolean
|
status: String,
|
||||||
): LiveData<Result<Unit>> = liveData {
|
imagePart: MultipartBody.Part?,
|
||||||
emit(Result.Loading)
|
sppirtPart: MultipartBody.Part?,
|
||||||
|
halalPart: MultipartBody.Part?
|
||||||
|
) {
|
||||||
|
_productCreationResult.value = Result.Loading
|
||||||
|
viewModelScope.launch {
|
||||||
val result = repository.addProduct(
|
val result = repository.addProduct(
|
||||||
name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, isActive
|
name, description, price, stock, minOrder, weight, isPreOrder, duration, categoryId, status, imagePart, sppirtPart, halalPart
|
||||||
)
|
)
|
||||||
emit(result)
|
_productCreationResult.value = result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Optional: for store detail if you need it later
|
// Optional: for store detail if you need it later
|
||||||
// fun loadStoreDetail(storeId: Int) {
|
// fun loadStoreDetail(storeId: Int) {
|
||||||
@ -92,4 +99,5 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel()
|
|||||||
// _storeDetail.value = storeResult
|
// _storeDetail.value = storeResult
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
10
app/src/main/res/drawable/bg_upload.xml
Normal file
10
app/src/main/res/drawable/bg_upload.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/black_100"
|
||||||
|
android:dashWidth="5dp"
|
||||||
|
android:dashGap="5dp" />
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
</shape>
|
BIN
app/src/main/res/drawable/ic_close.png
Normal file
BIN
app/src/main/res/drawable/ic_close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 521 B |
BIN
app/src/main/res/drawable/ic_delete.png
Normal file
BIN
app/src/main/res/drawable/ic_delete.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 425 B |
BIN
app/src/main/res/drawable/ic_location.png
Normal file
BIN
app/src/main/res/drawable/ic_location.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable/ic_person.png
Normal file
BIN
app/src/main/res/drawable/ic_person.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
8
app/src/main/res/drawable/shape_sells_title.xml
Normal file
8
app/src/main/res/drawable/shape_sells_title.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/darkblue_500" />
|
||||||
|
<corners
|
||||||
|
android:topRightRadius="4dp"
|
||||||
|
android:bottomRightRadius="4dp"/>
|
||||||
|
</shape>
|
@ -75,7 +75,6 @@
|
|||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_edit_profile"
|
android:id="@+id/btn_edit_profile"
|
||||||
android:text="Ubah Profil Toko"
|
android:text="Ubah Profil Toko"
|
||||||
android:textColor="@color/blue_500"
|
|
||||||
style="@style/button.small.secondary.short"
|
style="@style/button.small.secondary.short"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
@ -83,7 +82,7 @@
|
|||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/line_profile"
|
android:id="@+id/line_profile"
|
||||||
android:layout_width="380dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:background="@color/black_50"
|
android:background="@color/black_50"
|
||||||
|
@ -69,15 +69,61 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- ImageView untuk preview gambar -->
|
<!-- ViewSwitcher untuk Upload Gambar Produk -->
|
||||||
|
<ViewSwitcher
|
||||||
|
android:id="@+id/switcher_foto_produk"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="24dp">
|
||||||
|
|
||||||
|
<!-- Tampilan saat belum ada gambar di-upload -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/layout_upload_foto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_upload"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="13dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="44dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:src="@drawable/ic_upload"
|
||||||
|
android:contentDescription="Ikon Upload" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Tampilan saat gambar sudah di-upload -->
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:background="@drawable/bg_upload"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iv_preview_foto"
|
android:id="@+id/iv_preview_foto"
|
||||||
android:layout_width="72dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="72dp"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:contentDescription="Preview Gambar"
|
android:contentDescription="Preview Gambar"
|
||||||
android:src="@drawable/ic_upload"/>
|
android:src="@drawable/placeholder_image"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_remove_foto"
|
||||||
|
android:layout_width="12dp"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:layout_gravity="top|end"
|
||||||
|
android:layout_margin="6dp"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:src="@drawable/ic_close"
|
||||||
|
android:contentDescription="Hapus Gambar"
|
||||||
|
android:padding="4dp"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</ViewSwitcher>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@ -245,7 +291,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Harga Produk"
|
android:text="Harga Produk"
|
||||||
style="@style/body_medium"
|
style="@style/body_medium"
|
||||||
android:layout_marginRight="4dp"/>
|
android:layout_marginEnd="4dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -409,7 +455,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:background="@drawable/bg_text_field"
|
android:background="@drawable/bg_text_field"
|
||||||
android:gravity="center">
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/edt_berat_produk"
|
android:id="@+id/edt_berat_produk"
|
||||||
@ -549,7 +596,6 @@
|
|||||||
style="@style/body_medium"
|
style="@style/body_medium"
|
||||||
android:layout_marginEnd="4dp"/>
|
android:layout_marginEnd="4dp"/>
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -567,7 +613,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:background="@drawable/bg_text_field"
|
android:background="@drawable/bg_text_field"
|
||||||
android:gravity="center">
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/edt_durasi"
|
android:id="@+id/edt_durasi"
|
||||||
@ -592,6 +639,178 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- SPPIRT -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="24dp">
|
||||||
|
|
||||||
|
<!-- Label SPPIRT -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SPPIRT"
|
||||||
|
style="@style/body_medium"/>
|
||||||
|
|
||||||
|
<!-- ViewSwitcher: Switches antara upload box dan uploaded preview SPPIRT -->
|
||||||
|
<ViewSwitcher
|
||||||
|
android:id="@+id/switcher_sppirt"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<!-- Upload Prompt Layout -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/layout_upload_sppirt"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_upload"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:src="@drawable/ic_upload"
|
||||||
|
android:contentDescription="Ikon Unggah" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/body_small"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Unggah dokumen SPPIRT Anda di sini"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:layout_marginTop="8dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Uploaded File Preview Layout -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@drawable/bg_text_field"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_sppirt_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="sppirt.pdf"
|
||||||
|
style="@style/body_small"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_remove_sppirt"
|
||||||
|
android:layout_width="12dp"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:src="@drawable/ic_close"
|
||||||
|
app:tint="@color/black_300"
|
||||||
|
android:contentDescription="Hapus unggahan" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ViewSwitcher>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Halal -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="24dp">
|
||||||
|
|
||||||
|
<!-- Label Halal -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Sertifikasi Halal"
|
||||||
|
style="@style/body_medium"/>
|
||||||
|
|
||||||
|
<!-- ViewSwitcher: Switches antara upload box dan uploaded preview halal -->
|
||||||
|
<ViewSwitcher
|
||||||
|
android:id="@+id/switcher_halal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<!-- Upload Prompt Layout -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/layout_upload_halal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_upload"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:src="@drawable/ic_upload"
|
||||||
|
android:contentDescription="Ikon Unggah" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/body_small"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Unggah dokumen Sertifikasi Halal Anda di sini"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:layout_marginTop="8dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Uploaded File Preview Layout -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@drawable/bg_text_field"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_halal_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="sppirt.pdf"
|
||||||
|
style="@style/body_small"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_remove_halal"
|
||||||
|
android:layout_width="12dp"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:src="@drawable/ic_close"
|
||||||
|
app:tint="@color/black_300"
|
||||||
|
android:contentDescription="Hapus unggahan" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ViewSwitcher>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Produk Aktif -->
|
<!-- Produk Aktif -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="?android:attr/windowBackground">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/btn_edit_product"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:src="@drawable/ic_edit"
|
||||||
|
android:contentDescription="Edit Icon" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Ubah Produk"
|
||||||
|
style="@style/label_large"
|
||||||
|
android:layout_marginStart="16dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/btn_delete_product"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:src="@drawable/ic_delete"
|
||||||
|
android:contentDescription="Delete Icon" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Hapus Produk"
|
||||||
|
style="@style/label_large"
|
||||||
|
android:layout_marginStart="16dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
292
app/src/main/res/layout/item_sells_order.xml
Normal file
292
app/src/main/res/layout/item_sells_order.xml
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:paddingTop="16dp">
|
||||||
|
|
||||||
|
<!-- Order Header -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/shape_sells_title"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="@drawable/shape_sells_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_order_header"
|
||||||
|
android:layout_width="220dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/shape_sells_title"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_title"
|
||||||
|
style="@style/label_medium_prominent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Pesanan Perlu Dibuat Tagihan"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_number"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:text="No. Pesanan: 123456789"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:src="@drawable/ic_person"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_customer"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:text="Gracia Hotmauli"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:text="Buat tagihan sebelum:"
|
||||||
|
android:textColor="@color/black_300" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_due"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="25 Okt; 23.59"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:paddingHorizontal="4dp"
|
||||||
|
android:textColor="@color/darkblue_500"
|
||||||
|
android:background="@drawable/bg_product_active" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Order Detail -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_order_detail"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/layout_order_header"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Product Detail -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_order_product_detail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/iv_order_product"
|
||||||
|
android:layout_width="95dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:src="@drawable/placeholder_image"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:contentDescription="Order Product Image"
|
||||||
|
app:shapeAppearanceOverlay="@style/store_product_image"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="13dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/iv_order_product"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_product_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Jaket Pink Fuschia"
|
||||||
|
style="@style/label_medium_prominent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_product_variant"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="S"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textColor="@color/black_300"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="13dp"
|
||||||
|
android:gravity="end"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/iv_order_product"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/iv_order_product">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_product_qty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="x2"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_product_price"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Rp150.000"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_see_more"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:text="Lihat 3 produk lainnya"
|
||||||
|
android:gravity="center"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:fontFamily="@font/dmsans_italic"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/iv_order_product"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Total Price -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_qty"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="2 produk"
|
||||||
|
style="@style/label_large"
|
||||||
|
android:layout_alignParentStart="true"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_alignParentEnd="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Total:"
|
||||||
|
style="@style/label_large_prominent"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_price"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Rp300.000"
|
||||||
|
style="@style/label_large_prominent"
|
||||||
|
android:textColor="@color/blue_500"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="13dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_edit_order"
|
||||||
|
style="@style/button.small.secondary.medium"
|
||||||
|
android:text="Ubah Tagihan"
|
||||||
|
android:layout_marginEnd="10dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_confirm_order"
|
||||||
|
style="@style/button.small.active.medium"
|
||||||
|
android:text="Konfirmasi Tagihan" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:background="@color/black_50"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/layout_order_detail"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
318
app/src/main/res/layout/item_sells_payment.xml
Normal file
318
app/src/main/res/layout/item_sells_payment.xml
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:paddingTop="16dp">
|
||||||
|
|
||||||
|
<!-- Payment Header -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/shape_sells_title"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:background="@drawable/shape_sells_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_payment_header"
|
||||||
|
android:layout_width="220dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/shape_sells_title"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_title"
|
||||||
|
style="@style/label_medium_prominent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Pesanan Telah Dibayar"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_number"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:text="No. Pesanan: 123456789"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:text="Konfirmasi pembayaran sebelum:"
|
||||||
|
android:textColor="@color/black_300" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_due"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="25 Okt; 23.59"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:paddingHorizontal="4dp"
|
||||||
|
android:textColor="@color/darkblue_500"
|
||||||
|
android:background="@drawable/bg_product_active" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Order Detail -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_payment_detail"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/layout_payment_header"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Product Detail -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_payment_product_detail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/iv_payment_product"
|
||||||
|
android:layout_width="95dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:src="@drawable/placeholder_image"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:contentDescription="Payment Product Image"
|
||||||
|
app:shapeAppearanceOverlay="@style/store_product_image"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="13dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/iv_payment_product"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_product_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Jaket Pink Fuschia"
|
||||||
|
style="@style/label_medium_prominent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_product_variant"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="S"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textColor="@color/black_300"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="13dp"
|
||||||
|
android:gravity="end"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/iv_payment_product"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/iv_payment_product">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_product_qty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="x2"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_product_price"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Rp150.000"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_see_more"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:text="Lihat 3 produk lainnya"
|
||||||
|
android:gravity="center"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:fontFamily="@font/dmsans_italic"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/iv_payment_product"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Total Price -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_qty"
|
||||||
|
style="@style/label_large"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:text="2 produk" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_alignParentEnd="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Total:"
|
||||||
|
style="@style/label_large_prominent"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_price"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Rp300.000"
|
||||||
|
style="@style/label_large_prominent"
|
||||||
|
android:textColor="@color/blue_500"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:textAlignment="textEnd"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="13dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="158dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_alignParentStart="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:src="@drawable/ic_person"
|
||||||
|
app:tint="@color/black_500" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_customer"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textColor="@color/black_500"
|
||||||
|
android:text="Gracia Hotmauli"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:src="@drawable/ic_location" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_payment_location"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textColor="@color/black_500"
|
||||||
|
android:text="Serang"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_confirm_payment"
|
||||||
|
style="@style/button.small.active.medium"
|
||||||
|
android:text="Konfirmasi Pembayaran"
|
||||||
|
android:layout_alignParentEnd="true"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:background="@color/black_50"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/layout_payment_detail"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
255
app/src/main/res/layout/item_sells_shipment.xml
Normal file
255
app/src/main/res/layout/item_sells_shipment.xml
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:paddingTop="16dp">
|
||||||
|
|
||||||
|
<!-- Shipment Header -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/shape_sells_title"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:background="@drawable/shape_sells_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_shipment_header"
|
||||||
|
android:layout_width="220dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/shape_sells_title"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_title"
|
||||||
|
style="@style/label_medium_prominent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Pesanan Perlu Dikirim"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_number"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
android:text="No. Pesanan: 123456789"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:text="Kirim sebelum:"
|
||||||
|
android:textColor="@color/black_300" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_due"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="25 Okt; 23.59"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:paddingHorizontal="4dp"
|
||||||
|
android:textColor="@color/darkblue_500"
|
||||||
|
android:background="@drawable/bg_product_active" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Order Detail -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_shipment_detail"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/layout_shipment_header"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Product Detail -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_shipment_product_detail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/iv_shipment_product"
|
||||||
|
android:layout_width="95dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:src="@drawable/placeholder_image"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:contentDescription="Shipment Product Image"
|
||||||
|
app:shapeAppearanceOverlay="@style/store_product_image"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="13dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/iv_shipment_product"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_product_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Jaket Pink Fuschia"
|
||||||
|
style="@style/label_medium_prominent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_product_variant"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="S"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:textColor="@color/black_300"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_product_qty"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="x2"
|
||||||
|
style="@style/label_medium"
|
||||||
|
android:layout_marginStart="13dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/iv_shipment_product"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/iv_shipment_product"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_see_more"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:text="Lihat 3 produk lainnya"
|
||||||
|
android:gravity="center"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:fontFamily="@font/dmsans_italic"
|
||||||
|
android:textColor="@color/black_300"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/iv_shipment_product"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/black_50"/>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="13dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="158dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_alignParentStart="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:src="@drawable/ic_person"
|
||||||
|
app:tint="@color/black_500" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_customer"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textColor="@color/black_500"
|
||||||
|
android:text="Gracia Hotmauli"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:src="@drawable/ic_location" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_shipment_location"
|
||||||
|
style="@style/label_small"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textColor="@color/black_500"
|
||||||
|
android:text="Serang"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_confirm_shipment"
|
||||||
|
style="@style/button.small.active.medium"
|
||||||
|
android:text="Kirim Pesanan"
|
||||||
|
android:layout_alignParentEnd="true"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:background="@color/black_50"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/layout_shipment_detail"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -75,7 +75,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/ivMenu"
|
android:id="@+id/iv_menu"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:src="@drawable/ic_more_vertical"
|
android:src="@drawable/ic_more_vertical"
|
||||||
|
14
app/src/main/res/menu/product_options_menu.xml
Normal file
14
app/src/main/res/menu/product_options_menu.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_edit_product"
|
||||||
|
android:title="Ubah Produk"
|
||||||
|
android:icon="@drawable/ic_edit"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_delete_product"
|
||||||
|
android:title="Hapus Produk"
|
||||||
|
android:icon="@drawable/ic_delete"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
</menu>
|
@ -147,7 +147,7 @@
|
|||||||
<!-- Buttons -->
|
<!-- Buttons -->
|
||||||
|
|
||||||
<style name="button.large" parent="label_large_prominent">
|
<style name="button.large" parent="label_large_prominent">
|
||||||
<item name="android:padding">10.91dp</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:layout_height">40dp</item>
|
<item name="android:layout_height">40dp</item>
|
||||||
<item name="android:textAllCaps">false</item>
|
<item name="android:textAllCaps">false</item>
|
||||||
<item name="backgroundTint">@null</item>
|
<item name="backgroundTint">@null</item>
|
||||||
@ -217,7 +217,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="button.small" parent="label_medium_prominent">
|
<style name="button.small" parent="label_medium_prominent">
|
||||||
<item name="android:padding">7dp</item>
|
<item name="android:padding">2dp</item>
|
||||||
<item name="android:layout_height">30dp</item>
|
<item name="android:layout_height">30dp</item>
|
||||||
<item name="android:textAllCaps">false</item>
|
<item name="android:textAllCaps">false</item>
|
||||||
<item name="backgroundTint">@null</item>
|
<item name="backgroundTint">@null</item>
|
||||||
|
@ -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