fix(wallet-android): make in-app QR camera actually show through
Three issues broke the previous commit's "in-app camera" shipping as a dark non-fullscreen rectangle: 1. WebView was opaque. The @capacitor-mlkit/barcode-scanning plugin's startScan() renders a native camera preview UNDER the WebView, but on Android the WebView paints an opaque background by default — nothing below it ever shows. MainActivity.java now sets bridge.getWebView().setBackgroundColor(Color.TRANSPARENT) on create. The HTML/CSS keeps painting its own backgrounds, so this is only visible when the HTML side ALSO goes transparent (during a scan). 2. The .phone wrapper has an opaque dark-blue gradient (linear-gradient(180deg, rgba(19,26,42,.55), rgba(10,15,28,.55))) that stayed painted on top of the (now-transparent) WebView, blocking the preview. The scanner CSS now null-chains the whole stack (html → body → #root → .app-root → .phone) via background: transparent + background-image: none + border: 0 while body.barcode-scanner-active is set. 3. Modal was pinned to the .phone 420px-max column — on a 1080×2400 phone the scan frame + Cancel sat inside a narrow central strip while the native preview filled the whole screen. The modal now escapes with position: fixed; inset: 0; width: 100vw; height: 100dvh. The scan frame is centred at min(72vw, 320px), buttons sit at the bottom with a backdrop-blur chip so they stay legible against bright scenes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
3fddd71acc
commit
a5474b11aa
2 changed files with 81 additions and 11 deletions
|
|
@ -1,5 +1,28 @@
|
|||
package cash.deviant.wallet;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
public class MainActivity extends BridgeActivity {}
|
||||
/**
|
||||
* MainActivity — Capacitor BridgeActivity entry point for the Deviant wallet.
|
||||
*
|
||||
* Overridden to paint the WebView background transparent so the
|
||||
* @capacitor-mlkit/barcode-scanning plugin's `startScan()` can render its
|
||||
* native camera preview UNDER the WebView and have it actually show through.
|
||||
* The HTML/CSS continues to paint its own background (the dark starfield of
|
||||
* the `.phone` frame), so this transparency only matters when the HTML side
|
||||
* ALSO goes transparent — i.e. when `body.barcode-scanner-active` strips the
|
||||
* backgrounds for the duration of a scan. Outside of that, nothing visible
|
||||
* changes: HTML paints its own color on every pixel.
|
||||
*/
|
||||
public class MainActivity extends BridgeActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (bridge != null && bridge.getWebView() != null) {
|
||||
bridge.getWebView().setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -916,15 +916,62 @@
|
|||
|
||||
/* ─── In-app QR scanner overlay (native, Capacitor-mlkit startScan) ──────────
|
||||
The plugin renders the live camera preview UNDER the WebView by making the
|
||||
platform background transparent. For that to show through, we hide the whole
|
||||
React app via `body.barcode-scanner-active` and selectively un-hide only the
|
||||
scanner modal elements (anything tagged `.barcode-scanner-modal`). Result:
|
||||
the user sees the Deviant-styled scan frame + Cancel button over the native
|
||||
camera feed — not a Google-branded scanner activity. */
|
||||
body.barcode-scanner-active { background: transparent !important; visibility: hidden; }
|
||||
body.barcode-scanner-active #root { background: transparent !important; }
|
||||
platform background transparent (set in MainActivity.java via
|
||||
webView.setBackgroundColor(Color.TRANSPARENT)). For that to show through,
|
||||
EVERY opaque wrapper between the plugin and the pixel has to go transparent
|
||||
AND the whole React tree must be hidden except our scanner modal.
|
||||
|
||||
Chain of transparency (any opaque link breaks the preview):
|
||||
html → body → #root → .app-root → .phone → (modal elements, visible)
|
||||
|
||||
The `.barcode-scanner-modal` opt-out keeps the scan frame + Cancel button
|
||||
visible while everything else is hidden. */
|
||||
body.barcode-scanner-active,
|
||||
body.barcode-scanner-active html,
|
||||
body.barcode-scanner-active #root,
|
||||
body.barcode-scanner-active .app-root,
|
||||
body.barcode-scanner-active .phone {
|
||||
background: transparent !important;
|
||||
background-color: transparent !important;
|
||||
background-image: none !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
body.barcode-scanner-active { visibility: hidden; }
|
||||
body.barcode-scanner-active .barcode-scanner-modal,
|
||||
body.barcode-scanner-active .barcode-scanner-modal * { visibility: visible; }
|
||||
/* Make the backdrop fully transparent during a native scan so the preview is
|
||||
not dimmed by the modal's usual veil. */
|
||||
body.barcode-scanner-active .sheet-backdrop.barcode-scanner-modal { background: transparent !important; }
|
||||
|
||||
/* Pull the scanner modal out of the `.phone` 420px column so it covers the
|
||||
WHOLE physical screen — the native camera preview is full-screen, our
|
||||
overlay has to match. Fixed inset:0 ignores the ancestor's constraints. */
|
||||
body.barcode-scanner-active .modal.barcode-scanner-modal {
|
||||
position: fixed; inset: 0; max-width: none; width: 100vw; height: 100vh; height: 100dvh;
|
||||
background: transparent !important;
|
||||
display: flex; flex-direction: column; justify-content: space-between;
|
||||
padding: 24px 20px calc(32px + env(safe-area-inset-bottom)) 20px;
|
||||
z-index: 9999;
|
||||
}
|
||||
body.barcode-scanner-active .sheet-backdrop.barcode-scanner-modal {
|
||||
background: transparent !important;
|
||||
position: fixed; inset: 0;
|
||||
}
|
||||
/* Centre the scan frame vertically within the fullscreen modal. */
|
||||
body.barcode-scanner-active .modal.barcode-scanner-modal .scan-frame {
|
||||
width: min(72vw, 320px); aspect-ratio: 1 / 1; margin: auto;
|
||||
}
|
||||
/* Keep the row of Cancel + Paste buttons visible against the preview with a
|
||||
subtle inset shadow — otherwise they'd disappear over a bright scene. */
|
||||
body.barcode-scanner-active .modal.barcode-scanner-modal .row-btns {
|
||||
margin-top: auto;
|
||||
}
|
||||
body.barcode-scanner-active .modal.barcode-scanner-modal .row-btns .ghost {
|
||||
background: rgba(2, 4, 10, 0.72);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
}
|
||||
body.barcode-scanner-active .modal.barcode-scanner-modal .flow-head {
|
||||
background: rgba(2, 4, 10, 0.6);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
border-radius: 12px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue