share contact account numbers and PayMV QR for contacts
Auto Tag on Version Change / check-version (push) Successful in 3s
Auto Tag on Version Change / check-version (push) Successful in 3s
This commit is contained in:
@@ -3,6 +3,7 @@ package sh.sar.basedbank.ui.home
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -56,16 +57,25 @@ class ContactDetailsSheetFragment : BottomSheetDialogFragment() {
|
|||||||
binding.tvName.text = contact.name
|
binding.tvName.text = contact.name
|
||||||
|
|
||||||
binding.actionTransfer.visibility = if (contact.canTransfer) View.VISIBLE else View.GONE
|
binding.actionTransfer.visibility = if (contact.canTransfer) View.VISIBLE else View.GONE
|
||||||
|
// QR stays visible for every contact; greyed out where PayMV QR isn't supported yet
|
||||||
|
val canQr = canShowPayMvQr(contact)
|
||||||
|
binding.btnQr.isEnabled = canQr
|
||||||
|
binding.tvQrLabel.alpha = if (canQr) 1f else 0.38f
|
||||||
binding.actionEdit.visibility = if (contact.canEdit) View.VISIBLE else View.GONE
|
binding.actionEdit.visibility = if (contact.canEdit) View.VISIBLE else View.GONE
|
||||||
binding.actionDelete.visibility = if (contact.canDelete) View.VISIBLE else View.GONE
|
binding.actionDelete.visibility = if (contact.canDelete) View.VISIBLE else View.GONE
|
||||||
binding.actionRow.visibility =
|
|
||||||
if (contact.canTransfer || contact.canEdit || contact.canDelete) View.VISIBLE else View.GONE
|
|
||||||
|
|
||||||
binding.btnTransfer.setOnClickListener {
|
binding.btnTransfer.setOnClickListener {
|
||||||
val parent = contactsFragment
|
val parent = contactsFragment
|
||||||
dismiss()
|
dismiss()
|
||||||
parent?.openTransfer(contact)
|
parent?.openTransfer(contact)
|
||||||
}
|
}
|
||||||
|
binding.btnQr.setOnClickListener {
|
||||||
|
val activity = requireActivity() as HomeActivity
|
||||||
|
val bank = contactBank(contact) ?: return@setOnClickListener
|
||||||
|
val qrName = contact.realName.ifBlank { contact.name }
|
||||||
|
dismiss()
|
||||||
|
activity.showWithBackStack(PayMvQrFragment.forContact(contact.accountNumber, qrName, bank))
|
||||||
|
}
|
||||||
binding.btnEdit.setOnClickListener {
|
binding.btnEdit.setOnClickListener {
|
||||||
Toast.makeText(requireContext(), R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
@@ -79,6 +89,9 @@ class ContactDetailsSheetFragment : BottomSheetDialogFragment() {
|
|||||||
val copy = View.OnClickListener { copyAccount(contact.accountNumber) }
|
val copy = View.OnClickListener { copyAccount(contact.accountNumber) }
|
||||||
binding.rowAccount.setOnClickListener(copy)
|
binding.rowAccount.setOnClickListener(copy)
|
||||||
binding.btnCopyAccount.setOnClickListener(copy)
|
binding.btnCopyAccount.setOnClickListener(copy)
|
||||||
|
binding.btnShareAccount.setOnClickListener {
|
||||||
|
shareAccount(contact.realName.ifBlank { contact.name }, contact.accountNumber)
|
||||||
|
}
|
||||||
|
|
||||||
val showRealName = contact.realName.isNotBlank() && contact.realName != contact.name
|
val showRealName = contact.realName.isNotBlank() && contact.realName != contact.name
|
||||||
binding.tvRealName.text = contact.realName
|
binding.tvRealName.text = contact.realName
|
||||||
@@ -108,14 +121,30 @@ class ContactDetailsSheetFragment : BottomSheetDialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logo of the contact's bank; null when we have no logo for it (only MIB and BML for now). */
|
/** Which bank the contact's account is at ("BML" / "MIB"); null when we can't tell. */
|
||||||
private fun bankLogoRes(contact: ContactDisplay): Int? = when {
|
private fun contactBank(contact: ContactDisplay): String? = when {
|
||||||
contact.network == TransferNetwork.MIB -> R.drawable.mib_logo
|
contact.network == TransferNetwork.MIB -> "MIB"
|
||||||
contact.accountNumber.matches(Regex("^7\\d{12}$")) -> R.drawable.bml_logo_vector
|
contact.accountNumber.matches(Regex("^7\\d{12}$")) -> "BML"
|
||||||
contact.accountNumber.matches(Regex("^9\\d{16}$")) -> R.drawable.mib_logo
|
contact.accountNumber.matches(Regex("^9\\d{16}$")) -> "MIB"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Logo of the contact's bank; null when we have no logo for it (only MIB and BML for now). */
|
||||||
|
private fun bankLogoRes(contact: ContactDisplay): Int? = when (contactBank(contact)) {
|
||||||
|
"BML" -> R.drawable.bml_logo_vector
|
||||||
|
"MIB" -> R.drawable.mib_logo
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PayMV QR is only offered for contacts whose account is at BML for now.
|
||||||
|
* TODO: enable for MIB and other banks once their PayMV QR payloads are verified —
|
||||||
|
* PayMvQrFragment.forContact already takes the bank, so this check is the only gate.
|
||||||
|
*/
|
||||||
|
private fun canShowPayMvQr(contact: ContactDisplay): Boolean =
|
||||||
|
contactBank(contact) == "BML" &&
|
||||||
|
contact.currency?.contains("USD", ignoreCase = true) != true // PayMV QR is MVR only
|
||||||
|
|
||||||
private data class SourceProfile(val logoRes: Int, val bankNameRes: Int, val name: String)
|
private data class SourceProfile(val logoRes: Int, val bankNameRes: Int, val name: String)
|
||||||
|
|
||||||
/** Which of the user's own bank profiles this contact is saved under. */
|
/** Which of the user's own bank profiles this contact is saved under. */
|
||||||
@@ -149,6 +178,14 @@ class ContactDetailsSheetFragment : BottomSheetDialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun shareAccount(accountName: String, account: String) {
|
||||||
|
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||||
|
type = "text/plain"
|
||||||
|
putExtra(Intent.EXTRA_TEXT, "$accountName\n$account")
|
||||||
|
}
|
||||||
|
startActivity(Intent.createChooser(intent, getString(R.string.contact_share_account)))
|
||||||
|
}
|
||||||
|
|
||||||
private fun copyAccount(account: String) {
|
private fun copyAccount(account: String) {
|
||||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
clipboard.setPrimaryClip(ClipData.newPlainText("account", account))
|
clipboard.setPrimaryClip(ClipData.newPlainText("account", account))
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ class PayMvQrFragment : Fragment() {
|
|||||||
private val viewModel: HomeViewModel by activityViewModels()
|
private val viewModel: HomeViewModel by activityViewModels()
|
||||||
|
|
||||||
private var selectedAccount: BankAccount? = null
|
private var selectedAccount: BankAccount? = null
|
||||||
|
/** Set when opened for a saved contact: the QR is for their account, not one of ours. */
|
||||||
|
private var contactTarget: QrTarget? = null
|
||||||
private var generatedBitmap: Bitmap? = null
|
private var generatedBitmap: Bitmap? = null
|
||||||
private var generateJob: Job? = null
|
private var generateJob: Job? = null
|
||||||
private val dropdownProfileImageCache = mutableMapOf<String, Bitmap>()
|
private val dropdownProfileImageCache = mutableMapOf<String, Bitmap>()
|
||||||
@@ -59,7 +61,17 @@ class PayMvQrFragment : Fragment() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Who the QR pays into — one of our own accounts, or a contact's. */
|
||||||
|
private data class QrTarget(val accountNumber: String, val name: String, val bank: String)
|
||||||
|
|
||||||
|
private fun currentTarget(): QrTarget? = contactTarget
|
||||||
|
?: selectedAccount?.let { QrTarget(it.accountNumber, it.accountBriefName, it.bank) }
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
contactTarget = arguments?.let { args ->
|
||||||
|
val number = args.getString(ARG_ACCOUNT_NUMBER) ?: return@let null
|
||||||
|
QrTarget(number, args.getString(ARG_ACCOUNT_NAME).orEmpty(), args.getString(ARG_BANK).orEmpty())
|
||||||
|
}
|
||||||
val basePaddingBottom = view.paddingBottom
|
val basePaddingBottom = view.paddingBottom
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
|
||||||
val bottomNav = activity?.findViewById<View>(R.id.bottomNavigation)
|
val bottomNav = activity?.findViewById<View>(R.id.bottomNavigation)
|
||||||
@@ -68,7 +80,15 @@ class PayMvQrFragment : Fragment() {
|
|||||||
v.updatePadding(bottom = basePaddingBottom + navBarBottom)
|
v.updatePadding(bottom = basePaddingBottom + navBarBottom)
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
|
if (contactTarget != null) {
|
||||||
|
// Not our account, so no account picker and our phone number doesn't belong on it
|
||||||
|
binding.tilAccount.visibility = View.GONE
|
||||||
|
binding.layoutIncludePhone.visibility = View.GONE
|
||||||
|
binding.switchIncludePhone.isChecked = false
|
||||||
|
scheduleGenerate()
|
||||||
|
} else {
|
||||||
setupDropdown()
|
setupDropdown()
|
||||||
|
}
|
||||||
binding.etAmount.addTextChangedListener { scheduleGenerate() }
|
binding.etAmount.addTextChangedListener { scheduleGenerate() }
|
||||||
binding.etReference.addTextChangedListener { scheduleGenerate() }
|
binding.etReference.addTextChangedListener { scheduleGenerate() }
|
||||||
binding.switchIncludePhone.setOnCheckedChangeListener { _, _ -> scheduleGenerate() }
|
binding.switchIncludePhone.setOnCheckedChangeListener { _, _ -> scheduleGenerate() }
|
||||||
@@ -119,8 +139,8 @@ class PayMvQrFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun generateQr() {
|
private suspend fun generateQr() {
|
||||||
val account = selectedAccount ?: return
|
val target = currentTarget() ?: return
|
||||||
val acquirer = when (account.bank) {
|
val acquirer = when (target.bank) {
|
||||||
"BML" -> "MALBMVMV"
|
"BML" -> "MALBMVMV"
|
||||||
"MIB" -> "MADVMVMV"
|
"MIB" -> "MADVMVMV"
|
||||||
"FAHIPAY" -> "FAHIMVMV"
|
"FAHIPAY" -> "FAHIMVMV"
|
||||||
@@ -133,10 +153,10 @@ class PayMvQrFragment : Fragment() {
|
|||||||
?.let { "%.2f".format(it) }
|
?.let { "%.2f".format(it) }
|
||||||
|
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val includePhone = binding.switchIncludePhone.isChecked
|
val account = selectedAccount
|
||||||
|
val mobile = if (binding.switchIncludePhone.isChecked && contactTarget == null && account != null) {
|
||||||
val loginId = sh.sar.basedbank.util.ProfileImageStore.loginIdFromTag(account.loginTag)
|
val loginId = sh.sar.basedbank.util.ProfileImageStore.loginIdFromTag(account.loginTag)
|
||||||
val store = CredentialStore(ctx)
|
val store = CredentialStore(ctx)
|
||||||
val mobile = if (includePhone) {
|
|
||||||
when (account.bank) {
|
when (account.bank) {
|
||||||
"BML" -> store.loadBmlUserProfile(loginId)?.mobile
|
"BML" -> store.loadBmlUserProfile(loginId)?.mobile
|
||||||
"FAHIPAY" -> store.loadFahipayUserProfile(loginId)?.mobile
|
"FAHIPAY" -> store.loadFahipayUserProfile(loginId)?.mobile
|
||||||
@@ -154,8 +174,8 @@ class PayMvQrFragment : Fragment() {
|
|||||||
?.takeIf { it.isNotBlank() } ?: getString(R.string.paymvqr_reference_default)
|
?.takeIf { it.isNotBlank() } ?: getString(R.string.paymvqr_reference_default)
|
||||||
|
|
||||||
val bmp = withContext(Dispatchers.Default) {
|
val bmp = withContext(Dispatchers.Default) {
|
||||||
val payload = buildQrPayload(account.accountNumber, account.accountBriefName, acquirer, amountFormatted, mobile, purpose)
|
val payload = buildQrPayload(target.accountNumber, target.name, acquirer, amountFormatted, mobile, purpose)
|
||||||
renderQrCard(ctx, account, payload, amountFormatted)
|
renderQrCard(ctx, target, payload, amountFormatted)
|
||||||
}
|
}
|
||||||
if (_binding == null) return
|
if (_binding == null) return
|
||||||
generatedBitmap = bmp
|
generatedBitmap = bmp
|
||||||
@@ -224,7 +244,7 @@ class PayMvQrFragment : Fragment() {
|
|||||||
|
|
||||||
private fun renderQrCard(
|
private fun renderQrCard(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
account: BankAccount,
|
target: QrTarget,
|
||||||
qrPayload: String,
|
qrPayload: String,
|
||||||
amountStr: String?
|
amountStr: String?
|
||||||
): Bitmap {
|
): Bitmap {
|
||||||
@@ -246,7 +266,7 @@ class PayMvQrFragment : Fragment() {
|
|||||||
canvas.drawColor(Color.WHITE)
|
canvas.drawColor(Color.WHITE)
|
||||||
|
|
||||||
// --- Bank logo top-left ---
|
// --- Bank logo top-left ---
|
||||||
val logoRes = when (account.bank) {
|
val logoRes = when (target.bank) {
|
||||||
"BML" -> R.drawable.bml_logo_vector
|
"BML" -> R.drawable.bml_logo_vector
|
||||||
"MIB" -> R.drawable.mib_faisanet_logo
|
"MIB" -> R.drawable.mib_faisanet_logo
|
||||||
else -> R.drawable.fahipay_logo_long
|
else -> R.drawable.fahipay_logo_long
|
||||||
@@ -279,7 +299,7 @@ class PayMvQrFragment : Fragment() {
|
|||||||
paint.color = Color.WHITE
|
paint.color = Color.WHITE
|
||||||
paint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
|
paint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
|
||||||
paint.textAlign = Paint.Align.CENTER
|
paint.textAlign = Paint.Align.CENTER
|
||||||
val nameText = account.accountBriefName.uppercase()
|
val nameText = target.name.uppercase()
|
||||||
paint.textSize = 36f
|
paint.textSize = 36f
|
||||||
val maxNameW = boxR - boxL - 48f
|
val maxNameW = boxR - boxL - 48f
|
||||||
if (paint.measureText(nameText) > maxNameW) {
|
if (paint.measureText(nameText) > maxNameW) {
|
||||||
@@ -338,13 +358,13 @@ class PayMvQrFragment : Fragment() {
|
|||||||
|
|
||||||
private fun shareQr() {
|
private fun shareQr() {
|
||||||
val bmp = generatedBitmap ?: return
|
val bmp = generatedBitmap ?: return
|
||||||
val account = selectedAccount ?: return
|
val target = currentTarget() ?: return
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val uri = withContext(Dispatchers.IO) {
|
val uri = withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val dir = File(requireContext().cacheDir, "qr")
|
val dir = File(requireContext().cacheDir, "qr")
|
||||||
dir.mkdirs()
|
dir.mkdirs()
|
||||||
val safeName = account.accountBriefName.replace(Regex("[^A-Za-z0-9_]"), "_")
|
val safeName = target.name.replace(Regex("[^A-Za-z0-9_]"), "_")
|
||||||
val file = File(dir, "${safeName}_paymv_qr.png")
|
val file = File(dir, "${safeName}_paymv_qr.png")
|
||||||
FileOutputStream(file).use { bmp.compress(Bitmap.CompressFormat.PNG, 100, it) }
|
FileOutputStream(file).use { bmp.compress(Bitmap.CompressFormat.PNG, 100, it) }
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
@@ -366,11 +386,11 @@ class PayMvQrFragment : Fragment() {
|
|||||||
|
|
||||||
private fun saveQr() {
|
private fun saveQr() {
|
||||||
val bmp = generatedBitmap ?: return
|
val bmp = generatedBitmap ?: return
|
||||||
val account = selectedAccount ?: return
|
val target = currentTarget() ?: return
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val saved = withContext(Dispatchers.IO) {
|
val saved = withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val safeName = account.accountBriefName.replace(Regex("[^A-Za-z0-9_]"), "_")
|
val safeName = target.name.replace(Regex("[^A-Za-z0-9_]"), "_")
|
||||||
val filename = "${safeName}_PayMV_QR.png"
|
val filename = "${safeName}_PayMV_QR.png"
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
val values = ContentValues().apply {
|
val values = ContentValues().apply {
|
||||||
@@ -412,6 +432,21 @@ class PayMvQrFragment : Fragment() {
|
|||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ARG_ACCOUNT_NUMBER = "account_number"
|
||||||
|
private const val ARG_ACCOUNT_NAME = "account_name"
|
||||||
|
private const val ARG_BANK = "bank"
|
||||||
|
|
||||||
|
/** QR for a contact's account. [bank] is "BML" / "MIB" / "FAHIPAY", as on [BankAccount.bank]. */
|
||||||
|
fun forContact(accountNumber: String, name: String, bank: String) = PayMvQrFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putString(ARG_ACCOUNT_NUMBER, accountNumber)
|
||||||
|
putString(ARG_ACCOUNT_NAME, name)
|
||||||
|
putString(ARG_BANK, bank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Account dropdown adapter ──────────────────────────────────────────────
|
// ── Account dropdown adapter ──────────────────────────────────────────────
|
||||||
|
|
||||||
private inner class QrAccountAdapter(
|
private inner class QrAccountAdapter(
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M3,11h8V3H3V11zM5,5h4v4H5V5zM3,21h8v-8H3V21zM5,15h4v4H5V15zM13,3v8h8V3H13zM19,9h-4V5h4V9zM19,19h2v2h-2V19zM13,13h2v2h-2V13zM15,15h2v2h-2V15zM13,17h2v2h-2V17zM15,19h2v2h-2V19zM17,17h2v2h-2V17zM17,13h2v2h-2V13zM19,15h2v2h-2V15z" />
|
||||||
|
</vector>
|
||||||
@@ -95,6 +95,7 @@
|
|||||||
|
|
||||||
<!-- Include phone number toggle -->
|
<!-- Include phone number toggle -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutIncludePhone"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
|
|||||||
@@ -56,18 +56,62 @@
|
|||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:contentDescription="@string/transfer"
|
android:contentDescription="@string/transfer"
|
||||||
app:icon="@drawable/ic_send"
|
app:icon="@drawable/ic_send"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp"
|
||||||
app:iconSize="24dp" />
|
app:iconSize="24dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
|
android:gravity="center"
|
||||||
android:text="@string/transfer"
|
android:text="@string/transfer"
|
||||||
android:textAppearance="?attr/textAppearanceLabelMedium"
|
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||||
android:textColor="?attr/colorOnSurface" />
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/actionQr"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnQr"
|
||||||
|
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:contentDescription="@string/contact_qr"
|
||||||
|
app:icon="@drawable/ic_qr_code"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
app:iconSize="24dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvQrLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/contact_qr"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||||
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/actionEdit"
|
android:id="@+id/actionEdit"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -83,12 +127,20 @@
|
|||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:contentDescription="@string/contact_edit"
|
android:contentDescription="@string/contact_edit"
|
||||||
app:icon="@drawable/ic_edit"
|
app:icon="@drawable/ic_edit"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp"
|
||||||
app:iconSize="24dp" />
|
app:iconSize="24dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
|
android:gravity="center"
|
||||||
android:text="@string/contact_edit"
|
android:text="@string/contact_edit"
|
||||||
android:textAppearance="?attr/textAppearanceLabelMedium"
|
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||||
android:textColor="?attr/colorOnSurface" />
|
android:textColor="?attr/colorOnSurface" />
|
||||||
@@ -111,6 +163,13 @@
|
|||||||
android:contentDescription="@string/contact_delete"
|
android:contentDescription="@string/contact_delete"
|
||||||
app:backgroundTint="?attr/colorErrorContainer"
|
app:backgroundTint="?attr/colorErrorContainer"
|
||||||
app:icon="@drawable/ic_delete"
|
app:icon="@drawable/ic_delete"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorOnErrorContainer" />
|
app:iconTint="?attr/colorOnErrorContainer" />
|
||||||
|
|
||||||
@@ -118,6 +177,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
|
android:gravity="center"
|
||||||
android:text="@string/contact_delete"
|
android:text="@string/contact_delete"
|
||||||
android:textAppearance="?attr/textAppearanceLabelMedium"
|
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||||
android:textColor="?attr/colorError" />
|
android:textColor="?attr/colorError" />
|
||||||
@@ -174,6 +234,16 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btnShareAccount"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/contact_share_account"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_share"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/btnCopyAccount"
|
android:id="@+id/btnCopyAccount"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
|
|||||||
@@ -335,8 +335,10 @@
|
|||||||
<string name="contact_account_number">Account number</string>
|
<string name="contact_account_number">Account number</string>
|
||||||
<string name="contact_account_name">Account name</string>
|
<string name="contact_account_name">Account name</string>
|
||||||
<string name="contact_bank">Bank</string>
|
<string name="contact_bank">Bank</string>
|
||||||
|
<string name="contact_qr">QR</string>
|
||||||
<string name="contact_delete_warning">This can\'t be undone.</string>
|
<string name="contact_delete_warning">This can\'t be undone.</string>
|
||||||
<string name="contact_copy_account">Copy account number</string>
|
<string name="contact_copy_account">Copy account number</string>
|
||||||
|
<string name="contact_share_account">Share account details</string>
|
||||||
<string name="contact_account_copied">Account number copied</string>
|
<string name="contact_account_copied">Account number copied</string>
|
||||||
|
|
||||||
<!-- Financing -->
|
<!-- Financing -->
|
||||||
|
|||||||
Reference in New Issue
Block a user