mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-16 03:47:24 +00:00
fix address, edit address
This commit is contained in:
@ -82,7 +82,8 @@ data class Product(
|
||||
|
||||
data class CartItemCheckoutInfo(
|
||||
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(
|
||||
|
||||
@field:SerializedName("address")
|
||||
val address: Address,
|
||||
val address: AddressDetail,
|
||||
|
||||
@field:SerializedName("message")
|
||||
val message: String
|
||||
@ -14,7 +14,7 @@ data class AddressDetailResponse(
|
||||
data class AddressDetail(
|
||||
|
||||
@field:SerializedName("village_id")
|
||||
val villageId: String,
|
||||
val villageId: String?,
|
||||
|
||||
@field:SerializedName("is_store_location")
|
||||
val isStoreLocation: Boolean,
|
||||
@ -38,7 +38,7 @@ data class AddressDetail(
|
||||
val provinceId: String,
|
||||
|
||||
@field:SerializedName("phone")
|
||||
val phone: String,
|
||||
val phone: String?,
|
||||
|
||||
@field:SerializedName("street")
|
||||
val street: String,
|
||||
@ -47,7 +47,7 @@ data class AddressDetail(
|
||||
val subdistrict: String,
|
||||
|
||||
@field:SerializedName("recipient")
|
||||
val recipient: String,
|
||||
val recipient: String?,
|
||||
|
||||
@field:SerializedName("id")
|
||||
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.ReviewProductResponse
|
||||
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.CreateAddressResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.profile.EditProfileResponse
|
||||
@ -528,4 +529,9 @@ interface ApiService {
|
||||
suspend fun postResetPass(
|
||||
@Body request: ResetPassReq
|
||||
): 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.OrderDetailResponse
|
||||
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.ProductResponse
|
||||
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.profile.AddressDetailResponse
|
||||
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.UpdateAddressResponse
|
||||
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.CompletedOrderResponse
|
||||
@ -294,6 +298,30 @@ class OrderRepository(private val apiService: ApiService) {
|
||||
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?> {
|
||||
return try {
|
||||
val response = apiService.getUserProfile()
|
||||
@ -319,6 +347,7 @@ class OrderRepository(private val apiService: ApiService) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suspend fun uploadPaymentProof(request: AddEvidenceMultipartRequest): Result<AddEvidenceResponse> {
|
||||
return try {
|
||||
Log.d("OrderRepository", "Uploading payment proof...")
|
||||
|
@ -30,6 +30,8 @@ class CartActivity : AppCompatActivity() {
|
||||
private lateinit var sessionManager: SessionManager
|
||||
private lateinit var storeAdapter: StoreAdapter
|
||||
|
||||
private var TAG = "Cart Activity"
|
||||
|
||||
private val viewModel: CartViewModel by viewModels {
|
||||
BaseViewModelFactory {
|
||||
val apiService = ApiConfig.getApiService(sessionManager)
|
||||
@ -135,11 +137,33 @@ class CartActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun startCheckoutWithWholesaleInfo(checkoutItems: List<CartItemCheckoutInfo>) {
|
||||
// Extract cart item IDs and wholesale status
|
||||
val cartItemIds = checkoutItems.map { it.cartItem.cartItemId }
|
||||
val wholesaleArray = checkoutItems.map { it.isWholesale }.toBooleanArray()
|
||||
val wholesalePriceMap = viewModel.cartItemWholesalePrice.value ?: emptyMap()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -233,7 +257,5 @@ class CartActivity : AppCompatActivity() {
|
||||
val format = NumberFormat.getCurrencyInstance(Locale("id", "ID"))
|
||||
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.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.repository.OrderRepository
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
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>>>()
|
||||
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
|
||||
var selectedProvinceId: Int?
|
||||
get() = savedStateHandle.get<Int>("selectedProvinceId")
|
||||
@ -40,6 +55,9 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u
|
||||
get() = savedStateHandle.get<String>("selectedCityId")
|
||||
set(value) { savedStateHandle["selectedCityId"] = value }
|
||||
|
||||
var selectedSubdistrict: String? = null
|
||||
var selectedVillages: String? = null
|
||||
|
||||
init {
|
||||
// Load provinces on initialization
|
||||
getProvinces()
|
||||
@ -86,6 +104,8 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getProvinces() {
|
||||
_provincesState.value = ViewState.Loading
|
||||
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) {
|
||||
selectedProvinceId = id
|
||||
}
|
||||
|
||||
fun updateSelectedCityId(id: String) {
|
||||
selectedCityId = id
|
||||
}
|
||||
|
||||
fun loadUserProfile(){
|
||||
fun detailAddress(addressId: Int){
|
||||
viewModelScope.launch {
|
||||
when (val result = userRepo.fetchUserProfile()){
|
||||
is Result.Success -> _userProfile.postValue(result.data)
|
||||
is Result.Error -> _errorMessageUser.postValue(result.exception.message ?: "Unknown Error")
|
||||
is Result.Loading -> null
|
||||
try {
|
||||
val response = repository.getAddressDetail(addressId)
|
||||
if (response != 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 {
|
||||
private const val TAG = "AddAddressViewModel"
|
||||
}
|
||||
|
@ -74,13 +74,17 @@ class AddressActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
adapter = AddressAdapter { address ->
|
||||
// Select the address in the ViewModel
|
||||
viewModel.selectAddress(address.id)
|
||||
|
||||
// Return immediately with the selected address
|
||||
returnResultAndFinish(address.id)
|
||||
}
|
||||
adapter = AddressAdapter(
|
||||
onAddressClick = { address ->
|
||||
viewModel.selectAddress(address.id)
|
||||
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 {
|
||||
layoutManager = LinearLayoutManager(this@AddressActivity)
|
||||
|
@ -3,6 +3,7 @@ package com.alya.ecommerce_serang.ui.order.address
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
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
|
||||
|
||||
class AddressAdapter(
|
||||
private val onAddressClick: (AddressesItem) -> Unit
|
||||
private val onAddressClick: (AddressesItem) -> Unit,
|
||||
private val onEditClick: (AddressesItem) -> Unit
|
||||
) : ListAdapter<AddressesItem, AddressAdapter.AddressViewHolder>(DIFF_CALLBACK) {
|
||||
|
||||
private var selectedAddressId: Int? = null
|
||||
@ -47,18 +49,21 @@ class AddressAdapter(
|
||||
// Pass the whole address object to provide more context
|
||||
onAddressClick(address)
|
||||
}
|
||||
holder.editButton.setOnClickListener {
|
||||
onEditClick(address)
|
||||
}
|
||||
}
|
||||
|
||||
class AddressViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
private val tvName: TextView = itemView.findViewById(R.id.tv_name_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
|
||||
|
||||
fun bind(address: AddressesItem, isSelected: Boolean) {
|
||||
tvName.text = address.recipient
|
||||
tvDetail.text = "${address.street}, ${address.subdistrict}, ${address.phone}"
|
||||
|
||||
// Make selection more visible
|
||||
card.strokeWidth = if (isSelected) 3 else 0
|
||||
card.strokeColor = if (isSelected)
|
||||
ContextCompat.getColor(itemView.context, R.color.blue_400)
|
||||
|
@ -1,21 +1,418 @@
|
||||
package com.alya.ecommerce_serang.ui.order.address
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
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.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() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_edit_address)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
|
||||
private lateinit var binding: ActivityEditAddressBinding
|
||||
private lateinit var apiService: ApiService
|
||||
private lateinit var sessionManager: SessionManager
|
||||
|
||||
private var latitude: Double? = null
|
||||
private var longitude: Double? = null
|
||||
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:layout_width="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>
|
@ -36,8 +36,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/baseline_edit_24"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
<TextView
|
||||
|
Reference in New Issue
Block a user