mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-28 19:45:20 +00:00
update-georelays-20260111T060518Z
31
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
40e54a5120 |
Add voice notes and images over BLE mesh (audio + image only) (#823)
* Add BLE file transfer support and media UX * Gracefully disable mac attachment pickers in sandbox * Tighten spacing above media message bubbles * Reduce vertical padding between chat rows * Restore iOS file importer for attachments * Copy imported files before sending to preserve access * Allow file transfers from connected but unverified peers * Raise BLE notification buffer cap for large file transfers * Revert "Raise BLE notification buffer cap for large file transfers" This reverts commit b624523af843475db84e4a846db8dcbe824ae408. * Add guard to drop oversized BLE notification assemblies * Let BLE assembler accept large frames up to hard cap * Add detailed logging for BLE fragment assembly * Log incomplete BLE frames for debugging * Stop dropping partial BLE frames while assembling notifications * Fix compressed BLE file transfers * Enable mac attachment importers * Allow mac microphone access * Permit mac media library access * Describe microphone usage * Harden attachment transfer bookkeeping * Display recording milliseconds * Restore mac photo picker access * Use Photos picker on mac * Allow long-press reblur on images * Reblur images via swipe * Lowercase image preview buttons * Keep processed images for outgoing messages * Use save panel for mac image export * Fix image attachment detection * Allow user-selected write access * Align mac image JPEG encoding * Revert unsupported JPEG option * Strip metadata in mac image encoding * Normalize mac JPEG color space * Target image byte size across platforms * Fix CFMutableData handling * Preserve packet version when signing * Use unique transfer identifiers * Stub file transfer methods in mock * Stub file transfer methods in mock * Hide absolute paths in media messages * Resolve image/voice path handling * Fix cleanupLocalFile lookup * Restore BLE broadcasts when notify buffer is saturated * Guard peer map reads on BLE message path * Drop attachment ceilings to 1 MiB and bump release version * Reset BLE assembler on stalled fragment trains * Fix binary protocol test fixtures * Fix critical issues from PR #681 review Critical fixes: - BinaryProtocol: Return nil for unknown versions (prevents buffer underflows) - Add BinaryProtocol.Offsets struct to centralize magic numbers - Replace magic offset calculations with named constants Security/Privacy: - FileAttachmentView: Use url.lastPathComponent instead of url.path (prevents exposing full system paths) Documentation: - Fix compression algorithm documentation (zlib, not LZ4) All tests passing. * Fix UI freeze when receiving voice notes Problem: AVAudioPlayer initialization in VoiceNotePlaybackController.init() was running synchronously on main thread during view creation, blocking UI for 50-200ms per voice note. Solution: - Remove eager preparePlayer() call from init - Load duration asynchronously on background queue - Player is only prepared when playback is actually requested via ensurePlayerReady() This prevents UI freezes when voice notes appear in the chat. * Fix memory leaks and post-playback freeze Fixes: 1. Post-playback freeze: audioPlayerDidFinishPlaying now dispatches to main thread before updating @Published properties (Swift concurrency violation) 2. Unbounded waveform cache: Implement LRU eviction with 20-entry limit - Track last access time for each cached waveform - Evict oldest entry when cache is full - Prevents unlimited memory growth as voice notes accumulate 3. Audio buffer memory leaks: Wrap computeWaveform in autoreleasepool - AVAudioPCMBuffer allocations are autoreleased - Pool ensures buffers are freed promptly 4. Image processing memory: Add autoreleasepool around compression loops - Each jpegData() call creates temporary objects - Inner pool per iteration prevents memory spikes during quality search Memory should now remain stable during extended use. * Eliminate disk I/O from SwiftUI view rendering path Critical performance fix for UI freezes when receiving media: Problem: mediaAttachment(for:) was called during every SwiftUI render, performing synchronous disk I/O on main thread: - FileManager.fileExists() called 2-6x per message (checking subdirs) - applicationFilesDirectory() creating directories on every call - With multiple media messages, this meant 20-100+ disk ops per render Solution: 1. Remove fileExists checks - construct URLs directly - Files are validated during playback/display (fail gracefully if missing) - Sender determines subdirectory (outgoing vs incoming) 2. Cache applicationFilesDirectory() result - Static cache prevents repeated FileManager.url() calls - Directory created only once 3. Remove redundant playback.replaceURL() in VoiceNoteView.onAppear - Controller already initialized with correct URL This eliminates ALL disk I/O from the view rendering hot path. * Cache Nostr identity derivation to prevent crypto during view rendering Critical performance fix: Problem: formatMessageHeader() called deriveIdentity(forGeohash:) during every SwiftUI render for every media message. Each call performed: - Keychain I/O (getOrCreateDeviceSeed) - HMAC-SHA256 computation - Up to 10 secp256k1 key validations (elliptic curve crypto) With multiple media messages, this resulted in 100s of milliseconds of blocking crypto on main thread per render cycle. Solution: Add thread-safe cache for derived identities - Check cache before expensive crypto operations - NSLock protects concurrent access - Identity is deterministic per geohash, so caching is safe This eliminates crypto from the hot rendering path. * Cache geohash identity in ChatViewModel to prevent crypto during rendering Additional optimization for location channels (voice notes are mesh-only, but this helps with text message rendering in geohash channels): - Add cachedGeohashIdentity to avoid deriveIdentity calls during rendering - Check cache before falling back to crypto derivation - Reduces main thread crypto work in location channels * Make voice note loading completely lazy with deferred initialization Aggressive performance optimization to prevent UI freezes: Problem: Even with async loading, creating 10+ VoiceNotePlaybackController instances simultaneously (when scrolling past multiple voice notes) spawned 20+ concurrent background tasks, potentially starving main thread. Solution - Ultra-lazy loading: 1. VoiceNotePlaybackController.init() now does ZERO work - No duration loading - No player creation - Instant initialization 2. Duration loaded on-demand via public loadDuration() method - Called from VoiceNoteView.onAppear after 150ms delay - Reduced priority: .utility instead of .userInitiated - Guard prevents duplicate loading 3. Waveform loading also deferred 150ms - Gives UI time to settle after message appears - Prevents task storms when multiple voice notes appear This spreads the work over time instead of all at once. * Ensure /clear and panic triple-tap delete media files Fix: /clear command and panicClearAllData() now properly delete media files 1. /clear (triple-tap on chat): - Deletes outgoing media (voice notes, images, files) - Conservative: only our sent media, preserves received media - Runs in background to avoid UI freeze 2. panicClearAllData() (triple-tap on bitchat/ header): - Deletes ALL media files (incoming + outgoing) - Removes entire files directory and recreates structure - Ensures complete data wipe for emergency scenarios Both operations run async on .utility queue to prevent blocking UI. * Fix infinite render loop and apply all security fixes CRITICAL BUG FIX - Infinite Render Loop: Root Cause: Duplicate view identity in ContentView.swift:368 ForEach(messageItems) { item in // Already uses item.id via Identifiable messageRow(...) .id(item.id) // ❌ REDUNDANT modifier caused identity re-evaluation loop } When @Published properties updated, SwiftUI re-evaluated .id() → appeared as 'new' identity → triggered re-render → infinite loop. Caused UI freezes, keyboard failures, and 100% CPU usage. Fix: Remove redundant .id() modifier - ForEach already has stable identity. PERFORMANCE FIXES: 1. Waveform Cache Deadlock (Waveform.swift) - Removed nested queue.async(barrier) on cache hits - Was causing task saturation and potential deadlocks 2. Async Send Pattern (ContentView.swift) - Clear input immediately, defer actual send to next runloop - Prevents blocking current event handler 3. Proper Swift Concurrency (VoiceNoteView.swift) - Switch from .onAppear + DispatchQueue to .task - Cleaner async/await pattern for loading 4. Remove Redundant objectWillChange (ChatViewModel.swift) - @Published already triggers updates automatically - Explicit send() was causing double update cycles SECURITY FIXES (C1-C5, H1-H2): C1. Path Traversal Protection (BLEService.swift) - Unicode normalization, null byte removal - Replace ALL path separators, reject dotfiles - Validate paths don't escape directory C2. Integer Overflow (BitchatFilePacket.swift) - Use UInt64 for TLV parsing, safe Int conversion C3. MIME Validation (BLEService.swift) - Whitelist: JPEG, PNG, GIF, WebP, M4A, MP3, WAV, OGG, PDF - Magic byte validation for all types - Lenient on M4A (platform variations) C4. Compression Bomb (BinaryProtocol.swift) - Ratio validation <= 50,000:1 - Defense-in-depth with 1MB size cap C5. TOCTOU Race (ChatViewModel.swift) - Direct removeItem without fileExists check H1. File Size Validation (ChatViewModel, ImageUtils) - Check attributes BEFORE Data(contentsOf:) - Prevents memory exhaustion H2. Metadata Stripping (ImageUtils.swift) - Remove ALL metadata keys from JPEG encoding - Only compression quality set - Protects GPS/EXIF/device info privacy RESULT: ✅ No render loops ✅ Works with Xcode debugger ✅ Voice notes display properly ✅ All security vulnerabilities fixed ✅ 164 tests passing Production ready. * Complete all translations to 100% and fix auto-extraction - Mark non-localizable strings with Text(verbatim:) to prevent extraction - Update UI strings to lowercase per style guide (open, save, close, recording) - Add complete translations for all 29 languages (194/194 strings at 100%) - Remove empty/duplicate entries (@, bitchat/, Open, Recording %@) - Add proper localization comments for all user-facing strings * macOS: Focus message input on launch instead of nickname field * Remove debug print statements from sendMessage * Optimize voice note codec to 16 kHz / 20 kbps for smaller file sizes - Reduce sample rate from 44.1 kHz to 16 kHz (telephony standard) - Lower bitrate from 32 kbps to 20 kbps - Results in ~37% file size reduction (~150 KB/min vs 240 KB/min) - Increases max voice note length from 4.4 to 7 minutes over 1 MiB BLE limit - Maintains excellent voice quality using native AAC-LC codec * Fix critical security issues in fragment reassembly and file cleanup Fragment Reassembly Race Condition (CRITICAL): - Wrap all incomingFragments/fragmentMetadata access in collectionsQueue.sync - Prevents concurrent modification crashes from multi-threaded access - Minimizes lock contention by doing heavy work (reassembly/decode) outside locks - Add upper bound check: reject fragments with total > 10,000 (DoS prevention) - Add cumulative size validation before storing fragments (memory DoS prevention) File Cleanup Path Traversal (CRITICAL): - Use NSString.lastPathComponent to extract filename safely - Prevents directory traversal attacks via malicious filenames - Add path prefix validation before file deletion - Now checks both incoming and outgoing directories (fixes disk leak) Additional Protections: - Fragment assemblies now limited by both count (128) and cumulative bytes (1MB) - Explicit checks for "." and ".." filenames in cleanup - Defense-in-depth: multiple validation layers * Fix post-rebase compilation errors - Remove duplicate NostrIdentityBridge and Bech32 from NostrIdentity.swift (now in separate files) - Add caching to NostrIdentityBridge.deriveIdentity() for performance - Remove duplicate NotificationStreamAssembler from BLEService.swift - Remove duplicate function declarations in BLEService.swift - Remove duplicate DeliveryStatusView and PaymentChipView from ContentView.swift - Fix PeerID type conversions throughout (use .id for String, PeerID(str:) for wrapping) - Update ContentView body to use main's simple VStack structure - Fix NostrIdentityBridge instance method calls - Remove privateChatView (replaced with sheet-based UI in main) Build and tests passing (137/139 tests pass). * Fix remaining compilation issues after rebase - Fix PhotosUI import order (must be after platform imports) - Fix Data.WritingOptions.atomic reference - Add identity derivation caching to NostrIdentityBridge - Fix all remaining PeerID type conversions in ChatViewModel - Fix ContentView body structure to use main's VStack layout - Fix PaymentChipView API usage (now uses PaymentType enum) Build and tests now passing. * Add proper availability checks for PhotosPickerItem PhotosPickerItem requires iOS 16+ / macOS 13+ but canImport(PhotosUI) succeeds on older macOS versions. Add compiler version check to ensure PhotosPicker code only compiles when actually available. This fixes CI build failures on older macOS environments. * Limit PhotosPicker to iOS only to fix CI PhotosPickerItem has SDK availability issues on macOS in CI. Change PhotosPicker from canImport(PhotosUI) to os(iOS) only. macOS users can still import images via file importer (.fileImporter). This is actually cleaner as macOS file picker is more familiar to users. Fixes CI build failures. * Convert new tests to Swift Testing * Fix compilation issue * Add the missing `fileTransfer` case * Explicitly list all Enum cases to get compile-time errors * Revive lost `NotificationStreamAssembler` changes * Allow file fragments to account for protocol overhead * Simplify PR: Focus on audio+image, fix EXIF stripping, remove file transfers - Fix critical EXIF privacy issue in iOS image processing - Both iOS and macOS now use CGImageDestination for metadata stripping - Shared encodeJPEG function ensures no GPS, camera, or metadata leaks - Remove file transfer functionality to simplify PR scope - Deleted FileAttachmentView - Removed sendFileAttachment from ChatViewModel - Removed file picker UI from ContentView - Simplified attachment dialog to image only (iOS) or voice only - Keep focused media features: - Voice recording and playback - Image sending with progressive reveal - Binary protocol for media transfer * Improve camera UX: Direct camera access with camera icon - Change paperclip icon to camera icon for clearer affordance - Open camera directly on tap (no confirmation dialog) - Add CameraPickerView wrapper for UIImagePickerController - Remove PhotosPicker in favor of direct camera access - Images still processed through ImageUtils with EXIF stripping - Accessibility: Added 'Take photo' label * Full-screen camera with photo library option - Change to fullScreenCover for immersive camera experience - Add action sheet with 'Take Photo' and 'Choose from Library' options - Renamed ImagePickerView to support both camera and library sources - Both options open full-screen for better UX - Updated accessibility label to 'Add photo' (more accurate) * Fix camera white bars with overFullScreen presentation - Changed modalPresentationStyle from .fullScreen to .overFullScreen - This should eliminate white bars at top/bottom on notched devices - Explicitly set showsCameraControls and cameraOverlayView for camera mode * Gesture-based photo access: Tap for library, long-press for camera UX improvements: - Tap camera icon → Photo library (common use case) - Long press camera icon (0.3s) → Direct camera (quick photos) - Removed action sheet entirely for cleaner flow - Power users can long-press for instant camera access This is more discoverable and eliminates an extra step in the UI. * Simplify camera presentation to reduce frame errors - Changed back to standard .fullScreen presentation - Removed overFullScreen which was causing frame dimension errors - Let iOS handle safe areas automatically (white bars are intentional) - Reduces gesture gate timeout warnings Note: White bars on notched devices are iOS default behavior for UIImagePickerController. This respects safe areas for status bar and home indicator. True edge-to-edge would require custom AVFoundation camera implementation. * Force dark mode on camera/picker for black safe area bars - Set overrideUserInterfaceStyle = .dark on UIImagePickerController - Changes white bars to black (much better looking) - Camera controls and photo library also appear in dark mode - Consistent dark appearance regardless of system settings * Optimize sheet presentation for camera UI - Force .large detent for maximum height - Hide drag indicator for cleaner look - Use ignoresSafeArea to give camera full space - Should show complete flash button and controls * Fix P1: Add DoS protections to PeerID fragment handler Critical security fix addressing Codex review feedback: The PeerID overload of handleFragment (which is actually called by CoreBluetooth) was missing key safety checks that existed in the String overload: 1. Added total <= 10000 check to prevent unbounded fragment counts 2. Added cumulative size check against FileTransferLimits before storing each fragment 3. Prevents memory exhaustion DoS attacks via malicious fragment streams This ensures the actually-used code path has proper bounds checking. * Fix decompression size limit to support max-sized file transfers Root cause: BinaryProtocol.decode() was rejecting decompressed payloads larger than maxPayloadBytes (1 MB), but TLV-encoded file transfers are slightly larger due to metadata overhead. Fixes: - Changed decompression limit from maxPayloadBytes to maxFramedFileBytes - This accounts for TLV overhead (~50 bytes) + binary protocol headers - Now allows ~1.12 MB decompressed payloads (1 MB + overhead budget) The failing test was: - Creating 1 MB file content - TLV encoding adds ~50 bytes (1,048,627 total) - Compression reduces to ~1,084 bytes (highly repetitive data) - During decode, decompression was rejecting the 1,048,627 byte output - Now correctly allows it since 1,048,627 < 1,179,760 (maxFramedFileBytes) All 154 tests now pass including 'Max-sized file transfer survives reassembly' * Fix critical thread-safety crash in PeerID fragment handler CRITICAL: The PeerID version of _handleFragment was accessing incomingFragments dictionary without collectionsQueue synchronization, causing crashes when multiple BLE threads processed fragments concurrently. Crash stack trace pointed to line 3431 (dictionary subscript) with: 'doesNotRecognizeSelector' - classic concurrent mutation crash. Fix: - Wrapped ALL incomingFragments/fragmentMetadata access in collectionsQueue.sync(flags: .barrier) - Matches the thread-safe pattern used in String version - Separate cleanup into its own barrier block after reassembly - Prevents concurrent dictionary mutations from multiple BLE threads This is the same pattern as the String version (line 1128) which didn't crash. * Remove Localizable.xcstrings formatting noise The Localizable.xcstrings file had massive formatting-only changes (spacing: 'key' vs 'key :') that added 50K+ lines to the PR diff. This was just Xcode reformatting with no actual string changes. Reverted to main's version to keep PR focused on actual code changes. * Add macOS photo picker support - Added MacImagePickerView with NSOpenPanel for macOS - macOS shows photo.circle.fill icon (no camera hardware) - Opens native file picker for images (.png, .jpeg, .heic) - Images processed through ImageUtils with EXIF stripping - Simple sheet with Select/Cancel buttons Cross-platform photo sharing now works: - iOS: Tap for library, long-press for camera - macOS: Tap for file picker * Add Localizable strings for camera and voice features Xcode auto-generated localization strings for new UI elements: - Camera/photo picker labels - Voice recording UI strings - Media attachment descriptions These are legitimate new strings needed for the audio+image feature, not just formatting changes. --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: islam <2553451+qalandarov@users.noreply.github.com> |
||
|
|
56f1c37129 |
Regenerate info.plist by adding the missing keys (#576)
`xcodegen` probably uses alphabetical sorting so had to commit the info.plist to avoid discrepancies |
||
|
|
5fd9140ffa |
QR verification: live challenge/response over Noise; persistence, offline badges, and UX/perf polish (#510)
* 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> |
||
|
|
b09710a7aa |
Feature/location channels (#459)
* Require signed announces; add Ed25519 key/signature/timestamp TLVs and verify
- Protocol: AnnouncementPacket now requires ed25519PublicKey (0x03), announceSignature (0x04), and announceTimestamp (0x05). Encoder emits, decoder requires; unknown TLVs still tolerated.
- NoiseEncryptionService: add canonical announce sign/verify helpers using context 'bitchat-announce-v1'.
- BLEService: sign Announce, include TLVs; on receive verify (±5 min skew) and ignore unverified; store ed25519 key and isVerifiedNickname in PeerInfo.
- Preserve 8-byte on-wire IDs to keep BLE headers small; no per-message bloat.
* Fix Data.append usage for timestamp bytes in Packets and NoiseEncryptionService (use append(contentsOf:) on UnsafeRawBufferPointer)
* BLEService: fix non-optional announce fields and unwrap signature result; enforce required verification path
* Enforce verified-only public messages; append peerID suffix on nickname collisions in handleMessage
* Suffix duplicate nicknames with peerID prefix in snapshots and getPeerNicknames; ensures lists and messages disambiguate 'jack' vs 'jack'
* Include self nickname in collision detection: suffix remote 'jack' when it matches our nickname in lists and public chat
* UI labels: remove space before '#abcd' suffix in names (public chat, peer lists, snapshots)
* Style '#abcd' suffix light gray:
- Public chat: color suffix in sender via AttributedString segments
- People list: split name and color suffix segment; add helper splitNameSuffix()
* Debounce 'bitchatters nearby' notification: add 60s grace before reset when mesh goes empty; cancel reset when peers return
* Lighten '#abcd' suffix: use Color.secondary.opacity(0.6) in public chat sender and People list
* Toolbar peers indicator: use blue when Bluetooth peers present (was default text color)
* Toolbar peers indicator: use grey when zero peers (was red)
* Toolbar peers indicator: use system grey (Color.secondary) when zero peers, not green
* Fix crash: mutate peripherals dict on BLE queue (not main). Move scan restart to BLE queue as well.
* Reduce connect timeout churn: back off peripherals that time out (15s), increase timeout to 8s, skip non-connectable adverts, and demote timeout log to debug; clean backoff map periodically
* Mentions: support '@name#abcd' disambiguation; filter hashtag/URL styling inside mentions; deliver notifications only to the specified suffixed target when collisions exist
* Fix string interpolation in mention log (escape sequence)
* Mentions: parse '@name#abcd' in sender/receiver; render mention suffix grey (not orange/blue/underlined); ensure receiver notifications trigger for suffixed tokens
* Mentions: include own suffixed token 'name#<myIDprefix>' in valid tokens so '@name#abcd' to self is recognized and notified
* Public actions: show own system message by processing own public messages (remove early-return). Private /hug: add local system message for sender's chat.
* Grammar: change local '/hug' message to past tense ('you hugged/slapped'). Notifications: only fire 'bitchatters nearby' on rising-edge; remove 5-min re-fire and increase empty reset grace to 10m.
* Public /hug echo: add local system message so sender sees action immediately (no reliance on echo)
* Fix visibility: expose addPublicSystemMessage on ChatViewModel and use it from CommandProcessor
* Implement iOS Location Channels (geohash public chats)
- Domain: add ChannelID, GeohashChannel(Level), lightweight geohash encoder
- Identity: derive per-geohash Nostr keys (HMAC-SHA256 device seed)
- Nostr: kind 20000 + #g tag, nickname tag (n), filter helper
- iOS: LocationChannelManager (permissions, one-shot location), Info.plist string
- UI: toolbar # badge (#mesh or #<level>), sheet (irc style, full-row taps, settings link)
- VM: subscribe/send for active channel, clear timeline on switch, nickname cache
- Emotes: route public via Nostr/mesh without echo, local system confirmation, emojis restored
- Haptics: detect hugs/slaps for nickname#abcd and trigger on receiver
- Rendering: remove hashtag/mention formatting (plain monospaced)
Note: iOS-only; macOS unaffected.
* Lifecycle and persistence: resubscribe on foreground/relay connect, cap dedup set, persist mesh timeline.
- ChatViewModel: resubscribe geohash on app foreground and relay reconnect
- Add processed Nostr events cap (2k) with eviction
- Persist mesh public messages in meshTimeline; hydrate on switching to #mesh
- Local geochat messages use nostr: senderPeerID for classification
- Tests: fix JSON contains assertion for #g tag
* Fix Swift 6 concurrency warnings: remove closure-based NC observer, wrap relay reconnect resubscribe in Task @MainActor, resubscribe in appDidBecomeActive selector.
* Location Channels polish: live geohash refresh while sheet open; keep selection stable; toolbar shows #<geohash>; sheet labels show human level + #geohash.
* Add per-geohash in-memory timelines and cap private chats to 1337.
- ChatViewModel: persist geohash messages in geoTimelines[geohash] with cap; hydrate timeline on channel switch
- PrivateChatManager: trim per-peer chats to 1337 on send/receive
- Toolbar badge: prevent wrapping with lineLimit(1)/truncation
* Toolbar badge layout + brand color; Teleport custom geohash; Live refresh uses startUpdatingLocation with significant distance.
- Toolbar: right-justify geohash, head truncation, use brand green
- Sheet: add #custom geohash textfield + join; keep minimal IRClike style
- Manager: startUpdatingLocation()/stopUpdatingLocation() with distanceFilter=250 while sheet is open
* Location sheet live updates: reduce distanceFilter to 21m for more frequent geohash refreshes while open.
* Toolbar badge spacing/width; Sheet: rename to #geohash and button 'teleport'.
- Move # label closer to peer count and widen to avoid truncation
- Change custom field placeholder to '#geohash' and action button to 'teleport' with monospaced font
* Sheet polish: style 'teleport' button with subtle background, disable until valid; prefix '#' label and placeholder 'geohash'; center + style 'remove location permission' and hide separators for these rows. Toolbar: adjust spacing/width for # label.
* Sheet UX: restrict custom geohash input to valid base32 (lowercase, max 12), reduce spacing so placeholder sits closer to '#', add divider under country row, style 'remove permission' and hide row separators as before. Toolbar: minor spacing/width already adjusted.
* Sheet behavior: show channel list even without permission; add green 'get location and my geohash' button; ensure only one separator between country and teleport by removing manual Divider and showing default row separator; refine teleport input filtering and spacing.
* Channel activity nudges: notify after 9 minutes inactivity only in background; triple-tap clear also clears persistent timelines.
- ChatViewModel: track last activity per channel; send local notification when new activity resumes while app in background (with small cooldown)
- CommandProcessor: /clear clears current public channel persistence via viewModel helper
* Fix compile: add activeChannelDisplayName() and clearCurrentPublicTimeline() helpers in ChatViewModel.
* Fix concurrent dictionary access in BLEService.broadcastPacket: snapshot shared collections under collectionsQueue to avoid CocoaDictionary iterator crashes.
* People: channel-aware list and counts
- Sidebar: NETWORK → PEOPLE; removed PEOPLE subheader/icon
- Toolbar: blue #mesh badge; green #<geohash> badge; count color by channel
- Geohash participants: track per-geohash unique senders with 5m decay; publish list
- Update on geohash send/receive; 30s prune timer; channel switch hooks
No changes to mesh peer UX; mesh list retained as-is.
* BLE: snapshot collections for thread-safe access; stopServices uses snapshot; safe characteristic snapshot in broadcast path
LocationChannelsSheet: rename button label to 'remove location access'
* Channel sheet: show current peer counts
- Mesh row shows connected mesh peers count
- Geohash rows show 5m-active participant counts via ViewModel
- Live-updates while sheet is open
* Channel sheet: pluralize counts as 'person/people' in titles
* Geohash sampling: subscribe to all available channels while sheet open
- ViewModel: add multi-channel sampling subscriptions and per-geohash participant updates
- Sheet: start sampling on appear, sync on list changes, stop on disappear
* Channel sheet: render counts '(N person/people)' in smaller font next to label
* Channel sheet: use square brackets for counts and adjust parsing; fix mesh title to '#mesh'
* Geohash DMs: implement send/receive via NIP-17 with per-geohash identity
- NostrEmbeddedBitChat: add no-recipient encoder for geohash DMs
- NostrTransport: add sendPrivateMessageGeohash(using provided identity)
- ChatViewModel:
• startGeohashDM + mapping helpers
• subscribe to per-geohash gift wraps; store DMs in conversations keyed by 'nostr_<prefix>'
• route sendPrivateMessage() for 'nostr_' to Nostr geohash send; local echo and status
• map pubkeys from geohash public events for DM initiation
• resubscribe DM feed on reconnect and channel switch; unsubscribe on leave
- ContentView: long-press 'private message' starts geohash DM when sender is nostr
* Geohash DMs UX: tap participants to DM; support /msg nickname in geohash; DM notifications
- People (geohash) list: bold 'you', sort to top, tap to open DM
- ChatViewModel.getPeerIDForNickname resolves geohash names to nostr_ conv keys
- Geohash DM receive: send local notification when not viewing
* Geohash DMs polish: header title, star hidden, self-DM blocked, message icon, delivered/read ACKs
- Header shows '#<geohash>/@name#abcd' for geohash DMs; hide favorite star
- Geohash people row: add small message icon; prevent self tap
- Prevent sending geohash DM to self
- Send delivery/read ACKs on receive; handle delivered/read to update status
* Geohash DMs: hide encryption status icon in DM header
* BLE: fix data race in broadcast path
- Snapshot peripherals via Array(values) and filter outside sync
- Snapshot subscribedCentrals and centralToPeerID under collectionsQueue
- Mutate subscribedCentrals under collectionsQueue barriers in didSubscribe/unsubscribe
* LocationChannelsSheet: open fully by default (large detent only)
* BLE: remove unused centralMapSnapshot variable
* Geohash DMs: only notify on incoming PM when app is backgrounded; avoid foreground noise
* GeoDM: reliable delivered/read receipts, background-only notifications, and UI tweak
- Implement delivered + read receipts for geohash DMs; send READ on open\n- Handle relay OK acks for gift-wrap sends; resubscribe processes PM/DELIVERED/READ\n- Prevent mesh Noise handshakes for virtual geohash peers (nostr_*)\n- Notify GeoDMs only in background; suppress alerts for already-read msgs\n- Logging: promote key GeoDM receive logs; demote/remove verbose noise\n- UI: remove trailing envelope button from geohash People list
* Fix: remove duplicate variable declarations in AnnouncementPacket.decode()
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
|
||
|
|
845ffc601b |
Refactor/robustness (#446)
* Refactor BitChat for improved robustness and performance Major refactoring to simplify architecture and fix critical issues: Architecture Improvements: - Replace complex BluetoothMeshService with simplified SimplifiedBluetoothService - Consolidate message routing and peer management into unified services - Remove redundant caching layers and optimize performance Bug Fixes: - Fix critical BLE peer mapping corruption in mesh networks - Fix encrypted message routing failures in multi-peer scenarios - Fix app freezes and Main Thread Checker warnings - Fix BLE message delivery in dual-role connections - Fix favorite toggle UI not updating instantly - Fix Nostr offline messaging with 24-hour message filtering Features: - Add command processor for chat commands - Add autocomplete service for mentions and commands - Improve private chat management with dedicated service - Add unified peer service for consistent state management Performance: - Optimize BLE reconnection speed - Reduce excessive logging throughout codebase - Improve message deduplication efficiency - Optimize UI updates and state management * Improvements refactor robust (#441) * remove unused code * remove more * TLV for announcement * restore * restore * restore? * messages tlv too (#442) * Fix Nostr notification and read receipt issues, add TLV encoding, cleanup unused code ## Notification & Read Receipt Fixes - Fixed toolbar notification icon appearing incorrectly on app restart for already-read messages - Fixed read receipts being incorrectly deleted on startup when privateChats was empty - Fixed messages not being marked as read when opening chat for first time - Fixed senderPeerID not being updated during message consolidation - Added startup phase logic to block old messages (>30s) while allowing recent ones - Fixed unread status checking across all storage locations (ephemeral, stable Noise keys, temporary Nostr IDs) ## TLV Encoding Implementation - Implemented Type-Length-Value encoding for private message payloads - Added PrivateMessagePacket struct with TLV encode/decode methods - Enhanced message structure for better extensibility and robustness ## Code Cleanup - Removed unused PeerStateManager class and related dependencies - Removed dead protocol types (DeliveryAck, ProtocolAck/Nack, NoiseIdentityAnnouncement) - Cleaned up BitchatDelegate by removing unused methods - Removed excessive debug logging throughout ChatViewModel - Added test-only ProtocolNack helper for integration tests ## Technical Details - Messages stored under three ID types: ephemeral peer IDs, stable Noise key hexes, temporary Nostr IDs - Fixed cleanupOldReadReceipts() to skip when privateChats is empty or during startup - Updated message consolidation to properly update senderPeerID - Restored NIP-17 timestamp randomization (±15 minutes) for privacy --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> |
||
|
|
a92828471b | Fix App Store submission: remove invalid background-processing from UIBackgroundModes | ||
|
|
aa1ecf40fc |
Fix iOS background Bluetooth connectivity issues (#378)
- Implement Core Bluetooth state restoration with restoration identifiers - Add background task management to protect critical BLE operations - Fix aggressive battery optimization that killed background connectivity - Disable scan duty cycling in background (was causing 89-97% downtime) - Add missing didEnterBackground/willEnterForeground notifications - Fix advertising cutoff in low battery conditions (now only <10%) - Add background-processing entitlement to Info.plist - Optimize scan parameters for background vs foreground modes These changes address the issue where devices lose mesh connectivity when the app is backgrounded, ensuring continuous Bluetooth operation within iOS background execution limits. Co-authored-by: jack <jackjackbits@users.noreply.github.com> |
||
|
|
a97d5c2d5e |
Implement Nostr NIP-17 for offline messaging and performance optimizations (#358)
* Implement Nostr NIP-17 integration for offline mutual favorite messaging - Add Nostr relay connectivity and NIP-17 gift-wrapped private messages - Implement dual transport system: Bluetooth mesh + Nostr relays - Add favorites persistence with mutual detection and Nostr key exchange - Support offline messaging for mutual favorites via Nostr relays - Handle peer identity rotation with automatic favorite key updates - Fix UI to show all favorites (online and offline) in peer list - Add proper message routing based on peer availability - Update peer list icons: 📶 for mesh, 🌐 for Nostr, 🌙 for one-sided - Fix toolbar display for offline peers in private chat view - Add network entitlements for macOS and iOS - Implement automatic noise key updates when peers reconnect * Implement Nostr NIP-17 for private messaging between mutual favorites - Add support for NIP-17 gift-wrapped private messages with double encryption - Enable private messaging via Nostr when mutual favorites are offline - Fix peer reconnection issues: users now stay in private chat when peer reconnects - Fix read receipt delivery: send pending receipts when peer comes back online - Add message ID tracking through Nostr transport for proper delivery acknowledgments - Update peer noise key mapping when peers reconnect with different IDs - Check for Nostr messages when app becomes active - Implement 7-day message retrieval window for better reliability * Fix private message UI refresh and adjust PEOPLE header spacing - Fix UI not updating when receiving private messages on mesh - Add immediate batch processing for messages in active chat - Force UI update when viewing current chat peer - Ensure real-time message display without navigation - Reduce PEOPLE header spacing from 16 to 12 points for tighter UI * Fix build errors and unused value warnings in Nostr favorites integration * Implement read receipts via Nostr - Added sendReadReceipt method to MessageRouter to send receipts via mesh or Nostr - Added handleReadReceipt to process incoming read receipts from Nostr - Made ReadReceipt.readerID mutable to allow updates - Added missing notification names and error cases - Uncommented and enabled read receipt handling in ChatViewModel - Read receipts now work seamlessly via both mesh and Nostr transports * Fix ReadReceipt initialization - use correct constructor * Implement persistent message deduplication for Nostr - Added ProcessedMessagesService to track messages across app restarts - Store processed message IDs and last timestamp in UserDefaults - Skip already processed messages when receiving from Nostr - Adjust subscription filter to use smart timestamp (last processed or 24h) - Prevents duplicate messages when reconnecting to Nostr relays * Fix peer list UI not updating to Nostr mode on disconnect - Remove peer from peerNicknames when connection state changes to disconnected - Ensures UI properly reflects peer disconnection state - Peer list now correctly shows Nostr mode (🌐) when peer walks out of range * Update peer count to include Nostr peers and improve UI indicators - Peer count now shows total peers including those available via Nostr - Count appears purple when only Nostr peers are connected - Private message header shows purple globe icon for Nostr transport - Consistent visual language for Nostr connectivity across the app * Improve RSSI real-time updates and fix UI flashing - Reduce RSSI update timer from 10s to 5s and per-peripheral from 5s to 3s - Add RSSI change detection with 2 dBm threshold for responsive updates - Always update previous RSSI values to fix gradual change detection bug - Trigger RSSI read on peer authentication for immediate status - Fix UI flashing 'nobody around' by removing array clearing on updates - Add proper cleanup of RSSI tracking on disconnect and peer rotation * Fix favorite nickname updates and peer list filtering - Add updateNickname method to FavoritesPersistenceService to update nicknames while preserving favorite status - Update announce handler to check for existing favorites and update their nicknames - Remove dead BluetoothMeshService+PublicAPI.swift file - Move sendFavoriteNotification to main BluetoothMeshService - Fix peer list to only show connected peers and user's favorites (not peers who favorite the user) - Remove UI logic for showing peers who favorite us but we don't favorite back * Remove dead code and fix ghost connections Phase 1 - Remove abandoned peer ID rotation code: - Remove previousPeerID property and rotationGracePeriod constant - Remove grace period logic from isPeerIDOurs() - Remove previousPeerID handling from announce packets - Pass nil for previousPeerID in identity announcements Phase 2 - Fix ghost connections from relayed packets: - CRITICAL FIX: Only add peers to activePeers if they have a peripheral connection - Check for peripheral connection before marking peer as active - Prevents ghost connections when announce packets are relayed - Log warning when rejecting relayed announce without peripheral Phase 3 - Begin consolidating redundant peer tracking: - Create new PeerSession class to unify peer data in one place - Add helper methods for PeerSession management - Integrate PeerSession into announce packet handling - Update authentication state changes to use PeerSession - Update peripheral mapping and RSSI to sync with PeerSession - Update disconnect and leave handling to update PeerSession - Add consolidated getter methods for peer info This fixes the issue where peers appeared connected without actually having a Bluetooth connection, and begins the migration to a cleaner single-source-of-truth peer tracking system. * Fix multiple connect messages on peer restart - Move hasPeripheralConnection check outside sync block to fix scope issue - Add debug logging to track connect message conditions - Ensure connect messages only show on first connection or reconnection with peripheral * Optimize RSSI updates for better battery life - Add app state tracking to BluetoothMeshService - Only update RSSI when app is in foreground and peer list is visible - Add setPeerListVisible method to control RSSI updates - Remove individual periodic RSSI updates in favor of centralized timer - Update ContentView to notify mesh service of peer list visibility changes - Improve battery efficiency by avoiding unnecessary RSSI reads * Initialize peer list visibility state on view appear - Ensure RSSI timer state is properly initialized when view loads - Call setPeerListVisible with initial showSidebar value * Fix duplicate peers and multiple disconnect messages - Fixed duplicate peer entries when relay-connected by adding relay-connected peers to connectedNicknames set - Added deduplication logic for disconnect messages with 2-second window to prevent multiple disconnect notifications for same peer - Added cleanup for old disconnect notification tracking to prevent memory growth * Fix peer count indicator color logic - Show green for any mesh peer (direct Bluetooth or relay connected) - Show purple only for Nostr-only peers (no mesh connections) - Show red only when no peers are reachable at all - Fixed to use meshPeerCount instead of viewModel.isConnected which only checked direct connections * Fix relay connection issues and peripheral mapping cleanup - Fixed relay-connected peers being marked as directly connected when receiving identity announce - Added proper cleanup of temp peripheral mappings when discovering real peer ID - Fixed disconnect notification deduplication cleanup - Improved debug logging to show actual connection state (direct/relay/nostr/offline) - Added debug logging for relay connection detection - Fixed compiler warning about unused variable * Fix Unknown peer disconnect notifications and disable faulty relay detection - Add check to prevent disconnect notifications for Unknown peers that never announced - Disable relay connection detection until proper relay tracking is implemented - In a 2-peer network, peers should never show as relay-connected * Fix RSSI updates and peer visibility after reconnection - Add updatePeers() call in didUpdatePeerList to refresh RSSI values in UI - Track version hello times to better detect direct connections - Allow peers to be marked active if recent version hello received - Fix thread safety for version hello tracking - Clean up old version hello times to prevent memory leaks * Remove RSSI tracking completely and replace with radio icon for mesh connections * Fix build errors after RSSI removal - Add missing peripheralID declaration in didDiscover delegate method - Remove obsolete setPeerListVisible calls from ContentView * Center private message header elements using ZStack layout - Replace HStack with ZStack for perfect centering - Globe/nick/lock cluster now always centered regardless of button sizes - Back and favorite buttons positioned in overlay HStack * Fix private chat view showing Unknown when peer reconnects with new ID - Update FavoritesPersistenceService to notify with both old and new keys - Handle peer ID changes in ChatViewModel to migrate private chat data - Update selectedPrivateChatPeer when favorite's noise key changes - Maintain chat history and unread status across peer ID changes * Fix read receipts after peer reconnection and replace nos.lol relay - Updated sendReadReceipt to resolve current peer ID when peers reconnect with new IDs - Enhanced MessageRouter to check favorites for current noise keys - Replaced nos.lol relay with relay.snort.social to avoid PoW requirements * Fix message routing to use Nostr when peers are disconnected Changed message routing logic to check actual peer connection status using isPeerConnected() instead of just checking if peer exists in nickname list. This ensures that offline mutual favorites correctly route messages through Nostr instead of attempting Bluetooth handshakes. Also added safety check to prevent starting private chat with ourselves. * Add debug logging for Nostr timestamp randomization Added logging to track the random offset being applied to Nostr event timestamps to debug why messages appear 8-9 minutes in the future. * Fix Nostr timestamp issue by reducing randomization range Temporarily reduced the timestamp randomization from +/-15 minutes to +/-1 minute to address messages appearing 8-9 minutes in the future. Added detailed UTC/local time logging to help debug the issue. The random offset should have been evenly distributed but was consistently showing positive offsets. This change mitigates the issue while we investigate the root cause. * Fix message routing for offline favorites and reduce Nostr timestamp randomization - Fix transport selection to properly detect disconnected peers using isPeerConnected() - Change from checking peer nicknames to checking actual connection status - Reduce Nostr timestamp randomization from ±15 minutes to ±1 minute - Add detailed timestamp logging for debugging * Improve PM header UI and encryption status display - Show transport icons (radio/link/globe) in PM header matching peer list - Always show lock icon if noise session ever established (no handshake icon) - Change verified icon from shield to checkmark seal - Use consistent green color (textColor) for PM header and encryption icons * Update AI_CONTEXT.md with comprehensive Nostr implementation details - Add Nostr and MessageRouter to architecture diagram - Document NIP-17 gift wrap implementation - Explain favorites integration and mutual requirement - Detail message routing logic and transport selection - Add security considerations and debugging tips - Update common tasks with Nostr-specific guidance * Fix data consistency issues in favorites, chat migration, and bloom filter - Fix favorites deduplication to use public key instead of nickname Prevents losing favorites when multiple peers use same nickname - Fix private chat migration to use fingerprints instead of nicknames Prevents merging unrelated conversations that share nicknames Fallback to nickname matching only for legacy data without fingerprints - Fix bloom filter reset to preserve messages from last 10 minutes Prevents duplicate message processing after bloom filter resets Keeps processedMessages for 10 minutes while bloom filter resets every 5 * Add mutual favorites internet messaging to app info * Remove excessive debug/info logging for production readiness - Removed ~140 debug/info level logs across core services - Preserved critical logs: errors, warnings, security events, state changes - Kept logs for: peer join/leave, favorite status, mutual relationships - Cleaned up verbose logging in: Bluetooth mesh, Nostr, message routing - Improved performance by reducing log I/O overhead 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Implement performance optimizations and fix build warnings - Add UI update debouncing (50ms) to prevent excessive SwiftUI refreshes - Implement memory bounds for processedMessages with LRU eviction - Add encryption queue cleanup for disconnected peers - Optimize peer lookups from O(n) to O(1) with indexed dictionary - Fix multiple compiler warnings (unused variables, missing break statements) - Optimize peer counting with single-pass reduce operation - Fix ViewBuilder control flow issue in ContentView - Fix Dictionary initialization type mismatches with Array wrapper * Add TTL-based cleanup for Noise handshake sessions - Add session TTL (5 minutes) and max session limit (50) to NoiseHandshakeCoordinator - Clean up old established sessions to prevent unbounded memory growth - Move handshake cleanup timer out of DEBUG conditional for production use - Run cleanup every 60 seconds in production (vs 30s in debug) - Clean up crypto state immediately on peer disconnect - Prevents memory leaks from accumulating Noise sessions * Pre-compute and store fingerprints in PeerSession for O(1) lookups - Store fingerprint in PeerSession when peer authenticates - Update getPeerFingerprint() and getFingerprint() to check PeerSession first - Replace all noiseService.getPeerFingerprint() calls with optimized version - Eliminates repeated SHA256 calculations during message processing - Improves performance for favorite checks and encryption status updates * Implement exponential backoff for Nostr relay connections - Add reconnection tracking fields to Relay struct (attempts, timing) - Replace fixed 5-second delay with exponential backoff (1s → 2s → 4s... max 5min) - Stop reconnection attempts after 10 failures to prevent infinite retries - Reset attempt counter on successful connection - Add utility methods: retryConnection(), getRelayStatuses(), resetAllConnections() - DNS failures still bypass retry logic as before - Improves battery life and reduces server load from constant reconnection attempts --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
79d9f8ee88 |
Add network availability notifications when bitchatters are nearby
- Show notification when network transitions from empty to having peers - Single notification per session, resets when network becomes empty - Background Bluetooth modes enabled for iOS - Generic message: 'bitchatters nearby\! 1 person around' or 'X people around' |
||
|
|
022050193f |
Fix macOS Bluetooth entitlements and remove debug logging
- Created separate macOS entitlements file with required Bluetooth permission - Fixed "Bluetooth unsupported" issue on Mac by adding com.apple.security.device.bluetooth entitlement - Removed all debug logging from BluetoothMeshService - Re-enabled scan duty cycling - Reverted RSSI threshold back to -90 dBm from temporary -100 dBm debug value |
||
|
|
c6d74b7574 |
Fix macOS Bluetooth permissions by adding proper entitlements
- Create separate bitchat-macOS.entitlements file with com.apple.security.device.bluetooth - Update project.yml to use the macOS-specific entitlements for the macOS target - Regenerate Xcode project with proper entitlements configuration This fixes the 'Bluetooth unsupported' issue on macOS which was caused by missing device.bluetooth entitlement required for sandboxed apps |
||
|
|
cb2a1801cd |
Update project configuration with code signing and launch settings
- Add development team L3N5LHJD5Y to all targets in project.yml - Add automatic code signing settings to test targets - Fix UIRequiresFullScreen setting to false for launch storyboard compatibility - Update Info.plist with proper launch configuration - Ensure all targets have consistent code signing configuration |
||
|
|
fc5e83612a |
Fix iPhone 16 screen display issue with proper launch screen
- Add LaunchScreen.storyboard to properly support all iPhone models - Configure UILaunchStoryboardName in Info.plist for full screen display - Add UIRequiresFullScreen to prevent black bars on newer devices - Update project.yml to include launch screen in iOS target resources - Add proper interface orientation support for iPhone and iPad |
||
|
|
c352542331 |
Fix macOS build error and iPhone 16 display issues
- Split multi-platform target into separate iOS and macOS targets to prevent iOS share extension from being embedded in macOS build - Add launch screen configuration and full screen support for proper iPhone 16 display - Configure iOS-specific Info.plist entries for background modes and interface orientations |
||
|
|
d5ccf6bc0b |
Add iOS share extension with rich link previews
- Implement share extension to receive URLs from other apps - Display shared links with emoji indicator and rich preview cards - Add custom compact link preview with image, title, and domain - Configure app groups for data sharing between extension and main app - Handle URL detection and parsing in share extension - Update message formatting to show only emoji for shared links - Add proper entitlements and activation rules for share extension |
||
|
|
244af2197c |
Fix share extension functionality
- Add debugging logs to help diagnose sharing issues - Improve completion handling in share extension - Check for shared content when app becomes active - Fix async handling of shared content processing |
||
|
|
7f6a32e350 |
Add iOS Share Extension support
- Create share extension to handle shared content from other apps - Support sharing text, URLs, and prepare for future image support - Use app groups for data sharing between extension and main app - Add URL scheme handling for app communication - Add entitlements for app groups - Display system message when content is shared - Update project configuration to include share extension |
||
|
|
2e56245a7e |
Fix deadlock in DeliveryTracker causing macOS app freeze
- Fixed nested lock acquisition in trackMessage/scheduleTimeout - Properly handle lock release before calling methods that need locks - Ensure retryDelivery and handleTimeout don't cause deadlocks - Release locks before calling external methods |
||
|
|
78cb8b1039 |
Fix delivery confirmation for private messages
- Pass message ID from ChatViewModel to BluetoothMeshService - Preserve original message ID when creating ACK messages - Move delivery tracking to ChatViewModel for consistent IDs - Update project.yml to match current project structure |
||
|
|
cbcfaed7a2 |
Fix compilation errors and prepare for App Store submission
- Fix NotificationService warnings by replacing unused error parameters with _ - Add public domain header to NotificationService.swift - Fix BluetoothMeshService compilation errors: - Replace removeAll with filter for processedKeyExchanges cleanup - Remove duplicate cleanupStalePeers function declaration - Remove duplicate peerLastSeenTimestamps property declaration - All code now compiles cleanly for both iOS and macOS targets |
||
|
|
00e75fff72 |
Fix connect/disconnect/connect pattern on initial connection
- Added duplicate connection detection in key exchange handler - When same peer connects through multiple peripherals, keep only one - Track intentional disconnects to suppress disconnect messages - Don't show disconnect message when dropping duplicate connections - This prevents the confusing connect/disconnect/connect pattern The issue was that both devices try to connect to each other simultaneously, creating duplicate connections. One gets dropped, but now it's handled gracefully. |
||
|
|
f2031f3973 |
Update project configuration and generate Xcode project
- Removed test targets from project.yml (causing dependency issues) - Generated fresh Xcode project with xcodegen - Project now includes proper Assets.xcassets configuration - Ready for App Store build and submission |
||
|
|
4d61cec032 |
Prepare for App Store submission
- Added public domain headers to all test files - Updated Info.plist with required App Store keys: - ITSAppUsesNonExemptEncryption = NO - LSApplicationCategoryType = Social Networking - UIRequiresFullScreen = YES - Created proper Assets.xcassets structure - Configured AppIcon.appiconset with all icon references - Removed last TODO comment - Created comprehensive App Store submission checklist - Updated project.yml to include Assets.xcassets The app is now ready for App Store submission. All debug code has been removed, icons are configured, and privacy/security compliance is documented. |
||
|
|
e3cc469bf8 |
Remove voice memo references and improve duplicate message prevention
- Remove NSMicrophoneUsageDescription from Info.plist and project.yml - Add millisecond timestamps to prevent same-second message collisions - Include payload hash in message ID for absolute uniqueness - Add recentlySentMessages tracking to prevent any duplicate sends - Reduce retries from 2 to 1 for broadcast messages - Clean up sent message tracking after 10 seconds |
||
|
|
7b3cfb6227 |
Fix Bluetooth errors and improve store-and-forward
- Add peripheral state checks before all write operations - Fix 'can only accept commands while connected' errors - Check characteristic write properties to avoid ATT errors - Preserve original timestamps in store-and-forward messages - Only log crypto errors once per peer to reduce noise - Store-and-forward now correctly maintains message ordering The timestamp preservation ensures messages appear in the correct chronological order even when delivered later via store-and-forward. |
||
|
|
fe986ed397 |
Fix encryption key exchange and add persistent identity for favorites
- Implement three-tier key system: ephemeral encryption, ephemeral signing, persistent identity - Fix signature verification by properly separating KeyAgreement and Signing keys - Add persistent identity key for favorites that survives app restarts - Fix Data subscript crashes by converting to byte arrays - Add proper error handling for key exchange - Private messages remain fully encrypted with ephemeral keys |
||
|
|
6652d1f429 |
Fix voice recording and notification issues
- Fix mic button gesture handling by removing Button wrapper - Use direct gesture on ZStack for more reliable touch detection - Add debug logging for recording start/stop - Fix notification delivery on iOS - Change from checking .background to checking != .active - Notifications now work when app is inactive or background - Add NSUserNotificationsUsageDescription to Info.plist - Improve voice note fragment transmission - Reduce fragment size from 400 to 200 bytes for better reliability - Simplify fragment timing from batch-based to linear 100ms delays - Lower packet size threshold from 512 to 400 bytes for fragmentation - Add peripheral connection state checking before writes - Better error logging throughout transmission pipeline - Add comprehensive debug logging for troubleshooting - Log audio file size and duration - Log peripheral connection states during broadcast - Log fragment send progress with timing info |
||
|
|
2993fc3e06 |
Implement favorites, notifications, and improve fragment handling
- Add favorites functionality for peers with persistent storage - Star icon to toggle favorites in sidebar - Favorites appear at top of peer list - Storage persists across app launches using peer ID - Add local notifications for mentions and private messages - Notifications appear when app is in background - Separate notification types for mentions vs private messages - Request notification permissions on app launch - Fix sidebar header alignment to match main toolbar (44pt) - Add background color to sidebar header for visual consistency - Improve voice note fragment transmission - Send fragments in batches of 5 with delays to prevent congestion - Better logging to debug fragment transmission issues - Reduce delay between fragments from 50ms to batch-based timing - Fix other UI issues - Ensure mic recording ripples originate from mic button - Update sidebar to swipe from right edge smoothly |
||
|
|
94a9888ef5 |
Add push-to-talk voice notes functionality
- Added voice note support to BitchatMessage with audio data and duration
- Updated binary protocol to encode/decode voice notes (flag 0x40)
- Created AudioRecordingService for recording up to 10s voice clips
- Created AudioPlaybackService for playing voice notes
- Added microphone permission to Info.plist and project.yml
- Implemented push-to-talk UI with mic button in ContentView
- Voice notes use AAC compression at 16kHz/32kbps for small file sizes
- Added play/pause buttons for voice notes in message list
- Voice notes display as '🎤 Voice note (X.Xs)' in chat
- Platform-specific audio session handling for iOS/macOS
|
||
|
|
4b98aa7918 |
Fix iOS background BLE, RSSI tracking, and peer nickname display
- Add UIBackgroundModes for bluetooth-central/peripheral to restore background messaging - Implement RSSI tracking with proper peer ID mapping and UI updates - Fix announce packet delivery for immediate nickname display - Convert to binary protocol for 62-69% size reduction - Fix peer count to exclude self from display - Add platform-specific UI improvements (font sizes, dropdown styling) |
||
|
|
7e90bf6369 | Initial commit: Bluetooth mesh chat app with end-to-end encryption |