redegsigned contacts page: removed delete and edit buttons from contacts list, made a new contacts sheet and moved buttons there
Auto Tag on Version Change / check-version (push) Successful in 4s
Auto Tag on Version Change / check-version (push) Successful in 4s
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
package sh.sar.basedbank.ui.home
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import sh.sar.basedbank.R
|
||||
import sh.sar.basedbank.databinding.SheetContactDetailsBinding
|
||||
import sh.sar.basedbank.util.ContactDisplay
|
||||
import sh.sar.basedbank.util.ContactImageCache
|
||||
import sh.sar.basedbank.util.ContactListParser
|
||||
import sh.sar.basedbank.util.CredentialStore
|
||||
import sh.sar.basedbank.util.TransferNetwork
|
||||
|
||||
/** Contact details drawer shown when a row in [ContactsFragment] is tapped. */
|
||||
class ContactDetailsSheetFragment : BottomSheetDialogFragment() {
|
||||
|
||||
private var _binding: SheetContactDetailsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private val viewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
private val contactsFragment get() = parentFragment as? ContactsFragment
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = SheetContactDetailsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val args = requireArguments()
|
||||
val contactId = args.getString(ARG_CONTACT_ID)
|
||||
val profileId = args.getString(ARG_PROFILE_ID)
|
||||
viewModel.contacts.observe(viewLifecycleOwner) { contacts ->
|
||||
val contact = contacts.firstOrNull { it.benefNo == contactId && it.profileId == profileId }
|
||||
?.let { ContactListParser.from(it) }
|
||||
if (contact == null) dismissAllowingStateLoss() else bind(contact)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bind(contact: ContactDisplay) {
|
||||
val sizePx = resources.getDimensionPixelSize(android.R.dimen.app_icon_size).coerceAtLeast(96) * 2
|
||||
val photo = contact.imageHash?.let { ContactImageCache.load(requireContext(), it) }
|
||||
binding.ivPhoto.setImageBitmap(photo ?: contactInitialsBitmap(contact.name, contact.bankColor, sizePx))
|
||||
|
||||
binding.tvName.text = contact.name
|
||||
|
||||
binding.actionTransfer.visibility = if (contact.canTransfer) 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.actionRow.visibility =
|
||||
if (contact.canTransfer || contact.canEdit || contact.canDelete) View.VISIBLE else View.GONE
|
||||
|
||||
binding.btnTransfer.setOnClickListener {
|
||||
val parent = contactsFragment
|
||||
dismiss()
|
||||
parent?.openTransfer(contact)
|
||||
}
|
||||
binding.btnEdit.setOnClickListener {
|
||||
Toast.makeText(requireContext(), R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
binding.btnDelete.setOnClickListener {
|
||||
val parent = contactsFragment
|
||||
dismiss()
|
||||
parent?.confirmDelete(contact)
|
||||
}
|
||||
|
||||
binding.tvAccount.text = contact.accountNumber
|
||||
val copy = View.OnClickListener { copyAccount(contact.accountNumber) }
|
||||
binding.rowAccount.setOnClickListener(copy)
|
||||
binding.btnCopyAccount.setOnClickListener(copy)
|
||||
|
||||
val showRealName = contact.realName.isNotBlank() && contact.realName != contact.name
|
||||
binding.tvRealName.text = contact.realName
|
||||
binding.rowRealName.visibility = if (showRealName) View.VISIBLE else View.GONE
|
||||
|
||||
binding.tvCurrency.text = contact.currency ?: ""
|
||||
binding.rowCurrency.visibility = if (contact.currency != null) View.VISIBLE else View.GONE
|
||||
|
||||
binding.tvBank.text = contact.bankName ?: ""
|
||||
binding.rowBank.visibility = if (contact.bankName != null) View.VISIBLE else View.GONE
|
||||
val bankLogo = bankLogoRes(contact)
|
||||
if (bankLogo != null) {
|
||||
binding.ivBankIcon.setImageResource(bankLogo)
|
||||
binding.ivBankIcon.imageTintList = null
|
||||
}
|
||||
|
||||
binding.sourceSection.visibility = View.GONE
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
val appContext = requireContext().applicationContext
|
||||
val source = withContext(Dispatchers.IO) { sourceProfile(appContext, contact) }
|
||||
val b = _binding ?: return@launch
|
||||
if (source == null) return@launch
|
||||
b.ivSourceIcon.setImageResource(source.logoRes)
|
||||
b.tvSource.text = source.name
|
||||
b.tvSourceBank.setText(source.bankNameRes)
|
||||
b.sourceSection.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 {
|
||||
contact.network == TransferNetwork.MIB -> R.drawable.mib_logo
|
||||
contact.accountNumber.matches(Regex("^7\\d{12}$")) -> R.drawable.bml_logo_vector
|
||||
contact.accountNumber.matches(Regex("^9\\d{16}$")) -> R.drawable.mib_logo
|
||||
else -> null
|
||||
}
|
||||
|
||||
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. */
|
||||
private fun sourceProfile(context: Context, contact: ContactDisplay): SourceProfile? {
|
||||
val store = CredentialStore(context)
|
||||
return when (contact.network) {
|
||||
TransferNetwork.BML -> {
|
||||
// BML contacts carry either the loginId or a BML profileId
|
||||
val loginId = store.getBmlLoginIds().firstOrNull { loginId ->
|
||||
loginId == contact.profileId ||
|
||||
store.loadBmlProfiles(loginId).any { it.profileId == contact.profileId }
|
||||
} ?: return null
|
||||
val profile = store.loadBmlProfiles(loginId).firstOrNull { it.profileId == contact.profileId }
|
||||
val fullName = store.loadBmlUserProfile(loginId)?.fullName?.takeIf { it.isNotBlank() }
|
||||
val name = (if (profile != null && profile.profileType == "business") profile.name else fullName ?: profile?.name)
|
||||
?: return null
|
||||
SourceProfile(R.drawable.bml_logo_vector, R.string.bml_name, name)
|
||||
}
|
||||
TransferNetwork.FAHIPAY -> {
|
||||
val name = store.getFahipayLoginIds().firstNotNullOfOrNull { loginId ->
|
||||
store.loadFahipayUserProfile(loginId)?.fullName?.takeIf { it.isNotBlank() }
|
||||
} ?: return null
|
||||
SourceProfile(R.drawable.fahipay_logo, R.string.fahipay_name, name)
|
||||
}
|
||||
else -> {
|
||||
val profile = store.getMibLoginIds().firstNotNullOfOrNull { loginId ->
|
||||
store.loadMibProfiles(loginId).firstOrNull { it.profileId == contact.profileId }
|
||||
} ?: return null
|
||||
SourceProfile(R.drawable.mib_logo, R.string.mib_name, profile.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyAccount(account: String) {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("account", account))
|
||||
Toast.makeText(requireContext(), R.string.contact_account_copied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ARG_CONTACT_ID = "contact_id"
|
||||
private const val ARG_PROFILE_ID = "profile_id"
|
||||
|
||||
fun newInstance(contact: ContactDisplay) = ContactDetailsSheetFragment().apply {
|
||||
arguments = bundleOf(ARG_CONTACT_ID to contact.id, ARG_PROFILE_ID to contact.profileId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,14 +11,13 @@ import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import sh.sar.basedbank.R
|
||||
import sh.sar.basedbank.databinding.ItemContactBinding
|
||||
import sh.sar.basedbank.util.ContactDisplay
|
||||
|
||||
class ContactsAdapter(
|
||||
private val imageCache: MutableMap<String, Bitmap>,
|
||||
private val onImageNeeded: (hash: String) -> Unit,
|
||||
private val onDeleteClick: (ContactDisplay) -> Unit,
|
||||
private val onContactClick: (ContactDisplay) -> Unit,
|
||||
private val onTransferClick: (ContactDisplay) -> Unit
|
||||
) : RecyclerView.Adapter<ContactsAdapter.ViewHolder>() {
|
||||
|
||||
@@ -66,12 +65,9 @@ class ContactsAdapter(
|
||||
val pos = holder.bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) onTransferClick(displayed[pos])
|
||||
}
|
||||
binding.btnEditContact.setOnClickListener {
|
||||
Toast.makeText(it.context, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
binding.btnDeleteContact.setOnClickListener {
|
||||
binding.root.setOnClickListener {
|
||||
val pos = holder.bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) onDeleteClick(displayed[pos])
|
||||
if (pos != RecyclerView.NO_POSITION) onContactClick(displayed[pos])
|
||||
}
|
||||
binding.root.setOnLongClickListener {
|
||||
val pos = holder.bindingAdapterPosition
|
||||
@@ -107,24 +103,22 @@ class ContactsAdapter(
|
||||
if (contact.detail != null) android.view.View.VISIBLE else android.view.View.GONE
|
||||
binding.btnTransferContact.visibility =
|
||||
if (contact.canTransfer) android.view.View.VISIBLE else android.view.View.GONE
|
||||
binding.btnEditContact.visibility =
|
||||
if (contact.canEdit) android.view.View.VISIBLE else android.view.View.GONE
|
||||
binding.btnDeleteContact.visibility =
|
||||
if (contact.canDelete) android.view.View.VISIBLE else android.view.View.GONE
|
||||
|
||||
if (photo != null) {
|
||||
binding.ivContactPhoto.setImageBitmap(photo)
|
||||
} else {
|
||||
binding.ivContactPhoto.setImageBitmap(
|
||||
makeInitialsBitmap(contact.name, contact.bankColor)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeInitialsBitmap(name: String, colorHex: String): Bitmap {
|
||||
val sizePx = binding.ivContactPhoto.context.resources
|
||||
.getDimensionPixelSize(android.R.dimen.app_icon_size)
|
||||
.coerceAtLeast(96)
|
||||
binding.ivContactPhoto.setImageBitmap(
|
||||
contactInitialsBitmap(contact.name, contact.bankColor, sizePx)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun contactInitialsBitmap(name: String, colorHex: String, sizePx: Int): Bitmap {
|
||||
val bgColor = try { Color.parseColor(colorHex) } catch (e: Exception) { Color.GRAY }
|
||||
val bm = Bitmap.createBitmap(sizePx, sizePx, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bm)
|
||||
@@ -138,6 +132,4 @@ class ContactsAdapter(
|
||||
val metrics = paint.fontMetrics
|
||||
canvas.drawText(letter, sizePx / 2f, sizePx / 2f - (metrics.ascent + metrics.descent) / 2f, paint)
|
||||
return bm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,20 @@ package sh.sar.basedbank.ui.home
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Typeface
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.os.Bundle
|
||||
import android.util.Base64
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
@@ -59,7 +66,7 @@ class ContactsFragment : Fragment() {
|
||||
ContactsAdapter(
|
||||
imageCache = sharedImageCache,
|
||||
onImageNeeded = { hash -> fetchImage(hash) },
|
||||
onDeleteClick = { contact -> confirmDelete(contact) },
|
||||
onContactClick = { contact -> showDetails(contact) },
|
||||
onTransferClick = { contact -> openTransfer(contact) }
|
||||
).also { a ->
|
||||
a.setFilter(page.categoryId, currentSearch)
|
||||
@@ -170,7 +177,12 @@ class ContactsFragment : Fragment() {
|
||||
binding.viewPager.setCurrentItem(savedPosition.coerceIn(0, pages.size - 1), false)
|
||||
}
|
||||
|
||||
private fun openTransfer(contact: ContactDisplay) {
|
||||
private fun showDetails(contact: ContactDisplay) {
|
||||
if (childFragmentManager.findFragmentByTag("contact_details") != null) return
|
||||
ContactDetailsSheetFragment.newInstance(contact).show(childFragmentManager, "contact_details")
|
||||
}
|
||||
|
||||
internal fun openTransfer(contact: ContactDisplay) {
|
||||
val fragment = TransferFragment.newInstance(
|
||||
accountNumber = contact.accountNumber,
|
||||
displayName = contact.name,
|
||||
@@ -181,10 +193,26 @@ class ContactsFragment : Fragment() {
|
||||
(requireActivity() as HomeActivity).showWithBackStack(fragment)
|
||||
}
|
||||
|
||||
private fun confirmDelete(contact: ContactDisplay) {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
internal fun confirmDelete(contact: ContactDisplay) {
|
||||
val ctx = requireContext()
|
||||
val errorColor = MaterialColors.getColor(binding.root, com.google.android.material.R.attr.colorError)
|
||||
val icon = ContextCompat.getDrawable(ctx, R.drawable.ic_delete)?.mutate()?.apply { setTint(errorColor) }
|
||||
|
||||
val prompt = getString(R.string.contact_delete_message, contact.name)
|
||||
val message = SpannableStringBuilder(prompt).apply {
|
||||
val start = prompt.indexOf(contact.name)
|
||||
if (start >= 0) setSpan(StyleSpan(Typeface.BOLD), start, start + contact.name.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
append("\n").append(contact.accountNumber)
|
||||
append("\n\n")
|
||||
val warnStart = length
|
||||
append(getString(R.string.contact_delete_warning))
|
||||
setSpan(ForegroundColorSpan(errorColor), warnStart, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_BasedBank_DestructiveDialog)
|
||||
.setIcon(icon)
|
||||
.setTitle(R.string.contact_delete_title)
|
||||
.setMessage(getString(R.string.contact_delete_message, contact.name))
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.contact_delete) { _, _ -> deleteContact(contact) }
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
|
||||
@@ -13,6 +13,8 @@ data class ContactDisplay(
|
||||
val network: TransferNetwork,
|
||||
val bankColor: String,
|
||||
val detail: String?, // pre-formatted "Name · CCY · Bank" line; null = hide row
|
||||
val bankName: String?, // shown in the contact details sheet; null = hide row
|
||||
val currency: String?, // shown in the contact details sheet; null = hide row
|
||||
val imageHash: String?,
|
||||
val profileId: String, // MIB profile ID or BML loginTag (needed by ContactManager)
|
||||
val transferSubtitle: String, // "Bank · accountNumber" shown in transfer screen
|
||||
|
||||
@@ -15,6 +15,8 @@ object BmlContactParser {
|
||||
network = TransferNetwork.BML,
|
||||
bankColor = contact.bankColor,
|
||||
detail = "${contact.benefName} · ${contact.transferCyDesc} · ${contact.benefBankName}",
|
||||
bankName = contact.benefBankName.takeIf { it.isNotBlank() },
|
||||
currency = contact.transferCyDesc.takeIf { it.isNotBlank() },
|
||||
imageHash = contact.customerImgHash,
|
||||
profileId = contact.profileId,
|
||||
transferSubtitle = "${contact.benefBankName} · ${contact.benefAccount}",
|
||||
|
||||
@@ -15,6 +15,8 @@ object FahipayContactParser {
|
||||
network = TransferNetwork.FAHIPAY,
|
||||
bankColor = contact.bankColor,
|
||||
detail = null, // Fahipay contacts show no detail line
|
||||
bankName = contact.benefBankName.takeIf { it.isNotBlank() },
|
||||
currency = contact.transferCyDesc.takeIf { it.isNotBlank() },
|
||||
imageHash = contact.customerImgHash,
|
||||
profileId = contact.profileId,
|
||||
transferSubtitle = contact.benefAccount,
|
||||
|
||||
@@ -21,6 +21,8 @@ object MibContactParser {
|
||||
network = network,
|
||||
bankColor = contact.bankColor,
|
||||
detail = "${contact.benefName} · ${contact.transferCyDesc} · ${contact.benefBankName}",
|
||||
bankName = contact.benefBankName.takeIf { it.isNotBlank() },
|
||||
currency = contact.transferCyDesc.takeIf { it.isNotBlank() },
|
||||
imageHash = contact.customerImgHash,
|
||||
profileId = contact.profileId,
|
||||
transferSubtitle = "${contact.benefBankName} · ${contact.benefAccount}",
|
||||
|
||||
@@ -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="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.61 -4.7,-4.2z" />
|
||||
</vector>
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="10dp">
|
||||
|
||||
@@ -26,25 +27,6 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnEditContact"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_edit"
|
||||
android:padding="6dp"
|
||||
android:contentDescription="@string/contact_edit" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnDeleteContact"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:padding="6dp"
|
||||
android:tint="?attr/colorError"
|
||||
android:contentDescription="@string/contact_delete" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnTransferContact"
|
||||
android:layout_width="36dp"
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
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">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="24dp">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/ivPhoto"
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="112dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:scaleType="centerCrop"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearance.Circle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:textAppearance="?attr/textAppearanceHeadlineSmall"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actionRow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actionTransfer"
|
||||
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/btnTransfer"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:contentDescription="@string/transfer"
|
||||
app:icon="@drawable/ic_send"
|
||||
app:iconSize="24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/transfer"
|
||||
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actionEdit"
|
||||
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/btnEdit"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:contentDescription="@string/contact_edit"
|
||||
app:icon="@drawable/ic_edit"
|
||||
app:iconSize="24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/contact_edit"
|
||||
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actionDelete"
|
||||
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/btnDelete"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:contentDescription="@string/contact_delete"
|
||||
app:backgroundTint="?attr/colorErrorContainer"
|
||||
app:icon="@drawable/ic_delete"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnErrorContainer" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/contact_delete"
|
||||
android:textAppearance="?attr/textAppearanceLabelMedium"
|
||||
android:textColor="?attr/colorError" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rowAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="64dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_manage_card"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/contact_account_number"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnCopyAccount"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/contact_copy_account"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_copy"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rowRealName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="64dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_contacts"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvRealName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/contact_account_name"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rowCurrency"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="64dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_currency"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCurrency"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/contact_currency"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rowBank"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="64dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivBankIcon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_nav_finances"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBank"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/contact_bank"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sourceSection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivSourceIcon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSource"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSourceBank"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
@@ -332,6 +332,12 @@
|
||||
<string name="contact_delete_message">Remove %s from your contacts?</string>
|
||||
<string name="contact_deleted">Contact deleted</string>
|
||||
<string name="contact_delete_failed">Could not delete contact</string>
|
||||
<string name="contact_account_number">Account number</string>
|
||||
<string name="contact_account_name">Account name</string>
|
||||
<string name="contact_bank">Bank</string>
|
||||
<string name="contact_delete_warning">This can\'t be undone.</string>
|
||||
<string name="contact_copy_account">Copy account number</string>
|
||||
<string name="contact_account_copied">Account number copied</string>
|
||||
|
||||
<!-- Financing -->
|
||||
<string name="financing_empty">No financing deals found</string>
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="ShapeAppearance.Circle" parent="ShapeAppearance.Material3.Corner.Full" />
|
||||
|
||||
<!-- Destructive confirmation dialog: centered icon/title, filled red confirm button -->
|
||||
<style name="ThemeOverlay.BasedBank.DestructiveDialog" parent="ThemeOverlay.Material3.MaterialAlertDialog.Centered">
|
||||
<item name="buttonBarPositiveButtonStyle">@style/Widget.BasedBank.DestructiveDialogButton</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.BasedBank.DestructiveDialogButton" parent="Widget.Material3.Button">
|
||||
<item name="backgroundTint">?attr/colorError</item>
|
||||
<item name="android:textColor">?attr/colorOnError</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.BasedBank" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/seed_primary</item>
|
||||
<item name="colorSecondary">@color/seed_secondary</item>
|
||||
|
||||
Reference in New Issue
Block a user