mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-13 02:32:22 +00:00
add cancel and logout
This commit is contained in:
@ -1,50 +1,17 @@
|
|||||||
package com.alya.ecommerce_serang.app
|
package com.alya.ecommerce_serang.app
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.util.Log
|
|
||||||
import com.google.firebase.FirebaseApp
|
|
||||||
import com.google.firebase.messaging.FirebaseMessaging
|
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class App : Application(){
|
class App : Application(){
|
||||||
private val TAG = "AppSerang"
|
// private val TAG = "AppSerang"
|
||||||
|
//
|
||||||
|
//// var tokenTes: String? = null
|
||||||
|
//
|
||||||
|
// override fun onCreate() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
// var tokenTes: String? = null
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
|
|
||||||
// Initialize Firebase
|
|
||||||
FirebaseApp.initializeApp(this)
|
|
||||||
|
|
||||||
// Request FCM token at app startup
|
|
||||||
retrieveFCMToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun retrieveFCMToken() {
|
|
||||||
FirebaseMessaging.getInstance().token
|
|
||||||
.addOnCompleteListener { task ->
|
|
||||||
if (!task.isSuccessful) {
|
|
||||||
Log.e(TAG, "Failed to get FCM token", task.exception)
|
|
||||||
return@addOnCompleteListener
|
|
||||||
}
|
|
||||||
|
|
||||||
val token = task.result
|
|
||||||
// tokenTes = token
|
|
||||||
Log.d(TAG, "FCM token retrieved: $token")
|
|
||||||
|
|
||||||
// Save token locally
|
|
||||||
val sharedPreferences = getSharedPreferences("FCM_PREFS", Context.MODE_PRIVATE)
|
|
||||||
sharedPreferences.edit().putString("FCM_TOKEN", token).apply()
|
|
||||||
|
|
||||||
// Send to your server
|
|
||||||
sendTokenToServer(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sendTokenToServer(token: String) {
|
|
||||||
Log.d(TAG, "Would send token to server: $token")
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.dto
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class CancelOrderReq (
|
||||||
|
@SerializedName("order_id")
|
||||||
|
val orderId: Int,
|
||||||
|
|
||||||
|
@SerializedName("reason")
|
||||||
|
val reason: String
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.response.customer.order
|
||||||
|
|
||||||
|
data class CancelOrderResponse(
|
||||||
|
val data: DataCancel,
|
||||||
|
val message: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class DataCancel(
|
||||||
|
val reason: String,
|
||||||
|
val createdAt: String,
|
||||||
|
val id: Int,
|
||||||
|
val orderId: Int
|
||||||
|
)
|
||||||
|
|
@ -22,6 +22,9 @@ class ApiConfig {
|
|||||||
val client = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.addInterceptor(loggingInterceptor)
|
.addInterceptor(loggingInterceptor)
|
||||||
.addInterceptor(authInterceptor)
|
.addInterceptor(authInterceptor)
|
||||||
|
.connectTimeout(60, TimeUnit.SECONDS) // Increase to 60 seconds
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS) // Increase to 60 seconds
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
|
@ -3,6 +3,7 @@ package com.alya.ecommerce_serang.data.api.retrofit
|
|||||||
|
|
||||||
import com.alya.ecommerce_serang.data.api.dto.AddEvidenceRequest
|
import com.alya.ecommerce_serang.data.api.dto.AddEvidenceRequest
|
||||||
import com.alya.ecommerce_serang.data.api.dto.AddPaymentInfoResponse
|
import com.alya.ecommerce_serang.data.api.dto.AddPaymentInfoResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.CancelOrderReq
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CartItem
|
import com.alya.ecommerce_serang.data.api.dto.CartItem
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CityResponse
|
import com.alya.ecommerce_serang.data.api.dto.CityResponse
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CompletedOrderRequest
|
import com.alya.ecommerce_serang.data.api.dto.CompletedOrderRequest
|
||||||
@ -35,6 +36,7 @@ import com.alya.ecommerce_serang.data.api.response.customer.cart.AddCartResponse
|
|||||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.DeleteCartResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.cart.DeleteCartResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.ListCartResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.cart.ListCartResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.UpdateCartResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.cart.UpdateCartResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CancelOrderResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateOrderResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateOrderResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateReviewResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateReviewResponse
|
||||||
@ -163,6 +165,11 @@ interface ApiService {
|
|||||||
@Body request: OrderRequest
|
@Body request: OrderRequest
|
||||||
): Response<CreateOrderResponse>
|
): Response<CreateOrderResponse>
|
||||||
|
|
||||||
|
@POST("order/cancel")
|
||||||
|
suspend fun cancelOrder(
|
||||||
|
@Body cancelReq: CancelOrderReq
|
||||||
|
): Response<CancelOrderResponse>
|
||||||
|
|
||||||
@GET("order/detail/{id}")
|
@GET("order/detail/{id}")
|
||||||
suspend fun getDetailOrder(
|
suspend fun getDetailOrder(
|
||||||
@Path("id") orderId: Int
|
@Path("id") orderId: Int
|
||||||
|
@ -2,16 +2,17 @@ package com.alya.ecommerce_serang.data.repository
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.alya.ecommerce_serang.data.api.dto.AddEvidenceMultipartRequest
|
import com.alya.ecommerce_serang.data.api.dto.AddEvidenceMultipartRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.CancelOrderReq
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CompletedOrderRequest
|
import com.alya.ecommerce_serang.data.api.dto.CompletedOrderRequest
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CourierCostRequest
|
import com.alya.ecommerce_serang.data.api.dto.CourierCostRequest
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CreateAddressRequest
|
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.dto.OrderRequest
|
||||||
import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy
|
import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy
|
||||||
import com.alya.ecommerce_serang.data.api.dto.OrdersItem
|
|
||||||
import com.alya.ecommerce_serang.data.api.dto.ReviewProductItem
|
import com.alya.ecommerce_serang.data.api.dto.ReviewProductItem
|
||||||
import com.alya.ecommerce_serang.data.api.dto.UpdateCart
|
import com.alya.ecommerce_serang.data.api.dto.UpdateCart
|
||||||
import com.alya.ecommerce_serang.data.api.dto.UserProfile
|
import com.alya.ecommerce_serang.data.api.dto.UserProfile
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.DataItemCart
|
import com.alya.ecommerce_serang.data.api.response.customer.cart.DataItemCart
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CancelOrderResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateOrderResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateOrderResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateReviewResponse
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CreateReviewResponse
|
||||||
@ -491,4 +492,23 @@ class OrderRepository(private val apiService: ApiService) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun cancelOrder(cancelReq: CancelOrderReq): Result<CancelOrderResponse>{
|
||||||
|
return try{
|
||||||
|
val response= apiService.cancelOrder(cancelReq)
|
||||||
|
|
||||||
|
if (response.isSuccessful){
|
||||||
|
response.body()?.let { cancelOrderResponse ->
|
||||||
|
Result.Success(cancelOrderResponse)
|
||||||
|
} ?: run {
|
||||||
|
Result.Error(Exception("Failed to cancel order"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val errorMsg = response.errorBody()?.string() ?: "Unknown Error"
|
||||||
|
Result.Error(Exception(errorMsg))
|
||||||
|
}
|
||||||
|
}catch (e: Exception){
|
||||||
|
Result.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package com.alya.ecommerce_serang.ui
|
package com.alya.ecommerce_serang.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@ -20,11 +22,15 @@ import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
|||||||
import com.alya.ecommerce_serang.databinding.ActivityMainBinding
|
import com.alya.ecommerce_serang.databinding.ActivityMainBinding
|
||||||
import com.alya.ecommerce_serang.ui.notif.WebSocketManager
|
import com.alya.ecommerce_serang.ui.notif.WebSocketManager
|
||||||
import com.alya.ecommerce_serang.utils.SessionManager
|
import com.alya.ecommerce_serang.utils.SessionManager
|
||||||
|
import com.google.firebase.FirebaseApp
|
||||||
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
private val TAG = "MainActivity"
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
private lateinit var apiService: ApiService
|
private lateinit var apiService: ApiService
|
||||||
private lateinit var sessionManager: SessionManager
|
private lateinit var sessionManager: SessionManager
|
||||||
@ -65,6 +71,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
windowInsets
|
windowInsets
|
||||||
}
|
}
|
||||||
|
// Initialize Firebase
|
||||||
|
FirebaseApp.initializeApp(this)
|
||||||
|
|
||||||
|
// Request FCM token at app startup
|
||||||
|
retrieveFCMToken()
|
||||||
|
|
||||||
requestNotificationPermissionIfNeeded()
|
requestNotificationPermissionIfNeeded()
|
||||||
|
|
||||||
@ -151,4 +162,31 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun retrieveFCMToken() {
|
||||||
|
FirebaseMessaging.getInstance().token
|
||||||
|
.addOnCompleteListener { task ->
|
||||||
|
if (!task.isSuccessful) {
|
||||||
|
Log.e(TAG, "Failed to get FCM token", task.exception)
|
||||||
|
return@addOnCompleteListener
|
||||||
|
}
|
||||||
|
|
||||||
|
val token = task.result
|
||||||
|
// tokenTes = token
|
||||||
|
Log.d(TAG, "FCM token retrieved: $token")
|
||||||
|
|
||||||
|
// Save token locally
|
||||||
|
val sharedPreferences = getSharedPreferences("FCM_PREFS", Context.MODE_PRIVATE)
|
||||||
|
sharedPreferences.edit().putString("FCM_TOKEN", token).apply()
|
||||||
|
|
||||||
|
// Send to your server
|
||||||
|
sendTokenToServer(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendTokenToServer(token: String) {
|
||||||
|
Log.d(TAG, "Would send token to server: $token")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -508,6 +508,14 @@ class RegisterStoreActivity : AppCompatActivity() {
|
|||||||
viewModel.subdistrict.value = s.toString()
|
viewModel.subdistrict.value = s.toString()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
binding.etBankName.addTextChangedListener(object: TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||||
|
override fun afterTextChanged(s: Editable?) {
|
||||||
|
viewModel.subdistrict.value = s.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.alya.ecommerce_serang.ui.order
|
package com.alya.ecommerce_serang.ui.order
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -9,6 +10,7 @@ import com.alya.ecommerce_serang.data.api.dto.CourierCostRequest
|
|||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostsItem
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CourierCostsItem
|
||||||
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 kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ShippingViewModel(
|
class ShippingViewModel(
|
||||||
@ -30,12 +32,71 @@ class ShippingViewModel(
|
|||||||
/**
|
/**
|
||||||
* Load shipping options based on address, product, and quantity
|
* Load shipping options based on address, product, and quantity
|
||||||
*/
|
*/
|
||||||
|
// fun loadShippingOptions(addressId: Int, productId: Int, quantity: Int) {
|
||||||
|
// _isLoading.value = true
|
||||||
|
// _errorMessage.value = ""
|
||||||
|
//
|
||||||
|
// val costProduct = CostProduct(
|
||||||
|
// productId = productId,
|
||||||
|
// quantity = quantity
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// viewModelScope.launch {
|
||||||
|
// // Define the courier services to try
|
||||||
|
// val courierServices = listOf("pos", "jne", "tiki")
|
||||||
|
//
|
||||||
|
// // Create a mutable list to collect successful courier options
|
||||||
|
// val availableCourierOptions = mutableListOf<CourierCostsItem>()
|
||||||
|
//
|
||||||
|
// // Try each courier service
|
||||||
|
// for (courier in courierServices) {
|
||||||
|
// try {
|
||||||
|
// // Create a request for this specific courier
|
||||||
|
// val courierRequest = CourierCostRequest(
|
||||||
|
// addressId = addressId,
|
||||||
|
// itemCost = listOf(costProduct),
|
||||||
|
// courier = courier // Add the courier to the request
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// // Make a separate API call for each courier
|
||||||
|
// val result = repository.getCountCourierCost(courierRequest)
|
||||||
|
//
|
||||||
|
// when (result) {
|
||||||
|
// is Result.Success -> {
|
||||||
|
// // Add this courier's options to our collection
|
||||||
|
// result.data.courierCosts?.let { costs ->
|
||||||
|
// availableCourierOptions.addAll(costs)
|
||||||
|
// }
|
||||||
|
// // Update UI with what we have so far
|
||||||
|
// _shippingOptions.value = availableCourierOptions
|
||||||
|
// }
|
||||||
|
// is Result.Error -> {
|
||||||
|
// // Log the error but continue with next courier
|
||||||
|
// Log.e("ShippingViewModel", "Error fetching cost for courier $courier: ${result.exception.message}")
|
||||||
|
// }
|
||||||
|
// is Result.Loading -> {
|
||||||
|
// // Handle loading state
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// // Log the exception but continue with next courier
|
||||||
|
// Log.e("ShippingViewModel", "Exception for courier $courier: ${e.message}")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Show error only if we couldn't get any shipping options
|
||||||
|
// if (availableCourierOptions.isEmpty()) {
|
||||||
|
// _errorMessage.value = "No shipping options available. Please try again later."
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// _isLoading.value = false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
fun loadShippingOptions(addressId: Int, productId: Int, quantity: Int) {
|
fun loadShippingOptions(addressId: Int, productId: Int, quantity: Int) {
|
||||||
// Reset previous state
|
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
_errorMessage.value = ""
|
_errorMessage.value = ""
|
||||||
|
|
||||||
// Prepare the request
|
|
||||||
val costProduct = CostProduct(
|
val costProduct = CostProduct(
|
||||||
productId = productId,
|
productId = productId,
|
||||||
quantity = quantity
|
quantity = quantity
|
||||||
@ -43,34 +104,47 @@ class ShippingViewModel(
|
|||||||
|
|
||||||
val request = CourierCostRequest(
|
val request = CourierCostRequest(
|
||||||
addressId = addressId,
|
addressId = addressId,
|
||||||
itemCost = listOf(costProduct) // Wrap in a list
|
itemCost = listOf(costProduct)
|
||||||
)
|
)
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
var success = false
|
||||||
// Fetch courier costs
|
var attempt = 0
|
||||||
val result = repository.getCountCourierCost(request)
|
val maxAttempts = 3
|
||||||
|
|
||||||
when (result) {
|
while (!success && attempt < maxAttempts) {
|
||||||
is Result.Success -> {
|
attempt++
|
||||||
// Update shipping options directly with courier costs
|
|
||||||
_shippingOptions.value = result.data.courierCosts
|
try {
|
||||||
}
|
val result = repository.getCountCourierCost(request)
|
||||||
is Result.Error -> {
|
|
||||||
// Handle error case
|
when (result) {
|
||||||
_errorMessage.value = result.exception.message ?: "Unknown error occurred"
|
is Result.Success -> {
|
||||||
}
|
_shippingOptions.value = result.data.courierCosts
|
||||||
is Result.Loading -> {
|
success = true
|
||||||
// Typically handled by the loading state
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||||
|
Log.e("ShippingViewModel", "Attempt $attempt failed: ${result.exception.message}")
|
||||||
|
// Wait before retrying
|
||||||
|
delay(120000)
|
||||||
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Loading -> {
|
||||||
|
// Handle loading state
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("ShippingViewModel", "Attempt $attempt exception: ${e.message}")
|
||||||
|
// Wait before retrying
|
||||||
|
delay(1000)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
// Catch any unexpected exceptions
|
|
||||||
_errorMessage.value = e.localizedMessage ?: "An unexpected error occurred"
|
|
||||||
} finally {
|
|
||||||
// Always set loading to false
|
|
||||||
_isLoading.value = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After all attempts, check if we have any shipping options
|
||||||
|
if (!success || _shippingOptions.value.isNullOrEmpty()) {
|
||||||
|
_errorMessage.value = "No shipping options available. Please try again later."
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -398,7 +398,7 @@ class AddAddressActivity : AppCompatActivity() {
|
|||||||
isRequestingLocation = false
|
isRequestingLocation = false
|
||||||
Toast.makeText(this, "Timeout lokasi, menggunakan lokasi default", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, "Timeout lokasi, menggunakan lokasi default", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}, 15000) // 15 seconds timeout
|
}, 60000) // 15 seconds timeout
|
||||||
|
|
||||||
// Try getting last known location first
|
// Try getting last known location first
|
||||||
try {
|
try {
|
||||||
|
@ -5,8 +5,10 @@ import androidx.lifecycle.LiveData
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.CancelOrderReq
|
||||||
import com.alya.ecommerce_serang.data.api.dto.CompletedOrderRequest
|
import com.alya.ecommerce_serang.data.api.dto.CompletedOrderRequest
|
||||||
import com.alya.ecommerce_serang.data.api.dto.OrdersItem
|
import com.alya.ecommerce_serang.data.api.dto.OrdersItem
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.customer.order.CancelOrderResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderListItemsItem
|
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderListItemsItem
|
||||||
import com.alya.ecommerce_serang.data.api.response.customer.order.Orders
|
import com.alya.ecommerce_serang.data.api.response.customer.order.Orders
|
||||||
import com.alya.ecommerce_serang.data.api.response.order.CompletedOrderResponse
|
import com.alya.ecommerce_serang.data.api.response.order.CompletedOrderResponse
|
||||||
@ -31,6 +33,11 @@ class HistoryViewModel(private val repository: OrderRepository) : ViewModel() {
|
|||||||
private val _orderDetails = MutableLiveData<Orders>()
|
private val _orderDetails = MutableLiveData<Orders>()
|
||||||
val orderDetails: LiveData<Orders> get() = _orderDetails
|
val orderDetails: LiveData<Orders> get() = _orderDetails
|
||||||
|
|
||||||
|
private val _cancelOrderStatus = MutableLiveData<Result<CancelOrderResponse>>()
|
||||||
|
val cancelOrderStatus: LiveData<Result<CancelOrderResponse>> = _cancelOrderStatus
|
||||||
|
private val _isCancellingOrder = MutableLiveData<Boolean>()
|
||||||
|
val isCancellingOrder: LiveData<Boolean> = _isCancellingOrder
|
||||||
|
|
||||||
// LiveData untuk OrderItems
|
// LiveData untuk OrderItems
|
||||||
private val _orderItems = MutableLiveData<List<OrderListItemsItem>>()
|
private val _orderItems = MutableLiveData<List<OrderListItemsItem>>()
|
||||||
val orderItems: LiveData<List<OrderListItemsItem>> get() = _orderItems
|
val orderItems: LiveData<List<OrderListItemsItem>> get() = _orderItems
|
||||||
@ -131,4 +138,26 @@ class HistoryViewModel(private val repository: OrderRepository) : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cancelOrder(cancelReq: CancelOrderReq) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
_cancelOrderStatus.value = Result.Loading
|
||||||
|
val result = repository.cancelOrder(cancelReq)
|
||||||
|
_cancelOrderStatus.value = result
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("HistoryViewModel", "Error cancelling order: ${e.message}")
|
||||||
|
_cancelOrderStatus.value = Result.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshOrders(status: String = "all") {
|
||||||
|
Log.d(TAG, "Refreshing orders with status: $status")
|
||||||
|
// Clear current orders before fetching new ones
|
||||||
|
_orders.value = ViewState.Loading
|
||||||
|
|
||||||
|
// Re-fetch the orders with the current status
|
||||||
|
getOrderList(status)
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package com.alya.ecommerce_serang.ui.order.history
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.ContextWrapper
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -17,6 +18,7 @@ import android.widget.ImageView
|
|||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.findViewTreeLifecycleOwner
|
import androidx.lifecycle.findViewTreeLifecycleOwner
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -24,6 +26,7 @@ import com.alya.ecommerce_serang.R
|
|||||||
import com.alya.ecommerce_serang.data.api.dto.OrdersItem
|
import com.alya.ecommerce_serang.data.api.dto.OrdersItem
|
||||||
import com.alya.ecommerce_serang.data.api.dto.ReviewUIItem
|
import com.alya.ecommerce_serang.data.api.dto.ReviewUIItem
|
||||||
import com.alya.ecommerce_serang.ui.order.detail.PaymentActivity
|
import com.alya.ecommerce_serang.ui.order.detail.PaymentActivity
|
||||||
|
import com.alya.ecommerce_serang.ui.order.history.cancelorder.CancelOrderBottomSheet
|
||||||
import com.alya.ecommerce_serang.ui.order.review.CreateReviewActivity
|
import com.alya.ecommerce_serang.ui.order.review.CreateReviewActivity
|
||||||
import com.alya.ecommerce_serang.ui.product.ReviewProductActivity
|
import com.alya.ecommerce_serang.ui.product.ReviewProductActivity
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
@ -150,7 +153,7 @@ class OrderHistoryAdapter(
|
|||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
text = itemView.context.getString(R.string.canceled_order_btn)
|
text = itemView.context.getString(R.string.canceled_order_btn)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
showCancelOrderDialog(order.orderId.toString())
|
showCancelOrderBottomSheet(order.orderId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deadlineDate.apply {
|
deadlineDate.apply {
|
||||||
@ -171,7 +174,7 @@ class OrderHistoryAdapter(
|
|||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
text = itemView.context.getString(R.string.canceled_order_btn)
|
text = itemView.context.getString(R.string.canceled_order_btn)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
showCancelOrderDialog(order.orderId.toString())
|
showCancelOrderBottomSheet(order.orderId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +229,6 @@ class OrderHistoryAdapter(
|
|||||||
text = itemView.context.getString(R.string.claim_complaint)
|
text = itemView.context.getString(R.string.claim_complaint)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
showCancelOrderDialog(order.orderId.toString())
|
showCancelOrderDialog(order.orderId.toString())
|
||||||
// Handle click event
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
btnRight.apply {
|
btnRight.apply {
|
||||||
@ -492,6 +494,48 @@ class OrderHistoryAdapter(
|
|||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showCancelOrderBottomSheet(orderId : Int) {
|
||||||
|
val context = itemView.context
|
||||||
|
|
||||||
|
// We need a FragmentManager to show the bottom sheet
|
||||||
|
// Try to get it from the context
|
||||||
|
val fragmentActivity = when (context) {
|
||||||
|
is FragmentActivity -> context
|
||||||
|
is ContextWrapper -> {
|
||||||
|
val baseContext = context.baseContext
|
||||||
|
if (baseContext is FragmentActivity) {
|
||||||
|
baseContext
|
||||||
|
} else {
|
||||||
|
// Log error and show a Toast instead if we can't get a FragmentManager
|
||||||
|
Log.e("OrderHistoryAdapter", "Cannot show bottom sheet: Context is not a FragmentActivity")
|
||||||
|
Toast.makeText(context, "Cannot show cancel order dialog", Toast.LENGTH_SHORT).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// Log error and show a Toast instead if we can't get a FragmentManager
|
||||||
|
Log.e("OrderHistoryAdapter", "Cannot show bottom sheet: Context is not a FragmentActivity")
|
||||||
|
Toast.makeText(context, "Cannot show cancel order dialog", Toast.LENGTH_SHORT).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and show the bottom sheet using the obtained FragmentManager
|
||||||
|
val bottomSheet = CancelOrderBottomSheet(
|
||||||
|
orderId = orderId,
|
||||||
|
onOrderCancelled = {
|
||||||
|
// Handle the successful cancellation
|
||||||
|
// Refresh the data
|
||||||
|
viewModel.refreshOrders() // Assuming there's a method to refresh orders
|
||||||
|
|
||||||
|
// Show a success message
|
||||||
|
Toast.makeText(context, "Order cancelled successfully", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
bottomSheet.show(fragmentActivity.supportFragmentManager, CancelOrderBottomSheet.TAG)
|
||||||
|
}
|
||||||
|
|
||||||
private fun addReviewProduct(order: OrdersItem) {
|
private fun addReviewProduct(order: OrdersItem) {
|
||||||
// Use ViewModel to fetch order details
|
// Use ViewModel to fetch order details
|
||||||
viewModel.getOrderDetails(order.orderId)
|
viewModel.getOrderDetails(order.orderId)
|
||||||
|
@ -0,0 +1,173 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.order.history.cancelorder
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.Spinner
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.alya.ecommerce_serang.R
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.CancelOrderReq
|
||||||
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||||
|
import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||||
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
|
import com.alya.ecommerce_serang.ui.order.history.HistoryViewModel
|
||||||
|
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||||
|
import com.alya.ecommerce_serang.utils.SessionManager
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
|
||||||
|
class CancelOrderBottomSheet(
|
||||||
|
private val orderId: Int,
|
||||||
|
private val onOrderCancelled: () -> Unit
|
||||||
|
) : BottomSheetDialogFragment() {
|
||||||
|
private lateinit var sessionManager: SessionManager
|
||||||
|
|
||||||
|
private val viewModel: HistoryViewModel by viewModels {
|
||||||
|
BaseViewModelFactory {
|
||||||
|
val apiService = ApiConfig.getApiService(sessionManager)
|
||||||
|
val orderRepository = OrderRepository(apiService)
|
||||||
|
HistoryViewModel(orderRepository)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var selectedReason: CancelOrderReq? = null
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return inflater.inflate(R.layout.layout_cancel_order_bottom, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
sessionManager = SessionManager(requireContext())
|
||||||
|
|
||||||
|
val tvTitle = view.findViewById<TextView>(R.id.tv_title)
|
||||||
|
val spinnerReason = view.findViewById<Spinner>(R.id.spinner_reason)
|
||||||
|
val btnCancel = view.findViewById<Button>(R.id.btn_cancel)
|
||||||
|
val btnConfirm = view.findViewById<Button>(R.id.btn_confirm)
|
||||||
|
|
||||||
|
// Set the title
|
||||||
|
tvTitle.text = "Cancel Order #$orderId"
|
||||||
|
|
||||||
|
// Set up the spinner with cancellation reasons
|
||||||
|
setupReasonSpinner(spinnerReason)
|
||||||
|
|
||||||
|
// Handle button clicks
|
||||||
|
btnCancel.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
btnConfirm.setOnClickListener {
|
||||||
|
if (selectedReason == null) {
|
||||||
|
Toast.makeText(context, "Please select a reason", Toast.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelOrder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupReasonSpinner(spinner: Spinner) {
|
||||||
|
val reasons = getCancellationReasons()
|
||||||
|
val adapter = CancelReasonAdapter(requireContext(), reasons)
|
||||||
|
spinner.adapter = adapter
|
||||||
|
|
||||||
|
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||||
|
selectedReason = reasons[position]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||||
|
selectedReason = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCancellationReasons(): List<CancelOrderReq> {
|
||||||
|
// These should ideally come from the server or a configuration
|
||||||
|
return listOf(
|
||||||
|
CancelOrderReq(1, "Changed my mind"),
|
||||||
|
CancelOrderReq(2, "Found a better option"),
|
||||||
|
CancelOrderReq(3, "Ordered by mistake"),
|
||||||
|
CancelOrderReq(4, "Delivery time too long"),
|
||||||
|
CancelOrderReq(5, "Other reason")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancelOrder() {
|
||||||
|
// Validate reason selection
|
||||||
|
if (selectedReason == null) {
|
||||||
|
Toast.makeText(context, "Mohon pilih alasan pembatalan", Toast.LENGTH_SHORT).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cancel request
|
||||||
|
val cancelRequest = CancelOrderReq(
|
||||||
|
orderId = orderId,
|
||||||
|
reason = selectedReason!!.reason
|
||||||
|
)
|
||||||
|
Log.d(TAG, "Sending cancel request to ViewModel: orderId=${cancelRequest.orderId}, reason='${cancelRequest.reason}'")
|
||||||
|
|
||||||
|
|
||||||
|
// Submit the cancellation
|
||||||
|
viewModel.cancelOrder(cancelRequest)
|
||||||
|
|
||||||
|
// Observe the status
|
||||||
|
viewModel.cancelOrderStatus.observe(viewLifecycleOwner) { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> {
|
||||||
|
// Show loading indicator
|
||||||
|
// showLoading(true)
|
||||||
|
}
|
||||||
|
is Result.Success -> {
|
||||||
|
// Hide loading indicator
|
||||||
|
showLoading(false)
|
||||||
|
|
||||||
|
// Show success message
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"Pesanan berhasil dibatalkan",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
Log.d(TAG, "Cancel order status: SUCCESS, message: ${result.data.message}")
|
||||||
|
|
||||||
|
// Notify callback and close dialog
|
||||||
|
onOrderCancelled()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
// Hide loading indicator
|
||||||
|
showLoading(false)
|
||||||
|
Log.e(TAG, "Cancel order status: ERROR", result.exception)
|
||||||
|
|
||||||
|
|
||||||
|
// Show error message
|
||||||
|
val errorMsg = result.exception.message ?: "Gagal membatalkan pesanan"
|
||||||
|
Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private fun showLoading(isLoading: Boolean) {
|
||||||
|
// binding.progressBar.isVisible = isLoading
|
||||||
|
// binding.btnCancel.isEnabled = !isLoading
|
||||||
|
// binding.btnConfirm.isEnabled = !isLoading
|
||||||
|
// }
|
||||||
|
|
||||||
|
private fun showLoading(isLoading: Boolean) {
|
||||||
|
// Implement loading indicator if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "CancelOrderBottomSheet"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.order.history.cancelorder
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.alya.ecommerce_serang.R
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.CancelOrderReq
|
||||||
|
|
||||||
|
class CancelReasonAdapter(
|
||||||
|
context: Context,
|
||||||
|
private val reasons: List<CancelOrderReq>
|
||||||
|
) : ArrayAdapter<CancelOrderReq>(context, 0, reasons) {
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
return createItemView(position, convertView, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
return createItemView(position, convertView, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createItemView(position: Int, recycledView: View?, parent: ViewGroup): View {
|
||||||
|
val reason = getItem(position) ?: return recycledView ?: View(context)
|
||||||
|
|
||||||
|
val view = recycledView ?: LayoutInflater.from(context)
|
||||||
|
.inflate(R.layout.item_cancel_order, parent, false)
|
||||||
|
|
||||||
|
val tvReason = view.findViewById<TextView>(R.id.tv_reason)
|
||||||
|
tvReason.text = reason.reason
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.alya.ecommerce_serang.ui.profile
|
package com.alya.ecommerce_serang.ui.profile
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.app.ProgressDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@ -9,19 +11,24 @@ import android.view.ViewGroup
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
||||||
import com.alya.ecommerce_serang.R
|
import com.alya.ecommerce_serang.R
|
||||||
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.retrofit.ApiConfig
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||||
import com.alya.ecommerce_serang.data.repository.UserRepository
|
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||||
import com.alya.ecommerce_serang.databinding.FragmentProfileBinding
|
import com.alya.ecommerce_serang.databinding.FragmentProfileBinding
|
||||||
|
import com.alya.ecommerce_serang.ui.auth.LoginActivity
|
||||||
import com.alya.ecommerce_serang.ui.auth.RegisterStoreActivity
|
import com.alya.ecommerce_serang.ui.auth.RegisterStoreActivity
|
||||||
|
import com.alya.ecommerce_serang.ui.order.address.AddressActivity
|
||||||
import com.alya.ecommerce_serang.ui.order.history.HistoryActivity
|
import com.alya.ecommerce_serang.ui.order.history.HistoryActivity
|
||||||
import com.alya.ecommerce_serang.ui.profile.mystore.MyStoreActivity
|
import com.alya.ecommerce_serang.ui.profile.mystore.MyStoreActivity
|
||||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||||
import com.alya.ecommerce_serang.utils.SessionManager
|
import com.alya.ecommerce_serang.utils.SessionManager
|
||||||
import com.alya.ecommerce_serang.utils.viewmodel.ProfileViewModel
|
import com.alya.ecommerce_serang.utils.viewmodel.ProfileViewModel
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ProfileFragment : Fragment() {
|
class ProfileFragment : Fragment() {
|
||||||
|
|
||||||
@ -85,6 +92,16 @@ class ProfileFragment : Fragment() {
|
|||||||
val intent = Intent(requireContext(), HistoryActivity::class.java)
|
val intent = Intent(requireContext(), HistoryActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.cardLogout.setOnClickListener({
|
||||||
|
logout()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.cardAddress.setOnClickListener({
|
||||||
|
val intent = Intent(requireContext(), AddressActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeUserProfile() {
|
private fun observeUserProfile() {
|
||||||
@ -115,4 +132,41 @@ class ProfileFragment : Fragment() {
|
|||||||
.placeholder(R.drawable.placeholder_image)
|
.placeholder(R.drawable.placeholder_image)
|
||||||
.into(profileImage)
|
.into(profileImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun logout(){
|
||||||
|
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle("Konfirmasi")
|
||||||
|
.setMessage("Apakah anda yakin ingin keluar?")
|
||||||
|
.setPositiveButton("Ya") { _, _ ->
|
||||||
|
actionLogout()
|
||||||
|
}
|
||||||
|
.setNegativeButton("Tidak", null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun actionLogout(){
|
||||||
|
val loadingDialog = ProgressDialog(requireContext()).apply {
|
||||||
|
setMessage("Mohon ditunggu")
|
||||||
|
setCancelable(false)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
try {
|
||||||
|
delay(500)
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
sessionManager.clearAll()
|
||||||
|
val intent = Intent(requireContext(), LoginActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(
|
||||||
|
requireContext(),
|
||||||
|
"Gagal keluar: ${e.message}",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -57,8 +57,6 @@ class SessionManager(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//clear data when log out
|
//clear data when log out
|
||||||
fun clearAll() {
|
fun clearAll() {
|
||||||
sharedPreferences.edit() {
|
sharedPreferences.edit() {
|
||||||
|
@ -27,6 +27,9 @@ class ProfileViewModel(private val userRepository: UserRepository) : ViewModel()
|
|||||||
private val _checkStore = MutableLiveData<Boolean>()
|
private val _checkStore = MutableLiveData<Boolean>()
|
||||||
val checkStore: LiveData<Boolean> = _checkStore
|
val checkStore: LiveData<Boolean> = _checkStore
|
||||||
|
|
||||||
|
private val _logout = MutableLiveData<Boolean>()
|
||||||
|
val logout : LiveData<Boolean> = _checkStore
|
||||||
|
|
||||||
fun loadUserProfile(){
|
fun loadUserProfile(){
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
when (val result = userRepository.fetchUserProfile()){
|
when (val result = userRepository.fetchUserProfile()){
|
||||||
@ -57,8 +60,6 @@ class ProfileViewModel(private val userRepository: UserRepository) : ViewModel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun editProfileDirect(
|
fun editProfileDirect(
|
||||||
context: Context,
|
context: Context,
|
||||||
username: String,
|
username: String,
|
||||||
@ -97,6 +98,17 @@ class ProfileViewModel(private val userRepository: UserRepository) : ViewModel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun logout(){
|
||||||
|
viewModelScope.launch {
|
||||||
|
try{
|
||||||
|
|
||||||
|
} catch (e: Exception){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ProfileViewModel"
|
private const val TAG = "ProfileViewModel"
|
||||||
}
|
}
|
||||||
|
5
app/src/main/res/drawable/baseline_info_24.xml
Normal file
5
app/src/main/res/drawable/baseline_info_24.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#211E1E" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
|
||||||
|
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/baseline_logout_24.xml
Normal file
5
app/src/main/res/drawable/baseline_logout_24.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#211E1E" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5zM4,5h8V3H4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h8v-2H4V5z"/>
|
||||||
|
|
||||||
|
</vector>
|
8
app/src/main/res/drawable/bg_bottom_sheet.xml
Normal file
8
app/src/main/res/drawable/bg_bottom_sheet.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="16dp"
|
||||||
|
android:topRightRadius="16dp" />
|
||||||
|
</shape>
|
8
app/src/main/res/drawable/bg_spinner_reason.xml
Normal file
8
app/src/main/res/drawable/bg_spinner_reason.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/light_gray" />
|
||||||
|
</shape>
|
@ -231,13 +231,14 @@
|
|||||||
android:text="10. Bank *"
|
android:text="10. Bank *"
|
||||||
android:textColor="@android:color/black" />
|
android:textColor="@android:color/black" />
|
||||||
|
|
||||||
<Spinner
|
<EditText
|
||||||
android:id="@+id/spinner_bank"
|
android:id="@+id/et_bank_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:background="@android:drawable/btn_dropdown"
|
android:background="@android:drawable/editbox_background"
|
||||||
android:hint="Pilih jawaban Anda di sini"
|
android:hint="Isi jawaban Anda di sini"
|
||||||
|
android:inputType="text"
|
||||||
android:padding="12dp" />
|
android:padding="12dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -118,6 +118,7 @@
|
|||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:paddingVertical="8dp"
|
android:paddingVertical="8dp"
|
||||||
|
android:textSize="16sp"
|
||||||
android:fontFamily="@font/dmsans_medium"
|
android:fontFamily="@font/dmsans_medium"
|
||||||
android:text="Pesanan Saya"
|
android:text="Pesanan Saya"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@ -129,7 +130,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:textSize="12sp"
|
android:textSize="14sp"
|
||||||
android:padding="0dp"
|
android:padding="0dp"
|
||||||
android:fontFamily="@font/dmsans_light"
|
android:fontFamily="@font/dmsans_light"
|
||||||
android:text="Lihat Riwayat Pesanan"
|
android:text="Lihat Riwayat Pesanan"
|
||||||
@ -164,6 +165,8 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="@font/dmsans_regular"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:text="@string/waiting_payment" />
|
android:text="@string/waiting_payment" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@ -185,6 +188,8 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/dmsans_regular"
|
||||||
|
android:textSize="12sp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:text="@string/packages" />
|
android:text="@string/packages" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@ -206,6 +211,8 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/dmsans_regular"
|
||||||
|
android:textSize="12sp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:text="@string/delivery" />
|
android:text="@string/delivery" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@ -223,103 +230,176 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
|
android:textSize="16sp"
|
||||||
android:text="Pengaturan Akun"
|
android:text="Pengaturan Akun"
|
||||||
android:fontFamily="@font/dmsans_medium"
|
android:fontFamily="@font/dmsans_medium"
|
||||||
app:layout_constraintTop_toBottomOf="@id/cardPesanan" />
|
app:layout_constraintTop_toBottomOf="@id/cardPesanan" />
|
||||||
|
|
||||||
<!-- Address -->
|
<!-- Address -->
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:id="@+id/ivAddress"
|
android:id="@+id/container_settings"
|
||||||
android:layout_width="24dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:src="@drawable/ic_address"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/tvAddress"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tvAddress" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvAddress"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:orientation="vertical"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
android:text="Alamat"
|
app:layout_constraintTop_toBottomOf="@id/tvPengaturanAkun"
|
||||||
app:layout_constraintEnd_toStartOf="@id/ivAddressArrow"
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
app:layout_constraintStart_toEndOf="@id/ivAddress"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvPengaturanAkun" />
|
<!-- Address Card -->
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_address"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="2dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivAddress"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/ic_address"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAddress"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="Alamat"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:fontFamily="@font/dmsans_regular"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/ivAddress"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/ivAddressArrow" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivAddressArrow"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_arrow_right"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<!-- About Card -->
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_about"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="2dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivAbout"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/baseline_info_24"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAbout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="Tentang"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/ivAbout"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/ivAboutArrow" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivAboutArrow"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_arrow_right"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<!-- Logout Card -->
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_logout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="2dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivLogout"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/baseline_logout_24"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvLogout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="Keluar"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/ivLogout"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/ivLogoutArrow" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivLogoutArrow"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_arrow_right"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivAddressArrow"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:src="@drawable/ic_arrow_right"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/tvAddress"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tvAddress" />
|
|
||||||
|
|
||||||
<!-- About -->
|
<!-- About -->
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivAbout"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/tvAbout"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tvAbout" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvAbout"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:text="Tentang"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/ivAboutArrow"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/ivAbout"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvAddress" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivAboutArrow"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:src="@drawable/ic_arrow_right"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/tvAbout"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tvAbout" />
|
|
||||||
|
|
||||||
<!-- Logout -->
|
<!-- Logout -->
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivLogout"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/tvLogout"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tvLogout" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvLogout"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:text="Keluar"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/ivLogoutArrow"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/ivLogout"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvAbout" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivLogoutArrow"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:src="@drawable/ic_arrow_right"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/tvLogout"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tvLogout" />
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
8
app/src/main/res/layout/item_cancel_order.xml
Normal file
8
app/src/main/res/layout/item_cancel_order.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/tv_reason"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="14sp" />
|
@ -1,16 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginVertical="8dp"
|
android:layout_marginVertical="8dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
<RadioButton
|
<RadioButton
|
||||||
@ -27,7 +29,7 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/courier_name_cost"
|
android:id="@+id/courier_name_cost"
|
||||||
android:fontFamily="@font/dmsans_bold"
|
android:fontFamily="@font/dmsans_semibold"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -40,8 +42,8 @@
|
|||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:paddingHorizontal="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:text="Estimasi 3-4 hari"/>
|
android:text="Estimasi 3-4 hari"/>
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/cost_price"
|
android:id="@+id/cost_price"
|
||||||
@ -53,12 +55,16 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:text="Rp15.0000"/>
|
android:text="Rp15.0000"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<View
|
<View
|
||||||
android:id="@+id/divider"
|
android:id="@+id/divider"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
android:background="#E0E0E0"
|
android:background="#E0E0E0"
|
||||||
app:layout_constraintTop_toBottomOf="@id/linear_toolbar" />
|
app:layout_constraintTop_toBottomOf="@id/content" />
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
73
app/src/main/res/layout/layout_cancel_order_bottom.xml
Normal file
73
app/src/main/res/layout/layout_cancel_order_bottom.xml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_bottom_sheet"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/dmsans_semibold"
|
||||||
|
android:text="Batalkan Pesanan"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="18sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_reason_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Alasan batalkan pesanan:"
|
||||||
|
android:fontFamily="@font/dmsans_regular"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner_reason"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/bg_spinner_reason"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_reason_label" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_cancel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:backgroundTint="@color/black_200"
|
||||||
|
android:text="Kembali"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn_confirm"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/spinner_reason" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_confirm"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:backgroundTint="@color/blue_500"
|
||||||
|
android:text="Batal"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/btn_cancel"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn_cancel"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/btn_cancel" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Reference in New Issue
Block a user