Commit Graph

121 Commits

Author SHA1 Message Date
lemon 3a772af66e Update Agora app icons 2026-05-15 19:37:23 -07:00
Alex Gleason 740fc1c63c Merge ditto/main into agora
Pulls in 387 commits from ditto/main while preserving Agora-specific
features. Where the two codebases diverged on the same concept, kept
the Agora side per project direction.

Kept Agora-specific:
- SparkWallet stack (over Ditto's nostr-derived Bitcoin wallet)
- Communities (NIP-72 + chat + members), Messages, Organizers,
  Actions, Verified, Appearance settings
- DMProviderWrapper, country/organizer moderation in NoteMoreMenu
- 'Agora' branding, pub.agora.app bundle ID, version 2.8.0
- Built-in theme system (src/themes.ts) only

Rejected from Ditto:
- All Blobbi virtual pet code (80+ files, route, provider, sidebar,
  kind labels, feed setting, NIP.md entries, CSS animations)
- Custom theme events (kinds 36767/16767) — ThemesPage, ThemeContent,
  active profile themes, theme snapshot recovery
- On-chain zaps (kind 8333) and the entire Bitcoin wallet implementation
  (useBitcoinWallet, bitcoin-signers, BitcoinContentHeader,
  bitcoinjs-lib / @bitcoinerlab/secp256k1 / ecpair / tiny-secp256k1)
- ZapSuccessScreen (depended on dropped bitcoin lib)

Pulled in from Ditto:
- .agents/skills/* (12 new specialized skills, slim AGENTS.md)
- @nostrify bumps to 0.52 / 0.6 / 0.37
- New routes/pages: Music, Podcasts, Videos, Vines, Wikipedia, Books,
  Bluesky, Archive, AIChat, Trends, Webxdc, Highlights, Decks, Emojis,
  Development, Treasures, Colors, Packs
- Birdstar feed integration (kinds 2473, 12473, 30621)
- Wikipedia/Wikidata/Scryfall lookup in ExternalContentPage
- release-notes CI job + extract-release-notes.mjs script
- nsite:// URI handling in feed/sidebar
- iOS fastlane setup
- src/lib/avatarShape.ts + Avatar shape prop (kept for new Music/People
  components that depend on it)

Preserved Agora's ABSOLUTE 'NEVER COMMIT' rule at the top of AGENTS.md
and dropped Ditto's contradicting 'Commit at the end of every task'
section.

Validation: npm run test passes (tsc, eslint, 40/40 vitest, vite build).
2026-05-13 18:35:03 -05:00
Alex Gleason 814d1909f6 release: v2.14.4 2026-05-11 14:01:54 -07:00
Alex Gleason b8773c47d7 Automate App Store releases via self-hosted Mac runner
Mirror the existing Android publishing flow for iOS. The pipeline
gains two jobs: build-ipa runs on a self-hosted Mac runner and
produces a signed App Store IPA; publish-app-store runs on a shared
Linux runner and submits the prebuilt IPA to App Store Connect.

Build pipeline (.gitlab-ci.yml):
- build-ipa (Mac, stage build, parallel with build-apk): decodes the
  ASC API key, runs match (with api_key, so cert validity is verified
  against Apple before xcodebuild starts), builds web assets, syncs
  Capacitor, stamps MARKETING_VERSION. Uploads Ditto-${CI_COMMIT_TAG}
  .ipa to GitLab's Generic Packages registry.
- publish-app-store (Linux ruby:3.3, needs: [build-ipa]): gem
  install fastlane, decode the ASC API key, extract the changelog
  section into release_notes.txt, fastlane submit_release with
  IPA_PATH pointing at the inherited artifact. No Xcode, no signing,
  no keychain \u2014 pure Apple API call.
- release job now needs both build-apk and build-ipa, and links three
  assets (APK / AAB / IPA).

fastlane (ios/fastlane/Fastfile, Matchfile, Appfile, metadata/):
- Four lanes: build_ipa (CI build), submit_release (CI publish, reads
  IPA_PATH from env), release (single-step convenience for local
  dev), submit_only (debug lane to re-submit an already-uploaded
  build).
- Match config points at the private gitlab.com/soapbox-pub
  /certificates repo. App Store Connect API key is built inline in
  the Fastfile to avoid a collision with match's APP_STORE_CONNECT
  _API_KEY_PATH env var (match wants a JSON descriptor, the action
  writes a raw .p8). CI overrides CODE_SIGN_STYLE=Manual via xcargs
  so the Xcode project can stay on Automatic for local development.

Vite config (vite.config.ts):
- Renames the build-time config override env var from CONFIG_FILE to
  DITTO_CONFIG_FILE. GitLab Runner sets CONFIG_FILE to its own TOML
  config in job env, which broke vite's loader.

App-side changes:
- ios/App/App.xcodeproj/project.pbxproj: team GZLTTH5DLM stamped in;
  MARKETING_VERSION gets stamped from the tag at build time.
- public/CHANGELOG.md, package.json: v2.14.3.

Skills + AGENTS.md updated to reflect the six-job pipeline (test /
deploy unchanged, build now has two jobs, release / publish updated)
and to document Mac-runner operations, fastlane match cert rotation,
and local debugging workflows.
2026-05-11 12:59:04 -07:00
Alex Gleason c85f65a99a release: v2.14.2 2026-05-11 09:47:26 -07:00
Alex Gleason ac901ac096 release: v2.14.1 2026-05-10 19:42:40 -07:00
Alex Gleason 845c270f60 release: v2.14.0 2026-05-09 16:36:05 -07:00
Alex Gleason 9810f813a8 release: v2.13.1 2026-05-05 23:06:07 -05:00
Alex Gleason 6c58b087ae release: v2.13.0 2026-05-05 20:48:38 -05:00
Alex Gleason 973acd7e9b Inject NIP-07 signer into nsites and drop native sandbox path
When a logged-in user opens an nsite preview, a window.nostr provider is
injected into the sandboxed iframe. The provider proxies signEvent, nip04,
and nip44 calls to the parent signer over the existing JSON-RPC bridge.

A permission system gates each operation:
- getPublicKey is auto-allowed (clicking Run implies consent)
- signEvent prompts are granular per event kind (like Amber)
- encrypt/decrypt prompts are per operation type
- Users can check 'Remember for this site' to persist decisions
- Permissions are scoped to (userPubkey, siteId) in localStorage

The nsite preview nav bar gains a shield icon that opens a popover for
managing stored permissions.

Kind labels for the signer nudge, the permission prompt, and the post-
detail loading title now route through a central KIND_LABELS registry
(src/lib/kindLabels.ts) instead of three divergent inline maps.

The native SandboxPlugin (iOS WKWebView / Android WebView overlay) is
removed; SandboxFrame now always uses iframe.diy, so native behavior
matches web. This drops ~1100 lines of native code, the Android-only
blob prefetch workaround in NsitePreviewDialog, and the createPluginCall
registration in MainActivity and capacitor.config.json.
2026-05-05 12:15:31 -05:00
Alex Gleason d2cf678491 Fix sing-to-Blobbi mic access on Android and preview playback on iOS
The sing action uses getUserMedia + MediaRecorder, which in a browser is
gated only by the standard web mic prompt. In Capacitor's Android
WebView it additionally requires the RECORD_AUDIO permission to be
declared in AndroidManifest.xml; without it the WebView rejects with
NotAllowedError and no system prompt is ever shown, so tapping record
silently fails on the Android app while working fine in the browser.

Also add MODIFY_AUDIO_SETTINGS, which some devices require for the
echoCancellation / noiseSuppression / autoGainControl constraints that
InlineSingCard passes to getUserMedia.

Separately, reorder AUDIO_MIME_CANDIDATES to prefer audio/mp4/aac over
audio/webm;codecs=opus. iOS WKWebView cannot decode WebM/Opus in an
<audio> element, so the recorded Blob's preview URL failed to load on
iOS. Android WebView and desktop Chromium both support mp4/aac, so
preferring it first is safe cross-platform. This mirrors the ordering
already used by useVoiceRecorder.ts.
2026-05-05 09:20:01 -05:00
Alex Gleason 9c74ddcaa9 release: v2.12.2 2026-05-04 21:57:23 -05:00
Alex Gleason b639bd7a58 release: v2.12.1 2026-05-01 22:22:46 -05:00
Alex Gleason af67e7f812 release: v2.12.0 2026-04-30 10:52:37 -05:00
Alex Gleason 460926fa99 release: v2.11.2 2026-04-28 14:47:03 -05:00
Alex Gleason 71fe5aaa3a release: v2.11.1 2026-04-28 14:10:21 -05:00
Alex Gleason 00412385c8 release: v2.11.0 2026-04-28 12:05:35 -05:00
Chad Curtis 0ba6bacaf5 release: v2.10.5 2026-04-25 03:30:27 -05:00
Chad Curtis 5080970366 release: v2.10.4 2026-04-23 15:35:54 -05:00
Chad Curtis bfee3dfdf1 release: v2.10.3 2026-04-20 19:40:48 -05:00
Alex Gleason 91fe272bea release: v2.10.2 2026-04-18 09:19:01 -05:00
Alex Gleason 54a49f1ece release: v2.10.1 2026-04-17 22:43:30 -05:00
Alex Gleason cb26238729 release: v2.10.0 2026-04-17 19:34:53 -05:00
Alex Gleason 482c99281c release: v2.9.0 2026-04-17 15:43:30 -05:00
sam 9550094ffb wip mega dump/migration from ditto 2026-04-17 12:10:11 +05:45
Alex Gleason 71918f8381 release: v2.8.0 2026-04-16 18:05:50 -05:00
Alex Gleason 7073cadb43 release: v2.7.1 2026-04-16 16:09:12 -05:00
Alex Gleason 0d3b8ed23d Harden CSS/URL handling, NWC storage, and Android backup
- Sanitize event-sourced URLs before CSS url() interpolation in
  ProfileCard banner and letter stationery background (closes H-1, H-2)
- Sanitize event-sourced font families at the parse layer and in letter
  card/detail consumers that bypass resolveStationery (closes M-6)
- Export sanitizeCssString for broader reuse
- Route NWC wallet connection URIs and active pointer through a new
  useSecureLocalStorage hook, storing in iOS Keychain / Android KeyStore
  on native (closes M-1)
- Add removeItem to secureStorage
- Add Android backup/data-extraction rules that exclude WebView storage
  and Capacitor secure-storage SharedPreferences so wallet credentials
  don't leak via Google Auto Backup (closes M-5)
- Document that GOOGLE_PLAY_SERVICE_ACCOUNT_JSON must be base64-encoded
  to match what the CI job expects (closes M-2)
2026-04-16 14:20:26 -05:00
Alex Gleason 2d52aa8a56 release: v2.7.0 2026-04-14 16:01:08 -05:00
Alex Gleason cc702027b0 Add native haptic feedback to all key interactions
Install @capacitor/haptics and add a centralized haptics utility
(src/lib/haptics.ts) that uses the native taptic engine on iOS/Android
and falls back to navigator.vibrate() on web.

Haptics added to:
- Switch component (covers 36+ toggle switches app-wide)
- PullToRefresh threshold (covers 15+ pages)
- MobileBottomNav tab taps
- ReactionButton (like/unlike, double-click heart)
- RepostMenu (repost/undo repost)
- ZapDialog button press + payment success (NWC and WebLN)
- FollowButton and ProfilePage follow toggle
- ComposeBox (post, voice message, and poll publish success)
- NoteMoreMenu (bookmark, pin, mute)
- VinesFeedPage reaction and repost buttons
- ProfileReactionButton and ExternalReactionButton
- NoteCard share button
- BlobbiRoomShell swipe navigation

Replaces raw navigator.vibrate() calls in GameControls and
SendAnimation with the new cross-platform haptics utility, fixing
haptic feedback on iOS where the Vibration API is not available.
2026-04-14 11:06:18 -05:00
Alex Gleason 32908f7b4f release: v2.6.6 2026-04-12 14:32:14 -05:00
Alex Gleason 7cba044b9d release: v2.6.5 2026-04-11 18:15:04 -05:00
Alex Gleason dc81585f9a Pre-fetch all nsite blobs on Android before WebView navigates
Android's shouldInterceptRequest blocks a pool of ~6 IO threads, each
waiting for JS to respond via the Capacitor bridge. With 200+ files
each requiring a network round-trip to Blossom, loading is painfully
slow. iOS doesn't have this problem — WKURLSchemeHandler is async.

Split the native plugin lifecycle into create() and navigate():
- create() adds the WebView container with spinner overlay (visible)
- navigate() loads the entry URL (triggers fetch interception)

On Android, onReady downloads all manifest blobs in parallel (12
concurrent fetches) into an in-memory cache while the native
ProgressBar spinner animates. Once navigate() fires, every resolveFile
call is an instant cache hit.

On iOS/web, onReady is a no-op and navigate() fires immediately.
2026-04-11 17:20:21 -05:00
Alex Gleason dceda199c3 Add loading spinners to native sandbox WebViews
iOS: load inline spinner HTML (centered spinning ring on dark background)
before navigating to the real content URL. Supports light/dark mode via
prefers-color-scheme. The spinner is replaced when the real page loads.

Android: use a native ProgressBar overlay instead of HTML — the HTML
spinner froze because constant Capacitor bridge calls saturated the
main thread, starving the WebView compositor. The native ProgressBar
animates on the render thread independently. Wrapped in a FrameLayout
with a dark overlay behind the spinner.

Both platforms: set WebView background to #14161f (app dark theme)
instead of white. Increased Android shouldInterceptRequest timeout
from 10s to 60s to prevent premature timeouts on large nsites.
2026-04-11 17:20:01 -05:00
Alex Gleason 8967012035 release: v2.6.4 2026-04-11 15:43:47 -05:00
Alex Gleason 357ba7d8c8 fix: migrate to SystemBars API for Android 16+ safe area inset support
Android 16 (API 36) enforces edge-to-edge rendering unconditionally,
breaking @capacitor/status-bar's setOverlaysWebView and setBackgroundColor.
Additionally, a Chromium bug (<140) causes env(safe-area-inset-*) to report
0 in some Android WebViews.

- Replace @capacitor/status-bar with SystemBars from @capacitor/core 8+
- Enable insetsHandling: 'css' in capacitor.config.ts so the SystemBars
  plugin injects --safe-area-inset-* CSS variables on Android
- Update all safe area CSS utilities and inline styles to use
  var(--safe-area-inset-*, env(safe-area-inset-*, 0px)) fallback pattern
- Remove @capacitor/status-bar dependency (no longer needed)
2026-04-11 14:47:15 -05:00
Alex Gleason 207ca6893a Add iCloud Keychain credential saving/restoring on iOS via @capgo/capacitor-autofill-save-password
- Use SecAddSharedWebCredential to prompt 'Save Password?' on signup
- Use ASAuthorizationPasswordProvider to restore credentials on login
- Add webcredentials:ditto.pub Associated Domains entitlement
- Deploy apple-app-site-association for domain validation
- Keep existing Chromium PasswordCredential flow as web fallback
- Add saveNsec() helper: native credential manager on iOS/Android,
  file download + bonus PasswordCredential on web
- Single 'Continue' button triggers the appropriate save method per platform
2026-04-11 14:01:34 -05:00
Alex Gleason 37df5d0bd1 release: v2.6.3 2026-04-10 23:27:38 -05:00
Alex Gleason ac1e82b52d release: v2.6.2 2026-04-08 23:38:31 -05:00
Alex Gleason 82632bb76c Store nostr:login in secure storage on native platforms
Use capacitor-secure-storage-plugin to persist login credentials
(nsec keys) in iOS Keychain / Android KeyStore instead of plaintext
localStorage. Web behavior is unchanged. Existing native users are
auto-migrated on first launch: if secure storage is empty but
localStorage has data, it is moved over and the plaintext copy is
removed.

Also ignore ios/ directory in ESLint (Capacitor-generated files).
2026-04-08 22:20:48 -05:00
Alex Gleason 5ee8bc1cc0 Improve mobile search UX: lock scroll, hide bottom nav, dismiss accessory bar, and fix close behavior 2026-04-08 22:04:26 -05:00
Alex Gleason e482afbd3f Fix sandbox origin isolation and Android build issues 2026-04-08 20:47:42 -05:00
Alex Gleason f25139103c Add native SandboxPlugin for iOS and Android 2026-04-08 20:47:28 -05:00
Chad Curtis 3ee491a63b Add push vs persistent notification delivery option for Android
Default to push mode (no foreground service). Persistent mode with
the always-on background polling service is opt-in via the new
Delivery Method section in notification settings.

- Add notificationStyle ('push' | 'persistent') to EncryptedSettings
- Show radio group in NotificationSettings on native platforms
- Pass notificationStyle through Capacitor plugin to SharedPreferences
- DittoNotificationPlugin starts/stops foreground service on style change
- MainActivity only starts service on launch when style is persistent
- Re-enable unread polling on native when push mode is active
2026-04-07 10:54:30 -05:00
Alex Gleason 0a5e72efd0 release: v2.6.1 2026-04-06 00:58:23 -05:00
Chad Curtis 283b31813c release: v2.6.0 2026-04-05 08:31:35 -05:00
Alex Gleason 431c388129 release: v2.5.2 2026-04-04 13:54:13 -05:00
Alex Gleason e67f90582b release: v2.5.1 2026-04-03 23:31:09 -05:00
Alex Gleason 9b36bf3325 release: v2.5.0 2026-04-03 23:09:20 -05:00
Alex Gleason 8b824f8cc9 release: v2.4.1 2026-04-02 23:12:45 -05:00