diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3e68783..4259d5c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,8 @@
+
+
-
+ @Body createAddressRequest: CreateAddressRequest
+ ): Response
@GET("mystore")
suspend fun getStore (): Response
@@ -95,8 +100,23 @@ interface ApiService {
@Body cartRequest: CartItem
): Response
+ @PUT("cart/update")
+ suspend fun updateCart(
+ @Body updateCart: UpdateCart
+ ): Response
+
@POST("couriercost")
suspend fun countCourierCost(
@Body courierCost : CourierCostRequest
- ): CourierCostResponse
+ ): Response
+
+ @GET("cities/{id}")
+ suspend fun getCityProvId(
+ @Path("id") provId : Int
+ ): Response
+
+ @GET("provinces")
+ suspend fun getListProv(
+ ): Response
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt
index c4c0114..c924899 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt
@@ -1,10 +1,14 @@
package com.alya.ecommerce_serang.data.repository
import android.util.Log
+import com.alya.ecommerce_serang.data.api.dto.CreateAddressRequest
import com.alya.ecommerce_serang.data.api.dto.OrderRequest
import com.alya.ecommerce_serang.data.api.response.order.CreateOrderResponse
+import com.alya.ecommerce_serang.data.api.response.order.ListCityResponse
+import com.alya.ecommerce_serang.data.api.response.order.ListProvinceResponse
import com.alya.ecommerce_serang.data.api.response.product.ProductResponse
import com.alya.ecommerce_serang.data.api.response.product.StoreResponse
+import com.alya.ecommerce_serang.data.api.response.profile.CreateAddressResponse
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import retrofit2.Response
@@ -33,17 +37,31 @@ class OrderRepository(private val apiService: ApiService) {
return if (response.isSuccessful) response.body() else null
}
+ //post data with message/response
+ suspend fun addAddress(createAddressRequest: CreateAddressRequest): Result {
+ return try {
+ val response = apiService.createAddress(createAddressRequest)
+ if (response.isSuccessful){
+ response.body()?.let {
+ Result.Success(it)
+ } ?: Result.Error(Exception("Add Address failed"))
+ } else {
+ Log.e("OrderRepository", "Error: ${response.errorBody()?.string()}")
+ Result.Error(Exception(response.errorBody()?.string() ?: "Unknown error"))
+ }
+ } catch (e: Exception) {
+ Result.Error(e)
+ }
+ }
- //not yet implement the api service address
-// suspend fun getAddressDetails(addressId: Int): AddressesItem {
-// // Simulate API call to get address details
-// kotlinx.coroutines.delay(300) // Simulate network request
-// // Return mock data
-// return AddressesItem(
-// id = addressId,
-// label = "Rumah",
-// fullAddress = "Jl. Pegangasan Timur No. 42, Jakarta"
-// )
-// }
+ suspend fun getListProvinces(): ListProvinceResponse? {
+ val response = apiService.getListProv()
+ return if (response.isSuccessful) response.body() else null
+ }
+
+ suspend fun getListCities(provId : Int): ListCityResponse?{
+ val response = apiService.getCityProvId(provId)
+ return if (response.isSuccessful) response.body() else null
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt
index 15fde04..5b4c97c 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt
@@ -10,12 +10,9 @@ import com.alya.ecommerce_serang.data.api.retrofit.ApiService
class UserRepository(private val apiService: ApiService) {
+ //post data without message/response
suspend fun requestOtpRep(email: String): OtpResponse {
-
-// fun requestOtpRep(email: String): Result {
-
return apiService.getOTP(OtpRequest(email))
-
}
suspend fun registerUser(request: RegisterRequest): String {
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressActivity.kt
index eaad1db..86b16d5 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressActivity.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressActivity.kt
@@ -1,21 +1,289 @@
package com.alya.ecommerce_serang.ui.order
+import android.annotation.SuppressLint
+import android.content.pm.PackageManager
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
-import com.alya.ecommerce_serang.R
+import androidx.constraintlayout.motion.widget.Debug.getLocation
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+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.order.CitiesItem
+import com.alya.ecommerce_serang.data.api.response.order.ProvincesItem
+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.databinding.ActivityAddAddressBinding
+import com.alya.ecommerce_serang.utils.SavedStateViewModelFactory
+import com.alya.ecommerce_serang.utils.SessionManager
+import kotlinx.coroutines.launch
class AddAddressActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContentView(R.layout.activity_add_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: ActivityAddAddressBinding
+ private lateinit var apiService: ApiService
+ private lateinit var sessionManager: SessionManager
+ private lateinit var profileUser: UserProfile
+ private lateinit var locationManager: LocationManager
+
+ private var latitude: Double? = null
+ private var longitude: Double? = null
+ private val provinceAdapter by lazy { ProvinceAdapter(this) }
+ private val cityAdapter by lazy { CityAdapter(this) }
+
+ private val viewModel: AddAddressViewModel by viewModels {
+ SavedStateViewModelFactory(this) { savedStateHandle ->
+ val apiService = ApiConfig.getApiService(sessionManager)
+ val orderRepository = OrderRepository(apiService)
+ AddAddressViewModel(orderRepository, savedStateHandle)
}
}
-}
\ No newline at end of file
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityAddAddressBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ sessionManager = SessionManager(this)
+ apiService = ApiConfig.getApiService(sessionManager)
+ locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
+
+ setupToolbar()
+ setupAutoComplete()
+ setupButtonListeners()
+ collectFlows()
+ requestLocationPermission()
+
+
+ }
+
+ private fun viewModelAddAddress(request: CreateAddressRequest) {
+ // Call the private fun in your ViewModel using reflection or expose it in ViewModel
+ val method = AddAddressViewModel::class.java.getDeclaredMethod("addAddress", CreateAddressRequest::class.java)
+ method.isAccessible = true
+ method.invoke(viewModel, request)
+ }
+ // UI setup methods
+ private fun setupToolbar() {
+ binding.toolbar.setNavigationOnClickListener { finish() }
+ }
+
+ private fun setupAutoComplete() {
+ // Set adapters
+ binding.autoCompleteProvinsi.setAdapter(provinceAdapter)
+ binding.autoCompleteKabupaten.setAdapter(cityAdapter)
+
+ // Set listeners
+ binding.autoCompleteProvinsi.setOnItemClickListener { _, _, position, _ ->
+ provinceAdapter.getProvinceId(position)?.let { provinceId ->
+ viewModel.getCities(provinceId)
+ binding.autoCompleteKabupaten.text.clear()
+ }
+ }
+
+ binding.autoCompleteKabupaten.setOnItemClickListener { _, _, position, _ ->
+ cityAdapter.getCityId(position)?.let { cityId ->
+ viewModel.selectedCityId = cityId
+ }
+ }
+ }
+
+ private fun setupButtonListeners() {
+ binding.buttonSimpan.setOnClickListener {
+ validateAndSubmitForm()
+ }
+ }
+
+ private fun collectFlows() {
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.provincesState.collect { state ->
+ handleProvinceState(state)
+ }
+ }
+
+ launch {
+ viewModel.citiesState.collect { state ->
+ handleCityState(state)
+ }
+ }
+
+ launch {
+ viewModel.addressSubmissionState.collect { state ->
+ handleAddressSubmissionState(state)
+ }
+ }
+ }
+ }
+ }
+
+ private fun handleProvinceState(state: ViewState>) {
+ when (state) {
+ is ViewState.Loading -> null //showProvinceLoading(true)
+ is ViewState.Success -> {
+ provinceAdapter.updateData(state.data)
+ }
+ is ViewState.Error -> {
+ showError(state.message)
+ }
+ }
+ }
+
+ private fun handleCityState(state: ViewState>) {
+ when (state) {
+ is ViewState.Loading -> null //showCityLoading(true)
+ is ViewState.Success -> {
+// showCityLoading(false)
+ cityAdapter.updateData(state.data)
+ }
+ is ViewState.Error -> {
+// showCityLoading(false)
+ showError(state.message)
+ }
+ }
+ }
+
+ private fun handleAddressSubmissionState(state: ViewState) {
+ when (state) {
+ is ViewState.Loading -> showSubmitLoading(true)
+ is ViewState.Success -> {
+ showSubmitLoading(false)
+ showSuccessAndFinish(state.data)
+ }
+ is ViewState.Error -> {
+ showSubmitLoading(false)
+ showError(state.message)
+ }
+ }
+ }
+
+// private fun showProvinceLoading(isLoading: Boolean) {
+// // Implement province loading indicator
+// binding.provinceProgressBar?.visibility = if (isLoading) View.VISIBLE else View.GONE
+// }
+//
+// private fun showCityLoading(isLoading: Boolean) {
+// // Implement city loading indicator
+// binding.cityProgressBar?.visibility = if (isLoading) View.VISIBLE else View.GONE
+// }
+//
+ private fun showSubmitLoading(isLoading: Boolean) {
+ binding.buttonSimpan.isEnabled = !isLoading
+ binding.buttonSimpan.text = if (isLoading) "Menyimpan..." else "Simpan"
+ // You might want to show a progress bar as well
+ }
+
+ private fun showError(message: String) {
+ Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
+ }
+
+ private fun showSuccessAndFinish(message: String) {
+ Toast.makeText(this, "Sukses: $message", Toast.LENGTH_SHORT).show()
+ finish()
+ }
+
+ private fun validateAndSubmitForm() {
+ val lat = latitude
+ val long = longitude
+
+ if (lat == null || long == null) {
+ showError("Lokasi belum terdeteksi")
+ return
+ }
+
+ val street = binding.etDetailAlamat.text.toString()
+ val subDistrict = binding.etKecamatan.text.toString()
+ val postalCode = binding.etKodePos.text.toString()
+ val recipient = binding.etNamaPenerima.text.toString()
+ val phone = binding.etNomorHp.text.toString()
+ val userId = profileUser.userId
+ val isStoreLocation = false
+
+ val provinceId = viewModel.selectedProvinceId
+ val cityId = viewModel.selectedCityId
+
+ if (street.isBlank() || recipient.isBlank() || phone.isBlank()) {
+ showError("Lengkapi semua field wajib")
+ return
+ }
+
+ if (provinceId == null) {
+ showError("Pilih provinsi terlebih dahulu")
+ return
+ }
+
+ if (cityId == null) {
+ showError("Pilih kota/kabupaten terlebih dahulu")
+ return
+ }
+
+ val request = CreateAddressRequest(
+ lat = lat,
+ long = long,
+ street = street,
+ subDistrict = subDistrict,
+ cityId = cityId,
+ provId = provinceId,
+ postCode = postalCode,
+ detailAddress = street,
+ userId = userId,
+ recipient = recipient,
+ phone = phone,
+ isStoreLocation = isStoreLocation
+ )
+
+ viewModel.addAddress(request)
+ }
+
+ private val locationPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
+ if (granted) getLocation() else Toast.makeText(this, "Izin lokasi ditolak",Toast.LENGTH_SHORT).show()
+ }
+
+ private fun requestLocationPermission() {
+ locationPermissionLauncher.launch(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ }
+
+ @SuppressLint("MissingPermission")
+ private fun requestLocation() {
+ val isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
+ val isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
+
+ if (!isGpsEnabled && !isNetworkEnabled) {
+ Toast.makeText(this, "Provider lokasi tidak tersedia", Toast.LENGTH_SHORT).show()
+ return
+ }
+
+ val provider = if (isGpsEnabled) LocationManager.GPS_PROVIDER else LocationManager.NETWORK_PROVIDER
+
+ locationManager.requestSingleUpdate(provider, object : LocationListener {
+ override fun onLocationChanged(location: Location) {
+ latitude = location.latitude
+ longitude = location.longitude
+ }
+
+ override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
+ override fun onProviderEnabled(provider: String) {}
+ override fun onProviderDisabled(provider: String) {
+ Toast.makeText(this@AddAddressActivity, "Provider dimatikan", Toast.LENGTH_SHORT).show()
+ }
+ }, null)
+ }
+
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == 100 && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ requestLocation()
+ } else {
+ Toast.makeText(this, "Location permission denied", Toast.LENGTH_SHORT).show()
+ }
+ }
+}
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressViewModel.kt
new file mode 100644
index 0000000..0f1e09c
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/AddAddressViewModel.kt
@@ -0,0 +1,105 @@
+package com.alya.ecommerce_serang.ui.order
+
+import android.util.Log
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.alya.ecommerce_serang.data.api.dto.CreateAddressRequest
+import com.alya.ecommerce_serang.data.api.response.order.CitiesItem
+import com.alya.ecommerce_serang.data.api.response.order.ProvincesItem
+import com.alya.ecommerce_serang.data.repository.OrderRepository
+import com.alya.ecommerce_serang.data.repository.Result
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+class AddAddressViewModel(private val repository: OrderRepository, private val savedStateHandle: SavedStateHandle): ViewModel() {
+ // Flow states for data
+ private val _addressSubmissionState = MutableStateFlow>(com.alya.ecommerce_serang.ui.order.ViewState.Loading)
+ val addressSubmissionState = _addressSubmissionState.asStateFlow()
+
+ private val _provincesState = MutableStateFlow>>(com.alya.ecommerce_serang.ui.order.ViewState.Loading)
+ val provincesState = _provincesState.asStateFlow()
+
+ private val _citiesState = MutableStateFlow>>(com.alya.ecommerce_serang.ui.order.ViewState.Loading)
+ val citiesState = _citiesState.asStateFlow()
+
+ // Stored in SavedStateHandle for configuration changes
+ var selectedProvinceId: Int?
+ get() = savedStateHandle.get("selectedProvinceId")
+ set(value) { savedStateHandle["selectedProvinceId"] = value }
+
+ var selectedCityId: Int?
+ get() = savedStateHandle.get("selectedCityId")
+ set(value) { savedStateHandle["selectedCityId"] = value }
+
+ init {
+ // Load provinces on initialization
+ getProvinces()
+ }
+
+ fun addAddress(request: CreateAddressRequest){
+ viewModelScope.launch {
+ when (val result = repository.addAddress(request)) {
+ is Result.Success -> {
+ val message = result.data.message // Ambil `message` dari CreateAddressResponse
+ _addressSubmissionState.value = ViewState.Success(message)
+ }
+ is Result.Error -> {
+ _addressSubmissionState.value = ViewState.Error(result.exception.message ?: "Unknown error")
+ }
+ is Result.Loading -> {
+ // Optional, karena sudah set Loading di awal
+ }
+ }
+ }
+ }
+
+ fun getProvinces(){
+ viewModelScope.launch {
+ try {
+ val result = repository.getListProvinces()
+ result?.let {
+ _provincesState.value = com.alya.ecommerce_serang.ui.order.ViewState.Success(it.provinces)
+ }
+ } catch (e: Exception) {
+ Log.e("AddAddressViewModel", "Error fetching provinces: ${e.message}")
+ }
+ }
+ }
+
+ fun getCities(provinceId: Int){
+ viewModelScope.launch {
+ try {
+ selectedProvinceId = provinceId
+ val result = repository.getListCities(provinceId)
+ result?.let {
+ _citiesState.value = com.alya.ecommerce_serang.ui.order.ViewState.Success(it.cities)
+ }
+ } catch (e: Exception) {
+ Log.e("AddAddressViewModel", "Error fetching cities: ${e.message}")
+ }
+ }
+ }
+
+ fun setSelectedProvinceId(id: Int) {
+ selectedProvinceId = id
+ }
+
+ fun setSelectedCityId(id: Int) {
+ selectedCityId = id
+ }
+
+ fun getSelectedProvinceId(): Int? = selectedProvinceId
+ fun getSelectedCityId(): Int? = selectedCityId
+
+ companion object {
+ private const val TAG = "AddAddressViewModel"
+ }
+}
+
+sealed class ViewState {
+ object Loading : com.alya.ecommerce_serang.ui.order.ViewState()
+ data class Success(val data: T) : com.alya.ecommerce_serang.ui.order.ViewState()
+ data class Error(val message: String) : com.alya.ecommerce_serang.ui.order.ViewState()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/ProvinceAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/ProvinceAdapter.kt
new file mode 100644
index 0000000..5af133a
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/ProvinceAdapter.kt
@@ -0,0 +1,49 @@
+package com.alya.ecommerce_serang.ui.order
+
+import android.content.Context
+import android.widget.ArrayAdapter
+import com.alya.ecommerce_serang.data.api.response.order.CitiesItem
+import com.alya.ecommerce_serang.data.api.response.order.ProvincesItem
+
+// UI adapters and helpers
+class ProvinceAdapter(
+ context: Context,
+ resource: Int = android.R.layout.simple_dropdown_item_1line
+) : ArrayAdapter(context, resource, ArrayList()) {
+
+ private val provinces = ArrayList()
+
+ fun updateData(newProvinces: List) {
+ provinces.clear()
+ provinces.addAll(newProvinces)
+
+ clear()
+ addAll(provinces.map { it.province })
+ notifyDataSetChanged()
+ }
+
+ fun getProvinceId(position: Int): Int? {
+ return provinces.getOrNull(position)?.provinceId?.toIntOrNull()
+ }
+}
+
+class CityAdapter(
+ context: Context,
+ resource: Int = android.R.layout.simple_dropdown_item_1line
+) : ArrayAdapter(context, resource, ArrayList()) {
+
+ private val cities = ArrayList()
+
+ fun updateData(newCities: List) {
+ cities.clear()
+ cities.addAll(newCities)
+
+ clear()
+ addAll(cities.map { it.cityName })
+ notifyDataSetChanged()
+ }
+
+ fun getCityId(position: Int): Int? {
+ return cities.getOrNull(position)?.cityId?.toIntOrNull()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt
index 9673190..e224d9e 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt
@@ -1,7 +1,10 @@
package com.alya.ecommerce_serang.utils
+import androidx.lifecycle.AbstractSavedStateViewModelFactory
+import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
+import androidx.savedstate.SavedStateRegistryOwner
class BaseViewModelFactory(
private val creator: () -> VM
@@ -10,4 +13,20 @@ class BaseViewModelFactory(
@Suppress("UNCHECKED_CAST")
return creator() as T
}
+}
+
+// Add a new factory for SavedStateHandle ViewModels
+class SavedStateViewModelFactory(
+ private val owner: SavedStateRegistryOwner,
+ private val creator: (SavedStateHandle) -> VM
+) : AbstractSavedStateViewModelFactory(owner, null) {
+
+ @Suppress("UNCHECKED_CAST")
+ override fun create(
+ key: String,
+ modelClass: Class,
+ handle: SavedStateHandle
+ ): T {
+ return creator(handle) as T
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_add_address.xml b/app/src/main/res/layout/activity_add_address.xml
index a65d055..8872804 100644
--- a/app/src/main/res/layout/activity_add_address.xml
+++ b/app/src/main/res/layout/activity_add_address.xml
@@ -131,7 +131,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:hint="Pilih Kabupaten / Kota"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
diff --git a/app/src/main/res/layout/activity_address.xml b/app/src/main/res/layout/activity_address.xml
index 6ad6c1d..ec92734 100644
--- a/app/src/main/res/layout/activity_address.xml
+++ b/app/src/main/res/layout/activity_address.xml
@@ -29,9 +29,11 @@
android:textAlignment="textEnd"
android:layout_gravity="center"
android:paddingEnd="16dp"
+ android:paddingVertical="16dp"
android:textColor="@color/blue_500"
android:fontFamily="@font/dmsans_semibold"
android:textSize="14sp"
+ android:clickable="true"
android:text="Tambah Alamat"
tools:ignore="RtlCompat" />
diff --git a/app/src/main/res/layout/activity_checkout.xml b/app/src/main/res/layout/activity_checkout.xml
index 2a992f2..6ffe7e6 100644
--- a/app/src/main/res/layout/activity_checkout.xml
+++ b/app/src/main/res/layout/activity_checkout.xml
@@ -47,13 +47,23 @@
android:layout_gravity="start"
android:padding="8dp">
+
+