forked from shihaam/thijooree
add connetivity banners
This commit is contained in:
@@ -2,6 +2,7 @@ package sh.sar.basedbank.api.bml
|
|||||||
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import sh.sar.basedbank.api.models.BankAccount
|
import sh.sar.basedbank.api.models.BankAccount
|
||||||
|
import sh.sar.basedbank.api.models.BankServerException
|
||||||
|
|
||||||
data class BmlUserInfo(
|
data class BmlUserInfo(
|
||||||
val fullName: String,
|
val fullName: String,
|
||||||
@@ -27,6 +28,7 @@ class BmlAccountClient {
|
|||||||
val json = resp.body?.string()
|
val json = resp.body?.string()
|
||||||
resp.close()
|
resp.close()
|
||||||
if (code == 401 || code == 419) throw AuthExpiredException()
|
if (code == 401 || code == 419) throw AuthExpiredException()
|
||||||
|
if (code in 500..599) throw BankServerException("BML")
|
||||||
return parseDashboard(json ?: return emptyList(), loginTag, profileName, profileId)
|
return parseDashboard(json ?: return emptyList(), loginTag, profileName, profileId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +38,7 @@ class BmlAccountClient {
|
|||||||
val code = resp.code
|
val code = resp.code
|
||||||
resp.close()
|
resp.close()
|
||||||
if (code == 401 || code == 419) throw AuthExpiredException()
|
if (code == 401 || code == 419) throw AuthExpiredException()
|
||||||
|
if (code in 500..599) throw BankServerException("BML")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchUserInfo(session: BmlSession): BmlUserInfo? {
|
fun fetchUserInfo(session: BmlSession): BmlUserInfo? {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import okhttp3.OkHttpClient
|
|||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import sh.sar.basedbank.api.models.BankAccount
|
import sh.sar.basedbank.api.models.BankAccount
|
||||||
|
import sh.sar.basedbank.api.models.BankServerException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class FahipayAccountClient {
|
class FahipayAccountClient {
|
||||||
@@ -27,8 +28,10 @@ class FahipayAccountClient {
|
|||||||
Request.Builder().url("$BASE_URL/actions/getprofile/?lang=en")
|
Request.Builder().url("$BASE_URL/actions/getprofile/?lang=en")
|
||||||
.auth(session).build()
|
.auth(session).build()
|
||||||
).execute()
|
).execute()
|
||||||
|
val code = resp.code
|
||||||
val json = resp.body?.string() ?: throw Exception("Empty profile response")
|
val json = resp.body?.string() ?: throw Exception("Empty profile response")
|
||||||
resp.close()
|
resp.close()
|
||||||
|
if (code in 500..599) throw BankServerException("Fahipay")
|
||||||
val obj = JSONObject(json)
|
val obj = JSONObject(json)
|
||||||
val props = obj.optJSONObject("props") ?: JSONObject()
|
val props = obj.optJSONObject("props") ?: JSONObject()
|
||||||
return FahipayUserProfile(
|
return FahipayUserProfile(
|
||||||
@@ -47,8 +50,10 @@ class FahipayAccountClient {
|
|||||||
Request.Builder().url("$BASE_URL/actions/getbalance/?lang=en")
|
Request.Builder().url("$BASE_URL/actions/getbalance/?lang=en")
|
||||||
.auth(session).build()
|
.auth(session).build()
|
||||||
).execute()
|
).execute()
|
||||||
|
val code = resp.code
|
||||||
val json = resp.body?.string() ?: return 0.0
|
val json = resp.body?.string() ?: return 0.0
|
||||||
resp.close()
|
resp.close()
|
||||||
|
if (code in 500..599) throw BankServerException("Fahipay")
|
||||||
return try {
|
return try {
|
||||||
val obj = JSONObject(json)
|
val obj = JSONObject(json)
|
||||||
if (obj.optBoolean("error")) 0.0 else obj.optDouble("balance", 0.0)
|
if (obj.optBoolean("error")) 0.0 else obj.optDouble("balance", 0.0)
|
||||||
|
|||||||
@@ -373,6 +373,7 @@ class MibLoginFlow(private val credentialStore: CredentialStore) {
|
|||||||
.build()
|
.build()
|
||||||
val response = client.newCall(request).execute()
|
val response = client.newCall(request).execute()
|
||||||
if (response.code == 419) throw SessionExpiredException()
|
if (response.code == 419) throw SessionExpiredException()
|
||||||
|
if (response.code in 500..599) throw sh.sar.basedbank.api.models.BankServerException("MIB")
|
||||||
return response.body?.string() ?: throw IllegalStateException("Empty response body")
|
return response.body?.string() ?: throw IllegalStateException("Empty response body")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package sh.sar.basedbank.api.models
|
package sh.sar.basedbank.api.models
|
||||||
|
|
||||||
|
/** Thrown by a bank API client when the server returns an HTTP 5xx response. */
|
||||||
|
class BankServerException(val bankName: String) : Exception("Server error from $bankName")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unified account model used across all banks (MIB, BML, Fahipay, ...).
|
* Unified account model used across all banks (MIB, BML, Fahipay, ...).
|
||||||
* The [bank] field identifies which bank owns this account.
|
* The [bank] field identifies which bank owns this account.
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
|||||||
import sh.sar.basedbank.BasedBankApp
|
import sh.sar.basedbank.BasedBankApp
|
||||||
import sh.sar.basedbank.R
|
import sh.sar.basedbank.R
|
||||||
import sh.sar.basedbank.api.bml.AuthExpiredException
|
import sh.sar.basedbank.api.bml.AuthExpiredException
|
||||||
|
import sh.sar.basedbank.api.models.BankServerException
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import sh.sar.basedbank.api.bml.BmlAccountClient
|
import sh.sar.basedbank.api.bml.BmlAccountClient
|
||||||
import sh.sar.basedbank.api.bml.BmlContactsClient
|
import sh.sar.basedbank.api.bml.BmlContactsClient
|
||||||
import sh.sar.basedbank.api.bml.BmlForeignLimitsClient
|
import sh.sar.basedbank.api.bml.BmlForeignLimitsClient
|
||||||
@@ -547,14 +549,25 @@ fun applyNavLabelVisibility() {
|
|||||||
autoRefresh(store)
|
autoRefresh(store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showConnectivityBanner(message: String) {
|
||||||
|
binding.connectivityBanner.text = message
|
||||||
|
binding.connectivityBanner.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideConnectivityBanner() {
|
||||||
|
binding.connectivityBanner.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
private fun autoRefresh(store: CredentialStore) {
|
private fun autoRefresh(store: CredentialStore) {
|
||||||
val mibLoginIds = store.getMibLoginIds()
|
val mibLoginIds = store.getMibLoginIds()
|
||||||
val bmlLoginIds = store.getBmlLoginIds()
|
val bmlLoginIds = store.getBmlLoginIds()
|
||||||
val fahipayLoginIds = store.getFahipayLoginIds()
|
val fahipayLoginIds = store.getFahipayLoginIds()
|
||||||
if (mibLoginIds.isEmpty() && bmlLoginIds.isEmpty() && fahipayLoginIds.isEmpty()) return
|
if (mibLoginIds.isEmpty() && bmlLoginIds.isEmpty() && fahipayLoginIds.isEmpty()) return
|
||||||
binding.refreshIndicator.visibility = View.VISIBLE
|
binding.refreshIndicator.visibility = View.VISIBLE
|
||||||
|
hideConnectivityBanner()
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
val refreshErrors = ConcurrentLinkedQueue<String>()
|
||||||
// One async job per MIB login, all run in parallel
|
// One async job per MIB login, all run in parallel
|
||||||
val mibJobs = mibLoginIds.mapNotNull { loginId ->
|
val mibJobs = mibLoginIds.mapNotNull { loginId ->
|
||||||
val creds = store.loadMibCredentials(loginId) ?: return@mapNotNull null
|
val creds = store.loadMibCredentials(loginId) ?: return@mapNotNull null
|
||||||
@@ -568,7 +581,15 @@ fun applyNavLabelVisibility() {
|
|||||||
app.mibLoginFlows[loginId] = flow
|
app.mibLoginFlows[loginId] = flow
|
||||||
store.saveMibProfiles(loginId, flow.lastProfiles)
|
store.saveMibProfiles(loginId, flow.lastProfiles)
|
||||||
accounts
|
accounts
|
||||||
} catch (_: Exception) { AccountCache.load(this@HomeActivity).filter { it.loginTag == "mib_$loginId" } }
|
} catch (e: java.io.IOException) {
|
||||||
|
refreshErrors.add("NO_INTERNET")
|
||||||
|
AccountCache.load(this@HomeActivity).filter { it.loginTag == "mib_$loginId" }
|
||||||
|
} catch (e: BankServerException) {
|
||||||
|
refreshErrors.add("SERVER:${e.bankName}")
|
||||||
|
AccountCache.load(this@HomeActivity).filter { it.loginTag == "mib_$loginId" }
|
||||||
|
} catch (_: Exception) {
|
||||||
|
AccountCache.load(this@HomeActivity).filter { it.loginTag == "mib_$loginId" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,6 +644,14 @@ fun applyNavLabelVisibility() {
|
|||||||
tryRefresh()
|
tryRefresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
refreshErrors.add("NO_INTERNET")
|
||||||
|
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
||||||
|
.filter { it.profileId == profile.profileId }
|
||||||
|
} catch (e: BankServerException) {
|
||||||
|
refreshErrors.add("SERVER:${e.bankName}")
|
||||||
|
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
||||||
|
.filter { it.profileId == profile.profileId }
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
||||||
.filter { it.profileId == profile.profileId }
|
.filter { it.profileId == profile.profileId }
|
||||||
@@ -638,6 +667,12 @@ fun applyNavLabelVisibility() {
|
|||||||
val accounts = BmlAccountClient().fetchAccounts(session, loginTag)
|
val accounts = BmlAccountClient().fetchAccounts(session, loginTag)
|
||||||
app.bmlSessions[loginId] = session
|
app.bmlSessions[loginId] = session
|
||||||
allAccounts += accounts
|
allAccounts += accounts
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
refreshErrors.add("NO_INTERNET")
|
||||||
|
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
||||||
|
} catch (e: BankServerException) {
|
||||||
|
refreshErrors.add("SERVER:${e.bankName}")
|
||||||
|
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
allAccounts += AccountCache.loadBml(this@HomeActivity, loginId)
|
||||||
}
|
}
|
||||||
@@ -689,6 +724,12 @@ fun applyNavLabelVisibility() {
|
|||||||
app.fahipaySessions[loginId] = session
|
app.fahipaySessions[loginId] = session
|
||||||
AccountCache.saveFahipay(this@HomeActivity, loginId, accounts)
|
AccountCache.saveFahipay(this@HomeActivity, loginId, accounts)
|
||||||
accounts
|
accounts
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
refreshErrors.add("NO_INTERNET")
|
||||||
|
AccountCache.loadFahipay(this@HomeActivity, loginId)
|
||||||
|
} catch (e: BankServerException) {
|
||||||
|
refreshErrors.add("SERVER:${e.bankName}")
|
||||||
|
AccountCache.loadFahipay(this@HomeActivity, loginId)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
AccountCache.loadFahipay(this@HomeActivity, loginId)
|
AccountCache.loadFahipay(this@HomeActivity, loginId)
|
||||||
}
|
}
|
||||||
@@ -708,6 +749,17 @@ fun applyNavLabelVisibility() {
|
|||||||
viewModel.accounts.postValue((mibAccounts + bmlAccounts + fahipayAccounts).filterVisibleAccounts())
|
viewModel.accounts.postValue((mibAccounts + bmlAccounts + fahipayAccounts).filterVisibleAccounts())
|
||||||
binding.refreshIndicator.visibility = View.GONE
|
binding.refreshIndicator.visibility = View.GONE
|
||||||
|
|
||||||
|
val noInternet = refreshErrors.any { it == "NO_INTERNET" }
|
||||||
|
val serverErrors = refreshErrors.filter { it.startsWith("SERVER:") }
|
||||||
|
.map { it.removePrefix("SERVER:") }.distinct()
|
||||||
|
when {
|
||||||
|
noInternet -> showConnectivityBanner(getString(R.string.connectivity_no_internet))
|
||||||
|
serverErrors.isNotEmpty() -> showConnectivityBanner(
|
||||||
|
getString(R.string.connectivity_server_error, serverErrors.joinToString(", "))
|
||||||
|
)
|
||||||
|
else -> hideConnectivityBanner()
|
||||||
|
}
|
||||||
|
|
||||||
for ((_, session) in app.bmlSessions) refreshBmlLimits(session)
|
for ((_, session) in app.bmlSessions) refreshBmlLimits(session)
|
||||||
for ((loginId, session) in app.mibSessions) {
|
for ((loginId, session) in app.mibSessions) {
|
||||||
val profiles = app.mibProfilesMap[loginId] ?: emptyList()
|
val profiles = app.mibProfilesMap[loginId] ?: emptyList()
|
||||||
|
|||||||
@@ -40,6 +40,20 @@
|
|||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/connectivityBanner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#C62828"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -141,4 +141,8 @@
|
|||||||
<!-- Home -->
|
<!-- Home -->
|
||||||
<string name="accounts">އެކައުންޓްތައް</string>
|
<string name="accounts">އެކައުންޓްތައް</string>
|
||||||
<string name="available_balance">ލިބެން ހުރި ބެލެންސް</string>
|
<string name="available_balance">ލިބެން ހުރި ބެލެންސް</string>
|
||||||
|
|
||||||
|
<!-- Connectivity banner -->
|
||||||
|
<string name="connectivity_no_internet">އިންޓަނެޓް ބައްލަވާ، ދެން ތިޖޫރީ ލޯޑް ކުރޭ</string>
|
||||||
|
<string name="connectivity_server_error">%s އާ ގުޅުމުގައި މައްސަލައެއް</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -302,4 +302,8 @@
|
|||||||
<string name="card_action_freeze">Freeze</string>
|
<string name="card_action_freeze">Freeze</string>
|
||||||
<string name="card_action_block">Block</string>
|
<string name="card_action_block">Block</string>
|
||||||
<string name="cards_empty">No cards found</string>
|
<string name="cards_empty">No cards found</string>
|
||||||
|
|
||||||
|
<!-- Connectivity banner -->
|
||||||
|
<string name="connectivity_no_internet">Please check your connection and reload Thijooree</string>
|
||||||
|
<string name="connectivity_server_error">Connectivity issue with %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user