perf: project-wide optimization pass + UI/theme fixes
Optimization (audited across src/, typecheck green): - Crash guards: PurchaseAuction data?.result + stray text-node, AuctionItemDetail length>0, LiveAuction user?.contractorId, KYC params guard - Hoisted render-defined components: Login MinimalInput (keyboard-focus bug), TenderFullDetail Section/InfoBox (subtree remount) - Memoized hot paths: Spreadsheet ColumnHeaderRow/DataRow, list makeStyles, shared infinite-query select (stops per-render flatMap) - Removed hot-path/in-list console logs; SkeletonList 10->1 shimmer UI/theme: themed AppToast, redesigned sidebar drawer, list empty states, KYC WebView cleanup Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7853bab639
commit
95d8e0a925
@@ -11,9 +11,14 @@ class MainActivity : ReactActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// FLAG_SECURE: the app displays sealed-bid amounts, Aadhaar OTPs and other
|
||||
// regulated PII. Block screenshots, screen recording and the app-switcher
|
||||
// thumbnail in release builds; debug builds stay capturable for QA.
|
||||
// FLAG_SECURE fail-closed baseline: the app displays sealed-bid amounts,
|
||||
// Aadhaar OTPs and other regulated PII. Release builds start fully secured so
|
||||
// nothing leaks before JS boots (or if the ScreenGuard bridge fails to load).
|
||||
// Once running, per-screen protection is driven from JS — the central
|
||||
// controller (core/security/screenGuard.ts, wired via NavigationContainer)
|
||||
// CLEARS this flag for non-sensitive screens and re-applies it for the
|
||||
// protected ones. Debug builds start capturable for QA and are likewise
|
||||
// toggled per screen by the same controller.
|
||||
if (!BuildConfig.DEBUG) {
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_SECURE,
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
import com.facebook.soloader.SoLoader
|
||||
import com.procure.excel.ExcelPackage
|
||||
import com.procure.security.ScreenGuardPackage
|
||||
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
@@ -20,6 +21,7 @@ class MainApplication : Application(), ReactApplication {
|
||||
override fun getPackages(): List<ReactPackage> =
|
||||
PackageList(this).packages.apply {
|
||||
add(ExcelPackage())
|
||||
add(ScreenGuardPackage())
|
||||
}
|
||||
|
||||
override fun getJSMainModuleName(): String = "index"
|
||||
|
||||
@@ -317,7 +317,13 @@ class ExcelModule(private val reactContext: ReactApplicationContext) :
|
||||
for (i in 0 until edits.length()) {
|
||||
applyEdit(wb, edits.getJSONObject(i))
|
||||
}
|
||||
// Ask consumers (Excel) to recalculate; HyperFormula already did in-app.
|
||||
// Recompute every formula so its CACHED <v> reflects the new inputs.
|
||||
// Excel/LibreOffice would recalc on open, but cache-only consumers
|
||||
// (the web BOQ viewer reads the stored value and never recalculates)
|
||||
// otherwise see the template's stale result. Per-cell + try/catch so a
|
||||
// single POI-unsupported function can't blank the whole workbook.
|
||||
recalculateFormulas(wb)
|
||||
// Belt-and-suspenders for recalc-capable consumers.
|
||||
wb.setForceFormulaRecalculation(true)
|
||||
|
||||
val bos = ByteArrayOutputStream()
|
||||
@@ -329,6 +335,29 @@ class ExcelModule(private val reactContext: ReactApplicationContext) :
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate all formula cells in-place so their cached results are written to
|
||||
* the file. Runs per-cell in a try/catch: POI cannot evaluate every Excel
|
||||
* function, and a NotImplemented failure on one cell must not abort the save
|
||||
* or clear the other results.
|
||||
*/
|
||||
private fun recalculateFormulas(wb: Workbook) {
|
||||
val evaluator = wb.creationHelper.createFormulaEvaluator()
|
||||
for (sheet in wb) {
|
||||
for (row in sheet) {
|
||||
for (cell in row) {
|
||||
if (cell.cellType == CellType.FORMULA) {
|
||||
try {
|
||||
evaluator.evaluateFormulaCell(cell)
|
||||
} catch (_: Throwable) {
|
||||
/* leave this cell's cached value as-is */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyEdit(wb: Workbook, edit: JSONObject) {
|
||||
val sheetIndex = edit.getInt("sheet")
|
||||
if (sheetIndex < 0 || sheetIndex >= wb.numberOfSheets) return
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.procure.security
|
||||
|
||||
import android.view.WindowManager
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
|
||||
/**
|
||||
* ScreenGuard — runtime FLAG_SECURE toggle.
|
||||
*
|
||||
* FLAG_SECURE blocks screenshots, screen recording and the app-switcher
|
||||
* thumbnail for the whole Activity window. The app is single-Activity, so
|
||||
* flipping the flag as the user navigates gives per-screen protection. WHICH
|
||||
* screens are protected lives entirely in JS (see core/security/screenGuard.ts);
|
||||
* this module only applies the decision. Window flags must be mutated on the UI
|
||||
* thread.
|
||||
*/
|
||||
class ScreenGuardModule(private val reactContext: ReactApplicationContext) :
|
||||
ReactContextBaseJavaModule(reactContext) {
|
||||
|
||||
override fun getName(): String = "ScreenGuard"
|
||||
|
||||
@ReactMethod
|
||||
fun setSecure(enable: Boolean) {
|
||||
val activity = currentActivity ?: return
|
||||
activity.runOnUiThread {
|
||||
val window = activity.window ?: return@runOnUiThread
|
||||
if (enable) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.procure.security
|
||||
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.bridge.NativeModule
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.uimanager.ViewManager
|
||||
|
||||
/**
|
||||
* Registers [ScreenGuardModule] with React Native. Added manually in
|
||||
* MainApplication.getPackages(); accessible from JS via NativeModules.ScreenGuard.
|
||||
*/
|
||||
class ScreenGuardPackage : ReactPackage {
|
||||
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
|
||||
listOf(ScreenGuardModule(reactContext))
|
||||
|
||||
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
||||
emptyList()
|
||||
}
|
||||
Reference in New Issue
Block a user