- Remove maxLines=10 on post text so content is never truncated
- Profile header/card/tabs now scroll with content instead of staying
sticky — scrolls away naturally as you browse posts
- Floating compact header (back + avatar + name) slides in when
scrolling up and the full header is out of view
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded 400.dp max with window-relative height so media
(images and videos) never overflow the visible area and controls
are always accessible without scrolling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace WindowPlacement.Fullscreen (macOS maximize-only) with
GraphicsDevice.setFullScreenWindow() for true exclusive fullscreen that
hides menu bar and dock. Split single cycling view mode button into two
distinct toggles (theater + fullscreen). Hide all navigation chrome
(sidebar, nav rail, dividers, arrows, overlay menus) during fullscreen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bundle VLC via ir.mahozad.vlc-setup plugin (all plugins for network playback)
- BundledVlcDiscoverer (Win/Linux) and MacOsVlcDiscoverer for bundled VLC discovery
- Lazy player activation — no VLC calls during composition, only on play click
- Pre-init VLC on background thread at startup
- Video controls: seek slider, volume, mute, fullscreen (two-row layout, no clipping)
- Buffering indicator (CircularProgressIndicator) while loading
- ActiveMediaManager enforces single-player — pauses others when new video plays
- Fullscreen passes seek position so lightbox resumes from current playback point
- LightboxOverlay renders videos (DesktopVideoPlayer) or images (ZoomableImage)
- Gitignore downloaded VLC binaries (appResources/{linux,macos,windows}/)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Build IMetaTag (NIP-92) from upload metadata (mime, sha256, dim, blurhash, size)
- Use TextNoteEvent.build directly with tag initializer for imeta injection
- Add drag-and-drop file support via Compose DragAndDropTarget
- Filter dropped files by media extension whitelist
- Visual border highlight on drag-over state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Notes/Gallery PrimaryTabRow to UserProfileScreen
- Subscribe to PictureEvent (kind 20) for gallery grid
- Wire GalleryTab composable with image click callbacks
- Wire LightboxOverlay for full-screen image viewing
- Pass onImageClick to FeedNoteCard in notes tab
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ChatPane: display ChatFileAttachment for encrypted file header events
- DesktopPreferences: add blossom server list persistence
- Settings: add MediaServerSettings section above relay settings
- ComposeNoteDialog: use preferred blossom server from preferences
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused: MediaAspectRatioCache, VideoPlayerState, resetZoom,
onDoubleClick, delete/headUpload/createDeleteAuth, encryptAndUpload,
EncryptedUploadResult, unused options params, formatAudioTime dupe
- Fix VlcjPlayerPool.release() accumulating stale event listeners
- Fix SaveMediaAction FileDialog running on IO instead of EDT
- Pre-allocate video frame ByteArray to avoid ~240MB/s GC pressure
- Pool audio players in VlcjPlayerPool instead of factory-per-instance
- Remove listener in onDispose before returning player to pool
- Fix acquire() race condition by moving poll inside synchronized
- Reduce memory cache to 15%/256MB with weak references
- Parallelize server health checks
- Remove redundant Content-Type/Content-Length headers
- Deduplicate BlurHashFetcher bitmap conversion via bufferedImageToSkiaBitmap
- Hoist audioExtensions to top-level constant, rename allMediaUrls
- Remove nonfunctional Save button and dead decryptedBytes state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 9: AudioPlayer composable using VLCJ --no-video factory,
play/pause/seek controls, NoteCard splits audio from video URLs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 8: MediaServerSettings UI for add/remove/reorder Blossom servers,
ServerHealthCheck with 5s timeout HEAD requests, status indicators.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 7: PictureDisplay composable for kind 20 events with image-first
layout, GalleryTab with adaptive grid of thumbnails, lightbox support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 6: AESGCM encrypt/decrypt for DM file attachments, Blossom
upload of encrypted files, ChatFileAttachment composable with
auto-decrypt for images and file type display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 5: Full-screen lightbox overlay with mouse wheel zoom + pan,
left/right gallery carousel, keyboard shortcuts (Esc/arrows/Ctrl+S),
save to disk via FileDialog. Images in NoteCard are clickable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 4: VLCJ player pool (max 3 instances), DirectRendering via
CallbackVideoSurface → Skia Bitmap → Compose Image. Video controls
with auto-hide, seek, play/pause. Graceful fallback when VLC missing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 3: Native file dialog, AWT clipboard paste handler, media
attachment UI with thumbnails, and ComposeNoteDialog media integration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
RootContent now stays composed when overlays are shown, preventing
search results and other state from being destroyed on navigation.
Overlay wrapped in opaque Surface to cover root content visually.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Overlay screens (UserProfileScreen, ThreadScreen) already render their
own back+title header. Remove the redundant SinglePaneHeader bar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace raw MutableSet with synchronized EventDeduplicator class.
Remove dual dedup in addNoteResults — trackRelayEvent now gates all
event processing. SearchScreen callbacks skip dupes early via return
value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove feedSub/contactList debug prints from FeedScreen, suppress
GiftWrapEvent decryption failure log (expected for others' wraps),
and add slf4j-nop to silence "No SLF4J providers" console warnings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pulsating green heart icon shows NIP-46 signer connection status in both
DeckSidebar and SinglePaneLayout NavigationRail. Tooltip displays last
ping time. SignerConnectionState moved to commons for KMP sharing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The nostrconnect flow was trusting params[0] from the signer's connect
message as the user's pubkey. Some signers (e.g. nsec.app) don't put
the actual user pubkey there, causing all relay subscriptions to query
the wrong identity — contact lists, profiles, and DMs all returned empty.
Now calls remoteSigner.getPublicKey() after the handshake to get the
verified pubkey from the signer. Also stabilizes FeedScreen relay
subscriptions with distinctUntilChanged() and adds relay.primal.net
to defaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds client-initiated NIP-46 (nostrconnect://) flow so users can pair
with a remote signer (e.g. Amber) by scanning a QR code instead of
manually copying a bunker:// URI.
Changes:
- Fix RemoteSignerManager to decrypt NIP-44 content before parsing
- Add CoroutineScope to NostrSignerRemote for async event callbacks
- Add loginWithNostrConnect() to AccountManager with 120s timeout
- Add QrCodeCanvas composable using ZXing for QR generation
- Add "Connect" tab to LoginCard showing QR + copyable URI + waiting state
- Wire nostrconnect flow through LoginScreen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces webcam-capture (broken on Apple Silicon) with ffmpeg
avfoundation capture. Opens a live preview dialog that scans
for QR codes from the FaceTime camera. Works natively on arm64.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses webcam-capture + ZXing to scan QR codes from the camera.
Click the QR icon on the login screen to open a webcam scanner
dialog that auto-detects bunker:// URIs from Amber's QR display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a QR scan button to the login card that decodes QR codes from
clipboard images or image files using ZXing. Useful for scanning
bunker:// URIs from Amber's QR display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All user-initiated logouts now pass deleteKey=true to remove
nsec from secure storage, clear last_npub, and delete bunker state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace boolean isSearching with counter-based activeSubscriptionCount
so loading state stays true until both subs (people + notes) complete
- Add indeterminate LinearProgressIndicator overlaid on search bar bottom
border with matching 12dp rounding, replacing "Searching relays..." text
- Send search REQs to all configured relays (relayStatuses) instead of
only connected ones — fixes NIP-50 relays never receiving search queries
- Move clearResults/startSearching out of remember() into LaunchedEffect
to avoid side effects during composition
- Fix history saving partial queries by replacing LaunchedEffect with
snapshotFlow to properly observe isSearching transitions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract DateUtils (isLeapYear, dateToUnix, timestampToDate) to deduplicate
identical implementations in QueryParser and QuerySerializer
- Move SavedSearch data class from desktopApp to commons/search
- Replace local formatTimestamp with existing toTimeAgo from commons/util
- Remove dead code: resolveAuthorName, _authorSuggestions (never called)
- Remove dead code: createOrFilters (never wired into SearchScreen)
- Remove unused ICacheProvider dependency from AdvancedSearchBarState
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 6: Integration and polish.
- Escape key closes advanced panel or clears search
- Search history shown in empty state (recent + saved searches)
- Auto-save to history when search completes
- Updated empty state with operator hint examples
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 5: Persistent search history using Java Preferences API.
- Last 20 queries stored, deduped by serialized text
- Saved searches with labels and timestamps
- Uses QuerySerializer/QueryParser for round-trip serialization (no new deps)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 4: Desktop UI composables for advanced search.
- Rewrite SearchScreen.kt to use AdvancedSearchBarState with TextFieldValue
- Add AdvancedSearchPanel with kind presets, author chips, date range, hashtags, language
- Add SearchResultsList with sticky headers for People/Notes/Articles/Other sections
- Make QueryParser.parseDateToTimestamp and QuerySerializer.timestampToDate public
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>