- Single hover zone on entire video — no more flickering from competing
zones. Play button always visible when paused, bottom controls appear
on hover (works in fullscreen too)
- Media height capped to 50% of window (min 200dp) so post text is
never pushed off-screen by large media
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Center play button always visible when paused
- Pause button appears on center hover when playing
- Bottom controls bar only appears when hovering the bottom area
- Controls also show when paused for discoverability
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Controls (play button, seek bar, volume) are hidden by default and
appear when the mouse enters the video area. They auto-hide 2s after
the mouse leaves.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add VideoThumbnailCache that grabs the first rendered frame from VLC
and caches it in memory. Videos in the feed now show a thumbnail
preview instead of a blank background before the user clicks play.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace plain-text NotePreviewCard with full NoteCard in search results
so images, videos, and author avatars are visible inline without having
to open the note.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove maxLines/TextOverflow from RichTextContent so post text is
never truncated
- Media height = window height minus 200dp chrome, so each image/video
fits in the visible area without scrolling
- Use ContentScale.Fit for images to scale down while keeping aspect
ratio instead of filling width and overflowing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
- Upload APK as a GitHub prerelease asset for direct .apk download
(no zip wrapping like artifacts)
- Remove commit comment, only comment on open PRs
- Clean up existing release with same tag before creating
https://claude.ai/code/session_0138kUcZaPQoQcAc7nA1KDbf
Use the artifact-id output from upload-artifact to construct a direct
GitHub artifact download URL. No third-party service needed — the URL
points to the artifact on GitHub which triggers a download when clicked.
https://claude.ai/code/session_0138kUcZaPQoQcAc7nA1KDbf
GitHub artifact URLs require authentication and don't provide direct
file downloads. nightly.link proxies artifact downloads, giving a
direct download link that works for anyone without GitHub login.
https://claude.ai/code/session_0138kUcZaPQoQcAc7nA1KDbf
- 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>
The Claude Code web egress proxy does not include dl.google.com in its
allowlist, causing the session-start hook to abort entirely (due to
set -euo pipefail) when Android SDK downloads fail. This cascading
failure also prevented local.properties creation and ANDROID_HOME export.
Additionally, JAVA_TOOL_OPTIONS contains nonProxyHosts entries for
*.google.com and *.googleapis.com, which causes the JVM to bypass the
proxy for Google Maven, resulting in connection failures.
Changes:
- Remove set -euo pipefail; use per-section error handling instead
- Fix JAVA_TOOL_OPTIONS: strip *.google.com from nonProxyHosts
- Fix no_proxy: remove *.google.com and *.googleapis.com entries
- Move local.properties and env exports before SDK download section
- Make SDK downloads non-fatal with clear warning messages
- Install standalone ktlint as fallback for spotlessApply
- Create spotless-apply wrapper script for proxy-blocked environments
- Update Stop hook to fall back to spotless-apply when Gradle fails
https://claude.ai/code/session_01HeWiRdKDTnMGfEBUegk3d1
Add PR commenting to the build-benchmark-apk workflow. When a build
completes, it now finds any open PR for the branch and posts a comment
with a direct download link to the benchmark APK artifact.
https://claude.ai/code/session_0138kUcZaPQoQcAc7nA1KDbf
- Use MessagingStyle for DM notifications with sender avatars and
conversation formatting (integrates with Android Bubbles/conversation space)
- Add Direct Reply action so users can respond to DMs from the
notification shade without opening the app
- Add Mark as Read action with SEMANTIC_ACTION_MARK_AS_READ for
Android Auto/Wear OS integration
- Apply notification grouping with InboxStyle summary notifications
for both DMs and Zaps (group keys were defined but never used)
- Use BigTextStyle for zap notifications so long messages expand
- Set proper notification categories (CATEGORY_MESSAGE for DMs,
CATEGORY_SOCIAL for zaps) for OS-level prioritization and DND bypass
- Fix PendingIntent flag from FLAG_MUTABLE to FLAG_IMMUTABLE where
mutability is not needed (security improvement)
- Replace blocking image load (executeBlocking) with suspend-friendly
Coil execute() on IO dispatcher
- Upgrade DM channel importance to IMPORTANCE_HIGH for heads-up display
https://claude.ai/code/session_012w6K8H4nvZYxeRryW2USAp
Adds filter chips (All / Zaps / Non-Zaps) to the transactions list.
Zap transactions are identified by having nostr metadata. The filter
is applied client-side via a combined Flow in WalletViewModel.
https://claude.ai/code/session_01CdNY7qYDRHJr1jhAFvVgzj
Replace the ElevatedButton in a sticky header with a delete icon
(Icons.Default.Delete) in the top bar actions area. The confirmation
dialog is preserved and now lives at the screen level, reading the
current feed state directly when confirmed.
https://claude.ai/code/session_01AbiBeDnT4KPKD16sKKaLD8
Add infinite scroll pagination to the wallet transactions screen.
When the user scrolls within 5 items of the bottom, the next page of
transactions is automatically fetched and appended. Uses the existing
NWC list_transactions limit/offset support and total_count to know
when all transactions have been loaded.
https://claude.ai/code/session_01CdNY7qYDRHJr1jhAFvVgzj