From 2e6a20dc2b3b2d625c5ca9c4c08d6d9a99c9371c Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Tue, 8 Sep 2026 19:11:51 +0700 Subject: [PATCH] Citrine: native cleartext config, default-pool write wiring, polished UI (1.3.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the local-relay integration so it actually works end-to-end and feels first-class. Native (Android): - android-templates/network_security_config.xml — permits cleartext for LOOPBACK ONLY (127.0.0.1 / localhost / ::1); all real traffic stays TLS. This is what lets ws://127.0.0.1 (Citrine) connect on API 28+, which otherwise silently blocks cleartext. - scripts/inject-network-security.mjs — idempotently copies the XML into res/xml/ and adds android:networkSecurityConfig to , mirroring the existing inject-amber-queries pattern so it survives `cap sync`. - Wired into android:init / android:sync / android:build. Reads AND writes now reach Citrine app-wide: - NostrProvider's NPool routers (reqRouter/eventRouter) fold in the active Citrine URL via a ref, so every default-pool query hits it first (instant local reads) and every useNostrPublish write also lands on-device (backup + offline capture). Previously only explicit useSkateRelays paths benefited. - A dedicated effect refreshes ['nostr'] queries when the local relay comes/goes so reads switch over immediately. Fully no-op off-Android (url stays null). UI/UX (Relays settings CitrineCard): - Four crisp states — off / searching / live / waiting — with a breathing then glowing status pip, benefit chips (Instant reads · Works offline · On-device backup) that pop in on connect, a spinning Recheck, an actionable install CTA, and a persistent encryption-reassurance note. - Graceful first-run: shows "searching" until the first probe settles (via new useCitrine.settled), never flashing the orange "not detected" state. Tailwind: added status-breathe / status-live / pop-in keyframes+animations. Co-authored-by: shakespeare.diy --- android-templates/network_security_config.xml | 35 ++++ package.json | 8 +- scripts/inject-network-security.mjs | 85 ++++++++ src/components/NostrProvider.tsx | 28 +++ src/hooks/useCitrine.ts | 10 +- src/pages/SettingsPage.tsx | 192 ++++++++++++++---- tailwind.config.ts | 36 +++- 7 files changed, 352 insertions(+), 42 deletions(-) create mode 100644 android-templates/network_security_config.xml create mode 100644 scripts/inject-network-security.mjs diff --git a/android-templates/network_security_config.xml b/android-templates/network_security_config.xml new file mode 100644 index 0000000..6c9a42f --- /dev/null +++ b/android-templates/network_security_config.xml @@ -0,0 +1,35 @@ + + + + + + + + + 127.0.0.1 + localhost + ::1 + + diff --git a/package.json b/package.json index 5cc669e..efadb48 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "skate-spots", "private": true, - "version": "1.3.0", + "version": "1.3.1", "type": "module", "homepage": "https://skate-spots.com", "scripts": { @@ -9,11 +9,11 @@ "build": "npm i --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'Project built successfully!'", "test": "npm i --silent && tsc --noEmit && eslint && vitest run --reporter=dot --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'All tests passed!'", "deploy": "npm i --silent && npm run build && npx -y nostr-deploy-cli deploy --skip-setup", - "android:init": "npm run android:build:apk && npx cap add android && npx cap sync android && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs", - "android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs", + "android:init": "npm run android:build:apk && npx cap add android && npx cap sync android && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs", + "android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs", "android:open": "npx cap open android", "android:version": "node scripts/sync-android-version.mjs", - "android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && cd android && ./gradlew assembleRelease", + "android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && node scripts/inject-network-security.mjs && cd android && ./gradlew assembleRelease", "android:build:apk": "CAPACITOR_BUILD=1 vite build && sed -i 's|||g' dist/index.html && sed -i 's|