forked from shihaam/thijooree
made transfer flow more friendly and vivid UI
This commit is contained in:
@@ -857,13 +857,20 @@ class TransferFragment : Fragment() {
|
|||||||
message: String? = null,
|
message: String? = null,
|
||||||
customView: android.view.View? = null,
|
customView: android.view.View? = null,
|
||||||
biometricSubtitle: String,
|
biometricSubtitle: String,
|
||||||
onConfirmed: () -> Unit
|
onConfirmed: (AlertDialog, android.widget.FrameLayout) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as android.view.inputmethod.InputMethodManager
|
||||||
|
imm.hideSoftInputFromWindow(requireView().windowToken, 0)
|
||||||
|
|
||||||
|
val frame = android.widget.FrameLayout(requireContext())
|
||||||
|
if (customView != null) frame.addView(customView)
|
||||||
|
|
||||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(title)
|
.setTitle(title)
|
||||||
.setPositiveButton(R.string.transfer_confirm) { _, _ -> onConfirmed() }
|
.setPositiveButton(R.string.transfer_confirm, null)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
|
||||||
if (customView != null) builder.setView(customView) else builder.setMessage(message)
|
.setCancelable(false)
|
||||||
|
if (customView != null) builder.setView(frame) else builder.setMessage(message)
|
||||||
val dialog = builder.show()
|
val dialog = builder.show()
|
||||||
val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||||
val biometricTransferConfirm = prefs.getBoolean("biometrics_transfer_confirm", false)
|
val biometricTransferConfirm = prefs.getBoolean("biometrics_transfer_confirm", false)
|
||||||
@@ -874,8 +881,7 @@ class TransferFragment : Fragment() {
|
|||||||
val prompt = BiometricPrompt(this, ContextCompat.getMainExecutor(requireContext()),
|
val prompt = BiometricPrompt(this, ContextCompat.getMainExecutor(requireContext()),
|
||||||
object : BiometricPrompt.AuthenticationCallback() {
|
object : BiometricPrompt.AuthenticationCallback() {
|
||||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
dialog.dismiss()
|
onConfirmed(dialog, frame)
|
||||||
onConfirmed()
|
|
||||||
}
|
}
|
||||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
if (errorCode != BiometricPrompt.ERROR_CANCELED &&
|
if (errorCode != BiometricPrompt.ERROR_CANCELED &&
|
||||||
@@ -894,6 +900,10 @@ class TransferFragment : Fragment() {
|
|||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||||
|
onConfirmed(dialog, frame)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,11 +922,27 @@ class TransferFragment : Fragment() {
|
|||||||
Toast.makeText(requireContext(), R.string.transfer_missing_internal_id, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), R.string.transfer_missing_internal_id, Toast.LENGTH_SHORT).show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val qrFromTypeLabel = AccountListParser.from(src)?.typeLabel
|
||||||
|
?: BmlDashboardParser.productLabel(src.accountTypeName)
|
||||||
|
val qrFromDetail = listOfNotNull("BML", qrFromTypeLabel.ifBlank { null }).joinToString(" · ")
|
||||||
|
val qrConfirmView = buildTransferConfirmView(
|
||||||
|
amountCurrency = info.currency,
|
||||||
|
amountValue = "%.2f".format(amount),
|
||||||
|
fromName = src.accountBriefName,
|
||||||
|
fromNumber = src.accountNumber,
|
||||||
|
fromDetail = qrFromDetail,
|
||||||
|
toName = info.merchantName,
|
||||||
|
toNumber = "",
|
||||||
|
toDetail = info.merchantAddress.ifBlank { "BML Merchant" }
|
||||||
|
)
|
||||||
showConfirmWithBiometric(
|
showConfirmWithBiometric(
|
||||||
title = getString(R.string.transfer),
|
title = getString(R.string.transfer),
|
||||||
message = "Pay ${info.currency} ${"%.2f".format(amount)} to ${info.merchantName}?\n\nFrom: ${src.accountBriefName} · ${src.accountNumber}",
|
customView = qrConfirmView,
|
||||||
biometricSubtitle = "${info.currency} ${"%.2f".format(amount)} → ${info.merchantName}",
|
biometricSubtitle = "${info.currency} ${"%.2f".format(amount)} → ${info.merchantName}",
|
||||||
onConfirmed = { executeBmlQrPayment(src, debitAccount, info, amount) }
|
onConfirmed = { dialog, frame ->
|
||||||
|
showProcessingInDialog(dialog, frame)
|
||||||
|
executeBmlQrPayment(src, debitAccount, info, amount, dialog, frame)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -971,18 +997,17 @@ class TransferFragment : Fragment() {
|
|||||||
val isUsdToMvr = currency.equals("USD", ignoreCase = true) && destCurrency.equals("MVR", ignoreCase = true)
|
val isUsdToMvr = currency.equals("USD", ignoreCase = true) && destCurrency.equals("MVR", ignoreCase = true)
|
||||||
val isSrcCredit = src.profileType == "BML_CREDIT"
|
val isSrcCredit = src.profileType == "BML_CREDIT"
|
||||||
|
|
||||||
val mainMsg = "Send $currency $amountStr to $destDisplay?\n\nFrom: ${src.accountBriefName} · ${src.accountNumber}"
|
val doTransfer: (AlertDialog, android.widget.FrameLayout) -> Unit = { dialog, frame ->
|
||||||
|
|
||||||
val doTransfer: () -> Unit = {
|
|
||||||
if (isBmlBusiness) {
|
if (isBmlBusiness) {
|
||||||
// Business profile: async OTP channel selection flow
|
// Business profile: async OTP channel selection flow — dismiss dialog first
|
||||||
|
dialog.dismiss()
|
||||||
startBmlBusinessOtpFlow(
|
startBmlBusinessOtpFlow(
|
||||||
src, resolvedAccountNumber, destDisplay, amount, amountStr, remarks,
|
src, resolvedAccountNumber, destDisplay, amount, amountStr, remarks,
|
||||||
isSrcCard, isDestMib, currency, allAccounts, allContacts, capturedToAvatar
|
isSrcCard, isDestMib, currency, allAccounts, allContacts, capturedToAvatar
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
showProcessingInDialog(dialog, frame)
|
||||||
binding.btnTransfer.isEnabled = false
|
binding.btnTransfer.isEnabled = false
|
||||||
(activity as? HomeActivity)?.setRefreshing(true)
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
val (ok, msg, receipt) = withContext(Dispatchers.IO) {
|
val (ok, msg, receipt) = withContext(Dispatchers.IO) {
|
||||||
if (!isSrcBml) {
|
if (!isSrcBml) {
|
||||||
@@ -992,14 +1017,15 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.btnTransfer.isEnabled = true
|
binding.btnTransfer.isEnabled = true
|
||||||
(activity as? HomeActivity)?.setRefreshing(false)
|
|
||||||
if (ok && receipt != null) {
|
if (ok && receipt != null) {
|
||||||
ReceiptStore.save(requireContext(), receipt)
|
ReceiptStore.save(requireContext(), receipt)
|
||||||
clearForm()
|
clearForm()
|
||||||
val activity = requireActivity() as HomeActivity
|
val activity = requireActivity() as HomeActivity
|
||||||
activity.triggerRefresh()
|
activity.triggerRefresh()
|
||||||
|
dialog.dismiss()
|
||||||
activity.showWithBackStack(TransferReceiptFragment.newInstance(receipt, capturedToAvatar))
|
activity.showWithBackStack(TransferReceiptFragment.newInstance(receipt, capturedToAvatar))
|
||||||
} else if (!ok) {
|
} else if (!ok) {
|
||||||
|
dialog.dismiss()
|
||||||
if (msg == "CONNECTIVITY") {
|
if (msg == "CONNECTIVITY") {
|
||||||
(activity as? HomeActivity)?.showConnectivityBanner(getString(R.string.connectivity_no_internet))
|
(activity as? HomeActivity)?.showConnectivityBanner(getString(R.string.connectivity_no_internet))
|
||||||
} else {
|
} else {
|
||||||
@@ -1010,56 +1036,202 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val warningView: android.view.View? = if (isUsdToMvr || isSrcCredit) {
|
val fromTypeLabel = AccountListParser.from(src)?.typeLabel
|
||||||
val ctx = requireContext()
|
?: if (src.bank == "BML") BmlDashboardParser.productLabel(src.accountTypeName)
|
||||||
val dp = resources.displayMetrics.density
|
else src.accountTypeName.ifBlank { src.profileType }
|
||||||
LinearLayout(ctx).apply {
|
val fromBankLabel = when (src.bank) {
|
||||||
orientation = LinearLayout.VERTICAL
|
"BML" -> "BML"
|
||||||
setPadding((24 * dp).toInt(), (16 * dp).toInt(), (24 * dp).toInt(), 0)
|
"FAHIPAY" -> "Fahipay"
|
||||||
addView(TextView(ctx).apply { text = mainMsg })
|
"MIB" -> "MIB"
|
||||||
if (isUsdToMvr) addView(TextView(ctx).apply {
|
else -> src.bank
|
||||||
text = "⚠ You are transferring from a USD account to an MVR account. The currency will be converted at the bank's rate and this cannot be reversed!"
|
}
|
||||||
setTextColor(Color.RED)
|
val fromDetail = listOfNotNull(fromBankLabel.ifBlank { null }, fromTypeLabel.ifBlank { null }).joinToString(" · ")
|
||||||
textSize = 16f
|
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
val toTypeLabel = resolvedToOwnAccount?.let { acc ->
|
||||||
setPadding(0, (16 * dp).toInt(), 0, 0)
|
AccountListParser.from(acc)?.typeLabel
|
||||||
})
|
?: if (acc.bank == "BML") BmlDashboardParser.productLabel(acc.accountTypeName)
|
||||||
if (isSrcCredit) addView(TextView(ctx).apply {
|
else acc.accountTypeName.ifBlank { acc.profileType }
|
||||||
text = "⚠ Transferring from a credit card is treated as a cash advance. Cash advance fees will be charged on the 10th of the month."
|
}
|
||||||
setTextColor(Color.RED)
|
val toBankLabel = resolvedToOwnAccount?.let { acc ->
|
||||||
textSize = 16f
|
when (acc.bank) {
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
"BML" -> "BML"
|
||||||
setPadding(0, (16 * dp).toInt(), 0, 0)
|
"FAHIPAY" -> "Fahipay"
|
||||||
})
|
"MIB" -> "MIB"
|
||||||
|
else -> acc.bank
|
||||||
}
|
}
|
||||||
} else null
|
} ?: when {
|
||||||
|
bankNameCapture.equals("MALBMVMV", ignoreCase = true) -> "BML"
|
||||||
|
bankNameCapture.equals("MADVMVMV", ignoreCase = true) -> "MIB"
|
||||||
|
bankNameCapture.isNotBlank() -> bankNameCapture
|
||||||
|
isDestMib -> "MIB"
|
||||||
|
else -> when (selectedFahipayService) {
|
||||||
|
"RAASTAS" -> "Ooredoo · Raastas"
|
||||||
|
"OOREDOO_BILL" -> "Ooredoo · Bill Pay"
|
||||||
|
"DHIRAAGU_RELOAD" -> "Dhiraagu · Reload"
|
||||||
|
"DHIRAAGU_BILL" -> "Dhiraagu · Bill Pay"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val toDetail = listOfNotNull(toBankLabel.ifBlank { null }, toTypeLabel?.ifBlank { null }).joinToString(" · ")
|
||||||
|
|
||||||
|
val warnings = buildList {
|
||||||
|
if (isUsdToMvr) add("⚠ You are transferring from a USD account to an MVR account. The currency will be converted at the bank's rate and this cannot be reversed!")
|
||||||
|
if (isSrcCredit) add("⚠ Transferring from a credit card is treated as a cash advance. Cash advance fees will be charged on the 10th of the month.")
|
||||||
|
}
|
||||||
|
val confirmView = buildTransferConfirmView(
|
||||||
|
amountCurrency = currency,
|
||||||
|
amountValue = "%.2f".format(amount),
|
||||||
|
fromName = src.accountBriefName,
|
||||||
|
fromNumber = src.accountNumber,
|
||||||
|
fromDetail = fromDetail,
|
||||||
|
toName = destDisplay,
|
||||||
|
toNumber = resolvedAccountNumber,
|
||||||
|
toDetail = toDetail,
|
||||||
|
warningTexts = warnings
|
||||||
|
)
|
||||||
showConfirmWithBiometric(
|
showConfirmWithBiometric(
|
||||||
title = getString(R.string.transfer),
|
title = getString(R.string.transfer),
|
||||||
message = if (warningView == null) mainMsg else null,
|
customView = confirmView,
|
||||||
customView = warningView,
|
biometricSubtitle = "$currency ${"%.2f".format(amount)} → $destDisplay",
|
||||||
biometricSubtitle = "$currency $amountStr → $destDisplay",
|
onConfirmed = { dialog, frame -> doTransfer(dialog, frame) }
|
||||||
onConfirmed = { doTransfer() }
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildTransferConfirmView(
|
||||||
|
amountCurrency: String,
|
||||||
|
amountValue: String,
|
||||||
|
fromName: String,
|
||||||
|
fromNumber: String,
|
||||||
|
fromDetail: String,
|
||||||
|
toName: String,
|
||||||
|
toNumber: String,
|
||||||
|
toDetail: String,
|
||||||
|
warningTexts: List<String> = emptyList()
|
||||||
|
): android.view.View {
|
||||||
|
val ctx = requireContext()
|
||||||
|
val dp = resources.displayMetrics.density
|
||||||
|
val colorOnSurface = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorOnSurface, Color.BLACK)
|
||||||
|
val colorMuted = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorOnSurfaceVariant, Color.GRAY)
|
||||||
|
val colorPrimary = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorPrimary, Color.BLUE)
|
||||||
|
val MATCH = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
val WRAP = LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
fun lp(w: Int = MATCH, h: Int = WRAP, init: LinearLayout.LayoutParams.() -> Unit = {}) =
|
||||||
|
LinearLayout.LayoutParams(w, h).apply(init)
|
||||||
|
|
||||||
|
fun accountBlock(label: String, name: String, number: String, detail: String) =
|
||||||
|
LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = lp()
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = label
|
||||||
|
textSize = 10f
|
||||||
|
isAllCaps = true
|
||||||
|
letterSpacing = 0.12f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
})
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = name
|
||||||
|
textSize = 16f
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
setTextColor(colorOnSurface)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
layoutParams = lp { topMargin = (2 * dp).toInt() }
|
||||||
|
})
|
||||||
|
if (number.isNotBlank()) addView(TextView(ctx).apply {
|
||||||
|
text = number
|
||||||
|
textSize = 13f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
})
|
||||||
|
if (detail.isNotBlank()) addView(TextView(ctx).apply {
|
||||||
|
text = detail
|
||||||
|
textSize = 12f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
alpha = 0.75f
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
setPadding((20 * dp).toInt(), (8 * dp).toInt(), (20 * dp).toInt(), (8 * dp).toInt())
|
||||||
|
|
||||||
|
// Currency + amount on same line, centered, baseline-aligned
|
||||||
|
addView(LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = lp { bottomMargin = (20 * dp).toInt() }
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = "$amountCurrency "
|
||||||
|
textSize = 16f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(WRAP, WRAP)
|
||||||
|
})
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = amountValue
|
||||||
|
textSize = 34f
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
setTextColor(colorPrimary)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
addView(accountBlock("From", fromName, fromNumber, fromDetail))
|
||||||
|
|
||||||
|
// Down arrow — centered
|
||||||
|
addView(ImageView(ctx).apply {
|
||||||
|
setImageResource(R.drawable.ic_arrow_right)
|
||||||
|
rotation = 90f
|
||||||
|
setColorFilter(colorMuted)
|
||||||
|
layoutParams = lp(WRAP, WRAP) {
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
width = (24 * dp).toInt()
|
||||||
|
height = (24 * dp).toInt()
|
||||||
|
topMargin = (12 * dp).toInt()
|
||||||
|
bottomMargin = (12 * dp).toInt()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
addView(accountBlock("To", toName, toNumber, toDetail))
|
||||||
|
|
||||||
|
for (warning in warningTexts) {
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = warning
|
||||||
|
setTextColor(Color.RED)
|
||||||
|
textSize = 14f
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
layoutParams = lp { topMargin = (16 * dp).toInt() }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun executeBmlQrPayment(
|
private fun executeBmlQrPayment(
|
||||||
src: BankAccount,
|
src: BankAccount,
|
||||||
debitAccount: String,
|
debitAccount: String,
|
||||||
info: BmlQrPayInfo,
|
info: BmlQrPayInfo,
|
||||||
amount: Double
|
amount: Double,
|
||||||
|
dialog: AlertDialog,
|
||||||
|
frame: android.widget.FrameLayout
|
||||||
) {
|
) {
|
||||||
val app = requireActivity().application as BasedBankApp
|
val app = requireActivity().application as BasedBankApp
|
||||||
val loginId = src.loginTag.removePrefix("bml_")
|
val loginId = src.loginTag.removePrefix("bml_")
|
||||||
val session = bmlSessionFor(src) ?: run {
|
val session = bmlSessionFor(src) ?: run {
|
||||||
|
dialog.dismiss()
|
||||||
Toast.makeText(requireContext(), R.string.transfer_session_unavailable, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), R.string.transfer_session_unavailable, Toast.LENGTH_SHORT).show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val otp = CredentialStore(requireContext()).loadBmlCredentials(loginId)?.otpSeed
|
val otp = CredentialStore(requireContext()).loadBmlCredentials(loginId)?.otpSeed
|
||||||
?.let { Totp.generate(it) }
|
?.let { Totp.generate(it) }
|
||||||
?: run { Toast.makeText(requireContext(), "OTP unavailable", Toast.LENGTH_SHORT).show(); return }
|
?: run { dialog.dismiss(); Toast.makeText(requireContext(), "OTP unavailable", Toast.LENGTH_SHORT).show(); return }
|
||||||
|
|
||||||
binding.btnTransfer.isEnabled = false
|
binding.btnTransfer.isEnabled = false
|
||||||
(activity as? HomeActivity)?.setRefreshing(true)
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
val result = withContext(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) {
|
||||||
@@ -1080,75 +1252,174 @@ class TransferFragment : Fragment() {
|
|||||||
sh.sar.basedbank.api.bml.BmlQrPayResult(false, errorMessage = e.message ?: "Payment failed")
|
sh.sar.basedbank.api.bml.BmlQrPayResult(false, errorMessage = e.message ?: "Payment failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(activity as? HomeActivity)?.setRefreshing(false)
|
|
||||||
if (_binding == null) return@launch
|
if (_binding == null) return@launch
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
dialog.dismiss()
|
||||||
binding.btnTransfer.isEnabled = true
|
binding.btnTransfer.isEnabled = true
|
||||||
Toast.makeText(requireContext(), "Failed to initiate payment", Toast.LENGTH_LONG).show()
|
Toast.makeText(requireContext(), "Failed to initiate payment", Toast.LENGTH_LONG).show()
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
showBmlQrSuccessDialog(
|
showSuccessInDialog(
|
||||||
merchant = result.merchant.ifBlank { info.merchantName },
|
dialog, frame,
|
||||||
amount = result.amount.ifBlank { "%.2f".format(amount) },
|
amountCurrency = result.currency.ifBlank { info.currency },
|
||||||
currency = result.currency.ifBlank { info.currency }
|
amountValue = result.amount.ifBlank { "%.2f".format(amount) },
|
||||||
)
|
fromName = src.accountBriefName,
|
||||||
|
toName = result.merchant.ifBlank { info.merchantName }
|
||||||
|
) {
|
||||||
|
clearForm()
|
||||||
|
(activity as? HomeActivity)?.triggerRefresh()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
dialog.dismiss()
|
||||||
binding.btnTransfer.isEnabled = true
|
binding.btnTransfer.isEnabled = true
|
||||||
Toast.makeText(requireContext(), result.errorMessage, Toast.LENGTH_LONG).show()
|
Toast.makeText(requireContext(), result.errorMessage, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showBmlQrSuccessDialog(merchant: String, amount: String, currency: String) {
|
private fun showProcessingInDialog(dialog: AlertDialog, frame: android.widget.FrameLayout) {
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.visibility = View.GONE
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)?.visibility = View.GONE
|
||||||
|
dialog.setCancelable(false)
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val dp = resources.displayMetrics.density
|
val dp = resources.displayMetrics.density
|
||||||
val container = android.widget.LinearLayout(ctx).apply {
|
val spinner = CircularProgressDrawable(ctx).apply {
|
||||||
orientation = android.widget.LinearLayout.VERTICAL
|
setStyle(CircularProgressDrawable.LARGE)
|
||||||
gravity = android.view.Gravity.CENTER_HORIZONTAL
|
setColorSchemeColors(com.google.android.material.color.MaterialColors.getColor(
|
||||||
setPadding((24 * dp).toInt(), (24 * dp).toInt(), (24 * dp).toInt(), (8 * dp).toInt())
|
requireView(), com.google.android.material.R.attr.colorPrimary, Color.GRAY))
|
||||||
|
start()
|
||||||
}
|
}
|
||||||
container.addView(android.widget.ImageView(ctx).apply {
|
frame.removeAllViews()
|
||||||
setImageResource(R.drawable.ic_check_circle)
|
frame.addView(LinearLayout(ctx).apply {
|
||||||
setColorFilter(android.graphics.Color.parseColor("#4CAF50"))
|
orientation = LinearLayout.VERTICAL
|
||||||
layoutParams = android.widget.LinearLayout.LayoutParams(
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
(64 * dp).toInt(), (64 * dp).toInt()
|
setPadding((24 * dp).toInt(), (24 * dp).toInt(), (24 * dp).toInt(), (24 * dp).toInt())
|
||||||
).apply { gravity = android.view.Gravity.CENTER_HORIZONTAL; bottomMargin = (16 * dp).toInt() }
|
addView(ImageView(ctx).apply {
|
||||||
|
setImageDrawable(spinner)
|
||||||
|
layoutParams = LinearLayout.LayoutParams((48 * dp).toInt(), (48 * dp).toInt()).apply {
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
bottomMargin = (12 * dp).toInt()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = "Processing..."
|
||||||
|
textSize = 16f
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
setTextColor(com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorOnSurface, Color.BLACK))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
container.addView(android.widget.TextView(ctx).apply {
|
|
||||||
text = "$currency $amount"
|
|
||||||
textSize = 28f
|
|
||||||
setTypeface(null, android.graphics.Typeface.BOLD)
|
|
||||||
setTextColor(com.google.android.material.color.MaterialColors.getColor(
|
|
||||||
requireView(), com.google.android.material.R.attr.colorOnSurface, android.graphics.Color.BLACK))
|
|
||||||
gravity = android.view.Gravity.CENTER
|
|
||||||
layoutParams = android.widget.LinearLayout.LayoutParams(
|
|
||||||
android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply { gravity = android.view.Gravity.CENTER_HORIZONTAL; bottomMargin = (8 * dp).toInt() }
|
|
||||||
})
|
|
||||||
container.addView(android.widget.TextView(ctx).apply {
|
|
||||||
text = merchant
|
|
||||||
textSize = 14f
|
|
||||||
setTextColor(com.google.android.material.color.MaterialColors.getColor(
|
|
||||||
requireView(), com.google.android.material.R.attr.colorOnSurfaceVariant, android.graphics.Color.GRAY))
|
|
||||||
gravity = android.view.Gravity.CENTER
|
|
||||||
layoutParams = android.widget.LinearLayout.LayoutParams(
|
|
||||||
android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply { gravity = android.view.Gravity.CENTER_HORIZONTAL }
|
|
||||||
})
|
|
||||||
MaterialAlertDialogBuilder(ctx)
|
|
||||||
.setTitle(R.string.bml_qr_payment_success)
|
|
||||||
.setView(container)
|
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
||||||
requireActivity().onBackPressedDispatcher.onBackPressed()
|
|
||||||
}
|
|
||||||
.setCancelable(false)
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showSuccessInDialog(
|
||||||
|
dialog: AlertDialog,
|
||||||
|
frame: android.widget.FrameLayout,
|
||||||
|
amountCurrency: String,
|
||||||
|
amountValue: String,
|
||||||
|
fromName: String,
|
||||||
|
toName: String,
|
||||||
|
onDone: () -> Unit
|
||||||
|
) {
|
||||||
|
val ctx = requireContext()
|
||||||
|
val dp = resources.displayMetrics.density
|
||||||
|
val colorOnSurface = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorOnSurface, Color.BLACK)
|
||||||
|
val colorMuted = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorOnSurfaceVariant, Color.GRAY)
|
||||||
|
val colorPrimary = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
requireView(), com.google.android.material.R.attr.colorPrimary, Color.BLUE)
|
||||||
|
val MATCH = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
val WRAP = LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
frame.removeAllViews()
|
||||||
|
frame.addView(LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
setPadding((24 * dp).toInt(), (20 * dp).toInt(), (24 * dp).toInt(), (8 * dp).toInt())
|
||||||
|
|
||||||
|
// Checkmark
|
||||||
|
addView(ImageView(ctx).apply {
|
||||||
|
setImageResource(R.drawable.ic_check_circle)
|
||||||
|
setColorFilter(Color.parseColor("#4CAF50"))
|
||||||
|
layoutParams = LinearLayout.LayoutParams((64 * dp).toInt(), (64 * dp).toInt()).apply {
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
bottomMargin = (16 * dp).toInt()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Currency + amount
|
||||||
|
addView(LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(MATCH, WRAP).apply {
|
||||||
|
bottomMargin = (16 * dp).toInt()
|
||||||
|
}
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = "$amountCurrency "
|
||||||
|
textSize = 16f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(WRAP, WRAP)
|
||||||
|
})
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = amountValue
|
||||||
|
textSize = 28f
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
setTextColor(colorPrimary)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// From row
|
||||||
|
addView(LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(MATCH, WRAP)
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = "From "
|
||||||
|
textSize = 12f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(WRAP, WRAP)
|
||||||
|
})
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = fromName
|
||||||
|
textSize = 13f
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
setTextColor(colorOnSurface)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// To row
|
||||||
|
addView(LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(MATCH, WRAP).apply {
|
||||||
|
topMargin = (4 * dp).toInt()
|
||||||
|
}
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = "To "
|
||||||
|
textSize = 12f
|
||||||
|
setTextColor(colorMuted)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(WRAP, WRAP)
|
||||||
|
})
|
||||||
|
addView(TextView(ctx).apply {
|
||||||
|
text = toName
|
||||||
|
textSize = 13f
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
setTextColor(colorOnSurface)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
val okBtn = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
okBtn?.visibility = View.VISIBLE
|
||||||
|
okBtn?.text = "OK"
|
||||||
|
okBtn?.setOnClickListener { dialog.dismiss(); onDone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun doMibTransfer(
|
private fun doMibTransfer(
|
||||||
src: BankAccount,
|
src: BankAccount,
|
||||||
destAccount: String,
|
destAccount: String,
|
||||||
@@ -1718,6 +1989,7 @@ class TransferFragment : Fragment() {
|
|||||||
requireActivity().title = getString(R.string.transfer)
|
requireActivity().title = getString(R.string.transfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
|
|||||||
Reference in New Issue
Block a user