Add Positive Pay, statement guide v1.0, onboarding, and switch every feature on

- Positive Pay on the 12 Oct /pps contract (account number, not account ID):
  OTP enrollment, cheque submit, saved cheques, detail and stop payment.
  Full flow passed on the phone against mobile-banking-backend.lincpay.
- Statement & Mini Statement guide v1.0 (14 Oct): mini statement JSON on
  Home and the Statement screen; dated PDF export with the password rule.
- Onboarding slides and splash screen, Inter font, shared Icon and
  TypewriterText components, nearby branches via OpenStreetMap.
- Every feature switched on; the 14 Oct switch set is kept in
  featureConfig.stage-2026-10-14.ts. Loans run on demo data until the
  backend has /loans routes.
- npm run android wraps run-android for shells spawned from VS Code.
- OpenProject work packages updated to 14-10-2026 status, with screenshots
  of Positive Pay, statement, loans and cards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Abin Toppo
2026-10-14 18:18:40 +05:30
co-authored by Claude Opus 5.5
parent 5fbd13ba12
commit f960a119e8
510 changed files with 20268 additions and 6483 deletions
+22
View File
@@ -117,3 +117,25 @@ dependencies {
implementation jscFlavor
}
}
/**
* Makes `gradlew clean` (and Android Studio's Clean Project) work.
*
* The app's native clean re-runs CMake before cleaning, and the app's CMake
* build pulls in each library's codegen output from
* node_modules/<lib>/android/build/generated/. `clean` deletes those library
* build folders first, so the configure step fails with "add_subdirectory given
* source ... which is not an existing directory" and the whole clean fails.
*
* There is nothing for that step to do that deleting the CMake folder does not
* do better, so it is skipped and `.cxx` goes with `build/`. The next build
* regenerates the codegen output before CMake needs it.
*/
tasks.configureEach { task ->
if (task.name.startsWith("externalNativeBuildClean")) {
task.enabled = false
}
}
tasks.named("clean") {
delete file(".cxx")
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,10 @@
package com.bankcbs.mobile
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
@@ -19,4 +24,43 @@ class MainActivity : ReactActivity() {
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
restoreAdjustResize()
}
/**
* Brings back `windowSoftInputMode="adjustResize"` on Android 15 and later.
*
* This app targets SDK 36, and from Android 15 a window targeting 35+ is forced edge-to-edge —
* the opt-out attribute is ignored at 36. An edge-to-edge window is never resized for the
* keyboard: the system only reports the keyboard as an IME inset and leaves the app to react.
* Every screen here was built on the window shrinking (that is what the manifest asks for, and
* what Android 14 and earlier still do), so on 15+ the keyboard simply covered the lower half of
* every form.
*
* Padding the content view by the IME inset is exactly the resize the system used to do: the
* React root ends at the top of the keyboard, scroll views shrink, and Android's ScrollView
* scrolls the focused field back into view on its own. Nothing in JS has to know.
*
* Gated on API 35 because below it the system still resizes the window itself, and padding on
* top of that would lift everything twice. It is also self-correcting above it: a window the
* system did resize reports no IME inset to its content, so the padding comes out as zero.
*/
private fun restoreAdjustResize() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
return
}
val content = findViewById<View>(android.R.id.content) ?: return
ViewCompat.setOnApplyWindowInsetsListener(content) { view, insets ->
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
view.setPadding(view.paddingLeft, view.paddingTop, view.paddingRight, ime.bottom)
// Passed on untouched, so safe-area-context and everything below still see the real
// status- and navigation-bar insets.
insets
}
}
}
@@ -22,6 +22,7 @@
First entry is the one `API_ORIGIN` currently points at; the rest
are addresses this build has been aimed at before. -->
<domain includeSubdomains="true">mobile-banking-backend.lincpay</domain>
<domain includeSubdomains="false">192.168.6.138</domain>
<domain includeSubdomains="false">10.209.40.168</domain>
<domain includeSubdomains="false">192.168.6.165</domain>
<domain includeSubdomains="false">192.168.1.11</domain>
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+12 -8
View File
@@ -2,20 +2,24 @@
"migIndex": 1,
"data": [
{
"path": "assets/fonts/Nunito-Bold.ttf",
"sha1": "a2d6a8de275b708042cfa663533194d18d2861c4"
"path": "assets/fonts/Inter-Bold.ttf",
"sha1": "9461e7c083137c2abe6d198f784fb0d341a527a1"
},
{
"path": "assets/fonts/Nunito-ExtraBold.ttf",
"sha1": "30b19033e24e4a79ca8a0ac3e780ab8e3d664185"
"path": "assets/fonts/Inter-ExtraBold.ttf",
"sha1": "872bc40675c084c451af1c3eb10e21c13e2008a3"
},
{
"path": "assets/fonts/Nunito-Regular.ttf",
"sha1": "6b19e7ffbd729c36ca7bbd0163a791d2716447a8"
"path": "assets/fonts/Inter-Medium.ttf",
"sha1": "c1d25d8c10adb45a970e71c387bbd6380f10992d"
},
{
"path": "assets/fonts/Nunito-SemiBold.ttf",
"sha1": "12eebee4d162f8f099235a42623369d5e57a6af9"
"path": "assets/fonts/Inter-Regular.ttf",
"sha1": "6e3430f906a4b42b4b63fd8f33e498a43d9f8d84"
},
{
"path": "assets/fonts/Inter-SemiBold.ttf",
"sha1": "b4bdaf6bdd6a479b46c452a7bbae13f5cb2079bf"
}
]
}