fix logo and add dialog pop up

This commit is contained in:
shaulascr
2025-08-27 01:30:22 +07:00
parent 57f3c463cb
commit 66595fcb48
13 changed files with 355 additions and 64 deletions

View File

@ -26,6 +26,7 @@ import com.alya.ecommerce_serang.data.repository.OrderRepository
import com.alya.ecommerce_serang.databinding.ActivityCheckoutBinding
import com.alya.ecommerce_serang.ui.order.address.AddressActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.PopUpDialog
import com.alya.ecommerce_serang.utils.SessionManager
import java.text.NumberFormat
import java.util.Locale
@ -372,7 +373,16 @@ class CheckoutActivity : AppCompatActivity() {
// Create order button
binding.btnPay.setOnClickListener {
if (validateOrder()) {
viewModel.createOrder()
PopUpDialog.showConfirmDialog(
context = this,
title = "Apakah anda yakin inging membuat pesanan?",
message = "Pastikan data yang dimasukkan sudah benar",
positiveText = "Ya",
negativeText = "Tidak",
onYesClicked = {
viewModel.createOrder()
}
)
}
}

View File

@ -40,8 +40,6 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
private val _orderCreated = MutableLiveData<Boolean>()
val orderCreated: LiveData<Boolean> = _orderCreated
// Initialize "Buy Now" checkout
fun initializeBuyNow(
storeId: Int,

View File

@ -21,15 +21,16 @@ import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toDrawable
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.dto.PaymentUpdate
import com.alya.ecommerce_serang.data.api.response.auth.StoreTypesItem
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.MyStoreRepository
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.ActivityRegisterStoreBinding
import com.alya.ecommerce_serang.ui.order.address.BankAdapter
import com.alya.ecommerce_serang.ui.order.address.CityAdapter
@ -38,6 +39,8 @@ import com.alya.ecommerce_serang.ui.order.address.SubdsitrictAdapter
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.FileUtils
import com.alya.ecommerce_serang.utils.ImageUtils
import com.alya.ecommerce_serang.utils.PopUpDialog
import com.alya.ecommerce_serang.utils.RegisterStoreViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
import com.alya.ecommerce_serang.utils.viewmodel.RegisterStoreViewModel
@ -46,8 +49,6 @@ import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import androidx.core.net.toUri
import com.alya.ecommerce_serang.data.api.dto.PaymentUpdate
class RegisterStoreActivity : AppCompatActivity() {
@ -85,11 +86,7 @@ class RegisterStoreActivity : AppCompatActivity() {
private val LOCATION_PERMISSION_REQUEST = 2001
private val viewModel: RegisterStoreViewModel by viewModels {
BaseViewModelFactory {
val apiService = ApiConfig.Companion.getApiService(sessionManager)
val orderRepository = UserRepository(apiService)
RegisterStoreViewModel(orderRepository)
}
RegisterStoreViewModelFactory(this, intent.extras)
}
private val myStoreViewModel: MyStoreViewModel by viewModels {
@ -260,8 +257,21 @@ class RegisterStoreActivity : AppCompatActivity() {
}
} else {
binding.btnRegister.setOnClickListener {
if (viewModel.validateForm()) viewModel.registerStore(this)
else Toast.makeText(this, "Harap lengkapi semua field yang wajib diisi", Toast.LENGTH_SHORT).show()
if (viewModel.validateForm()){
PopUpDialog.showConfirmDialog(
context = this,
title = "Apakah anda yakin ingin mendaftar toko?",
message = "Pastikan data yang dimasukkan sudah benar",
positiveText = "Ya",
negativeText = "Tidak",
onYesClicked = {
viewModel.registerStore(this)
}
)
}
else {
Toast.makeText(this, "Harap lengkapi semua field yang wajib diisi", Toast.LENGTH_SHORT).show()
}
}
}
validateRequiredFields()
@ -797,12 +807,21 @@ class RegisterStoreActivity : AppCompatActivity() {
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.storeName.value = s.toString()
if (viewModel.storeName.value != s.toString()) {
viewModel.storeName.value = s.toString()
}
Log.d(TAG, "Store name updated: ${s.toString()}")
validateRequiredFields()
}
})
viewModel.storeName.observe(this) { value ->
if (binding.etStoreName.text.toString() != value) {
binding.etStoreName.setText(value)
binding.etStoreName.setSelection(value.length) // Set cursor to end
}
}
binding.etStoreDescription.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) {}
@ -817,48 +836,80 @@ class RegisterStoreActivity : AppCompatActivity() {
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.street.value = s.toString()
if (viewModel.street.value != s.toString()) {
viewModel.street.value = s.toString()
}
Log.d(TAG, "Street address updated: ${s.toString()}")
validateRequiredFields()
}
})
viewModel.street.observe(this) { value ->
if (binding.etStreet.text.toString() != value) {
binding.etStreet.setText(value)
binding.etStreet.setSelection(value.length)
}
}
binding.etPostalCode.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.postalCode.value = s.toString().toIntOrNull() ?: 0
val newValue = s.toString().toIntOrNull() ?: 0
if (viewModel.postalCode.value != newValue) {
viewModel.postalCode.value = newValue
}
validateRequiredFields()
}
})
viewModel.postalCode.observe(this) { value ->
val currentText = binding.etPostalCode.text.toString()
val valueString = if (value == 0) "" else value.toString()
if (currentText != valueString) {
binding.etPostalCode.setText(valueString)
binding.etPostalCode.setSelection(valueString.length)
}
}
binding.etAddressDetail.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.addressDetail.value = s.toString()
if (viewModel.addressDetail.value != s.toString()) {
viewModel.addressDetail.value = s.toString()
}
Log.d(TAG, "Address detail updated: ${s.toString()}")
validateRequiredFields()
}
})
viewModel.addressDetail.observe(this) { value ->
if (binding.etAddressDetail.text.toString() != value) {
binding.etAddressDetail.setText(value)
binding.etAddressDetail.setSelection(value.length)
}
}
binding.etBankNumber.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?) {
val input = s.toString()
if (input.isNotEmpty()) {
val newValue = if (input.isNotEmpty()) {
try {
viewModel.bankNumber.value = input.toInt()
Log.d(TAG, "Bank number updated: $input")
input.toInt()
} catch (e: NumberFormatException) {
// Handle invalid input if needed
Log.e(TAG, "Failed to parse bank number. Input: $input, Error: $e")
0
}
} else {
// Handle empty input - perhaps set to 0 or null depending on your requirements
viewModel.bankNumber.value = 0 // or 0
Log.d(TAG, "Bank number set to default: 0")
0
}
if (viewModel.bankNumber.value != newValue) {
viewModel.bankNumber.value = newValue
Log.d(TAG, "Bank number updated: $newValue")
}
validateRequiredFields()
}
@ -888,16 +939,27 @@ class RegisterStoreActivity : AppCompatActivity() {
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.accountName.value = s.toString()
if (viewModel.accountName.value != s.toString()) {
viewModel.accountName.value = s.toString()
}
Log.d(TAG, "Account Name updated: ${s.toString()}")
validateRequiredFields()
}
})
viewModel.accountName.observe(this) { value ->
if (binding.etAccountName.text.toString() != value) {
binding.etAccountName.setText(value)
binding.etAccountName.setSelection(value.length)
}
}
Log.d(TAG, "setupDataBinding: Text field data binding setup completed")
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d(TAG, "onActivityResult: Request code: $requestCode, Result code: $resultCode")

View File

@ -27,6 +27,7 @@ import com.alya.ecommerce_serang.data.repository.SellsRepository
import com.alya.ecommerce_serang.databinding.ActivityDetailPaymentBinding
import com.alya.ecommerce_serang.ui.profile.mystore.sells.SellsProductAdapter
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.PopUpDialog
import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.AddressViewModel
import com.alya.ecommerce_serang.utils.viewmodel.SellsViewModel
@ -109,8 +110,18 @@ class DetailPaymentActivity : AppCompatActivity() {
binding.btnConfirmPayment.setOnClickListener {
sells?.orderId?.let {
viewModel.confirmPayment(it, "confirmed")
Toast.makeText(this, "Pembayaran dikonfirmasi", Toast.LENGTH_SHORT).show()
PopUpDialog.showConfirmDialog(
context = this,
title = "Apakah anda yakin?",
message = "Pastikan data pembayaran sudah sesuai",
positiveText = "Ya",
negativeText = "Tidak",
onYesClicked = {
viewModel.confirmPayment(it, "confirmed")
Toast.makeText(this, "Pembayaran dikonfirmasi", Toast.LENGTH_SHORT).show()
}
)
} ?: run {
Log.e("DetailPaymentActivity", "No order passed in intent")
}

View File

@ -1,10 +1,16 @@
package com.alya.ecommerce_serang.utils
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.AbstractSavedStateViewModelFactory
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.savedstate.SavedStateRegistryOwner
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.utils.viewmodel.RegisterStoreViewModel
class BaseViewModelFactory<VM : ViewModel>(
private val creator: () -> VM
@ -29,4 +35,30 @@ class SavedStateViewModelFactory<VM : ViewModel>(
): T {
return creator(handle) as T
}
}
class RegisterStoreViewModelFactory(
private val owner: SavedStateRegistryOwner,
private val defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
return when {
modelClass.isAssignableFrom(RegisterStoreViewModel::class.java) -> {
// Create SessionManager and ApiService
val context = if (owner is Context) owner else (owner as Fragment).requireContext()
val sessionManager = SessionManager(context)
val apiService = ApiConfig.getApiService(sessionManager)
val repository = UserRepository(apiService)
RegisterStoreViewModel(repository, handle) as T
}
else -> throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
}
}

View File

@ -0,0 +1,84 @@
package com.alya.ecommerce_serang.utils
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.alya.ecommerce_serang.R
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
object PopUpDialog {
fun showConfirmDialog(
context: Context,
title: String ,
message: String? = null,
iconRes: Int? = null,
positiveText: String? = null,
negativeText: String? = null,
onYesClicked: (() -> Unit)? = null,
onNoClicked: (() -> Unit)? = null
) {
val inflater = LayoutInflater.from(context)
val dialogView = inflater.inflate(R.layout.dialog_popup, null)
val iconView = dialogView.findViewById<ImageView>(R.id.dialogIcon)
val titleView = dialogView.findViewById<TextView>(R.id.dialogTitle)
val messageView = dialogView.findViewById<TextView>(R.id.dialogMessage)
val yesButton = dialogView.findViewById<MaterialButton>(R.id.btnYes)
val noButton = dialogView.findViewById<MaterialButton>(R.id.btnNo)
if (iconRes != null) {
iconView.setImageResource(iconRes)
iconView.visibility = View.VISIBLE
} else {
iconView.visibility = View.GONE
}
// Title
titleView.text = title
// Message
if (message.isNullOrEmpty()) {
messageView.visibility = View.GONE
} else {
messageView.text = message
messageView.visibility = View.VISIBLE
}
// Yes button (always visible, but customizable text)
if (positiveText.isNullOrEmpty()) {
yesButton.visibility = View.GONE
} else {
yesButton.text = positiveText
yesButton.visibility = View.VISIBLE
}
// No button (optional)
if (negativeText.isNullOrEmpty()) {
noButton.visibility = View.GONE
} else {
noButton.text = negativeText
noButton.visibility = View.VISIBLE
}
val dialog = MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_MyApp_AlertDialog)
.setView(dialogView)
.create()
yesButton.setOnClickListener {
onYesClicked?.invoke()
dialog.dismiss()
}
noButton.setOnClickListener {
onNoClicked?.invoke()
dialog.dismiss()
}
dialog.show()
}
}

View File

@ -7,7 +7,6 @@ import android.provider.OpenableColumns
import android.util.Log
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import kotlin.random.Random
@ -123,23 +122,4 @@ object UriToFileConverter {
null
}
}
fun getFilePathFromUri(uri: Uri, context: Context): String? {
// For Media Gallery
val projection = arrayOf(MediaStore.Images.Media.DATA)
try {
val cursor = context.contentResolver.query(uri, projection, null, null, null)
cursor?.use {
if (it.moveToFirst()) {
val columnIndex = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
return it.getString(columnIndex)
}
}
} catch (e: Exception) {
Log.e(TAG, "Error getting file path from URI", e)
}
// If the above method fails, try direct conversion
return uri.path
}
}

View File

@ -5,6 +5,7 @@ import android.net.Uri
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.response.auth.RegisterStoreResponse
@ -19,7 +20,8 @@ import com.alya.ecommerce_serang.utils.ImageUtils
import kotlinx.coroutines.launch
class RegisterStoreViewModel(
private val repository: UserRepository
private val repository: UserRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// LiveData for UI state
@ -56,20 +58,20 @@ class RegisterStoreViewModel(
var selectedBankName: String? = null
// Form fields
val storeName = MutableLiveData<String>()
val storeDescription = MutableLiveData<String>()
val storeTypeId = MutableLiveData<Int>()
val latitude = MutableLiveData<String>()
val longitude = MutableLiveData<String>()
val street = MutableLiveData<String>()
val subdistrict = MutableLiveData<String>()
val cityId = MutableLiveData<String>()
val provinceId = MutableLiveData<Int>()
val postalCode = MutableLiveData<Int>()
val addressDetail = MutableLiveData<String>()
val bankName = MutableLiveData<String>()
val bankNumber = MutableLiveData<Int>()
val accountName = MutableLiveData<String>()
val storeName: MutableLiveData<String> = savedStateHandle.getLiveData("storeName", "")
val storeDescription: MutableLiveData<String> = savedStateHandle.getLiveData("storeDescription", "")
val storeTypeId: MutableLiveData<Int> = savedStateHandle.getLiveData("storeTypeId", 0)
val latitude: MutableLiveData<String> = savedStateHandle.getLiveData("latitude", "")
val longitude: MutableLiveData<String> = savedStateHandle.getLiveData("longitude", "")
val street: MutableLiveData<String> = savedStateHandle.getLiveData("street", "")
val subdistrict: MutableLiveData<String> = savedStateHandle.getLiveData("subdistrict", "")
val cityId: MutableLiveData<String> = savedStateHandle.getLiveData("cityId", "")
val provinceId: MutableLiveData<Int> = savedStateHandle.getLiveData("provinceId", 0)
val postalCode: MutableLiveData<Int> = savedStateHandle.getLiveData("postalCode", 0)
val addressDetail: MutableLiveData<String> = savedStateHandle.getLiveData("addressDetail", "")
val bankName: MutableLiveData<String> = savedStateHandle.getLiveData("bankName", "")
val bankNumber: MutableLiveData<Int> = savedStateHandle.getLiveData("bankNumber", 0)
val accountName: MutableLiveData<String> = savedStateHandle.getLiveData("accountName", "")
// Files
var storeImageUri: Uri? = null
@ -79,6 +81,15 @@ class RegisterStoreViewModel(
var persetujuanUri: Uri? = null
var qrisUri: Uri? = null
fun getFieldValue(key: String): String {
return savedStateHandle.get<String>(key) ?: ""
}
// Helper function to update any field
fun updateField(key: String, value: String) {
savedStateHandle[key] = value
}
// Selected couriers
val selectedCouriers = mutableListOf<String>()

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="95dp" android:viewportHeight="101" android:viewportWidth="101" android:width="95dp">
<path android:fillColor="#BAE0BD" android:pathData="M50.56,97.03C25.06,97.03 4.31,76.28 4.31,50.78C4.31,25.28 25.06,4.53 50.56,4.53C76.06,4.53 96.81,25.28 96.81,50.78C96.81,76.28 76.06,97.03 50.56,97.03Z"/>
<path android:fillColor="#5E9C76" android:pathData="M50.56,5.78C75.31,5.78 95.56,26.03 95.56,50.78C95.56,75.53 75.31,95.78 50.56,95.78C25.81,95.78 5.56,75.53 5.56,50.78C5.56,26.03 25.81,5.78 50.56,5.78ZM50.56,3.28C24.31,3.28 3.06,24.53 3.06,50.78C3.06,77.03 24.31,98.28 50.56,98.28C76.81,98.28 98.06,77.03 98.06,50.78C98.06,24.53 76.81,3.28 50.56,3.28Z"/>
<path android:fillColor="#00000000" android:pathData="M28.56,51.03L43.06,65.53L76.06,32.53" android:strokeColor="#ffffff" android:strokeWidth="7.5"/>
</vector>

View File

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="100dp"
android:height="100dp"
android:viewportWidth="100"
android:viewportHeight="100">
<path
android:pathData="M50,96.88C24.15,96.88 3.13,75.85 3.13,50C3.13,24.15 24.15,3.13 50,3.13C75.85,3.13 96.88,24.15 96.88,50C96.88,75.85 75.85,96.88 50,96.88Z"
android:fillColor="#F78F8F"/>
<path
android:pathData="M50,3.75C75.5,3.75 96.25,24.5 96.25,50C96.25,75.5 75.5,96.25 50,96.25C24.5,96.25 3.75,75.5 3.75,50C3.75,24.5 24.5,3.75 50,3.75ZM50,2.5C23.77,2.5 2.5,23.77 2.5,50C2.5,76.23 23.77,97.5 50,97.5C76.23,97.5 97.5,76.23 97.5,50C97.5,23.77 76.23,2.5 50,2.5Z"
android:fillColor="#C74343"/>
<path
android:pathData="M34.97,70.33L29.67,65.03L65.03,29.67L70.33,34.97L34.97,70.33Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M29.67,34.97L34.97,29.67L70.33,65.03L65.03,70.33L29.67,34.97Z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -4,8 +4,8 @@
<!-- Logo with controlled size -->
<item
android:width="120dp"
android:height="120dp"
android:width="200dp"
android:height="200dp"
android:drawable="@drawable/logo_psb_crop"
android:gravity="center" />
</layer-list>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
app:cardElevation="5dp"
app:cardCornerRadius="15dp"
app:cardBackgroundColor="@color/white"
android:padding="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/dialogIcon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:contentDescription="icon dialog"
android:visibility="gone" />
<TextView
android:id="@+id/dialogTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Judul"
android:layout_marginTop="16dp"
android:gravity="center"
android:textSize="18sp"
android:fontFamily="@font/dmsans_semibold"
android:textColor="?attr/colorOnSurface" />
<TextView
android:id="@+id/dialogMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:text="Pesan Dialog"
android:fontFamily="@font/dmsans_regular"
android:textSize="14sp"
android:textColor="?attr/colorOnSurfaceVariant" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnNo"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/dmsans_regular"
android:text="Tidak" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnYes"
style="@style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:fontFamily="@font/dmsans_regular"
android:text="Ya" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -339,7 +339,10 @@
<!-- Rounded corners -->
<item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.MyApp.MediumComponent</item>
<!-- Dialog background color -->
<item name="cardBackgroundColor">@color/white</item>
<item name="materialAlertDialogBodyTextStyle">@font/dmsans_regular</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="ShapeAppearance.MyApp.MediumComponent" parent="ShapeAppearance.Material3.Corner.Medium" />