toggle to enable or disable privacy mode and also privacy mode toggle
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 3s
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 3s
This commit is contained in:
@@ -37,6 +37,17 @@ class AccountHistoryAdapter(
|
||||
var onImageNeeded: ((counterpartyName: String) -> Unit)? = null
|
||||
var onIconUrlNeeded: ((url: String) -> Unit)? = null
|
||||
var onTransferClick: ((MibAccount) -> Unit)? = null
|
||||
private var hideAmounts: Boolean = false
|
||||
|
||||
fun setHideAmounts(hide: Boolean) {
|
||||
if (hideAmounts == hide) return
|
||||
hideAmounts = hide
|
||||
notifyItemChanged(0) // refresh header card
|
||||
// refresh all transaction rows
|
||||
for (i in displayItems.indices) {
|
||||
if (displayItems[i] is Item.Trx) notifyItemChanged(i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateImage(counterpartyName: String, bitmap: Bitmap) {
|
||||
imageCache[counterpartyName] = bitmap
|
||||
@@ -154,10 +165,10 @@ class AccountHistoryAdapter(
|
||||
b.tvHeaderAccountNumber.text = d.number
|
||||
b.tvHeaderPillBank.text = d.bankPill
|
||||
b.tvHeaderPillType.text = d.typeLabel
|
||||
b.tvHeaderAvailable.text = d.availableBalance
|
||||
b.tvHeaderBalance.text = d.workingBalance
|
||||
b.tvHeaderAvailable.text = if (hideAmounts) maskAmount(d.availableBalance) else d.availableBalance
|
||||
b.tvHeaderBalance.text = if (hideAmounts) maskAmount(d.workingBalance) else d.workingBalance
|
||||
if (d.blockedBalance != null) {
|
||||
b.tvHeaderBlocked.text = d.blockedBalance
|
||||
b.tvHeaderBlocked.text = if (hideAmounts) maskAmount(d.blockedBalance) else d.blockedBalance
|
||||
b.llHeaderBlocked.visibility = View.VISIBLE
|
||||
} else {
|
||||
b.llHeaderBlocked.visibility = View.GONE
|
||||
@@ -211,12 +222,17 @@ class AccountHistoryAdapter(
|
||||
|
||||
b.tvDate.text = formatTime(trx.date)
|
||||
|
||||
val sign = if (isCredit) "+" else "-"
|
||||
val absAmt = "%.2f".format(kotlin.math.abs(trx.amount))
|
||||
b.tvAmount.text = "$sign ${trx.currency} $absAmt"
|
||||
b.tvAmount.setTextColor(
|
||||
if (isCredit) Color.parseColor("#4CAF50") else Color.parseColor("#FF7043")
|
||||
)
|
||||
if (hideAmounts) {
|
||||
b.tvAmount.text = "${trx.currency} ••••••"
|
||||
b.tvAmount.setTextColor(Color.parseColor("#888888"))
|
||||
} else {
|
||||
val sign = if (isCredit) "+" else "-"
|
||||
val absAmt = "%.2f".format(kotlin.math.abs(trx.amount))
|
||||
b.tvAmount.text = "$sign ${trx.currency} $absAmt"
|
||||
b.tvAmount.setTextColor(
|
||||
if (isCredit) Color.parseColor("#4CAF50") else Color.parseColor("#FF7043")
|
||||
)
|
||||
}
|
||||
|
||||
b.root.setOnClickListener { showDetail(trx) }
|
||||
}
|
||||
@@ -282,6 +298,11 @@ class AccountHistoryAdapter(
|
||||
return FULL_DATE_FMT.format(date)
|
||||
}
|
||||
|
||||
fun maskAmount(formatted: String): String {
|
||||
val currency = formatted.substringBefore(' ', formatted)
|
||||
return "$currency ••••••"
|
||||
}
|
||||
|
||||
fun sourceColor(source: String) = when (source) {
|
||||
"MIB" -> "#FE860E"
|
||||
"BML", "BML_CARD" -> "#0066A1"
|
||||
|
||||
@@ -77,6 +77,8 @@ class AccountHistoryFragment : Fragment() {
|
||||
adapter.onTransferClick = { acc ->
|
||||
(activity as? HomeActivity)?.navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFrom(acc))
|
||||
}
|
||||
adapter.setHideAmounts(viewModel.hideAmounts.value ?: false)
|
||||
viewModel.hideAmounts.observe(viewLifecycleOwner) { adapter.setHideAmounts(it) }
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ class AccountsAdapter(
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
var onTransferClick: ((MibAccount) -> Unit)? = null
|
||||
private var hideAmounts: Boolean = false
|
||||
|
||||
private sealed class Item {
|
||||
data class SectionTitle(val label: String) : Item()
|
||||
@@ -36,6 +37,12 @@ class AccountsAdapter(
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun setHideAmounts(hide: Boolean) {
|
||||
if (hideAmounts == hide) return
|
||||
hideAmounts = hide
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private fun buildItems(accounts: List<MibAccount>): List<Item> = buildList {
|
||||
val displayed = accounts.mapNotNull { acc -> AccountListParser.from(acc)?.let { acc to it } }
|
||||
val nonCards = displayed.filter { !it.second.isCard }
|
||||
@@ -109,7 +116,7 @@ class AccountsAdapter(
|
||||
binding.tvAccountName.text = display.name
|
||||
binding.tvAccountNumber.text = display.number
|
||||
binding.tvAccountType.text = display.typeLabel
|
||||
binding.tvBalance.text = display.balance
|
||||
binding.tvBalance.text = if (hideAmounts) maskAmount(display.balance) else display.balance
|
||||
binding.btnTransfer.setOnClickListener { onTransferClick?.invoke(account) }
|
||||
binding.root.setOnClickListener { onAccountClick(account) }
|
||||
binding.root.setOnLongClickListener {
|
||||
@@ -127,7 +134,7 @@ class AccountsAdapter(
|
||||
binding.tvCardNumber.text = display.number
|
||||
binding.tvCardProduct.text = display.typeLabel
|
||||
binding.layoutCardBalance.visibility = View.VISIBLE
|
||||
binding.tvCardBalance.text = display.balance
|
||||
binding.tvCardBalance.text = if (hideAmounts) maskAmount(display.balance) else display.balance
|
||||
if (display.statusLabel != null) {
|
||||
binding.tvCardStatus.text = display.statusLabel
|
||||
binding.tvCardStatus.visibility = View.VISIBLE
|
||||
@@ -146,6 +153,11 @@ class AccountsAdapter(
|
||||
private const val TYPE_ACCOUNT = 1
|
||||
private const val TYPE_CARD = 2
|
||||
|
||||
fun maskAmount(formatted: String): String {
|
||||
val currency = formatted.substringBefore(' ', formatted)
|
||||
return "$currency ••••••"
|
||||
}
|
||||
|
||||
private fun copyToClipboard(context: Context, accountNumber: String) {
|
||||
val cm = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
cm.setPrimaryClip(ClipData.newPlainText("Account Number", accountNumber))
|
||||
|
||||
@@ -44,6 +44,7 @@ class AccountsFragment : Fragment() {
|
||||
}
|
||||
|
||||
viewModel.accounts.observe(viewLifecycleOwner) { adapter.updateAccounts(it) }
|
||||
viewModel.hideAmounts.observe(viewLifecycleOwner) { adapter.setHideAmounts(it) }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
||||
@@ -32,6 +32,11 @@ class DashboardFragment : Fragment() {
|
||||
viewModel.accounts.observe(viewLifecycleOwner) { updateBalances(it) }
|
||||
viewModel.financing.observe(viewLifecycleOwner) { updatePendingFinances(it) }
|
||||
viewModel.bmlLimits.observe(viewLifecycleOwner) { updateForeignLimits(it) }
|
||||
viewModel.hideAmounts.observe(viewLifecycleOwner) {
|
||||
updateBalances(viewModel.accounts.value ?: emptyList())
|
||||
updatePendingFinances(viewModel.financing.value ?: emptyList())
|
||||
updateForeignLimits(viewModel.bmlLimits.value ?: emptyList())
|
||||
}
|
||||
|
||||
val bottomPaddingBase = (16 * resources.displayMetrics.density).toInt()
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.buttonBar) { v, insets ->
|
||||
@@ -64,6 +69,12 @@ class DashboardFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun updateBalances(accounts: List<MibAccount>) {
|
||||
val hide = viewModel.hideAmounts.value ?: false
|
||||
if (hide) {
|
||||
binding.tvMvrBalance.text = "MVR ••••••"
|
||||
binding.tvUsdBalance.text = "USD ••••••"
|
||||
return
|
||||
}
|
||||
val mvrTotal = accounts
|
||||
.filter { it.currencyName.equals("MVR", ignoreCase = true) }
|
||||
.sumOf { it.availableBalance.replace(",", "").toDoubleOrNull() ?: 0.0 }
|
||||
@@ -76,31 +87,40 @@ class DashboardFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun updateForeignLimits(entries: List<HomeViewModel.BmlLimitsData>) {
|
||||
val hide = viewModel.hideAmounts.value ?: false
|
||||
binding.containerForeignLimits.removeAllViews()
|
||||
for (entry in entries) {
|
||||
for (limit in entry.limits) {
|
||||
val card = ItemForeignLimitBinding.inflate(layoutInflater, binding.containerForeignLimits, false)
|
||||
card.tvLimitUserName.text = entry.userName.ifBlank { "BML" }
|
||||
card.tvLimitType.text = limit.type
|
||||
card.tvLimitGeneral.text = "USD %,.0f / %,.0f".format(limit.generalRemaining, limit.generalCap)
|
||||
card.tvLimitMedical.text = "USD %,.0f".format(limit.medicalRemaining)
|
||||
card.tvLimitAtm.text = if (!limit.isAtmEnabled)
|
||||
"USD %,.0f / %,.0f · Disabled".format(limit.atmRemaining, limit.atmLimit)
|
||||
else
|
||||
"USD %,.0f / %,.0f".format(limit.atmRemaining, limit.atmLimit)
|
||||
card.tvLimitEcom.text = "USD %,.0f / %,.0f".format(limit.ecomRemaining, limit.ecomLimit)
|
||||
card.tvLimitPos.text = if (!limit.isPosEnabled)
|
||||
"USD %,.0f / %,.0f · Disabled".format(limit.posRemaining, limit.posLimit)
|
||||
else
|
||||
"USD %,.0f / %,.0f".format(limit.posRemaining, limit.posLimit)
|
||||
if (hide) {
|
||||
card.tvLimitGeneral.text = "USD ••••••"
|
||||
card.tvLimitMedical.text = "USD ••••••"
|
||||
card.tvLimitAtm.text = if (!limit.isAtmEnabled) "USD •••••• · Disabled" else "USD ••••••"
|
||||
card.tvLimitEcom.text = "USD ••••••"
|
||||
card.tvLimitPos.text = if (!limit.isPosEnabled) "USD •••••• · Disabled" else "USD ••••••"
|
||||
} else {
|
||||
card.tvLimitGeneral.text = "USD %,.0f / %,.0f".format(limit.generalRemaining, limit.generalCap)
|
||||
card.tvLimitMedical.text = "USD %,.0f".format(limit.medicalRemaining)
|
||||
card.tvLimitAtm.text = if (!limit.isAtmEnabled)
|
||||
"USD %,.0f / %,.0f · Disabled".format(limit.atmRemaining, limit.atmLimit)
|
||||
else
|
||||
"USD %,.0f / %,.0f".format(limit.atmRemaining, limit.atmLimit)
|
||||
card.tvLimitEcom.text = "USD %,.0f / %,.0f".format(limit.ecomRemaining, limit.ecomLimit)
|
||||
card.tvLimitPos.text = if (!limit.isPosEnabled)
|
||||
"USD %,.0f / %,.0f · Disabled".format(limit.posRemaining, limit.posLimit)
|
||||
else
|
||||
"USD %,.0f / %,.0f".format(limit.posRemaining, limit.posLimit)
|
||||
}
|
||||
binding.containerForeignLimits.addView(card.root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePendingFinances(deals: List<MibFinanceDeal>) {
|
||||
val total = deals.sumOf { it.outstandingAmount }
|
||||
binding.tvPendingFinances.text = "MVR %,.2f".format(total)
|
||||
val hide = viewModel.hideAmounts.value ?: false
|
||||
binding.tvPendingFinances.text = if (hide) "MVR ••••••" else "MVR %,.2f".format(deals.sumOf { it.outstandingAmount })
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
||||
@@ -16,6 +16,14 @@ import java.util.Locale
|
||||
class FinancingAdapter(private var deals: List<MibFinanceDeal>) :
|
||||
RecyclerView.Adapter<FinancingAdapter.ViewHolder>() {
|
||||
|
||||
private var hideAmounts: Boolean = false
|
||||
|
||||
fun setHideAmounts(hide: Boolean) {
|
||||
if (hideAmounts == hide) return
|
||||
hideAmounts = hide
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private val expandedPositions = mutableSetOf<Int>()
|
||||
private val amountFmt = NumberFormat.getNumberInstance(Locale.US).apply {
|
||||
minimumFractionDigits = 2
|
||||
@@ -52,19 +60,20 @@ class FinancingAdapter(private var deals: List<MibFinanceDeal>) :
|
||||
fun bind(deal: MibFinanceDeal, expanded: Boolean) {
|
||||
val ctx = binding.root.context
|
||||
val currency = deal.currency
|
||||
val hide = hideAmounts
|
||||
|
||||
binding.tvProductName.text = deal.productDesc
|
||||
binding.tvDealNo.text = ctx.getString(R.string.financing_deal_no_fmt, deal.dealNo)
|
||||
binding.tvStatus.text = deal.statusDesc
|
||||
binding.tvTotal.text = "$currency ${amountFmt.format(deal.dealAmount)}"
|
||||
binding.tvPaid.text = "$currency ${amountFmt.format(deal.paidAmount)}"
|
||||
binding.tvUnpaid.text = "$currency ${amountFmt.format(deal.outstandingAmount)}"
|
||||
binding.tvTotal.text = if (hide) "$currency ••••••" else "$currency ${amountFmt.format(deal.dealAmount)}"
|
||||
binding.tvPaid.text = if (hide) "$currency ••••••" else "$currency ${amountFmt.format(deal.paidAmount)}"
|
||||
binding.tvUnpaid.text = if (hide) "$currency ••••••" else "$currency ${amountFmt.format(deal.outstandingAmount)}"
|
||||
|
||||
// Progress bar
|
||||
val progress = if (deal.dealAmount > 0)
|
||||
((deal.paidAmount / deal.dealAmount) * 100).toInt().coerceIn(0, 100)
|
||||
else 0
|
||||
binding.progressBar.progress = progress
|
||||
binding.progressBar.progress = if (hide) 0 else progress
|
||||
|
||||
// Completion estimate
|
||||
binding.tvCompletion.text = completionText(deal, ctx)
|
||||
@@ -76,14 +85,14 @@ class FinancingAdapter(private var deals: List<MibFinanceDeal>) :
|
||||
|
||||
if (expanded) {
|
||||
binding.tvDealDate.text = formatDate(deal.dealDate)
|
||||
binding.tvInstallment.text = "$currency ${amountFmt.format(deal.installmentAmount)}"
|
||||
binding.tvInstallment.text = if (hide) "$currency ••••••" else "$currency ${amountFmt.format(deal.installmentAmount)}"
|
||||
binding.tvNumInstallments.text = deal.noOfInstallments.toString()
|
||||
binding.tvLastPaidDate.text = formatDate(deal.lastPaidDate)
|
||||
binding.tvLastPayAmount.text = "$currency ${amountFmt.format(deal.lastPayAmount)}"
|
||||
binding.tvLastPayAmount.text = if (hide) "$currency ••••••" else "$currency ${amountFmt.format(deal.lastPayAmount)}"
|
||||
|
||||
if (deal.overdueAmount > 0) {
|
||||
binding.rowOverdue.visibility = View.VISIBLE
|
||||
binding.tvOverdue.text = "$currency ${amountFmt.format(deal.overdueAmount)}"
|
||||
binding.tvOverdue.text = if (hide) "$currency ••••••" else "$currency ${amountFmt.format(deal.overdueAmount)}"
|
||||
} else {
|
||||
binding.rowOverdue.visibility = View.GONE
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ class FinancingFragment : Fragment() {
|
||||
binding.emptyView.visibility = if (deals.isEmpty()) View.VISIBLE else View.GONE
|
||||
binding.loadingView.visibility = View.GONE
|
||||
}
|
||||
viewModel.hideAmounts.observe(viewLifecycleOwner) { adapter.setHideAmounts(it) }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
||||
@@ -181,6 +181,9 @@ class HomeActivity : AppCompatActivity() {
|
||||
autoRefresh(store)
|
||||
}
|
||||
|
||||
// hideAmounts is always false on launch; eye feature just needs to be enabled
|
||||
viewModel.hideAmounts.value = false
|
||||
|
||||
// Show dashboard on first create
|
||||
if (savedInstanceState == null) {
|
||||
show(DashboardFragment())
|
||||
@@ -402,6 +405,11 @@ fun applyNavLabelVisibility() {
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.toolbar_menu, menu)
|
||||
val eyeEnabled = getSharedPreferences("prefs", MODE_PRIVATE).getBoolean("hide_sensitive_info", false)
|
||||
val eyeItem = menu.findItem(R.id.action_hide_amounts)
|
||||
eyeItem?.isVisible = eyeEnabled
|
||||
val hidden = viewModel.hideAmounts.value ?: false
|
||||
eyeItem?.setIcon(if (hidden) R.drawable.ic_visibility_off else R.drawable.ic_visibility)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -410,6 +418,12 @@ fun applyNavLabelVisibility() {
|
||||
lock()
|
||||
return true
|
||||
}
|
||||
if (item.itemId == R.id.action_hide_amounts) {
|
||||
val newHidden = !(viewModel.hideAmounts.value ?: false)
|
||||
viewModel.hideAmounts.value = newHidden
|
||||
invalidateOptionsMenu()
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,4 +16,6 @@ class HomeViewModel : ViewModel() {
|
||||
|
||||
data class BmlLimitsData(val userName: String, val limits: List<BmlForeignLimit>)
|
||||
val bmlLimits = MutableLiveData<List<BmlLimitsData>>(emptyList())
|
||||
|
||||
val hideAmounts = MutableLiveData<Boolean>(false)
|
||||
}
|
||||
|
||||
@@ -79,6 +79,17 @@ class SettingsSecurityFragment : Fragment() {
|
||||
(activity as? HomeActivity)?.resetAutolockTimer()
|
||||
}
|
||||
|
||||
// Hide sensitive information (enables/disables the eye icon in toolbar)
|
||||
val viewModel = (requireActivity() as HomeActivity).let {
|
||||
androidx.lifecycle.ViewModelProvider(it)[HomeViewModel::class.java]
|
||||
}
|
||||
binding.switchHideAmounts.isChecked = prefs.getBoolean("hide_sensitive_info", false)
|
||||
binding.switchHideAmounts.setOnCheckedChangeListener { _, isChecked ->
|
||||
prefs.edit().putBoolean("hide_sensitive_info", isChecked).apply()
|
||||
if (!isChecked) viewModel.hideAmounts.value = false
|
||||
requireActivity().invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
// Block screenshots
|
||||
val blockScreenshots = prefs.getBoolean("block_screenshots", true)
|
||||
binding.switchBlockScreenshots.isChecked = blockScreenshots
|
||||
|
||||
@@ -27,6 +27,13 @@ class TransactionAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val iconUrlCache = mutableMapOf<String, Bitmap>()
|
||||
var onImageNeeded: ((counterpartyName: String) -> Unit)? = null
|
||||
var onIconUrlNeeded: ((url: String) -> Unit)? = null
|
||||
private var hideAmounts: Boolean = false
|
||||
|
||||
fun setHideAmounts(hide: Boolean) {
|
||||
if (hideAmounts == hide) return
|
||||
hideAmounts = hide
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun updateImage(counterpartyName: String, bitmap: Bitmap) {
|
||||
imageCache[counterpartyName] = bitmap
|
||||
@@ -140,12 +147,17 @@ class TransactionAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
b.tvDate.text = AccountHistoryAdapter.formatTime(trx.date)
|
||||
|
||||
val sign = if (isCredit) "+" else "-"
|
||||
val absAmt = "%.2f".format(kotlin.math.abs(trx.amount))
|
||||
b.tvAmount.text = "$sign ${trx.currency} $absAmt"
|
||||
b.tvAmount.setTextColor(
|
||||
if (isCredit) Color.parseColor("#4CAF50") else Color.parseColor("#FF7043")
|
||||
)
|
||||
if (hideAmounts) {
|
||||
b.tvAmount.text = "${trx.currency} ••••••"
|
||||
b.tvAmount.setTextColor(Color.parseColor("#888888"))
|
||||
} else {
|
||||
val sign = if (isCredit) "+" else "-"
|
||||
val absAmt = "%.2f".format(kotlin.math.abs(trx.amount))
|
||||
b.tvAmount.text = "$sign ${trx.currency} $absAmt"
|
||||
b.tvAmount.setTextColor(
|
||||
if (isCredit) Color.parseColor("#4CAF50") else Color.parseColor("#FF7043")
|
||||
)
|
||||
}
|
||||
|
||||
b.root.setOnClickListener { showDetail(trx) }
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ class TransferHistoryFragment : Fragment() {
|
||||
adapter = TransactionAdapter()
|
||||
adapter.onImageNeeded = { name -> loadContactImage(name) }
|
||||
adapter.onIconUrlNeeded = { url -> loadMerchantIcon(url) }
|
||||
adapter.setHideAmounts(viewModel.hideAmounts.value ?: false)
|
||||
viewModel.hideAmounts.observe(viewLifecycleOwner) { adapter.setHideAmounts(it) }
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
|
||||
11
app/src/main/res/drawable/ic_visibility.xml
Normal file
11
app/src/main/res/drawable/ic_visibility.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39-6,-7.5-11,-7.5zM12,17c-2.76,0-5,-2.24-5,-5s2.24,-5 5,-5 5,2.24 5,5-2.24,5-5,5zM12,9c-1.66,0-3,1.34-3,3s1.34,3 3,3 3,-1.34 3,-3-1.34,-3-3,-3z" />
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_visibility_off.xml
Normal file
11
app/src/main/res/drawable/ic_visibility_off.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65-0.13,1.26-0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75-1.73,-4.39-6,-7.5-11,-7.5-1.4,0-2.74,0.25-3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21-0.08,0.43-0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33-1.41,0.53-2.2,0.53-2.76,0-5,-2.24-5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66-1.34,-3-3,-3l-0.17,0.01z" />
|
||||
</vector>
|
||||
@@ -162,6 +162,44 @@
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rowHideAmounts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_hide_amounts"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_hide_amounts_desc"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/switchHideAmounts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rowBlockScreenshots"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_hide_amounts"
|
||||
android:icon="@drawable/ic_visibility"
|
||||
android:title="@string/action_hide_amounts"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_lock"
|
||||
android:icon="@drawable/ic_lock"
|
||||
|
||||
@@ -110,6 +110,8 @@
|
||||
|
||||
<!-- Toolbar -->
|
||||
<string name="action_lock">Lock app</string>
|
||||
<string name="action_hide_amounts">Hide sensitive information</string>
|
||||
<string name="action_show_amounts">Show sensitive information</string>
|
||||
<string name="autolock_warning_title">Locking soon</string>
|
||||
<string name="autolock_warning_message">Locking in %d seconds</string>
|
||||
<string name="autolock_stay">Stay unlocked</string>
|
||||
@@ -137,6 +139,8 @@
|
||||
<string name="lang_english">English</string>
|
||||
<string name="lang_dhivehi">ދިވެހި</string>
|
||||
<string name="settings_privacy">Privacy</string>
|
||||
<string name="settings_hide_amounts">Hide sensitive information</string>
|
||||
<string name="settings_hide_amounts_desc">Masks account balances and financial figures across the app</string>
|
||||
<string name="settings_block_screenshots">Block Screenshots</string>
|
||||
<string name="settings_block_screenshots_desc">Prevents the app from appearing in the recents screen and blocks screen capture</string>
|
||||
<string name="settings_cache">Cache</string>
|
||||
|
||||
Reference in New Issue
Block a user