From 019b469556055e1fc8a58a016745a45b3e00b8bd Mon Sep 17 00:00:00 2001 From: shaulascr Date: Wed, 18 Jun 2025 16:43:03 +0700 Subject: [PATCH] fix price and chat date --- .../customer/order/OrderDetailResponse.kt | 2 +- .../ecommerce_serang/ui/chat/ChatActivity.kt | 11 ++- .../ecommerce_serang/ui/chat/ChatAdapter.kt | 84 +++++++++++++---- .../ecommerce_serang/ui/chat/ChatViewModel.kt | 93 ++++++++++++++++++- .../ui/home/HorizontalProductAdapter.kt | 21 ++++- .../ui/home/SearchResultAdapter.kt | 9 +- .../ui/order/PaymentMethodAdapter.kt | 6 ++ .../ui/order/ShippingAdapter.kt | 9 +- .../detail/AddEvidencePaymentActivity.kt | 38 +++++--- .../ui/order/detail/PaymentActivity.kt | 9 +- .../ui/order/detail/SpinnerCardAdapter.kt | 33 +++++++ .../detailorder/DetailOrderItemsAdapter.kt | 13 ++- .../detailorder/DetailOrderStatusActivity.kt | 45 +++++++-- .../ui/product/OtherProductAdapter.kt | 9 +- .../product/listproduct/ListProductAdapter.kt | 9 +- .../profile/mystore/chat/ChatStoreActivity.kt | 4 +- app/src/main/res/drawable/bg_date_header.xml | 6 ++ app/src/main/res/layout/item_date_header.xml | 21 +++++ .../res/layout/item_dialog_add_evidence.xml | 34 +++++++ .../res/layout/item_dialog_spinner_card.xml | 21 +++++ .../res/layout/item_order_detail_product.xml | 3 +- 21 files changed, 419 insertions(+), 61 deletions(-) create mode 100644 app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/SpinnerCardAdapter.kt create mode 100644 app/src/main/res/drawable/bg_date_header.xml create mode 100644 app/src/main/res/layout/item_date_header.xml create mode 100644 app/src/main/res/layout/item_dialog_add_evidence.xml create mode 100644 app/src/main/res/layout/item_dialog_spinner_card.xml diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt index 6530886..3adb6d4 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt @@ -80,7 +80,7 @@ data class Orders( val cancelReason: String? = null, @field:SerializedName("total_amount") - val totalAmount: String? = null, + val totalAmount: Int? = null, @field:SerializedName("user_id") val userId: Int, diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatActivity.kt index 2151030..39fc4a1 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatActivity.kt @@ -394,7 +394,10 @@ class ChatActivity : AppCompatActivity() { // Update messages val previousCount = chatAdapter.itemCount - chatAdapter.submitList(state.messages) { + + val displayItems = viewModel.getDisplayItems() + + chatAdapter.submitList(displayItems) { Log.d(TAG, "Messages submitted to adapter") // Only auto-scroll for new messages or initial load if (previousCount == 0 || state.messages.size > previousCount) { @@ -426,17 +429,15 @@ class ChatActivity : AppCompatActivity() { .error(R.drawable.placeholder_image) .into(binding.imgProduct) } + updateProductCardUI(state.hasProductAttachment) - binding.productContainer.visibility = View.VISIBLE + binding.productContainer.visibility = View.GONE } else { binding.productContainer.visibility = View.GONE } updateInputHint(state) - // Update product card visual feedback - updateProductCardUI(state.hasProductAttachment) - // Update attachment hint if (state.hasAttachment) { binding.editTextMessage.hint = getString(R.string.image_attached) diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatAdapter.kt index 05cfbfc..8a136f0 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatAdapter.kt @@ -8,6 +8,7 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.alya.ecommerce_serang.BuildConfig.BASE_URL import com.alya.ecommerce_serang.R +import com.alya.ecommerce_serang.databinding.ItemDateHeaderBinding import com.alya.ecommerce_serang.databinding.ItemMessageProductReceivedBinding import com.alya.ecommerce_serang.databinding.ItemMessageProductSentBinding import com.alya.ecommerce_serang.databinding.ItemMessageReceivedBinding @@ -17,22 +18,29 @@ import com.bumptech.glide.Glide class ChatAdapter( private val onProductClick: ((ProductInfo) -> Unit)? = null -) : ListAdapter(ChatMessageDiffCallback()) { +) : ListAdapter(ChatMessageDiffCallback()) { companion object { private const val VIEW_TYPE_MESSAGE_SENT = 1 private const val VIEW_TYPE_MESSAGE_RECEIVED = 2 private const val VIEW_TYPE_PRODUCT_SENT = 3 private const val VIEW_TYPE_PRODUCT_RECEIVED = 4 + private const val VIEW_TYPE_DATE_HEADER = 5 } override fun getItemViewType(position: Int): Int { - val message = getItem(position) - return when { - message.messageType == MessageType.PRODUCT && message.isSentByMe -> VIEW_TYPE_PRODUCT_SENT - message.messageType == MessageType.PRODUCT && !message.isSentByMe -> VIEW_TYPE_PRODUCT_RECEIVED - message.isSentByMe -> VIEW_TYPE_MESSAGE_SENT - else -> VIEW_TYPE_MESSAGE_RECEIVED + val item = getItem(position) + return when (item) { + is ChatDisplayItem.DateHeaderItem -> VIEW_TYPE_DATE_HEADER + is ChatDisplayItem.MessageItem -> { + val message = item.chatUiMessage + when { + message.messageType == MessageType.PRODUCT && message.isSentByMe -> VIEW_TYPE_PRODUCT_SENT + message.messageType == MessageType.PRODUCT && !message.isSentByMe -> VIEW_TYPE_PRODUCT_RECEIVED + message.isSentByMe -> VIEW_TYPE_MESSAGE_SENT + else -> VIEW_TYPE_MESSAGE_RECEIVED + } + } } } @@ -40,6 +48,10 @@ class ChatAdapter( val inflater = LayoutInflater.from(parent.context) return when (viewType) { + VIEW_TYPE_DATE_HEADER -> { + val binding = ItemDateHeaderBinding.inflate(inflater, parent, false) + DateHeaderViewHolder(binding) + } VIEW_TYPE_MESSAGE_SENT -> { val binding = ItemMessageSentBinding.inflate(inflater, parent, false) SentMessageViewHolder(binding) @@ -61,13 +73,34 @@ class ChatAdapter( } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val message = getItem(position) + val item = getItem(position) when (holder) { - is SentMessageViewHolder -> holder.bind(message) - is ReceivedMessageViewHolder -> holder.bind(message) - is SentProductViewHolder -> holder.bind(message) - is ReceivedProductViewHolder -> holder.bind(message) + is DateHeaderViewHolder -> { + if (item is ChatDisplayItem.DateHeaderItem) { + holder.bind(item) + } + } + is SentMessageViewHolder -> { + if (item is ChatDisplayItem.MessageItem) { + holder.bind(item.chatUiMessage) + } + } + is ReceivedMessageViewHolder -> { + if (item is ChatDisplayItem.MessageItem) { + holder.bind(item.chatUiMessage) + } + } + is SentProductViewHolder -> { + if (item is ChatDisplayItem.MessageItem) { + holder.bind(item.chatUiMessage) + } + } + is ReceivedProductViewHolder -> { + if (item is ChatDisplayItem.MessageItem) { + holder.bind(item.chatUiMessage) + } + } } } @@ -233,17 +266,36 @@ class ChatAdapter( } } } + + inner class DateHeaderViewHolder(private val binding: ItemDateHeaderBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(item: ChatDisplayItem.DateHeaderItem) { + binding.tvDate.text = item.formattedDate + } + } } /** * DiffUtil callback for optimizing RecyclerView updates */ -class ChatMessageDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: ChatUiMessage, newItem: ChatUiMessage): Boolean { - return oldItem.id == newItem.id +class ChatMessageDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: ChatDisplayItem, newItem: ChatDisplayItem): Boolean { + return when { + oldItem is ChatDisplayItem.MessageItem && newItem is ChatDisplayItem.MessageItem -> + oldItem.chatUiMessage.id == newItem.chatUiMessage.id + oldItem is ChatDisplayItem.DateHeaderItem && newItem is ChatDisplayItem.DateHeaderItem -> + oldItem.date == newItem.date + else -> false + } } - override fun areContentsTheSame(oldItem: ChatUiMessage, newItem: ChatUiMessage): Boolean { + override fun areContentsTheSame(oldItem: ChatDisplayItem, newItem: ChatDisplayItem): Boolean { return oldItem == newItem } +} + +sealed class ChatDisplayItem { + data class MessageItem(val chatUiMessage: ChatUiMessage) : ChatDisplayItem() + data class DateHeaderItem(val date: String, val formattedDate: String) : ChatDisplayItem() } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt index 677bf34..3b550f5 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt @@ -16,6 +16,9 @@ import com.alya.ecommerce_serang.utils.SessionManager import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.io.File +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date import java.util.Locale import java.util.TimeZone import javax.inject.Inject @@ -737,7 +740,8 @@ class ChatViewModel @Inject constructor( attachment = chatLine.attachment ?: "", status = chatLine.status, time = formattedTime, - isSentByMe = chatLine.senderId == currentUserId + isSentByMe = chatLine.senderId == currentUserId, + createdAt = chatLine.createdAt ) } @@ -781,7 +785,8 @@ class ChatViewModel @Inject constructor( time = formattedTime, isSentByMe = chatItem.senderId == currentUserId, messageType = messageType, - productInfo = productInfo + productInfo = productInfo, + createdAt = chatItem.createdAt ) // Fetch product info for non-current-user products @@ -923,6 +928,85 @@ class ChatViewModel @Inject constructor( Log.d(TAG, "ChatViewModel cleared - Disconnecting socket") socketService.disconnect() } + + fun getDisplayItems(): List { + return transformMessagesToDisplayItems(state.value?.messages ?: emptyList()) + } + + private fun transformMessagesToDisplayItems(messages: List): List { + if (messages.isEmpty()) return emptyList() + + val displayItems = mutableListOf() + var lastDate: String? = null + + for (message in messages) { + // Extract date from message timestamp + val messageDate = extractDateFromTimestamp(message.createdAt) // You need to implement this + + // Add date header if this is a new day + if (messageDate != lastDate) { + val formattedDate = formatDateHeader(messageDate) // You need to implement this + displayItems.add(ChatDisplayItem.DateHeaderItem(messageDate, formattedDate)) + lastDate = messageDate + } + + // Add the message + displayItems.add(ChatDisplayItem.MessageItem(message)) + } + + return displayItems + } + + private fun extractDateFromTimestamp(timestamp: String): String { + return try { + // Parse ISO 8601 format: "2025-05-27T08:36:53.946Z" + val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) + inputFormat.timeZone = TimeZone.getTimeZone("UTC") + + val date = inputFormat.parse(timestamp) + val outputFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + outputFormat.format(date ?: Date()) + } catch (e: Exception) { + Log.e(TAG, "Error parsing timestamp: $timestamp", e) + return timestamp.take(10) + } + } + + private fun formatDateHeader(dateString: String): String { + return try { + val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val messageDate = dateFormat.parse(dateString) ?: return dateString + + val today = Calendar.getInstance() + val yesterday = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -1) } + val messageCalendar = Calendar.getInstance().apply { time = messageDate } + + when { + isSameDay(messageCalendar, today) -> "Today" + isSameDay(messageCalendar, yesterday) -> "Yesterday" + isThisYear(messageCalendar, today) -> { + // Show "Mon, Dec 15" format for this year + SimpleDateFormat("EEE, MMM dd", Locale.getDefault()).format(messageDate) + } + else -> { + // Show "Dec 15, 2024" format for other years + SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(messageDate) + } + } + } catch (e: Exception) { + Log.e(TAG, "Error formatting date: $dateString", e) + dateString // Fallback to raw date + } + } + + private fun isSameDay(cal1: Calendar, cal2: Calendar): Boolean { + return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && + cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) + } + + private fun isThisYear(messageCalendar: Calendar, today: Calendar): Boolean { + return messageCalendar.get(Calendar.YEAR) == today.get(Calendar.YEAR) + } } enum class MessageType { @@ -949,9 +1033,12 @@ data class ChatUiMessage( val time: String, val isSentByMe: Boolean, val messageType: MessageType = MessageType.TEXT, - val productInfo: ProductInfo? = null + val productInfo: ProductInfo? = null, + val createdAt: String ) + + // representing UI state to screen data class ChatUiState( val messages: List = emptyList(), diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt index 55792f9..b89d7fd 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt @@ -2,6 +2,7 @@ package com.alya.ecommerce_serang.ui.home import android.util.Log import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView @@ -11,6 +12,8 @@ import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.alya.ecommerce_serang.data.api.response.customer.product.StoreItem import com.alya.ecommerce_serang.databinding.ItemProductGridBinding import com.bumptech.glide.Glide +import java.text.NumberFormat +import java.util.Locale class HorizontalProductAdapter( private var products: List, @@ -32,8 +35,17 @@ class HorizontalProductAdapter( Log.d("ProductAdapter", "Loading image: $fullImageUrl") tvProductName.text = product.name - tvProductPrice.text = product.price - rating.text = product.rating + tvProductPrice.text = formatCurrency(product.price.toDouble()) + val ratingStr = product.rating + val ratingValue = ratingStr?.toFloatOrNull() + + if (ratingValue != null && ratingValue > 0f) { + binding.rating.text = String.format("%.1f", ratingValue) + binding.rating.visibility = View.VISIBLE + } else { + binding.rating.text = "Belum ada rating" + binding.rating.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null) + } // Load image using Glide Glide.with(itemView) @@ -77,6 +89,11 @@ class HorizontalProductAdapter( diffResult.dispatchUpdatesTo(this) } + private fun formatCurrency(amount: Double): String { + val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID")) + return formatter.format(amount).replace(",00", "") + } + class ProductDiffCallback( private val oldList: List, private val newList: List diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt index b46a143..89d8e22 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt @@ -12,6 +12,8 @@ import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.alya.ecommerce_serang.data.api.response.customer.product.StoreItem import com.alya.ecommerce_serang.databinding.ItemProductGridBinding import com.bumptech.glide.Glide +import java.text.NumberFormat +import java.util.Locale class SearchResultsAdapter( private val onItemClick: (ProductsItem) -> Unit, @@ -46,7 +48,7 @@ class SearchResultsAdapter( fun bind(product: ProductsItem) { binding.tvProductName.text = product.name - binding.tvProductPrice.text = product.price + binding.tvProductPrice.text = formatCurrency(product.price.toDouble()) val fullImageUrl = if (product.image.startsWith("/")) { BASE_URL + product.image.removePrefix("/") // Append base URL if the path starts with "/" @@ -71,6 +73,11 @@ class SearchResultsAdapter( super.submitList(list) } + private fun formatCurrency(amount: Double): String { + val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID")) + return formatter.format(amount).replace(",00", "") + } + companion object { private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: ProductsItem, newItem: ProductsItem): Boolean { diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/PaymentMethodAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/PaymentMethodAdapter.kt index 86b7254..a520da2 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/PaymentMethodAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/PaymentMethodAdapter.kt @@ -48,6 +48,12 @@ class PaymentMethodAdapter( // Load payment icon if available if (!payment.qrisImage.isNullOrEmpty()) { +// val fullImageUrl = if (payment.qrisImage.startsWith("/")) { +// BASE_URL + payment.qrisImage.removePrefix("/") // Append base URL if the path starts with "/" +// } else { +// payment.qrisImage// Use as is if it's already a full URL +// } + Glide.with(ivPaymentMethod.context) .load(payment.qrisImage) .apply( diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/ShippingAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/ShippingAdapter.kt index bea432b..d311a86 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/ShippingAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/ShippingAdapter.kt @@ -6,6 +6,8 @@ import androidx.recyclerview.widget.RecyclerView import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostsItem import com.alya.ecommerce_serang.data.api.response.customer.order.ServicesItem import com.alya.ecommerce_serang.databinding.ItemShippingOrderBinding +import java.text.NumberFormat +import java.util.Locale class ShippingAdapter( private val onItemSelected: (CourierCostsItem, ServicesItem) -> Unit @@ -30,7 +32,7 @@ class ShippingAdapter( // Combine courier name and service courierNameCost.text = "${courierCostsItem.courier} - ${service.service}" estDate.text = "Estimasi ${service.etd} hari" - costPrice.text = "Rp${service.cost}" + costPrice.text = formatCurrency(service.cost.toDouble()) // Single click handler for both item and radio button val onClickAction = { @@ -90,6 +92,11 @@ class ShippingAdapter( } } + private fun formatCurrency(amount: Double): String { + val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID")) + return formatter.format(amount).replace(",00", "") + } + override fun getItemCount(): Int { return courierCostsList.sumOf { it.services.size } } diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt index fc37df7..1329a95 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt @@ -1,8 +1,8 @@ package com.alya.ecommerce_serang.ui.order.detail import android.Manifest -import android.R import android.app.Activity +import android.app.AlertDialog import android.app.DatePickerDialog import android.content.Intent import android.content.pm.PackageManager @@ -12,6 +12,7 @@ import android.os.Bundle import android.provider.MediaStore import android.util.Log import android.view.View +import android.view.ViewGroup import android.webkit.MimeTypeMap import android.widget.AdapterView import android.widget.ArrayAdapter @@ -25,6 +26,7 @@ import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.dto.AddEvidenceMultipartRequest import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig import com.alya.ecommerce_serang.data.repository.OrderRepository @@ -37,6 +39,7 @@ import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody import java.io.File +import java.text.NumberFormat import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale @@ -59,11 +62,9 @@ class AddEvidencePaymentActivity : AppCompatActivity() { } private val paymentMethods = arrayOf( - "Pilih metode pembayaran", "Transfer Bank", "E-Wallet", - "Virtual Account", - "Cash on Delivery" + "QRIS", ) // private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> @@ -128,11 +129,8 @@ class AddEvidencePaymentActivity : AppCompatActivity() { } private fun setupUI() { - // Set product details\ - - // Setup payment methods spinner - val adapter = ArrayAdapter(this, R.layout.simple_spinner_item, paymentMethods) - adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item) + val paymentMethods = listOf("Transfer Bank", "COD", "QRIS") + val adapter = SpinnerCardAdapter(this, paymentMethods) binding.spinnerPaymentMethod.adapter = adapter } @@ -219,15 +217,23 @@ class AddEvidencePaymentActivity : AppCompatActivity() { private fun showImagePickerOptions() { val options = arrayOf( "Pilih dari Galeri", - "Batal" + "Kembali" ) - androidx.appcompat.app.AlertDialog.Builder(this) - .setTitle("Pilih Bukti Pembayaran") - .setItems(options) { dialog, which -> + val adapter = object : ArrayAdapter(this, R.layout.item_dialog_add_evidence, R.id.tvOption, options) { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = super.getView(position, convertView, parent) + val divider = view.findViewById(R.id.divider) + divider.visibility = if (position == count - 1) View.GONE else View.VISIBLE + return view + } + } + + AlertDialog.Builder(this) + .setAdapter(adapter) { dialog, which -> when (which) { - 0 -> openGallery() // Gallery - 1 -> dialog.dismiss() // Cancel + 0 -> openGallery() + 1 -> dialog.dismiss() } } .show() @@ -440,6 +446,8 @@ class AddEvidencePaymentActivity : AppCompatActivity() { } + + companion object { private const val PERMISSION_REQUEST_CODE = 100 private const val TAG = "AddEvidenceActivity" diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt index d2c525a..c470b52 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt @@ -17,6 +17,7 @@ import com.alya.ecommerce_serang.data.repository.OrderRepository import com.alya.ecommerce_serang.databinding.ActivityPaymentBinding import com.alya.ecommerce_serang.utils.BaseViewModelFactory import com.alya.ecommerce_serang.utils.SessionManager +import java.text.NumberFormat import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale @@ -100,6 +101,7 @@ class PaymentActivity : AppCompatActivity() { // Log.d(TAG, "Button clicked - showing toast") // Toast.makeText(this@PaymentActivity, "Button works! OrderID: $orderId", Toast.LENGTH_LONG).show() // } + binding.btnUploadPaymentProof.apply { isEnabled = true isClickable = true @@ -134,7 +136,7 @@ class PaymentActivity : AppCompatActivity() { Log.d(TAG, "Order details received: $order") // Set total amount - binding.tvTotalAmount.text = order.totalAmount ?: "Rp0" + binding.tvTotalAmount.text = formatCurrency(order.totalAmount?.toDouble() ?: 0.00) Log.d(TAG, "Total Amount: ${order.totalAmount}") @@ -202,6 +204,11 @@ class PaymentActivity : AppCompatActivity() { } } + private fun formatCurrency(amount: Double): String { + val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID")) + return formatter.format(amount).replace(",00", "") + } + private fun showInstructions(type: String) { // Implementasi tampilkan instruksi val instructions = when (type) { diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/SpinnerCardAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/SpinnerCardAdapter.kt new file mode 100644 index 0000000..edd1988 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/SpinnerCardAdapter.kt @@ -0,0 +1,33 @@ +package com.alya.ecommerce_serang.ui.order.detail + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.TextView +import com.alya.ecommerce_serang.R + +class SpinnerCardAdapter( + context: Context, + private val items: List +) : ArrayAdapter(context, 0, items) { + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + // View shown when Spinner is collapsed + return createCardView(position, convertView, parent) + } + + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { + // View shown for dropdown items + return createCardView(position, convertView, parent) + } + + private fun createCardView(position: Int, convertView: View?, parent: ViewGroup): View { + val inflater = LayoutInflater.from(context) + val view = convertView ?: inflater.inflate(R.layout.item_dialog_spinner_card, parent, false) + val textView = view.findViewById(R.id.tvOption) + textView.text = items[position] + return view + } +} diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/detailorder/DetailOrderItemsAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/detailorder/DetailOrderItemsAdapter.kt index 58f5c43..924d4ef 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/detailorder/DetailOrderItemsAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/detailorder/DetailOrderItemsAdapter.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView +import com.alya.ecommerce_serang.BuildConfig.BASE_URL import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.response.customer.order.OrderListItemsItem import com.bumptech.glide.Glide @@ -39,11 +40,18 @@ class DetailOrderItemsAdapter : RecyclerView.Adapter, @@ -32,7 +34,7 @@ class OtherProductAdapter ( Log.d("ProductAdapter", "Loading image: $fullImageUrl") tvProductName.text = product.name - tvProductPrice.text = product.price + tvProductPrice.text = formatCurrency(product.price.toDouble()) rating.text = product.rating // Load image using Glide @@ -77,6 +79,11 @@ class OtherProductAdapter ( diffResult.dispatchUpdatesTo(this) } + private fun formatCurrency(amount: Double): String { + val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID")) + return formatter.format(amount).replace(",00", "") + } + class ProductDiffCallback( private val oldList: List, private val newList: List diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/product/listproduct/ListProductAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/product/listproduct/ListProductAdapter.kt index f0cb5f4..25314e5 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/product/listproduct/ListProductAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/product/listproduct/ListProductAdapter.kt @@ -11,6 +11,8 @@ import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.alya.ecommerce_serang.data.api.response.customer.product.StoreItem import com.alya.ecommerce_serang.databinding.ItemProductGridBinding import com.bumptech.glide.Glide +import java.text.NumberFormat +import java.util.Locale class ListProductAdapter( private var products: List, @@ -24,7 +26,7 @@ class ListProductAdapter( fun bind(product: ProductsItem) = with(binding) { tvProductName.text = product.name - tvProductPrice.text = product.price + tvProductPrice.text = formatCurrency(product.price.toDouble()) rating.text = product.rating val fullImageUrl = if (product.image.startsWith("/")) { @@ -68,6 +70,11 @@ class ListProductAdapter( notifyDataSetChanged() } + private fun formatCurrency(amount: Double): String { + val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID")) + return formatter.format(amount).replace(",00", "") + } + class ProductDiffCallback( private val oldList: List, private val newList: List diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/chat/ChatStoreActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/chat/ChatStoreActivity.kt index 8dfabfc..169f1de 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/chat/ChatStoreActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/chat/ChatStoreActivity.kt @@ -378,7 +378,9 @@ class ChatStoreActivity : AppCompatActivity() { // Update messages val previousCount = chatAdapter.itemCount - chatAdapter.submitList(state.messages) { + val displayItems = viewModel.getDisplayItems() + + chatAdapter.submitList(displayItems) { Log.d(TAG, "Messages submitted to adapter") // Only auto-scroll for new messages or initial load if (previousCount == 0 || state.messages.size > previousCount) { diff --git a/app/src/main/res/drawable/bg_date_header.xml b/app/src/main/res/drawable/bg_date_header.xml new file mode 100644 index 0000000..7539706 --- /dev/null +++ b/app/src/main/res/drawable/bg_date_header.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_date_header.xml b/app/src/main/res/layout/item_date_header.xml new file mode 100644 index 0000000..70aa5f8 --- /dev/null +++ b/app/src/main/res/layout/item_date_header.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dialog_add_evidence.xml b/app/src/main/res/layout/item_dialog_add_evidence.xml new file mode 100644 index 0000000..9756df8 --- /dev/null +++ b/app/src/main/res/layout/item_dialog_add_evidence.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_dialog_spinner_card.xml b/app/src/main/res/layout/item_dialog_spinner_card.xml new file mode 100644 index 0000000..96694bd --- /dev/null +++ b/app/src/main/res/layout/item_dialog_spinner_card.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/app/src/main/res/layout/item_order_detail_product.xml b/app/src/main/res/layout/item_order_detail_product.xml index f34e2a1..71f7ed1 100644 --- a/app/src/main/res/layout/item_order_detail_product.xml +++ b/app/src/main/res/layout/item_order_detail_product.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="8dp"> + android:paddingHorizontal="8dp">