mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-16 11:47:25 +00:00
fix address, edit address
This commit is contained in:
@ -82,7 +82,8 @@ data class Product(
|
|||||||
|
|
||||||
data class CartItemCheckoutInfo(
|
data class CartItemCheckoutInfo(
|
||||||
val cartItem: CartItemsItem,
|
val cartItem: CartItemsItem,
|
||||||
val isWholesale: Boolean
|
val isWholesale: Boolean,
|
||||||
|
val wholesalePrice: Int? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import com.google.gson.annotations.SerializedName
|
|||||||
data class AddressDetailResponse(
|
data class AddressDetailResponse(
|
||||||
|
|
||||||
@field:SerializedName("address")
|
@field:SerializedName("address")
|
||||||
val address: Address,
|
val address: AddressDetail,
|
||||||
|
|
||||||
@field:SerializedName("message")
|
@field:SerializedName("message")
|
||||||
val message: String
|
val message: String
|
||||||
@ -14,7 +14,7 @@ data class AddressDetailResponse(
|
|||||||
data class AddressDetail(
|
data class AddressDetail(
|
||||||
|
|
||||||
@field:SerializedName("village_id")
|
@field:SerializedName("village_id")
|
||||||
val villageId: String,
|
val villageId: String?,
|
||||||
|
|
||||||
@field:SerializedName("is_store_location")
|
@field:SerializedName("is_store_location")
|
||||||
val isStoreLocation: Boolean,
|
val isStoreLocation: Boolean,
|
||||||
@ -38,7 +38,7 @@ data class AddressDetail(
|
|||||||
val provinceId: String,
|
val provinceId: String,
|
||||||
|
|
||||||
@field:SerializedName("phone")
|
@field:SerializedName("phone")
|
||||||
val phone: String,
|
val phone: String?,
|
||||||
|
|
||||||
@field:SerializedName("street")
|
@field:SerializedName("street")
|
||||||
val street: String,
|
val street: String,
|
||||||
@ -47,7 +47,7 @@ data class AddressDetail(
|
|||||||
val subdistrict: String,
|
val subdistrict: String,
|
||||||
|
|
||||||
@field:SerializedName("recipient")
|
@field:SerializedName("recipient")
|
||||||
val recipient: String,
|
val recipient: String?,
|
||||||
|
|
||||||
@field:SerializedName("id")
|
@field:SerializedName("id")
|
||||||
val id: Int,
|
val id: Int,
|
||||||
|
@ -63,6 +63,7 @@ import com.alya.ecommerce_serang.data.api.response.customer.product.DetailStoreP
|
|||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.ReviewProductResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.product.ReviewProductResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressDetailResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.profile.CreateAddressResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.CreateAddressResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.profile.EditProfileResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.EditProfileResponse
|
||||||
@ -528,4 +529,9 @@ interface ApiService {
|
|||||||
suspend fun postResetPass(
|
suspend fun postResetPass(
|
||||||
@Body request: ResetPassReq
|
@Body request: ResetPassReq
|
||||||
): Response<ResetPassResponse>
|
): Response<ResetPassResponse>
|
||||||
|
|
||||||
|
@GET("address/detail/{id}")
|
||||||
|
suspend fun getDetailAddress(
|
||||||
|
@Path("id") addressId: Int
|
||||||
|
): Response<AddressDetailResponse>
|
||||||
}
|
}
|
@ -20,12 +20,16 @@ import com.alya.ecommerce_serang.data.api.response.customer.order.ListCityRespon
|
|||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.ListProvinceResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.ListProvinceResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderDetailResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderDetailResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderListResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderListResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.SubdistrictResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.VillagesResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.DetailPaymentItem
|
import com.alya.ecommerce_serang.data.api.response.customer.product.DetailPaymentItem
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreItem
|
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreItem
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressDetailResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.profile.CreateAddressResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.CreateAddressResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.UpdateAddressResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.order.AddEvidenceResponse
|
import com.alya.ecommerce_serang.data.api.response.order.AddEvidenceResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.order.ComplaintResponse
|
import com.alya.ecommerce_serang.data.api.response.order.ComplaintResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.order.CompletedOrderResponse
|
import com.alya.ecommerce_serang.data.api.response.order.CompletedOrderResponse
|
||||||
@ -294,6 +298,30 @@ class OrderRepository(private val apiService: ApiService) {
|
|||||||
return if (response.isSuccessful) response.body() else null
|
return if (response.isSuccessful) response.body() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getListSubdistrict(cityId : String): SubdistrictResponse? {
|
||||||
|
val response = apiService.getSubdistrict(cityId)
|
||||||
|
return if (response.isSuccessful) response.body() else null
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getListVillages(subId: String): VillagesResponse? {
|
||||||
|
val response = apiService.getVillages(subId)
|
||||||
|
return if (response.isSuccessful) response.body() else null
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getAddressDetail(addressId: Int): AddressDetailResponse? {
|
||||||
|
return try {
|
||||||
|
val response = apiService.getDetailAddress(addressId)
|
||||||
|
if (response.isSuccessful) response.body() else null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("OrderRepository", "Error getting address detail $e ")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateAddress(addressId: Int, params: Map<String, Any>): Response<UpdateAddressResponse> {
|
||||||
|
return apiService.updateAddress(addressId, params)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun fetchUserProfile(): Result<UserProfile?> {
|
suspend fun fetchUserProfile(): Result<UserProfile?> {
|
||||||
return try {
|
return try {
|
||||||
val response = apiService.getUserProfile()
|
val response = apiService.getUserProfile()
|
||||||
@ -319,6 +347,7 @@ class OrderRepository(private val apiService: ApiService) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun uploadPaymentProof(request: AddEvidenceMultipartRequest): Result<AddEvidenceResponse> {
|
suspend fun uploadPaymentProof(request: AddEvidenceMultipartRequest): Result<AddEvidenceResponse> {
|
||||||
return try {
|
return try {
|
||||||
Log.d("OrderRepository", "Uploading payment proof...")
|
Log.d("OrderRepository", "Uploading payment proof...")
|
||||||
|
@ -30,6 +30,8 @@ class CartActivity : AppCompatActivity() {
|
|||||||
private lateinit var sessionManager: SessionManager
|
private lateinit var sessionManager: SessionManager
|
||||||
private lateinit var storeAdapter: StoreAdapter
|
private lateinit var storeAdapter: StoreAdapter
|
||||||
|
|
||||||
|
private var TAG = "Cart Activity"
|
||||||
|
|
||||||
private val viewModel: CartViewModel by viewModels {
|
private val viewModel: CartViewModel by viewModels {
|
||||||
BaseViewModelFactory {
|
BaseViewModelFactory {
|
||||||
val apiService = ApiConfig.getApiService(sessionManager)
|
val apiService = ApiConfig.getApiService(sessionManager)
|
||||||
@ -135,11 +137,33 @@ class CartActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startCheckoutWithWholesaleInfo(checkoutItems: List<CartItemCheckoutInfo>) {
|
private fun startCheckoutWithWholesaleInfo(checkoutItems: List<CartItemCheckoutInfo>) {
|
||||||
// Extract cart item IDs and wholesale status
|
val wholesalePriceMap = viewModel.cartItemWholesalePrice.value ?: emptyMap()
|
||||||
val cartItemIds = checkoutItems.map { it.cartItem.cartItemId }
|
|
||||||
val wholesaleArray = checkoutItems.map { it.isWholesale }.toBooleanArray()
|
val updatedItems = checkoutItems.map { info ->
|
||||||
|
val wholesalePrice = wholesalePriceMap[info.cartItem.cartItemId]
|
||||||
|
|
||||||
|
val updatedCartItem = if (info.isWholesale && wholesalePrice != null) {
|
||||||
|
// Replace the price with wholesale price
|
||||||
|
info.cartItem.copy(price = wholesalePrice.toInt())
|
||||||
|
} else {
|
||||||
|
info.cartItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug log
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"cartItemId: ${updatedCartItem.cartItemId}, " +
|
||||||
|
"isWholesale: ${info.isWholesale}, " +
|
||||||
|
"wholesalePrice: $wholesalePrice, " +
|
||||||
|
"finalPrice: ${updatedCartItem.price}"
|
||||||
|
)
|
||||||
|
|
||||||
|
info.copy(cartItem = updatedCartItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
val cartItemIds = updatedItems.map { it.cartItem.cartItemId }
|
||||||
|
val wholesaleArray = updatedItems.map { it.isWholesale }.toBooleanArray()
|
||||||
|
|
||||||
// Start checkout activity with the cart items and wholesale info
|
|
||||||
CheckoutActivity.startForCart(this, cartItemIds, wholesaleArray)
|
CheckoutActivity.startForCart(this, cartItemIds, wholesaleArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +257,5 @@ class CartActivity : AppCompatActivity() {
|
|||||||
val format = NumberFormat.getCurrencyInstance(Locale("id", "ID"))
|
val format = NumberFormat.getCurrencyInstance(Locale("id", "ID"))
|
||||||
return format.format(amount).replace("Rp", "Rp ")
|
return format.format(amount).replace("Rp", "Rp ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ import com.alya.ecommerce_serang.data.api.dto.CreateAddressRequest
|
|||||||
import com.alya.ecommerce_serang.data.api.dto.UserProfile
|
import com.alya.ecommerce_serang.data.api.dto.UserProfile
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CitiesItem
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CitiesItem
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.ProvincesItem
|
import com.alya.ecommerce_serang.data.api.response.customer.order.ProvincesItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.SubdistrictsItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.VillagesItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressDetail
|
||||||
import com.alya.ecommerce_serang.data.repository.OrderRepository
|
import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||||
import com.alya.ecommerce_serang.data.repository.Result
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
import com.alya.ecommerce_serang.data.repository.UserRepository
|
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||||
@ -31,6 +34,18 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u
|
|||||||
private val _citiesState = MutableLiveData<ViewState<List<CitiesItem>>>()
|
private val _citiesState = MutableLiveData<ViewState<List<CitiesItem>>>()
|
||||||
val citiesState: LiveData<ViewState<List<CitiesItem>>> = _citiesState
|
val citiesState: LiveData<ViewState<List<CitiesItem>>> = _citiesState
|
||||||
|
|
||||||
|
private val _subdistrictState = MutableLiveData<Result<List<SubdistrictsItem>>>()
|
||||||
|
val subdistrictState: LiveData<Result<List<SubdistrictsItem>>> = _subdistrictState
|
||||||
|
|
||||||
|
private val _villagesState = MutableLiveData<Result<List<VillagesItem>>>()
|
||||||
|
val villagesState: LiveData<Result<List<VillagesItem>>> = _villagesState
|
||||||
|
|
||||||
|
private val _userAddress = MutableLiveData<AddressDetail>()
|
||||||
|
val userAddress: LiveData<AddressDetail> = _userAddress
|
||||||
|
|
||||||
|
private val _editAddress = MutableLiveData<Boolean>()
|
||||||
|
val editAddress: LiveData<Boolean> get() = _editAddress
|
||||||
|
|
||||||
// Stored in SavedStateHandle for configuration changes
|
// Stored in SavedStateHandle for configuration changes
|
||||||
var selectedProvinceId: Int?
|
var selectedProvinceId: Int?
|
||||||
get() = savedStateHandle.get<Int>("selectedProvinceId")
|
get() = savedStateHandle.get<Int>("selectedProvinceId")
|
||||||
@ -40,6 +55,9 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u
|
|||||||
get() = savedStateHandle.get<String>("selectedCityId")
|
get() = savedStateHandle.get<String>("selectedCityId")
|
||||||
set(value) { savedStateHandle["selectedCityId"] = value }
|
set(value) { savedStateHandle["selectedCityId"] = value }
|
||||||
|
|
||||||
|
var selectedSubdistrict: String? = null
|
||||||
|
var selectedVillages: String? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Load provinces on initialization
|
// Load provinces on initialization
|
||||||
getProvinces()
|
getProvinces()
|
||||||
@ -86,6 +104,8 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun getProvinces() {
|
fun getProvinces() {
|
||||||
_provincesState.value = ViewState.Loading
|
_provincesState.value = ViewState.Loading
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@ -125,24 +145,113 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSubdistrict(cityId: String) {
|
||||||
|
_subdistrictState.value = Result.Loading
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
|
||||||
|
selectedSubdistrict = cityId
|
||||||
|
val result = repository.getListSubdistrict(cityId)
|
||||||
|
result?.let {
|
||||||
|
_subdistrictState.postValue(Result.Success(it.subdistricts))
|
||||||
|
Log.d(TAG, "Cities loaded for province $cityId: ${it.subdistricts.size}")
|
||||||
|
} ?: run {
|
||||||
|
_subdistrictState.postValue(Result.Error(Exception("Failed to load cities")))
|
||||||
|
Log.e(TAG, "City result was null for province $cityId")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
_subdistrictState.postValue(Result.Error(Exception(e.message ?: "Error loading cities")))
|
||||||
|
Log.e(TAG, "Error fetching cities for province $cityId", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getVillages(subdistrictId: String) {
|
||||||
|
_villagesState.value = Result.Loading
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
|
||||||
|
selectedVillages = subdistrictId
|
||||||
|
val result = repository.getListVillages(subdistrictId)
|
||||||
|
result?.let {
|
||||||
|
_villagesState.postValue(Result.Success(it.villages))
|
||||||
|
Log.d(TAG, "Cities loaded for province $subdistrictId: ${it.villages.size}")
|
||||||
|
} ?: run {
|
||||||
|
_villagesState.postValue(Result.Error(Exception("Failed to load cities")))
|
||||||
|
Log.e(TAG, "City result was null for province $subdistrictId")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
_villagesState.postValue(Result.Error(Exception(e.message ?: "Error loading cities")))
|
||||||
|
Log.e(TAG, "Error fetching cities for province $subdistrictId", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setSelectedProvinceId(id: Int) {
|
fun setSelectedProvinceId(id: Int) {
|
||||||
selectedProvinceId = id
|
selectedProvinceId = id
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSelectedCityId(id: String) {
|
fun detailAddress(addressId: Int){
|
||||||
selectedCityId = id
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadUserProfile(){
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
when (val result = userRepo.fetchUserProfile()){
|
try {
|
||||||
is Result.Success -> _userProfile.postValue(result.data)
|
val response = repository.getAddressDetail(addressId)
|
||||||
is Result.Error -> _errorMessageUser.postValue(result.exception.message ?: "Unknown Error")
|
if (response != null){
|
||||||
is Result.Loading -> null
|
_userAddress.value = response.address
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Failed load address detail")
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e:Exception){
|
||||||
|
Log.e(TAG, "Error fetching address detail: $e", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateAddress(oldAddress: AddressDetail, newAddress: AddressDetail) {
|
||||||
|
val params = buildUpdateBody(oldAddress, newAddress)
|
||||||
|
if (params.isEmpty()) {
|
||||||
|
Log.d(TAG, "No changes detected")
|
||||||
|
_editAddress.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
val response = repository.updateAddress(oldAddress.id, params)
|
||||||
|
_editAddress.value = response.isSuccessful
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Error: ${e.message}")
|
||||||
|
_editAddress.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildUpdateBody(oldAddress: AddressDetail, newAddress: AddressDetail): Map<String, Any> {
|
||||||
|
|
||||||
|
val params = mutableMapOf<String, Any>()
|
||||||
|
|
||||||
|
fun addIfChanged(key: String, oldValue: Any?, newValue: Any?) {
|
||||||
|
if (newValue != null && newValue != oldValue) {
|
||||||
|
params[key] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addIfChanged("street", oldAddress.street, newAddress.street)
|
||||||
|
addIfChanged("province_id", oldAddress.provinceId, newAddress.provinceId)
|
||||||
|
addIfChanged("detail", oldAddress.detail, newAddress.detail)
|
||||||
|
addIfChanged("subdistrict", oldAddress.subdistrict, newAddress.subdistrict)
|
||||||
|
addIfChanged("city_id", oldAddress.cityId, newAddress.cityId)
|
||||||
|
addIfChanged("village_id", oldAddress.villageId, newAddress.villageId)
|
||||||
|
addIfChanged("postal_code", oldAddress.postalCode, newAddress.postalCode)
|
||||||
|
addIfChanged("phone", oldAddress.phone, newAddress.phone)
|
||||||
|
addIfChanged("recipient", oldAddress.recipient, newAddress.recipient)
|
||||||
|
addIfChanged("latitude", oldAddress.latitude, newAddress.latitude)
|
||||||
|
addIfChanged("longitude", oldAddress.longitude, newAddress.longitude)
|
||||||
|
addIfChanged("is_store_location", oldAddress.isStoreLocation, newAddress.isStoreLocation)
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "AddAddressViewModel"
|
private const val TAG = "AddAddressViewModel"
|
||||||
}
|
}
|
||||||
|
@ -74,13 +74,17 @@ class AddressActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
adapter = AddressAdapter { address ->
|
adapter = AddressAdapter(
|
||||||
// Select the address in the ViewModel
|
onAddressClick = { address ->
|
||||||
viewModel.selectAddress(address.id)
|
viewModel.selectAddress(address.id)
|
||||||
|
returnResultAndFinish(address.id)
|
||||||
// Return immediately with the selected address
|
},
|
||||||
returnResultAndFinish(address.id)
|
onEditClick = { address ->
|
||||||
}
|
val intent = Intent(this, EditAddressActivity::class.java)
|
||||||
|
intent.putExtra(EditAddressActivity.EXTRA_ADDRESS_ID, address.id)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
binding.rvSellerOrder.apply {
|
binding.rvSellerOrder.apply {
|
||||||
layoutManager = LinearLayoutManager(this@AddressActivity)
|
layoutManager = LinearLayoutManager(this@AddressActivity)
|
||||||
|
@ -3,6 +3,7 @@ package com.alya.ecommerce_serang.ui.order.address
|
|||||||
import android.view.LayoutInflater
|
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.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
@ -13,7 +14,8 @@ import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressesIte
|
|||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
|
||||||
class AddressAdapter(
|
class AddressAdapter(
|
||||||
private val onAddressClick: (AddressesItem) -> Unit
|
private val onAddressClick: (AddressesItem) -> Unit,
|
||||||
|
private val onEditClick: (AddressesItem) -> Unit
|
||||||
) : ListAdapter<AddressesItem, AddressAdapter.AddressViewHolder>(DIFF_CALLBACK) {
|
) : ListAdapter<AddressesItem, AddressAdapter.AddressViewHolder>(DIFF_CALLBACK) {
|
||||||
|
|
||||||
private var selectedAddressId: Int? = null
|
private var selectedAddressId: Int? = null
|
||||||
@ -47,18 +49,21 @@ class AddressAdapter(
|
|||||||
// Pass the whole address object to provide more context
|
// Pass the whole address object to provide more context
|
||||||
onAddressClick(address)
|
onAddressClick(address)
|
||||||
}
|
}
|
||||||
|
holder.editButton.setOnClickListener {
|
||||||
|
onEditClick(address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddressViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
class AddressViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
private val tvName: TextView = itemView.findViewById(R.id.tv_name_address)
|
private val tvName: TextView = itemView.findViewById(R.id.tv_name_address)
|
||||||
private val tvDetail: TextView = itemView.findViewById(R.id.tv_detail_address)
|
private val tvDetail: TextView = itemView.findViewById(R.id.tv_detail_address)
|
||||||
|
val editButton: ImageView = itemView.findViewById(R.id.iv_edit)
|
||||||
private val card: MaterialCardView = itemView as MaterialCardView
|
private val card: MaterialCardView = itemView as MaterialCardView
|
||||||
|
|
||||||
fun bind(address: AddressesItem, isSelected: Boolean) {
|
fun bind(address: AddressesItem, isSelected: Boolean) {
|
||||||
tvName.text = address.recipient
|
tvName.text = address.recipient
|
||||||
tvDetail.text = "${address.street}, ${address.subdistrict}, ${address.phone}"
|
tvDetail.text = "${address.street}, ${address.subdistrict}, ${address.phone}"
|
||||||
|
|
||||||
// Make selection more visible
|
|
||||||
card.strokeWidth = if (isSelected) 3 else 0
|
card.strokeWidth = if (isSelected) 3 else 0
|
||||||
card.strokeColor = if (isSelected)
|
card.strokeColor = if (isSelected)
|
||||||
ContextCompat.getColor(itemView.context, R.color.blue_400)
|
ContextCompat.getColor(itemView.context, R.color.blue_400)
|
||||||
|
@ -1,21 +1,418 @@
|
|||||||
package com.alya.ecommerce_serang.ui.order.address
|
package com.alya.ecommerce_serang.ui.order.address
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import com.alya.ecommerce_serang.R
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CitiesItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.ProvincesItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.SubdistrictsItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.VillagesItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.profile.AddressDetail
|
||||||
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||||
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||||
|
import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||||
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
|
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||||
|
import com.alya.ecommerce_serang.databinding.ActivityEditAddressBinding
|
||||||
|
import com.alya.ecommerce_serang.utils.SavedStateViewModelFactory
|
||||||
|
import com.alya.ecommerce_serang.utils.SessionManager
|
||||||
|
|
||||||
class EditAddressActivity : AppCompatActivity() {
|
class EditAddressActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
private lateinit var binding: ActivityEditAddressBinding
|
||||||
enableEdgeToEdge()
|
private lateinit var apiService: ApiService
|
||||||
setContentView(R.layout.activity_edit_address)
|
private lateinit var sessionManager: SessionManager
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
private var latitude: Double? = null
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
private var longitude: Double? = null
|
||||||
insets
|
private var addressId: Int = -1
|
||||||
|
private var currentAddress: AddressDetail? = null
|
||||||
|
private val provinceAdapter by lazy { ProvinceAdapter(this) }
|
||||||
|
private val cityAdapter by lazy { CityAdapter(this) }
|
||||||
|
private val subdistrictAdapter by lazy { SubdsitrictAdapter(this)}
|
||||||
|
private val villageAdapter by lazy { VillagesAdapter(this)}
|
||||||
|
|
||||||
|
private var provincesList = mutableListOf<ProvincesItem>()
|
||||||
|
private var citiesList = mutableListOf<CitiesItem>()
|
||||||
|
private var subdistrictsList = mutableListOf<SubdistrictsItem>()
|
||||||
|
private var villagesList = mutableListOf<VillagesItem>()
|
||||||
|
|
||||||
|
private val viewModel: AddAddressViewModel by viewModels {
|
||||||
|
SavedStateViewModelFactory(this) { savedStateHandle ->
|
||||||
|
val apiService = ApiConfig.getApiService(sessionManager)
|
||||||
|
val orderRepository = OrderRepository(apiService)
|
||||||
|
val userRepository = UserRepository(apiService)
|
||||||
|
AddAddressViewModel(orderRepository, userRepository, savedStateHandle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityEditAddressBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
sessionManager = SessionManager(this)
|
||||||
|
apiService = ApiConfig.getApiService(sessionManager)
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
|
enableEdgeToEdge()
|
||||||
|
|
||||||
|
// Apply insets to your root layout
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
||||||
|
val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
view.setPadding(
|
||||||
|
systemBars.left,
|
||||||
|
systemBars.top,
|
||||||
|
systemBars.right,
|
||||||
|
systemBars.bottom
|
||||||
|
)
|
||||||
|
windowInsets
|
||||||
|
}
|
||||||
|
|
||||||
|
addressId = intent.getIntExtra(EXTRA_ADDRESS_ID, -1)
|
||||||
|
if (addressId == -1) {
|
||||||
|
Toast.makeText(this, "Gagal mendapatkan alamat pengguna", Toast.LENGTH_SHORT).show()
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setupToolbar()
|
||||||
|
setupAdapters()
|
||||||
|
setupObservers()
|
||||||
|
setupListeners()
|
||||||
|
|
||||||
|
// Load address detail first
|
||||||
|
Log.d(TAG, "Loading address with ID: $addressId")
|
||||||
|
viewModel.detailAddress(addressId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupToolbar() {
|
||||||
|
binding.toolbar.setNavigationOnClickListener {
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupAdapters() {
|
||||||
|
// Set custom adapters to AutoCompleteTextViews
|
||||||
|
binding.autoCompleteProvinsi.setAdapter(provinceAdapter)
|
||||||
|
binding.autoCompleteKabupaten.setAdapter(cityAdapter)
|
||||||
|
binding.autoCompleteKecamatan.setAdapter(subdistrictAdapter)
|
||||||
|
binding.autoCompleteDesa.setAdapter(villageAdapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
// Observe address detail
|
||||||
|
viewModel.userAddress.observe(this) { address ->
|
||||||
|
currentAddress = address
|
||||||
|
Log.d(TAG, "Address loaded: $address")
|
||||||
|
populateAddressData(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe provinces
|
||||||
|
viewModel.provincesState.observe(this) { viewState ->
|
||||||
|
when (viewState) {
|
||||||
|
is ViewState.Loading -> {
|
||||||
|
binding.progressBar.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
is ViewState.Success -> {
|
||||||
|
binding.progressBar.visibility = View.GONE
|
||||||
|
provincesList.clear()
|
||||||
|
provincesList.addAll(viewState.data)
|
||||||
|
provinceAdapter.updateData(viewState.data)
|
||||||
|
|
||||||
|
// Set selected province if address is loaded
|
||||||
|
currentAddress?.let { address ->
|
||||||
|
setSelectedProvince(address.provinceId.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ViewState.Error -> {
|
||||||
|
binding.progressBar.visibility = View.GONE
|
||||||
|
Log.e(TAG, "Failed to load province ${viewState.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe cities
|
||||||
|
viewModel.citiesState.observe(this) { viewState ->
|
||||||
|
when (viewState) {
|
||||||
|
is ViewState.Loading -> {
|
||||||
|
binding.cityProgressBar.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
is ViewState.Success -> {
|
||||||
|
binding.cityProgressBar.visibility = View.GONE
|
||||||
|
citiesList.clear()
|
||||||
|
citiesList.addAll(viewState.data)
|
||||||
|
cityAdapter.updateData(viewState.data)
|
||||||
|
|
||||||
|
// Set selected city if address is loaded
|
||||||
|
currentAddress?.let { address ->
|
||||||
|
setSelectedCity(address.cityId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ViewState.Error -> {
|
||||||
|
binding.cityProgressBar.visibility = View.GONE
|
||||||
|
Log.e(TAG, "Failed to load cities ${viewState.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe subdistricts
|
||||||
|
viewModel.subdistrictState.observe(this) { result ->
|
||||||
|
when (result) {
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Loading -> {
|
||||||
|
// You can add loading indicator for subdistrict if needed
|
||||||
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Success -> {
|
||||||
|
subdistrictsList.clear()
|
||||||
|
subdistrictsList.addAll(result.data)
|
||||||
|
subdistrictAdapter.updateData(result.data)
|
||||||
|
|
||||||
|
// Set selected subdistrict if address is loaded
|
||||||
|
currentAddress?.let { address ->
|
||||||
|
setSelectedSubdistrict(address.subdistrict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||||
|
Log.e(TAG, "Failed to load subdistricy")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe villages
|
||||||
|
viewModel.villagesState.observe(this) { result ->
|
||||||
|
when (result) {
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Loading -> {
|
||||||
|
// You can add loading indicator for village if needed
|
||||||
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Success -> {
|
||||||
|
villagesList.clear()
|
||||||
|
villagesList.addAll(result.data)
|
||||||
|
villageAdapter.updateData(result.data)
|
||||||
|
|
||||||
|
// Set selected village if address is loaded
|
||||||
|
currentAddress?.let { address ->
|
||||||
|
setSelectedVillage(address.villageId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
Log.e(TAG, "Failed to load villages")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe update result
|
||||||
|
viewModel.editAddress.observe(this) { isSuccess ->
|
||||||
|
binding.submitProgressBar.visibility = View.GONE
|
||||||
|
binding.buttonSimpan.isEnabled = true
|
||||||
|
|
||||||
|
if (isSuccess) {
|
||||||
|
Log.d(TAG, "Address updated successfully")
|
||||||
|
finish()
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Failed to update address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
// Province selection
|
||||||
|
binding.autoCompleteProvinsi.setOnItemClickListener { _, _, position, _ ->
|
||||||
|
val provinceId = provinceAdapter.getProvinceId(position)
|
||||||
|
provinceId?.let { id ->
|
||||||
|
viewModel.getCities(id)
|
||||||
|
|
||||||
|
// Clear dependent dropdowns
|
||||||
|
clearCitySelection()
|
||||||
|
clearSubdistrictSelection()
|
||||||
|
clearVillageSelection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// City selection
|
||||||
|
binding.autoCompleteKabupaten.setOnItemClickListener { _, _, position, _ ->
|
||||||
|
val cityId = cityAdapter.getCityId(position)
|
||||||
|
cityId?.let { id ->
|
||||||
|
viewModel.getSubdistrict(id)
|
||||||
|
|
||||||
|
// Clear dependent dropdowns
|
||||||
|
clearSubdistrictSelection()
|
||||||
|
clearVillageSelection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subdistrict selection
|
||||||
|
binding.autoCompleteKecamatan.setOnItemClickListener { _, _, position, _ ->
|
||||||
|
val subdistrictId = subdistrictAdapter.getSubdistrictId(position)
|
||||||
|
subdistrictId?.let { id ->
|
||||||
|
viewModel.getVillages(id)
|
||||||
|
|
||||||
|
// Clear dependent dropdowns
|
||||||
|
clearVillageSelection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Village selection - auto-populate postal code
|
||||||
|
binding.autoCompleteDesa.setOnItemClickListener { _, _, position, _ ->
|
||||||
|
// val postalCode = villageAdapter.getPostalCode(position)
|
||||||
|
// postalCode?.let {
|
||||||
|
// binding.etKodePos.setText(it)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save button
|
||||||
|
binding.buttonSimpan.setOnClickListener {
|
||||||
|
saveAddress()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun populateAddressData(address: AddressDetail) {
|
||||||
|
binding.etNamaPenerima.setText(address.recipient ?: "")
|
||||||
|
binding.etNomorHp.setText(address.phone ?: "")
|
||||||
|
binding.etDetailAlamat.setText(address.detail ?: "")
|
||||||
|
binding.etKodePos.setText(address.postalCode ?: "")
|
||||||
|
|
||||||
|
// Province will be set when provinces are loaded
|
||||||
|
// City, subdistrict, village will be set in their respective observers
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSelectedProvince(provinceId: Int?) {
|
||||||
|
provinceId?.let { id ->
|
||||||
|
val position = provincesList.indexOfFirst { it.provinceId?.toIntOrNull() == id }
|
||||||
|
if (position >= 0) {
|
||||||
|
val provinceName = provincesList[position].province
|
||||||
|
binding.autoCompleteProvinsi.setText(provinceName, false)
|
||||||
|
viewModel.getCities(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSelectedCity(cityId: String?) {
|
||||||
|
cityId?.let { id ->
|
||||||
|
val position = citiesList.indexOfFirst { it.cityId?.toString() == id }
|
||||||
|
if (position >= 0) {
|
||||||
|
val cityName = citiesList[position].cityName
|
||||||
|
binding.autoCompleteKabupaten.setText(cityName, false)
|
||||||
|
viewModel.getSubdistrict(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSelectedSubdistrict(subdistrictId: String?) {
|
||||||
|
subdistrictId?.let { id ->
|
||||||
|
val position = subdistrictsList.indexOfFirst { it.subdistrictId?.toString() == id }
|
||||||
|
if (position >= 0) {
|
||||||
|
val subdistrictName = subdistrictsList[position].subdistrictName
|
||||||
|
binding.autoCompleteKecamatan.setText(subdistrictName, false)
|
||||||
|
viewModel.getVillages(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSelectedVillage(villageId: String?) {
|
||||||
|
villageId?.let { id ->
|
||||||
|
val position = villagesList.indexOfFirst { it.villageId?.toString() == id }
|
||||||
|
if (position >= 0) {
|
||||||
|
val villageName = villagesList[position].villageName
|
||||||
|
binding.autoCompleteDesa.setText(villageName, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// private fun populatePostalCodeFromVillage(villageId: String?) {
|
||||||
|
// villageId?.let { id ->
|
||||||
|
// val village = villagesList.find { it.villageId?.toString() == id }
|
||||||
|
// village?.postalCode?.let { postalCode ->
|
||||||
|
// if (binding.etKodePos.text.isNullOrEmpty()) {
|
||||||
|
// binding.etKodePos.setText(postalCode)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private fun clearCitySelection() {
|
||||||
|
binding.autoCompleteKabupaten.setText("", false)
|
||||||
|
citiesList.clear()
|
||||||
|
cityAdapter.updateData(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearSubdistrictSelection() {
|
||||||
|
binding.autoCompleteKecamatan.setText("", false)
|
||||||
|
subdistrictsList.clear()
|
||||||
|
subdistrictAdapter.updateData(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearVillageSelection() {
|
||||||
|
binding.autoCompleteDesa.setText("", false)
|
||||||
|
binding.etKodePos.setText("") // Clear postal code when village is cleared
|
||||||
|
villagesList.clear()
|
||||||
|
villageAdapter.updateData(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveAddress() {
|
||||||
|
currentAddress?.let { oldAddress ->
|
||||||
|
val newAddress = createNewAddressFromInputs(oldAddress)
|
||||||
|
|
||||||
|
binding.submitProgressBar.visibility = View.VISIBLE
|
||||||
|
binding.buttonSimpan.isEnabled = false
|
||||||
|
|
||||||
|
viewModel.updateAddress(oldAddress, newAddress)
|
||||||
|
} ?: run {
|
||||||
|
Log.d(TAG, "Address not loaded")
|
||||||
|
Toast.makeText(this, "Gagal mendapatkan alamat", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNewAddressFromInputs(oldAddress: AddressDetail): AddressDetail {
|
||||||
|
val selectedProvinceId = getSelectedProvinceId()
|
||||||
|
val selectedCityId = getSelectedCityId()
|
||||||
|
val selectedSubdistrictId = getSelectedSubdistrictId()
|
||||||
|
val selectedVillageId = getSelectedVillageId()
|
||||||
|
|
||||||
|
return oldAddress.copy(
|
||||||
|
recipient = binding.etNamaPenerima.text.toString().trim(),
|
||||||
|
phone = binding.etNomorHp.text.toString().trim(),
|
||||||
|
detail = binding.etDetailAlamat.text.toString().trim(),
|
||||||
|
postalCode = binding.etKodePos.text.toString().trim(),
|
||||||
|
provinceId = selectedProvinceId.toString(),
|
||||||
|
cityId = selectedCityId.toString(),
|
||||||
|
subdistrict = selectedSubdistrictId.toString(),
|
||||||
|
villageId = selectedVillageId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSelectedProvinceId(): Int? {
|
||||||
|
val selectedText = binding.autoCompleteProvinsi.text.toString()
|
||||||
|
val position = provincesList.indexOfFirst { it.province == selectedText }
|
||||||
|
return if (position >= 0) provinceAdapter.getProvinceId(position) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSelectedCityId(): String? {
|
||||||
|
val selectedText = binding.autoCompleteKabupaten.text.toString()
|
||||||
|
val position = citiesList.indexOfFirst { it.cityName == selectedText }
|
||||||
|
return if (position >= 0) cityAdapter.getCityId(position) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSelectedSubdistrictId(): String? {
|
||||||
|
val selectedText = binding.autoCompleteKecamatan.text.toString()
|
||||||
|
val position = subdistrictsList.indexOfFirst { it.subdistrictName == selectedText }
|
||||||
|
return if (position >= 0) subdistrictAdapter.getSubdistrictId(position) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSelectedVillageId(): String? {
|
||||||
|
val selectedText = binding.autoCompleteDesa.text.toString()
|
||||||
|
val position = villagesList.indexOfFirst { it.villageName == selectedText }
|
||||||
|
return if (position >= 0) villageAdapter.getVillageId(position) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EXTRA_ADDRESS_ID = "extra_address_id"
|
||||||
|
private const val TAG = "EditAddressActivity"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -5,6 +5,257 @@
|
|||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.order.address.EditAddressActivity">
|
android:background="@android:color/white"
|
||||||
|
tools:context=".ui.order.address.AddAddressActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:navigationIcon="@drawable/ic_back_24"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:title="Ubah Alamat" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="#E0E0E0"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/buttonSimpan"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/divider">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Nama Penerima"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etNamaPenerima"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/edit_text_background"
|
||||||
|
android:hint="Isi nama penerima"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Nomor Hp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etNomorHp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/edit_text_background"
|
||||||
|
android:hint="Isi nomor handphone aktif"
|
||||||
|
android:inputType="phone"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Detail Alamat"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etDetailAlamat"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/edit_text_background"
|
||||||
|
android:gravity="top"
|
||||||
|
android:hint="Isi detail alamat (nomor rumah, lantai, dll)"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:lines="3"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<!-- Provinsi -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Provinsi"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:hint="Pilih Provinsi"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
|
||||||
|
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/autoCompleteProvinsi"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Kabupaten / Kota -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Kabupaten / Kota"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:hint="Pilih Kota / Kabupaten"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
|
||||||
|
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/autoCompleteKabupaten"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/cityProgressBar"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- Kecamatan -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Kecamatan"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:hint="Pilih Kecamatan"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/autoCompleteKecamatan"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Desa"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:hint="Pilih Desa"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/autoCompleteDesa"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Kode Pos"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etKodePos"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/edit_text_background"
|
||||||
|
android:hint="Isi jawaban Anda di sini"
|
||||||
|
android:inputType="number"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSimpan"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:background="@drawable/button_address_background"
|
||||||
|
android:text="Simpan"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/submitProgressBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/buttonSimpan"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -36,8 +36,9 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/baseline_edit_24"
|
android:src="@drawable/baseline_edit_24"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="true"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
<TextView
|
<TextView
|
||||||
|
Reference in New Issue
Block a user