Commit Graph

299 Commits

Author SHA1 Message Date
Claude 1d208edd33 feat: migrate ThinPaddingTextField to BasicTextField(TextFieldState) for GIF keyboard support
Migrates all new post screens from the old BasicTextField(TextFieldValue)
to the new BasicTextField(TextFieldState) API, which properly sets
EditorInfo.contentMimeTypes to enable GIF keyboard input.

Key changes:
- Add TextFieldState-based ThinPaddingTextField overload (keep old for readonly dropdowns)
- Create UrlUserTagOutputTransformation for the new OutputTransformation API
- Create TextFieldState extension functions (insertUrlAtCursor, replaceCurrentWord, currentWord)
- Update IMessageField interface to use TextFieldState + onMessageChanged()
- Migrate all IMessageField implementors: ChannelNewMessageViewModel,
  ChatNewMessageViewModel, NewProductViewModel, NewPublicMessageViewModel,
  CommentPostViewModel, ShortNotePostViewModel, LongFormPostViewModel
- Update PreviewState to accept String instead of TextFieldValue
- Add TextFieldState overload to UserSuggestionState.replaceCurrentWord()
- Update all post screen call sites

https://claude.ai/code/session_01FDGf1Zi1pVvzFi3JY5agnJ
2026-03-28 19:09:38 +00:00
Vitor Pamplona 0c7e5fddea Fixes test cases 2026-03-28 09:41:09 -04:00
Vitor Pamplona 787b9ab9db Merge pull request #1905 from nrobi144/feat/desktop-cache-v2
feat(desktop): cache-centric architecture for desktop feeds
2026-03-27 15:45:34 -04:00
Vitor Pamplona 5d256bab2c stable subs 2026-03-26 15:21:08 -04:00
Vitor Pamplona 44c39b01ea Defers NIP05 Resolver/NamecoinResolver Builder until needed 2026-03-26 11:07:56 -04:00
nrobi144 2b95cc013a feat(cache): extract Kind3FollowListState + Nip65RelayListState to commons
- Add Kind3FollowListState to commons/commonMain with ICacheProvider
  + Kind3FollowListRepository interface for settings needs
- Add Nip65RelayListState to commons/commonMain with ICacheProvider
  + Nip65RelayListRepository interface with default relay sets
- Per-feature repository interfaces match existing EphemeralChatRepository
  / PublicChatListRepository pattern in commons
- Android originals unchanged — Desktop will use commons versions
- Static LocalCache.justConsumeMyOwnEvent calls replaced with cache param
2026-03-26 07:14:16 +02:00
nrobi144 7151d3052a feat(cache): extract BookmarkListState to commons/commonMain
- Move BookmarkListState from amethyst/ to commons/commonMain/
- Change cache param from LocalCache to ICacheProvider
- Android file becomes typealias to commons version
- No settings or decryptionCache dependencies (simplest State class)
- Pins bookmarkList AddressableNote via strong ref for GC retention
2026-03-26 07:14:16 +02:00
nrobi144 00b06a0e2a refactor(cache): move LargeSoftCache to commons/jvmAndroid, fix ICacheProvider types
- Move LargeSoftCache from amethyst/model to commons/jvmAndroid/model/cache
  so both Android and Desktop share the same WeakReference cache implementation
- Change ICacheProvider return types from Any? to proper types (User?, Note?)
  since these model classes already live in commons
- Remove unnecessary casts in ThreadAssembler, ChatNewMessageState, SearchBarState
- Improve LargeSoftCache.cleanUp() to use single-pass iterator (zero allocation)
- Update Android imports in LocalCache, LargeSoftCacheAddressExt, and test

Per Vitor's feedback on PR #1905: BoundedLargeCache evicts arbitrarily.
LargeSoftCache uses WeakReferences so GC respects the reference graph.
2026-03-26 07:13:27 +02:00
Vitor Pamplona 9f6684b044 Merge pull request #1942 from nrobi144/features/long-form-content
feat(desktop): highlight UX, shared stores, profile tabs, editor toolbar
2026-03-25 07:47:21 -04:00
nrobi144 e037254b39 fix(highlights): shared store, context menu, link rendering, publish, profile tabs
- Share DesktopHighlightStore and DesktopDraftStore at app level instead
  of per-column to fix cross-deck reactivity and draft persistence
- Replace broken clipboard-based highlight creation with
  LocalContextMenuRepresentation that piggybacks on Copy to get selected text
- Render highlights as highlight:// links instead of bold/italic markers
- Add collapsible highlights panel in article reader with edit/delete/publish
- Publish highlights to relays as NIP-84 events via HighlightPublishAction
- Add Reads tab (kind 30023) and Highlights tab (kind 9802) to profile
- Rewrite MarkdownToolbar with MarkdownEditorState for selection-aware
  toggle, Material icons, and keyboard shortcuts (Cmd+B/I/E/K)
- Wire DraftsScreen "New Draft" button to ArticleEditorScreen navigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 06:59:41 +02:00
Vitor Pamplona 2a2c61973e Avoids crashing the app in weird urls. 2026-03-24 13:30:36 -04:00
nrobi144 efa294ea72 feat(highlights): add article highlights and note-taking system
Phase 1: HighlightData model + DesktopHighlightStore (Preferences-based)
Phase 2: Text selection highlight via Cmd+H/Cmd+Shift+H, inline bold/italic
         rendering, HighlightAnnotationDialog, SelectionContainer wrapping
Phase 3: MyHighlightsScreen with grouped view, HighlightPublishAction for
         NIP-84 (kind 9802), deck/sidebar/menu wiring

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 12:16:54 +02:00
nrobi144 c75176891f feat(reads): integrate long-form into deck layout with zoom and reactions
- Wire Article, Editor, Drafts into DeckColumnType + DeckColumnContainer
- Add Drafts to sidebar nav, Add Column dialog, and Window menu
- Add article navigation (onNavigateToArticle) in SinglePaneLayout
- Add NoteActionsRow to ReadsScreen LongFormCards (zaps, reactions, replies)
- Add Cmd+/Cmd- zoom in ArticleReaderScreen via fontScale on RenderMarkdown
- Add kind 30023 to ProfileSubscription for long-form in user profiles
- Add fontScale param to RenderMarkdown using scaled LocalDensity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:18:37 +02:00
nrobi144 328fcf86d7 refactor(reads): address all review findings — security, performance, simplicity
P1 Critical:
- Add 300ms debounce on editor preview to prevent AST re-parse per keystroke
- Hoist Regex constants in ReadingTimeCalculator and TableOfContents
- Add URI scheme allowlist to editor onLinkClick (was missing vs reader)
- Add MAX_CONTENT_BYTES (100KB) validation before publish

P2 Important:
- Delete MarkdownSpikeScreen (278 LOC spike artifact)
- Delete HighlightCreator (95 LOC, zero callers — YAGNI)
- Delete DraftLongTextNoteEvent (162 LOC, no consumers — YAGNI)
- Replace ArticleMediaRenderer interface with onLinkClick lambda
- Extract inline subscription to FilterBuilders.longFormByAddress()
- Replace SimpleDateFormat with thread-safe DateTimeFormatter
- Remove dead placeholders (bookmark button, reactions row, unused param)
- Cache draft index in memory to avoid redundant disk reads
- Add TODO for publish-before-relay-ack issue

P3 Nice-to-have:
- Remove timestamp from subscription subId for stability
- Remove redundant slug ".." removal (regex handles it)
- Add metadata field length limits (title 256, summary 1024)
- Fix identical isMacOS branches in editor
- Validate image URLs (http/https only) in ArticleHeader

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:03:29 +02:00
nrobi144 4fcbffdb3b feat(reads): Phase 2 — editor, drafts, publish, highlights
- Create DraftLongTextNoteEvent (kind 30024) in quartz with EventFactory registration
- Create LongFormPublishAction for signing + publishing kind 30023 events
- Create split-pane ArticleEditorScreen with live markdown preview
- Create MarkdownToolbar (bold, italic, heading, link, image, code, quote)
- Create MetadataPanel (title, summary, banner, tags, slug)
- Create DesktopDraftStore with JSON index + .md files, atomic writes, slug sanitization
- Create DraftsScreen with draft list, delete, new draft button
- Create HighlightCreator dialog for kind 9802 highlight creation
- Add Drafts nav rail entry and Editor/Drafts screen routing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:59:52 +02:00
nrobi144 5ef36363cd feat(reads): Phase 1 — article reader with markdown, ToC, reading time
- Add richtext-commonmark deps to commons for shared markdown rendering
- Create RenderMarkdown composable with URL scheme allowlist (security)
- Create ArticleMediaRenderer interface for platform-specific media
- Create ArticleHeader with banner, title, author, reading time metadata
- Create TableOfContents with heading extraction and scroll-spy
- Create ReadingTimeCalculator (238 WPM prose, 80 WPM code, image decay)
- Create ArticleReaderScreen with Medium-style typography (680dp, 1.58x)
- Add DesktopScreen.Article navigation with address tag routing
- Update ReadsScreen to navigate via address tags instead of event IDs
- Responsive ToC sidebar (shown when window > 1100dp)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:59:52 +02:00
Claude 9202b60dcf test: add regression tests for 今北産業 URL crash (PR #1907)
Verifies that the Japanese phrase "今北産業" does not cause a
StringIndexOutOfBoundsException in Url.getPart() and is not
detected as a URL.

https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 20:46:59 +00:00
Claude e31e3829a6 test: add regression tests for PR #1907 URL crash fix
Tests cover the StringIndexOutOfBoundsException in Url.getPart() that
occurred when readEnd() trimmed trailing characters (e.g. ':') from a
detected URL but urlMarker indices remained pointing past the trimmed
string's end.

- UrlMarkerTest: three cases testing PORT/QUERY index at or beyond
  string length (the boundary conditions fixed by minOf clamping and
  the startIndex >= length guard)
- UrlsDetectorTest: regression for "今北産業" (no crash, 0 URLs) and
  for a bare "example.com:" host
- UrlParserTest: end-to-end regression for "今北産業" and "example.com:"

https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 20:31:28 +00:00
Vitor Pamplona 33ec43a5c3 Removing warnings 2026-03-23 10:39:56 -04:00
nrobi144 677bc6c34a fix(chess): add offchain.pub relay for jester interop
jester.nyo.dev uses offchain.pub as one of its relays. Adding it gives
us 2 shared relays (relay.damus.io + offchain.pub) instead of 1,
improving challenge visibility between Amethyst and Jester clients.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 08:26:09 +02:00
nrobi144 3eaf3d38a5 fix(chess): normalize SAN for cross-client interop
ChessEngine.makeMove() now normalizes SAN notation before passing to
chesslib, fixing games against jester.nyo.dev and other clients that
use different notation:

- Castling: 0-0 → O-O, 0-0-0 → O-O-O (zeros to letters)
- Annotations: strips !, ?, !!, ??, !?, ?! suffixes

Previously, chesslib rejected 0-0/0-0-0 causing ChessStateReconstructor
to mark games as desynced and skip remaining moves. Games appeared
permanently stuck, even after app restart.

Also fixes discoverUserGames() silently dropping games classified as
spectator — now adds them to spectatingGames instead.

23 new interop tests covering SAN variants, reconstruction, spectator
detection, and missing start event handling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 07:21:17 +02:00
Claude 695d3c7a23 feat: deprecate NIP-04 DM sending, always use NIP-17
NIP-04 encryption for sending DMs is now deprecated. All new messages
are sent using NIP-17 (gift-wrapped sealed messages). Reading NIP-04
messages remains supported for backward compatibility.

When a recipient lacks both a DM relay list (kind 10050) and NIP-65
inbox relays, the send button is disabled and a warning is shown
explaining that messages cannot be delivered.

Changes:
- ChatNewMessageState: Remove nip17/requiresNip17 toggles, add
  recipientsMissingDmRelays state, always send via NIP-17
- ChatNewMessageViewModel: Always use NIP-17, remove NIP-04 send
  paths, add recipient relay status checking
- ToggleNip17Button -> Nip17Indicator: Replace toggle with static
  NIP-17 indicator (always on)
- PrivateMessageEditFieldRow: Show warning when recipients lack
  DM relay lists, hide message input
- ChatFileSender: sendAll() always uses NIP-17
- Desktop ChatPane: Remove NIP-17 toggle, show relay warning
- ChatroomView: Reactively check recipient DM relay availability

https://claude.ai/code/session_01T7QhUW9cZogk4DxDXbbbJJ
2026-03-19 15:22:13 +00:00
Vitor Pamplona 78ffb9fce4 Merge branch 'main' into claude/event-sync-screen-sYGtN 2026-03-19 09:54:20 -04:00
nrobi144 24d4073b9b feat(media): encrypted file sharing in desktop DMs (NIP-17 Phase 6)
Add full send + receive encrypted media support in desktop DM chat:
- Paperclip attach button and drag-and-drop in ChatPane (NIP-17 mode only)
- AES-GCM encryption before upload to Blossom server
- ChatMessageEncryptedFileHeaderEvent (kind 15) wrapped in GiftWrap
- sendNip17EncryptedFile() added to IAccount interface and implementations
- DesktopUploadOrchestrator.uploadEncrypted() with proper encrypted hash
- DesktopBlossomClient ByteArray upload overload for encrypted blobs
- LRU cache in EncryptedMediaService to avoid re-downloading
- Error handling: retry on failure, disable send during upload

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 06:53:36 +02:00
Claude 5029db2302 refactor: reorganize nip47 wallet connect package into subpackages
Split the flat nip47WalletConnect package into logical subpackages:
- rpc/ - JSON-RPC protocol models (Request, Response, Notification, NwcMethod, NwcErrorCode, NwcTransaction, etc.)
- events/ - Nostr event types (LnZapPaymentRequestEvent, LnZapPaymentResponseEvent, NwcInfoEvent, NwcNotificationEvent)
- cache/ - Decryption caches (NostrWalletConnectRequestCache, NostrWalletConnectResponseCache)

Root level keeps the entry points: Nip47WalletConnect (URI parsing), Nip47Client, Nip47Server.
Existing subpackages (tags/, kotlinSerialization/, jackson/) remain unchanged.

https://claude.ai/code/session_018YcwMeTHPXmeqpbZHcBEUg
2026-03-17 19:04:24 +00:00
Vitor Pamplona 95c7adc90b Less warnings 2026-03-16 16:53:17 -04:00
davotoula 588cfe4c96 Unnecessary ?. / ?: / !! on non-null
Missing @OptIn annotations
Parameter name mismatches
Icons.Filled.*  / Icons.AutoMirrored.*
No cast needed / remove inline
LocalLifecycleOwner import fix
NIP-51 name() → title()
Chess gameId → startEventId
Nullable DecimalFormat safe calls
DelicateCoroutinesApi opt-in
2026-03-16 16:23:08 +01:00
Vitor Pamplona 2acf02945b Merge pull request #1840 from nrobi144/feat/desktop-advanced-search
feat(desktop): advanced search with NIP-50, collapsible sections, and nav state preservation
2026-03-16 08:14:18 -04:00
Vitor Pamplona 04b4429809 removes another deprecation 2026-03-15 20:57:46 -04:00
Vitor Pamplona d10b43c098 Migrates old Preview annotation 2026-03-15 20:55:55 -04:00
Vitor Pamplona 8b4a45cb5b Removing deprecated library addresses and deprecated apis 2026-03-15 20:52:01 -04:00
Vitor Pamplona 2c91fdea15 Avoids using format to write hex-encoded strings. 2026-03-15 11:03:50 -04:00
Vitor Pamplona 9b58a1be11 Fixing IO Dispatchers and scopes of choice. 2026-03-13 15:06:03 -04:00
Vitor Pamplona 00f2d46b53 Refines user status flow and isExpired running 2026-03-13 13:45:22 -04:00
Claude 82e500eee1 feat: complete NIP-38 implementation with p tag, emoji, and expiration support
- Add optional r/p/e/a/emoji tags to StatusEvent.create() for full spec compliance
- Add GENERAL and MUSIC type constants to StatusEvent
- Filter expired statuses in UserStatusCache.addStatus() and add removeExpired()
- Add p tag (profile reference) display in DisplayStatusInner
- Add NIP-30 custom emoji rendering in status display via CreateTextWithEmoji
- Allow status type parameter in UserStatusAction.create()

https://claude.ai/code/session_0117asp4mDiR65dxbAGKi2hg
2026-03-13 03:06:22 +00:00
Vitor Pamplona 0d9f390cd9 missing tests fix 2026-03-12 19:44:51 -04:00
Vitor Pamplona 21e29bbb3c Fixes test cases. 2026-03-12 19:42:46 -04:00
Vitor Pamplona fa67030b47 Adds support for BUD-10 Blossom URIs 2026-03-12 18:57:46 -04:00
nrobi144 5a437ed5ac feat(search): collapsible section headers + sorting + search improvements
- Collapsible sticky section headers with animated chevron
- Full header row clickable to toggle collapse
- SearchResultSorter, SearchSortOrder, pseudo-kind filtering
- TextFieldValue cursor preservation, relay timeout improvements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:23:27 +02:00
nrobi144 7180edf162 Merge upstream/main into feat/desktop-advanced-search
Resolve conflicts:
- RelayStatus.kt: keep both relay URLs
- SearchScreen.kt: keep advanced search implementation
- SinglePaneLayout.kt: add missing Spacer import

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:22:15 +02:00
Vitor Pamplona 0c040d8816 addresses long domain names for blossom and nostr profiles 2026-03-11 14:59:52 -04:00
Vitor Pamplona 1385feb066 fixes non-lowercase schemas on posts 2026-03-11 14:38:19 -04:00
nrobi144 3c6c368582 refactor(search): extract thread-safe EventDeduplicator, unify dedup
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>
2026-03-11 11:36:39 +02:00
nrobi144 edf764709d fix: resolve conflicts with upstream PR #1789 merge
- Add missing commons domain files (BunkerLoginUseCase, NostrConnectLoginUseCase)
- Restore CoroutineScope in NostrSignerRemote for suspend decrypt call
- Update isolation test: upstream removed `since` filter (PR #1789)
- Add new INostrClient interface methods to TrackingNostrClient mock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:35:56 +02:00
nrobi144 4d1d92db39 feat(desktop): add bunker heartbeat indicator to sidebar navigation
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>
2026-03-11 10:20:18 +02:00
nrobi144 eafedda99e feat(desktop): update login hints to mention bunker:// option
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:16:09 +02:00
nrobi144 979d07679c fix(search): loading indicator, result delivery, and history race
- 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>
2026-03-11 09:29:27 +02:00
nrobi144 a702dcc0ee fix(search): cleanup review findings — dead code, FQN refs, naming
- Remove unused `key` param from ExpandableSection
- Replace FQN references with imports in AdvancedSearchPanel and SearchScreen
- Use MetadataEvent.KIND instead of magic `0`
- Remove dead `relayStatuses` collection (only `connectedRelays` used)
- Remove CachedUserResult sealed variant (never constructed)
- Rename SearchHint `identifier` param to `example`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 07:28:04 +02:00
nrobi144 e8e2650fa9 refactor(search): extract shared code to commons, remove dead code
- 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>
2026-03-11 07:21:17 +02:00
Vitor Pamplona cdc9ff783d Accepts INIP05Client on the check and update function 2026-03-10 14:39:33 -04:00