Replace content.split('\n') and paragraph.split(' ') with index-based
scanning so no intermediate List<String> or line-substring allocations
are created during paragraph/word tokenization.
Key changes to findTextSegments:
- Scan for '\n' via indexOf to determine line boundaries without
allocating a List<String> or any line substrings.
- Compute trimEnd boundary in-place (no trimEnd() String copy).
- For each line, do a first pass with isRegularByIndex() that checks
every word using character-level inspection without creating substrings.
If all words are plain text the entire paragraph is represented as a
single RegularTextSegment(content.substring(lineStart, actualEnd)),
avoiding M per-word String allocations and the later joinToString.
- Only when a paragraph contains special tokens (URLs, hashtags,
mentions, emoji, etc.) fall back to the existing wordIdentifier()
path, which produces individual Segment objects as before.
- Short-circuit the final map pass for single-segment paragraphs
(already optimal) to skip an unnecessary joinToString + object creation.
New helpers:
- isRegularByIndex(): character-level fast path that detects all
token types (http/https, lnbc, cashu, NIP-19, emoji, email, phone,
schemeless URL, EmojiCoder variation selectors) without creating
a substring. Returns true only when the word is definitely plain text.
- isArabicInRange(): RTL detection directly on the source string range,
replacing the substring-based isArabic().
Behaviour is identical: the same Segment types are produced in the same
order for every input, as validated by the existing test suite.
https://claude.ai/code/session_01NXsow7yLBd6ModmGSsqR9g
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>