diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt
index 0a6c4a8..65b6c11 100644
--- a/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt
+++ b/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt
@@ -80,6 +80,8 @@ class TransferFragment : Fragment() {
private var resolvedAccountNumber = ""
private var resolvedRecipientName = ""
private var resolvedBankName = ""
+ /** Last real profile/contact photo loaded into the "To" card (not an initials placeholder). */
+ private var loadedToPhoto: Bitmap? = null
private var resolvedDestCurrency = "" // "MVR" / "USD" / "" if unknown
private var resolvedToOwnAccount: BankAccount? = null
@@ -1168,6 +1170,8 @@ class TransferFragment : Fragment() {
val destDisplay = binding.tvToAccountName.text?.toString() ?: resolvedAccountNumber
val bankNameCapture = resolvedBankName
val capturedToAvatar = (binding.ivToPhoto.drawable as? android.graphics.drawable.BitmapDrawable)?.bitmap
+ // The MIB receipt only takes a real photo; it draws its own initials placeholder otherwise
+ val capturedToPhoto = capturedToAvatar?.takeIf { it === loadedToPhoto }
val destCurrency = resolvedDestCurrency.ifBlank {
allAccounts.firstOrNull { it.accountNumber == resolvedAccountNumber }
@@ -1205,7 +1209,7 @@ class TransferFragment : Fragment() {
val activity = requireActivity() as HomeActivity
activity.triggerRefresh()
dialog.dismiss()
- activity.showWithBackStack(TransferReceiptFragment.newInstance(receipt, capturedToAvatar))
+ activity.showWithBackStack(TransferReceiptFragment.newInstance(receipt, capturedToPhoto))
} else if (!ok) {
dialog.dismiss()
if (msg == "CONNECTIVITY") {
@@ -1581,6 +1585,7 @@ class TransferFragment : Fragment() {
if (_binding != null) {
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivToPhoto.setImageBitmap(bitmap)
+ loadedToPhoto = bitmap
}
}
}
diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptData.kt b/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptData.kt
index f497a3c..73620f0 100644
--- a/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptData.kt
+++ b/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptData.kt
@@ -14,6 +14,8 @@ data class TransferReceiptData(
// MIB receipt fields
val mibReferenceNo: String = "",
val mibTransactionDate: String = "",
+ val mibFromProfileName: String = "",
+ val mibTransactionType: String = "", // "Own Transfer", "MIB Transfer", "Quick Transfer"
// BML receipt fields
val bmlFromName: String = "",
val bmlReference: String = "",
diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptFragment.kt
index 7841c2d..a071425 100644
--- a/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptFragment.kt
+++ b/app/src/main/java/sh/sar/basedbank/ui/home/TransferReceiptFragment.kt
@@ -63,6 +63,8 @@ class TransferReceiptFragment : Fragment() {
private const val ARG_REMARKS = "remarks"
private const val ARG_MIB_REF = "mib_ref"
private const val ARG_MIB_DATE = "mib_date"
+ private const val ARG_MIB_FROM_PROFILE = "mib_from_profile"
+ private const val ARG_MIB_TXN_TYPE = "mib_txn_type"
private const val ARG_BML_FROM_NAME = "bml_from_name"
private const val ARG_BML_REFERENCE = "bml_reference"
private const val ARG_BML_TIMESTAMP = "bml_timestamp"
@@ -91,6 +93,8 @@ class TransferReceiptFragment : Fragment() {
putString(ARG_REMARKS, data.remarks)
putString(ARG_MIB_REF, data.mibReferenceNo)
putString(ARG_MIB_DATE, data.mibTransactionDate)
+ putString(ARG_MIB_FROM_PROFILE, data.mibFromProfileName)
+ putString(ARG_MIB_TXN_TYPE, data.mibTransactionType)
putString(ARG_BML_FROM_NAME, data.bmlFromName)
putString(ARG_BML_REFERENCE, data.bmlReference)
putString(ARG_BML_TIMESTAMP, data.bmlTimestamp)
@@ -170,43 +174,64 @@ class TransferReceiptFragment : Fragment() {
private fun bindMib(binding: FragmentReceiptMibBinding) {
val args = requireArguments()
val fromLabel = args.getString(ARG_FROM_LABEL, "")
- val fromColor = args.getString(ARG_FROM_COLOR, "#FE860E")
val fromProfileHash = args.getString(ARG_FROM_PROFILE_HASH)
val toLabel = args.getString(ARG_TO_LABEL, "")
val currency = args.getString(ARG_CURRENCY, "MVR")
val amount = args.getString(ARG_AMOUNT, "")
// From avatar: initials first, then load profile image if hash available
- binding.ivFromAvatar.setImageBitmap(makeInitialsBitmap(fromLabel, fromColor))
+ binding.ivFromAvatar.setImageBitmap(makeMibInitialsBitmap(fromLabel))
binding.tvFromLabel.text = fromLabel
if (fromProfileHash != null) {
- loadProfileImage(fromProfileHash, isProfile = true) { binding.ivFromAvatar.setImageBitmap(it) }
+ loadProfileImage(fromProfileHash, isProfile = true) { binding.ivFromAvatar.setImageBitmap(circleCrop(it)) }
}
// To avatar: use already-rendered bitmap from TransferFragment if available
val toAvatar = pendingToAvatarBitmap
if (toAvatar != null) {
- binding.ivToAvatar.setImageBitmap(toAvatar)
+ binding.ivToAvatar.setImageBitmap(circleCrop(toAvatar))
} else {
- binding.ivToAvatar.setImageBitmap(makeInitialsBitmap(toLabel, "#607D8B"))
+ binding.ivToAvatar.setImageBitmap(makeMibInitialsBitmap(toLabel))
}
binding.tvToLabel.text = toLabel
binding.tvAmount.text = "$currency $amount"
+
+ val toBank = args.getString(ARG_TO_BANK, "")
+ val rawDate = args.getString(ARG_MIB_DATE, "")
binding.tvReferenceNo.text = args.getString(ARG_MIB_REF, "")
- binding.tvToAccount.text = args.getString(ARG_TO_ACCOUNT, "")
- binding.tvToBank.text = args.getString(ARG_TO_BANK, "")
- binding.tvTransactionDate.text = args.getString(ARG_MIB_DATE, "")
- binding.tvValueDate.text = args.getString(ARG_MIB_DATE, "")
+ binding.tvFromName.text = args.getString(ARG_MIB_FROM_PROFILE, "").ifBlank { fromLabel }
+ binding.tvToAccount.text = listOf(toLabel, args.getString(ARG_TO_ACCOUNT, ""))
+ .filter { it.isNotBlank() }.joinToString("\n")
+ binding.tvToBank.text = toBank
+ // Receipts saved before the type was recorded fall back to a guess from the bank
+ binding.tvTransactionType.text = args.getString(ARG_MIB_TXN_TYPE, "").ifBlank {
+ if (toBank == "MIB") "MIB Transfer" else "Quick Transfer"
+ }
+ binding.tvTransactionDate.text = formatMibDate(rawDate, "dd MMM yyyy HH:mm")
+ binding.tvValueDate.text = formatMibDate(rawDate, "dd MMM yyyy")
binding.tvPurpose.text = args.getString(ARG_REMARKS, "")
+ .takeUnless { it.isNullOrBlank() || it.trim() == "-" } ?: "N/A"
copyOnLongClick(
- binding.tvFromLabel, binding.tvToLabel, binding.tvAmount,
- binding.tvReferenceNo, binding.tvToAccount, binding.tvToBank,
- binding.tvTransactionDate, binding.tvValueDate, binding.tvPurpose
+ binding.tvFromLabel, binding.tvToLabel, binding.tvAmount, binding.tvStatus,
+ binding.tvReferenceNo, binding.tvFromName, binding.tvToAccount, binding.tvToBank,
+ binding.tvTransactionType, binding.tvTransactionDate, binding.tvValueDate, binding.tvPurpose
)
}
+ /** Reformats the MIB transfer date ("2026-05-16 15:10:25") to [pattern]; raw text if unparseable. */
+ private fun formatMibDate(raw: String, pattern: String): String {
+ if (raw.isBlank()) return ""
+ val out = DateTimeFormatter.ofPattern(pattern, Locale.US)
+ for (inPattern in listOf("yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "dd MMM yyyy HH:mm")) {
+ try {
+ return java.time.LocalDateTime.parse(raw.trim(), DateTimeFormatter.ofPattern(inPattern, Locale.US)).format(out)
+ } catch (_: Exception) { }
+ }
+ return raw
+ }
+
private fun loadProfileImage(hash: String, isProfile: Boolean, onLoaded: (Bitmap) -> Unit) {
val app = requireActivity().application as BasedBankApp
val sess = app.anyMibSession() ?: return
@@ -422,20 +447,38 @@ class TransferReceiptFragment : Fragment() {
}
}
- private fun makeInitialsBitmap(name: String, colorHex: String): Bitmap {
+ /** Center-crops [src] to a square and masks it to a circle. */
+ private fun circleCrop(src: Bitmap): Bitmap {
+ val size = minOf(src.width, src.height)
+ val out = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG).apply {
+ shader = android.graphics.BitmapShader(src, android.graphics.Shader.TileMode.CLAMP, android.graphics.Shader.TileMode.CLAMP).apply {
+ setLocalMatrix(android.graphics.Matrix().apply {
+ setTranslate(-(src.width - size) / 2f, -(src.height - size) / 2f)
+ })
+ }
+ }
+ Canvas(out).drawCircle(size / 2f, size / 2f, size / 2f, paint)
+ return out
+ }
+
+ /** MIB receipt placeholder: up to two initials in #1168F3 on a #C6E1FD circle. */
+ private fun makeMibInitialsBitmap(name: String): Bitmap {
val sizePx = (resources.displayMetrics.density * 52).toInt()
- val bgColor = try { Color.parseColor(colorHex) } catch (_: Exception) { Color.GRAY }
val bm = Bitmap.createBitmap(sizePx, sizePx, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bm)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
- paint.color = bgColor
+ paint.color = Color.parseColor("#C6E1FD")
canvas.drawCircle(sizePx / 2f, sizePx / 2f, sizePx / 2f, paint)
- paint.color = Color.WHITE
- paint.textSize = sizePx * 0.42f
+ paint.color = Color.parseColor("#1168F3")
+ paint.textSize = sizePx * 0.36f
paint.textAlign = Paint.Align.CENTER
- val letter = name.firstOrNull()?.uppercaseChar()?.toString() ?: "?"
+ paint.typeface = android.graphics.Typeface.DEFAULT_BOLD
+ val initials = name.split(Regex("\\s+"))
+ .mapNotNull { word -> word.firstOrNull { it.isLetterOrDigit() }?.uppercaseChar() }
+ .take(2).joinToString("").ifEmpty { "?" }
val metrics = paint.fontMetrics
- canvas.drawText(letter, sizePx / 2f, sizePx / 2f - (metrics.ascent + metrics.descent) / 2f, paint)
+ canvas.drawText(initials, sizePx / 2f, sizePx / 2f - (metrics.ascent + metrics.descent) / 2f, paint)
return bm
}
diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/transfer/MibTransferHandler.kt b/app/src/main/java/sh/sar/basedbank/ui/home/transfer/MibTransferHandler.kt
index a5c6cb4..8c670aa 100644
--- a/app/src/main/java/sh/sar/basedbank/ui/home/transfer/MibTransferHandler.kt
+++ b/app/src/main/java/sh/sar/basedbank/ui/home/transfer/MibTransferHandler.kt
@@ -129,6 +129,15 @@ class MibTransferHandler(
else -> bankName.ifBlank { "LOCAL" }
}
}
+ val isOwnAccount = isDestMib && app.mibAccounts.any {
+ it.accountNumber == destAccount && it.loginTag == src.loginTag &&
+ (src.profileId.isBlank() || it.profileId == src.profileId)
+ }
+ val transactionType = when {
+ isOwnAccount -> "Own Transfer"
+ isDestMib -> "MIB Transfer"
+ else -> "Quick Transfer"
+ }
return try {
// Switch to the profile that owns the source account
if (src.profileId.isNotBlank()) {
@@ -160,7 +169,9 @@ class MibTransferHandler(
toBank = toBank,
remarks = remarks,
mibReferenceNo = result.trxId,
- mibTransactionDate = result.date
+ mibTransactionDate = result.date,
+ mibFromProfileName = src.profileName,
+ mibTransactionType = transactionType
)
Triple(true, "BankTransaction ID: ${result.trxId}\n${result.date}", receipt)
} else {
diff --git a/app/src/main/java/sh/sar/basedbank/util/ReceiptStore.kt b/app/src/main/java/sh/sar/basedbank/util/ReceiptStore.kt
index fbcc986..e1bac74 100644
--- a/app/src/main/java/sh/sar/basedbank/util/ReceiptStore.kt
+++ b/app/src/main/java/sh/sar/basedbank/util/ReceiptStore.kt
@@ -40,6 +40,8 @@ object ReceiptStore {
remarks = o.optString("remarks"),
mibReferenceNo = o.optString("mibReferenceNo"),
mibTransactionDate = o.optString("mibTransactionDate"),
+ mibFromProfileName = o.optString("mibFromProfileName"),
+ mibTransactionType = o.optString("mibTransactionType"),
bmlFromName = o.optString("bmlFromName"),
bmlReference = o.optString("bmlReference"),
bmlTimestamp = o.optString("bmlTimestamp"),
@@ -76,6 +78,8 @@ object ReceiptStore {
put("remarks", d.remarks)
put("mibReferenceNo", d.mibReferenceNo)
put("mibTransactionDate", d.mibTransactionDate)
+ put("mibFromProfileName", d.mibFromProfileName)
+ put("mibTransactionType", d.mibTransactionType)
put("bmlFromName", d.bmlFromName)
put("bmlReference", d.bmlReference)
put("bmlTimestamp", d.bmlTimestamp)
diff --git a/app/src/main/res/drawable/bg_mib_receipt_header.xml b/app/src/main/res/drawable/bg_mib_receipt_header.xml
deleted file mode 100644
index 261ae7b..0000000
--- a/app/src/main/res/drawable/bg_mib_receipt_header.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/mib_logo_full.xml b/app/src/main/res/drawable/mib_logo_full.xml
new file mode 100644
index 0000000..a5b0eb7
--- /dev/null
+++ b/app/src/main/res/drawable/mib_logo_full.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/mib_receipt_header_bg.xml b/app/src/main/res/drawable/mib_receipt_header_bg.xml
new file mode 100644
index 0000000..8980193
--- /dev/null
+++ b/app/src/main/res/drawable/mib_receipt_header_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ -
+
+
+
diff --git a/app/src/main/res/drawable/mib_receipt_texture.png b/app/src/main/res/drawable/mib_receipt_texture.png
new file mode 100644
index 0000000..522e1c0
Binary files /dev/null and b/app/src/main/res/drawable/mib_receipt_texture.png differ
diff --git a/app/src/main/res/drawable/trx_success_bg.png b/app/src/main/res/drawable/trx_success_bg.png
deleted file mode 100644
index 35db358..0000000
Binary files a/app/src/main/res/drawable/trx_success_bg.png and /dev/null differ
diff --git a/app/src/main/res/layout/fragment_receipt_mib.xml b/app/src/main/res/layout/fragment_receipt_mib.xml
index a641cfb..6e6635b 100644
--- a/app/src/main/res/layout/fragment_receipt_mib.xml
+++ b/app/src/main/res/layout/fragment_receipt_mib.xml
@@ -15,7 +15,7 @@
android:overScrollMode="never"
android:scrollbars="none">
-
+
-
+
+ android:layout_height="160dp"
+ android:background="@drawable/mib_receipt_header_bg">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:paddingHorizontal="24dp">
-
+
+ android:scaleType="fitCenter"
+ android:contentDescription="@null" />
@@ -109,22 +69,25 @@
-
+
+ android:scaleType="fitCenter"
+ android:contentDescription="@null" />
@@ -140,81 +105,92 @@
-
+
-
-
+
+
+ android:paddingTop="14dp" />
-
+
-
+
-
-
-
+
+
-
+
-
+
-
-
-
+
+
-
+
-
+
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
+
-
+
-
-
-
+
+
-
+
-
+
-
-
-
+
+
-
-
-
-
+ android:contentDescription="Maldives Islamic Bank" />
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index ccea614..7eac7fa 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -8,4 +8,11 @@
#000000
#3D3E40
#1E1F21
+
+
+ #1A1A3C
+ #FFFFFF
+ #FFFFFF
+ #33335C
+ #FFFFFF
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 167d557..c5277b9 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -15,4 +15,12 @@
#E9E9E9
#EBEBEB
#E21B23
+
+
+ #FFFFFF
+ #000000
+ #000000
+ #CAC4D0
+ #000000
+ #1EA833