When a user visits their own profile and has no profile picture set,
show a semi-transparent upload button overlay directly on the profile
picture area. Tapping it opens the gallery picker, uploads the image
to the configured server (NIP-96 or Blossom), and immediately saves
the metadata — without requiring the user to navigate to the edit screen.
- Add uploadPictureAndSave() to NewUserMetadataViewModel: loads current
metadata, uploads the image, then saves all metadata with the new picture
- Add ProfilePictureWithUploadOverlay composable that wraps ZoomableUserPicture
and conditionally shows the upload overlay when isMe && no picture
- Add ProfilePictureUploadButton composable for the overlay UI with
loading state support
- Use ProfilePictureWithUploadOverlay in ProfileHeader instead of
ZoomableUserPicture directly
https://claude.ai/code/session_01XemJ8Hx9q4mMd1StZNY9CE
Audio URLs with `audio/*` MIME types in NIP-92 imeta tags were silently
dropped (createMediaContent returned null) because only `image/` and
`video/` prefixes were checked. They now map to MediaUrlVideo, which
Media3/ExoPlayer already handles correctly for audio playback.
Also adds common audio extensions (ogg, wav, flac, aac, opus, m4a) to
the extension-based fallback so audio files without imeta tags are also
detected.
Fixes https://github.com/vitorpamplona/amethyst/issues/1701https://claude.ai/code/session_01YSi64eXRokSy2GzYHoNFES
Covers the full expect/actual contract across all platforms (Android,
JVM, iOS):
- round-trip for empty, single-char, simple, unicode, and JSON strings
- repetitive input compresses to a smaller size
- gzip magic number (0x1F 0x8B) present in compressed output
- compressed bytes differ from raw input bytes
- decompress of invalid data throws an exception
- special/control characters survive a round-trip
https://claude.ai/code/session_0125CGfu6aMAnSv6ZzAxFHvV
Uses platform.zlib (built-in on all Apple targets) via Kotlin/Native
cinterop to provide the actual GZip implementation:
- compress: deflateInit2 with windowBits=31 (MAX_WBITS+16) for gzip
format; deflateBound gives a tight upper-bound so a single Z_FINISH
call is always enough – no output loop required.
- decompress: inflateInit2 with windowBits=47 (MAX_WBITS+32) for
automatic gzip/zlib format detection; output is collected in
fixed-size chunks to handle arbitrary decompressed sizes.
https://claude.ai/code/session_0125CGfu6aMAnSv6ZzAxFHvV
* 'main' of https://github.com/vitorpamplona/amethyst:
feat: consolidate drawer settings into a single Settings hub screen
New Crowdin translations by GitHub Action
Replace six individual drawer items (Relays, Media Servers, Security
Filters, Privacy Options, App Preferences, User Preferences) with a
single "Settings" entry that navigates to a new AllSettingsScreen hub.
The hub lists all six options as clickable rows, each navigating to
their existing screens unchanged.
https://claude.ai/code/session_017Z9x4PNJuMtMQgfYSxTVSU
Adds a comprehensive Claude skill covering Gradle setup, key management,
event creation/signing, relay client, subscriptions, NIP builders, and
platform-specific notes. Also updates the legacy quartz-kmp.md to redirect
to the new skill.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Uses new Media3 content view frames
- Redesigns video playback interface to remove unused buttons and modernize it.
- Adds our own buttons and indicators for the video playback
- Checks if PiP is supported and active before showing the button.
- Improves click interactions with the image dialog
- Fixes Surface release bugs
- Creates new interface for the Picture in Picture view
- Fixes muting and play buttons on the Picture in Picture
- Fixes incorrect aspect ratios of the AutoNonLazyGrid when multiple images exist for a single entry
- Adds Play buttons when the image fails to load so that people click and the post appears.
- Fix ListChangeFeedViewModel stuck on Loading for empty chatrooms by
adding invalidateData() call in init block
- Add DmBroadcastStatus sealed class and DmBroadcastBanner composable
in commons for relay send progress display
- Add DmSendTracker using sendAndWaitForResponse for confirmed delivery
- Wire send tracking through DesktopIAccount into ChatPane banner
- Fix audit risks: unsubscribe DMs on account change, wait for relay
connect before subscribing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sendWrappedReaction function was creating NIP-17 gift wraps via
NIP17Factory but never broadcasting them. Added sendGiftWraps() to
IAccount interface with implementations in both Desktop and Android.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace TODO stub with sendWrappedReaction using NIP17Factory.
createReactionWithinGroup creates gift-wrapped reactions for group privacy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- DesktopIAccount: sign + broadcast NIP-04/NIP-17 messages via relay layer
- Main.kt: activate DM subscriptions on login, consume events into cache
- NewDmDialog: user search dialog with SearchBarState + UserSearchCard
- DesktopMessagesScreen: wire Cmd+Shift+N and "+" button to NewDmDialog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>