- Use minimal-distance hue palette for mesh and geohash lists; align chat sender colors with list palette.
- Add foreground geo notifications for different channels; deep-link to bitchat://geohash/<gh>; per-geohash 60s cooldown; respect self/blocks.
- Global geohash sampling runs outside the sheet; delegate handles deeplinks and suppresses when already in-channel.
- Switch location channel sheet to continuous CoreLocation with 21m distance filter; add config knob.
- Only link geohash hashtags when standalone (no @name#abcd or word#abcd).
- Include mesh-reachable peers in mesh counts and in "bitchatters nearby" notification.
- Add TransportConfig knobs for palette and geo notifications.
* Sign public broadcasts; verify relayed messages via persisted signing keys; keep scheduled relays in sparse graphs and speed their jitter; persist announce signing key for offline auth; add short backoff after disconnect errors to reduce reconnect thrash
* Add connected vs reachable model: retain peers after link drop, expire after reachability window; expose all peers in snapshots; compute isReachable in UI; add meshReachable state and sorting; avoid removing peers on link events; notify UI on stale removals
* ContentView: handle new .meshReachable connection state in header icon switch (exhaustive switch fix)
* Logs: tag relayed announces as 'Reachable via mesh' and annotate public message logs with (direct|mesh) path for easier field analysis
* Fix syntax error: remove stray else/log inserted into writeOrEnqueue; keep logs clean
* UI: use 'point.3.connected.trianglepath.dotted' for mesh-reachable; change people count to include connected+reachable (exclude Nostr-only)
* UI: switch to 'point.3.filled.connected.trianglepath.dotted' for mesh-reachable icons in list and header
* Reachability: reduce retention to 21s for all peers (verified and unverified) to minimize stale presence
* mesh DMs/acks: route to reachable peers; queue READ/DELIVERED until handshake; add Transport.isPeerReachable; UI: hide offline non-mutuals; DM header: better name fallback + show transport + encryption icons; fix NostrTransport conformance
* Verification sheet: compute encryption status and fingerprint using short mesh ID mapping (fix 'not encrypted/handshake' for DMs with stable key)
* Announce cadence: faster discovery (4s), sparse 15±4s, dense 30±8s; initial 0.6s; post-subscribe 50ms; min-force 150ms; maintenance 5s; proactive announces on handshake + recent-traffic nudge
* Relay: increase broadcast TTL cap in sparse graphs to 6; tighten jitter for handshake (10–35ms) and directed (20–60ms) relays
* Range/robustness: store-and-forward for directed packets (15s) with flush on new links + periodic; announces: no subset + afterglow re-announce on first-seen; adaptive scanning: force ON when <=2 neighbors or recent traffic
* Fix warnings: remove unused msgID and unused mutable var in directed spool flush
* Announces: TTL 7 (sparse only) via RelayController; no fanout subset for announces; neighbor-change rebroadcast of last 2–3 announces. Fragments: faster pacing (5ms global, 4ms directed).
* Peer list: real-time icon updates by publishing snapshots on connectivity checks; add unread message indicator (envelope) next to peers with unread DMs
* UI: unread envelope uses orange; hasUnreadMessages checks Nostr conv key for peers with known Nostr pubkeys (geohash DM consistency)
* Logs/robustness: debounce disconnect notifications (1.5s), debounce 'reconnected' logs (2s), add weak-link cooldown after timeouts on very weak RSSI (<= -90)
* Peer icons: faster, accurate reachability\n\n- Run connectivity checks every maintenance tick (5s)\n- Publish peer snapshots on central unsubscribe for instant UI refresh\n- Lower inactivity timeout to 8s and disconnect debounce to 0.9s\n- Gate reachability on mesh-attached (>=1 direct link); no links => no reachable peers\n- Keep 21s retention for verified/unverified, but only when attached to mesh\n\nImproves list responsiveness when walking out of range and prevents stale 'reachable' states when isolated.
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Remove dead code and artifacts: drop PeerManager, unused views/types; delete LegacyTestProtocolTypes; update .gitignore; purge TestResult.xcresult and build.log
* Tests: gate verbose prints under DEBUG; ChatViewModel: remove legacy fingerprint helper and rely on UnifiedPeerService
* Share Extension: migrate to UIKit + UTTypes; drop Social/SLComposeServiceViewController
* Remove 'preparing to share …' system message; send shared content immediately
* Inline comment cleanup: drop legacy 'removed' breadcrumbs across protocols, services, view model, and views
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Improve BLE mesh relay and flooding
Add last-hop suppression using ingress-link tracking to prevent echo. Implement deterministic always-relay for handshakes and directed encrypted/fragments; widen jitter for broadcasts; keep TTL cap only for broadcast. Add deterministic K-of-N broadcast fanout to reduce amplification in dense topologies. Introduce backpressure-aware writes using canSendWriteWithoutResponse with per-peripheral queues and draining on peripheralIsReady. Minor helpers for messageID, deterministic selection, and maintenance cleanup.
* Tests: stabilize FragmentationTests and InputValidatorTests
Make _test_handlePacket mark synthetic peers verified/connected with normalized senderID to avoid drops in public-message reassembly tests. Tighten validatePeerID to reject non-hex strings when length equals 16 or 64; allow internal IDs only for other lengths. All iOS simulator tests pass locally.
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* QR verification scaffold: add Noise verify payload types, VerificationService with QR schema/signing, placeholder MyQR/Scan views, and UI entry points in header
* QR: fix VerificationQR mutability (sigHex var) and remove duplicate Data hex helpers to resolve redeclaration; wire signed payload assembly
* QR: render actual QR images with CoreImage; add copy button; keep scanner placeholder for now
* QR: fix SwiftUI modifiers — apply .interpolation(.none) and .resizable() to platform Image inside ImageWrapper; remove from wrapper usage
* QR: add iOS camera scanner using AVFoundation; integrate into Scan view; add NSCameraUsageDescription to Info.plist
* QR: make NoisePayloadType exhaustive in ChatViewModel switches by ignoring verifyChallenge/verifyResponse for now (placeholder)
* QR verification: speed + persistence + UX
- Inject live Noise into VerificationService; prewarm QR on app start
- Keep camera active; remove intermediate responder toast
- One-shot/dupe guards and deferred send on handshake
- Persist verified status immediately; standardize fingerprint (SHA-256)
- Show verified badge for offline favorites; mutual verification toast
- VERIFY sheet styling to match peer sheet; UI polish
- Logs to diagnose verified load + favorites mapping
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* NIP-17/44: adopt NIP-44 v2 (XChaCha20-Poly1305, v2: base64url), switch rumor kind to 14, randomize BIP-340 aux; add XChaCha20Poly1305Compat and wire-up
* Nostr DMs: ensure delivered/read acks are sent even without Noise key mapping by falling back to direct Nostr (geohash-style) acks to sender pubkey
* NIP-44 v2 decrypt: try both Y parities for x-only sender pubkeys (even then odd) to fix unwrap authentication failures
* Tests: add NIP-44 v2 ACK round-trip tests (delivered/read) using bitchat1 embedding and gift-wrap decrypt path
* UI: fix DM autoscroll IDs by using dm:<peer>|<id> for private chat item IDs and preserve anchors, ensuring scrollTo targets exist when opening/switching/new messages
* UI: fix string interpolation in DM/geohash context keys (remove escaped interpolation) to resolve 'unused ch' warnings and ensure proper IDs
* UI: MeshPeerList shows transport state icon: radio for mesh-connected, purple globe for mutual favorite/Nostr; fallback dim person for others
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* feat(notifications): unify DM notifications across transports; notify for unread+recent even in foreground; delegate suppresses if chat open
* fix(geohash): include own past geohash messages on channel load; skip only very recent self-echo (<15s) to avoid duplicates
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* feat(georelay): route geohash kind 20000 via nearest relays; add GeoRelayDirectory; target geohash subscriptions; avoid duplicate connections
* feat(georelay): fetch daily from remote CSV with fallback to bundled; cache to app support; prefetch on app load
* fix(georelay): make CSV parser nonisolated and call as Self.parseCSV to satisfy Swift 6 actor isolation
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Remove link previews: link URLs inline\n\n- Delete LinkPreviewView and all references\n- Strip preview usage from ContentView\n- Make detected URLs tappable via .link attribute\n- Add MessageTextHelpers for tokens/length checks\n- Wire helpers into iOS/macOS targets
* Peer list UX: match message colors, use map pin icon, stable ordering\n\n- Color list names and icons with same peer color as messages\n- Default icon mappin; teleported uses face.dashed (iOS)\n- Geohash: move teleported peers to bottom\n- Maintain stable order: append new peers, remove missing\n- Mesh list: replace state icons with colored mappin/person
* Fix peer list build errors: remove ambiguous Set type, avoid guard in ViewBuilder, remove duplicate bindings, and simplify person lookup
* Peer list: remove onChange expressions to avoid type-check issues; rely on ObservedObject updates
* Peer lists: simplify view structure to satisfy SwiftUI type checker (replace Group with VStack, flatten body)
* Peer lists: move ordering mutations to onAppear/onChange, keep body pure; fix result builder errors
* Fix: remove trailing modifiers outside if/else to avoid ViewBuilder type issues
* Color parity: fix seed cache to include color scheme; normalize Nostr seeds; switch to mappin.circle icon
* Peer colors: ensure exact match with message colors\n\n- Mesh list uses same seed logic as messages (getNoiseKeyForShortID fallback)\n- Color cache keyed by theme; normalize nostr seeds\n- Icons: use mappin.and.ellipse (default) and face.dashed for teleported\n- Teleport tag: accept "teleported" in addition to "teleport" and presence events
* Fix geohash color mismatch: populate nostrKeyMapping before building messages in resubscribe; also honor t,teleport tag for teleported state
* Message actions: username tap opens sheet via clickable AttributedString; message tap inserts @mention; rename to 'direct message'
* Cashu UX: suppress 'Show more' when message contains a Cashu token (chips handle rendering)
* Cashu detection: broaden regex (allow '.') + shorter min length; avoid long-text fallback when Cashu present so chips render and no full blob
* Geohash levels: rename region->province, country->region; update labels, precision, UI, manager mapping, tests; add Codable backward-compat for renamed cases
* Fix braces in LocationChannel.swift: close enum before extension to satisfy file-scope declarations
* Geohash links: make #geohash tappable and open that channel (bitchat://geohash/<gh>); handle in ContentView.onOpenURL with validation and selection
* Underline tappable #geohash mentions for clarity
* Geochat: sanitize timeline on channel switch to remove any blank-content entries (prevents blank rows)
* Xcode project: sync sources after UI changes (remove LinkPreview, add helpers, update build refs)
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* fix(geo-block): enable block/unblock for geohash users and enforce blocks\n\n- Add persisted set of blocked Nostr pubkeys in SecureIdentityStateManager\n- Check Nostr blocks for incoming messages (public + geo DMs)\n- Prevent sending geo DMs to blocked users\n- Extend /block and /unblock to resolve geohash display names to pubkeys and act accordingly\n- Improve /block list to show geohash blocks (visible names or #suffix)
* fix(geo-block): enforce blocks on geohash public and DM receive; add block/unblock actions to geohash people list
* fix: mark handlePublicMessage as @MainActor to call isMessageBlocked safely
* ui(block): show blocked indicator (nosign icon) next to blocked peers in mesh and geohash lists
* fix(geo-block): early-drop blocked pubkeys on geohash receive; filter blocked users from participants list
* fix(geo-block): purge existing geohash messages/DMs on block; block directly from chat using Nostr sender ID when available
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* feat(cashu): auto-link cashu tokens in chat
- Detect cashuA/cashuB tokens via regex and render as tappable links
- Style like URLs (underline; blue for others, orange for self)
- Add openURL handler for cashu: scheme to delegate to wallet on iOS
- Respect existing heavy-content gating and long-message collapsing
* feat(ln): auto-link Lightning invoices and LNURL + lightning: scheme\n\n- Detect BOLT11 (lnbc/lntb/lnbcrt...), LNURL bech32, and lightning: URIs\n- Render as tappable links with lightning: scheme; consistent styling\n- Handle lightning: in openURL alongside cashu:
* feat(links): replace raw Cashu/Lightning tokens with compact chips (🥜 pay via cashu / ⚡ pay via lightning) while keeping them tappable
* style(links): add subtle background highlight to cashu/lightning chips
* ui(links): render Lightning/Cashu as rounded chips under message with padding; remove inline chip text
* ui(links): increase chip padding and corner radius; add extra top padding for chip row
* scroll: auto-scroll to bottom when sending a new message (public + private), regardless of current scroll position
* scroll(geo): when switching geohashes, scroll to top of chat (first visible message)
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Feature: assign stable per-peer colors (non-self) across mesh/geohash/DM; keep self orange and mentions-to-me orange; cache colors
* Fix compile warnings: remove unused primaryColor in formatMessageAsText; remove unused CryptoKit import; mark peerColor/formatMessageAsText @MainActor to call main-actor helpers
* Fix: re-import CryptoKit for SHA256 usage in ChatViewModel
* Peer lists: apply same per-peer colors as chat (self orange); suffix uses lighter variant; geohash uses Nostr pubkey, mesh uses Noise key
* Fix warning: remove unused peerNicknames in MeshPeerList
* UI: add 'mention' action in message actions to prefill input with @nick#abcd and focus input
* UX: long-press a message to prefill @mention with sender's full nick#abcd and focus input
* UX: remove long-press mention; add context menu 'Copy message' that copies only the message body (no nick/timestamp)
* Geo teleported: robust tag detection (accept 't', 'teleport', and boolean-like values); mark self on send when tagging; should fix peer list icons
* Logs: add GeoTeleport diagnostics (incoming tags, self/peer marking, counts) to debug peer list dashed icon behavior
* Teleport persistence: store per-geohash teleported state in UserDefaults; initialize on startup; OR with location-derived status; sheet writes persisted flag on select/teleport
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Scroll UX: auto-scroll only when last item visible; preserve user position when scrolled up for mesh/geohash/DM; reduce blanking after very long messages
* iOS: re-enable keyboard autocomplete and default capitalization for message input
* Styling: stop blue/underline styling for #hashtags; render as normal text color (self=orange, others=green)
* Geo UI: ensure self shows teleported (face.dashed) if either per-session tag or manager flag is true
* Geo teleported: publish UI updates by assigning @Published Set instead of in-place insert; update on tag receipt and channel switch
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Geohash peers: show face.dashed for self when channel selected via teleport; face.smiling otherwise
* Geo presence: broadcast 'teleport' tag on geochat join; track teleported participants and show face.dashed for them in peer list
* Teleport tag: attach to actual geohash chat events (sendMessage, emotes, screenshots) instead of separate presence; remove presence emit
* Fix: show face.dashed for any teleported peer (not just self) in geohash list
* Geo list: show self immediately on channel switch and mark teleported state; clear teleported flags on leaving geochat
* Teleport persistence: recompute teleported based on current location vs selected geohash; add face.dashed icon to Teleport button label
* Styling: use lighter green/orange for #abcd suffix after nicknames in all chats (senders and @mentions)
* Peer lists: render #abcd suffix as lighter green/orange (self orange) in geohash and mesh lists
* Toolbar: move unread icon next to #channel badge and allow dynamic width; Peer lists: increase top spacing before first item
* Toolbar: prevent geohash channel badge from truncating; give it layout priority and fixed width
* Toolbar: make unread envelope independent from channel button (sits left of badge); fix accidental taps opening channel selector
* Toolbar: make unread envelope open most recent unread/private chat directly
* Geohash peer list: render self row fully orange (icon, base, suffix, '(you)')
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>