Files
threadcount-community/capacitor.config.ts
T
ThreadCount 822c0b7c0b ThreadCount Community edition
Uniform stock management for healthcare linen rooms: the coordinator app, the phone counter and the staff app, for your own server. Built from 8685140 on 2026-09-13. Licensed under the Functional Source License (FSL-1.1-ALv2).
2026-09-13 11:09:20 +10:00

85 lines
3.9 KiB
TypeScript

import type { CapacitorConfig } from "@capacitor/cli";
/* Two Android apps, one config.
*
* npx cap sync android → the counter app (tech.threadcount.app → /m)
* TC_APP=staff npx cap sync android → the staff app (tech.threadcount.staff → /my)
*
* The Capacitor 6 CLI has no --config flag and always reads this file from the working directory,
* so the alternative to branching here is swapping files around before every build — which is the
* kind of step that eventually ships the wrong app id to Play. One file, one env var, two
* `android.path`s, and neither project can overwrite the other.
*
* Both are the live site in a native shell, so the apps update when the site does and there is one
* copy of every rule rather than two. Each bundles only its own first-run screens, which are the
* only ones that must work before someone has signed in or has signal.
*/
const staff = process.env.TC_APP === "staff";
const counter: CapacitorConfig = {
appId: "tech.threadcount.app",
appName: "ThreadCount",
// Splash, welcome (with the video) and the offline screen.
webDir: "androidshell",
server: {
androidScheme: "https",
cleartext: false,
// The shell opens on its own bundled splash and welcome, then navigates to the site — the
// hosted one, or the self-hosted server the welcome screen saved (Community edition rooms run
// their own). Any host, because the saved one cannot be known at build time; the welcome
// screen is the only page that chooses it, and MainActivity honours the choice only from there.
allowNavigation: ["*"],
// A page that fails to load falls back to the bundled offline screen, not a browser error.
errorPath: "error.html",
},
android: {
// A stock count is read at arm's length under ward lighting; let the OS text size apply.
allowMixedContent: false,
// captureInput is deliberately absent. It swaps the WebView's input connection for a bare
// BaseInputConnection that never fills in the EditorInfo, so the keyboard sees no inputType on
// any field: the numeric two-factor box gets a QWERTY keyboard, one-time-code autofill is
// never offered, and a password manager loses the hints the assetlinks file goes out of its
// way to enable. It only buys anything for a hardware keyboard-wedge scanner, and neither app
// has one — every barcode here is read through the camera.
webContentsDebuggingEnabled: false,
},
plugins: {
SplashScreen: {
// Just long enough to cover the WebView starting. The bundled splash draws the mark from
// here, so this screen is plain ink — showing the mark twice, once still and once drawing,
// reads as a stutter.
launchShowDuration: 350,
backgroundColor: "#201e1dff",
androidSplashResourceName: "splash",
androidScaleType: "CENTER_CROP",
showSpinner: false,
},
},
};
/* The staff app.
*
* A separate app rather than a role switch inside the counter app, because the audiences share
* nothing. The counter app goes on a handful of ward phones belonging to the people who run the
* linen room; this one goes on every nurse's phone. One Play listing cannot describe both, and a
* wearer opening an app whose home screen is a stocktake counter would reasonably conclude they
* had installed the wrong thing.
*
* It carries no barcode scanner and asks for no camera permission: nothing a wearer does involves
* scanning, and an app that every clinical staff member installs should ask for as little as it
* possibly can.
*/
const staffApp: CapacitorConfig = {
...counter,
appId: "tech.threadcount.staff",
appName: "ThreadCount Staff",
webDir: "staffshell",
android: {
...counter.android,
// Its own native project, beside the counter app's rather than replacing it.
path: "android-staff",
},
};
export default staff ? staffApp : counter;