lazy loading

This commit is contained in:
2026-05-14 05:24:14 +05:00
parent 81a2be150f
commit 7026da9ccd
11 changed files with 131 additions and 75 deletions
@@ -7,7 +7,7 @@ import sh.sar.basedbank.api.mib.MibAccount
import sh.sar.basedbank.databinding.ItemAccountBinding
import sh.sar.basedbank.databinding.ItemProfileHeaderBinding
class AccountsAdapter(private val accounts: List<MibAccount>) :
class AccountsAdapter(accounts: List<MibAccount>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private sealed class Item {
@@ -15,7 +15,15 @@ class AccountsAdapter(private val accounts: List<MibAccount>) :
data class Account(val account: MibAccount) : Item()
}
private val items: List<Item> = buildList {
private val items: MutableList<Item> = buildItems(accounts).toMutableList()
fun updateAccounts(accounts: List<MibAccount>) {
items.clear()
items.addAll(buildItems(accounts))
notifyDataSetChanged()
}
private fun buildItems(accounts: List<MibAccount>): List<Item> = buildList {
var lastProfile = ""
for (account in accounts) {
if (account.profileName != lastProfile) {
@@ -1,26 +1,66 @@
package sh.sar.basedbank.ui.home
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import sh.sar.basedbank.BasedBankApp
import sh.sar.basedbank.api.mib.MibLoginFlow
import sh.sar.basedbank.databinding.ActivityHomeBinding
import sh.sar.basedbank.util.AccountCache
import sh.sar.basedbank.util.CredentialStore
class HomeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHomeBinding
private lateinit var adapter: AccountsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
val accounts = (application as BasedBankApp).accounts
val adapter = AccountsAdapter(accounts)
val app = application as BasedBankApp
// If we arrived here from a fresh manual login, accounts are already in memory.
// Otherwise load the last-known cache so the UI is instant.
val initial = if (app.accounts.isNotEmpty()) app.accounts else AccountCache.load(this)
adapter = AccountsAdapter(initial)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
if (app.accounts.isNotEmpty()) {
// Just logged in — persist the fresh data and we're done
AccountCache.save(this, app.accounts)
} else {
// Came from lock screen — refresh in background
val creds = CredentialStore(this).loadMibCredentials()
if (creds != null) autoRefresh(creds)
}
}
private fun autoRefresh(creds: CredentialStore.MibCredentials) {
binding.refreshIndicator.visibility = View.VISIBLE
val prefs = getSharedPreferences("mib_prefs", MODE_PRIVATE)
val flow = MibLoginFlow(prefs)
lifecycleScope.launch {
try {
val accounts = withContext(Dispatchers.IO) {
flow.login(creds.username, creds.passwordHash, creds.otpSeed)
}
(application as BasedBankApp).accounts = accounts
AccountCache.save(this@HomeActivity, accounts)
adapter.updateAccounts(accounts)
} catch (_: Exception) {
// Keep showing cached data silently
} finally {
binding.refreshIndicator.visibility = View.GONE
}
}
}
}
@@ -18,6 +18,7 @@ import kotlinx.coroutines.withContext
import sh.sar.basedbank.util.Totp
import sh.sar.basedbank.BasedBankApp
import sh.sar.basedbank.api.mib.MibLoginFlow
import sh.sar.basedbank.util.AccountCache
import sh.sar.basedbank.util.CredentialStore
import sh.sar.basedbank.databinding.FragmentCredentialsBinding
import sh.sar.basedbank.ui.home.HomeActivity
@@ -111,6 +112,7 @@ class CredentialsFragment : Fragment() {
}
Log.d(TAG, "Login succeeded, got ${accounts.size} accounts")
CredentialStore(requireContext()).saveMibCredentials(username, passwordHash, otpSeed)
AccountCache.save(requireContext(), accounts)
(requireActivity().application as BasedBankApp).accounts = accounts
startActivity(Intent(requireContext(), HomeActivity::class.java))
requireActivity().finish()
@@ -1,19 +1,8 @@
package sh.sar.basedbank.ui.login
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import sh.sar.basedbank.BasedBankApp
import sh.sar.basedbank.R
import sh.sar.basedbank.api.mib.MibLoginFlow
import sh.sar.basedbank.databinding.ActivityLoginBinding
import sh.sar.basedbank.ui.home.HomeActivity
import sh.sar.basedbank.util.CredentialStore
class LoginActivity : AppCompatActivity() {
@@ -23,31 +12,5 @@ class LoginActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
val creds = CredentialStore(this).loadMibCredentials()
if (creds != null) {
binding.navHostFragment.visibility = View.GONE
binding.autoLoginGroup.visibility = View.VISIBLE
autoLogin(creds)
}
}
private fun autoLogin(creds: CredentialStore.MibCredentials) {
val prefs = getSharedPreferences("mib_prefs", MODE_PRIVATE)
val flow = MibLoginFlow(prefs)
lifecycleScope.launch {
try {
val accounts = withContext(Dispatchers.IO) {
flow.login(creds.username, creds.passwordHash, creds.otpSeed)
}
(application as BasedBankApp).accounts = accounts
startActivity(Intent(this@LoginActivity, HomeActivity::class.java))
finish()
} catch (e: Exception) {
// Auto-login failed — fall back to manual login form
binding.autoLoginGroup.visibility = View.GONE
binding.navHostFragment.visibility = View.VISIBLE
}
}
}
}