This commit is contained in:
@@ -31,7 +31,9 @@ class AccountHistoryAdapter(
|
||||
private val displayItems = mutableListOf<Item>()
|
||||
private var lastInsertedDateKey = ""
|
||||
private val imageCache = mutableMapOf<String, Bitmap>()
|
||||
private val iconUrlCache = mutableMapOf<String, Bitmap>()
|
||||
var onImageNeeded: ((counterpartyName: String) -> Unit)? = null
|
||||
var onIconUrlNeeded: ((url: String) -> Unit)? = null
|
||||
|
||||
fun updateImage(counterpartyName: String, bitmap: Bitmap) {
|
||||
imageCache[counterpartyName] = bitmap
|
||||
@@ -41,6 +43,14 @@ class AccountHistoryAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateIconUrl(url: String, bitmap: Bitmap) {
|
||||
iconUrlCache[url] = bitmap
|
||||
displayItems.forEachIndexed { i, item ->
|
||||
if (item is Item.Trx && item.transaction.iconUrl == url)
|
||||
notifyItemChanged(i + 1) // +1 for account header at position 0
|
||||
}
|
||||
}
|
||||
|
||||
private var _showLoadingFooter = false
|
||||
var showLoadingFooter: Boolean
|
||||
get() = _showLoadingFooter
|
||||
@@ -182,7 +192,10 @@ class AccountHistoryAdapter(
|
||||
val name = trx.counterpartyName ?: trx.description
|
||||
val initial = name.firstOrNull()?.uppercaseChar()?.toString() ?: "?"
|
||||
|
||||
val bitmap = trx.counterpartyName?.let { imageCache[it] }
|
||||
val iconBitmap = trx.iconUrl?.let { iconUrlCache[it] }
|
||||
val contactBitmap = if (iconBitmap == null) trx.counterpartyName?.let { imageCache[it] } else null
|
||||
val bitmap = iconBitmap ?: contactBitmap
|
||||
|
||||
if (bitmap != null) {
|
||||
val rd = RoundedBitmapDrawableFactory.create(b.root.resources, bitmap)
|
||||
rd.isCircular = true
|
||||
@@ -196,7 +209,8 @@ class AccountHistoryAdapter(
|
||||
b.fvAvatar.background = circle
|
||||
b.tvInitial.visibility = View.VISIBLE
|
||||
b.tvInitial.text = initial
|
||||
if (trx.counterpartyName != null) onImageNeeded?.invoke(trx.counterpartyName)
|
||||
if (trx.iconUrl != null) onIconUrlNeeded?.invoke(trx.iconUrl)
|
||||
else if (trx.counterpartyName != null) onImageNeeded?.invoke(trx.counterpartyName)
|
||||
}
|
||||
b.tvDescription.text = trx.description
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package sh.sar.basedbank.ui.home
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
@@ -27,6 +29,7 @@ import sh.sar.basedbank.api.mib.Transaction
|
||||
import sh.sar.basedbank.api.mib.TransactionCache
|
||||
import sh.sar.basedbank.databinding.FragmentAccountHistoryBinding
|
||||
import sh.sar.basedbank.util.ContactImageCache
|
||||
import sh.sar.basedbank.util.MerchantIconCache
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
@@ -44,6 +47,7 @@ class AccountHistoryFragment : Fragment() {
|
||||
private var searchQuery = ""
|
||||
private var firstPageDone = false
|
||||
private val pendingImageNames = mutableSetOf<String>()
|
||||
private val pendingIconUrls = mutableSetOf<String>()
|
||||
|
||||
// Pagination state
|
||||
private var mibNextStart = 1
|
||||
@@ -77,6 +81,7 @@ class AccountHistoryFragment : Fragment() {
|
||||
|
||||
adapter = AccountHistoryAdapter(account)
|
||||
adapter.onImageNeeded = { name -> loadContactImage(name) }
|
||||
adapter.onIconUrlNeeded = { url -> loadMerchantIcon(url) }
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
@@ -266,6 +271,29 @@ class AccountHistoryFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMerchantIcon(url: String) {
|
||||
if (!pendingIconUrls.add(url)) return
|
||||
val cached = MerchantIconCache.load(requireContext(), url)
|
||||
if (cached != null) {
|
||||
binding.recyclerView.post { adapter.updateIconUrl(url, cached) }
|
||||
return
|
||||
}
|
||||
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val client = OkHttpClient()
|
||||
val response = client.newCall(Request.Builder().url(url).build()).execute()
|
||||
val bytes = response.body?.bytes() ?: return@launch
|
||||
response.close()
|
||||
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
|
||||
?: return@launch
|
||||
MerchantIconCache.save(requireContext(), url, bitmap)
|
||||
withContext(Dispatchers.Main) { adapter.updateIconUrl(url, bitmap) }
|
||||
} catch (_: Exception) {
|
||||
pendingIconUrls.remove(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
(activity as? HomeActivity)?.setRefreshing(false)
|
||||
super.onDestroyView()
|
||||
|
||||
Reference in New Issue
Block a user