Commit Graph

69 Commits

Author SHA1 Message Date
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 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
nrobi144 b3952ce9db feat(search): add keyboard shortcuts, search history UI, and operator hints
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>
2026-03-10 12:15:14 +02:00
nrobi144 e1abb037be feat(search): add SearchHistoryStore with recent queries and saved searches
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>
2026-03-10 12:13:34 +02:00
nrobi144 55154dddb2 feat(search): add advanced search UI with panel, results list, and SearchScreen rewrite
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>
2026-03-10 12:12:17 +02:00
nrobi144 c3a45822d5 feat(search): add SearchFilterFactory and SearchResultFilter
Phase 2: SearchFilterFactory converts SearchQuery → List<Filter> with
default 3-group kind splitting (Android parity), NIP-50 inline
extensions, OR query support. SearchResultFilter handles client-side
exclusions, reply/media pseudo-kind detection, dedup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:43:48 +02:00
Vitor Pamplona 9abd61e2de Improves package layout for nip64 chess 2026-03-04 09:25:38 -05:00
Vitor Pamplona 4060bef2be Lint 2026-03-04 09:19:21 -05:00
Vitor Pamplona ad578b394d Merge pull request #1759 from vitorpamplona/claude/refactor-nip64chess-structure-3iFIB
refactor: restructure nip64Chess to match nip88Polls pattern
2026-03-04 08:30:35 -05:00
nrobi144 db530a6820 fix(desktop): audit fixes for deck layout
Critical:
- GlobalFeed now renders global feed (was identical to HomeFeed)
- DeckState uses atomic _columns.update{} instead of non-atomic .value=
- lastKnownWidth marked @Volatile for thread safety

Medium:
- save() debounced 500ms via coroutine (was sync disk I/O per drag frame)
- Width redistribution fills gaps after clamping on column remove
- Hashtag column pre-fills search query
- ColumnNavigationState.stack exposed as StateFlow not MutableStateFlow
- Settings column deduped (focuses existing instead of adding duplicate)
- Exceptions logged in save/load instead of silently swallowed

Low:
- Thread column icon fixed (was Home, now Article)
- Drag divider hit target widened to 12dp (visual stays 4dp)
- Horizontal scroll added for column overflow
- Auto-fit columns on first composition / window resize
- Column shortcuts limited to actual column count
- Deterministic default column IDs
- Overlay fallback shows message instead of blank

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:02:22 +02:00
nrobi144 73b8059b55 feat(desktop): collapsible info panel in chess deck column
Hide GameInfo/MoveHistory/Actions panel by default in deck view
with a chevron toggle to expand. Add Chess to AddColumnDialog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:45:01 +02:00
nrobi144 991ac3b31b merge: integrate upstream main with chess PR #1702
Resolves merge conflicts in Main.kt, adds Chess column type
to deck layout (DeckColumnType, ColumnHeader, DeckColumnContainer,
DeckState, SinglePaneLayout, View menu). Updates DesktopMessagesScreen
calls for new relayManager/localCache params.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:33:44 +02:00
Claude 2df8a106d4 refactor: restructure nip64Chess to match nip88Polls pattern
Reorganize nip64Chess event classes into individual packages with
dedicated tag classes, TagArrayBuilderExt, and TagArrayExt files,
following the same structure used by nip88Polls.

New package structure:
- challenge/ - LiveChessGameChallengeEvent with PlayerColorTag, TimeControlTag
- accept/ - LiveChessGameAcceptEvent with ChallengeEventTag
- move/ - LiveChessMoveEvent with GameIdTag, MoveNumberTag, SanTag, FenTag
- end/ - LiveChessGameEndEvent with ResultTag, TerminationTag, WinnerTag
- draw/ - LiveChessDrawOfferEvent
- game/ - ChessGameEvent (Kind 64)
- jester/ - JesterEvent, JesterProtocol, JesterContent, JesterGameEvents

Each tag class follows the companion object pattern with isTag(),
parse(), and assemble() methods. Each event package includes
TagArrayBuilderExt for building and TagArrayExt for parsing.

https://claude.ai/code/session_01Qtzhka3p5N3Hbns4xrRbsv
2026-03-04 00:51:43 +00:00
nrobi144 afe126f393 feat(desktop): add single-pane/deck toggle with smart column resizing
- Add LayoutMode enum (SINGLE_PANE/DECK) persisted in DesktopPreferences
- SinglePaneLayout: NavigationRail + single content area reusing deck routing
- View menu "Deck Layout" toggle with Cmd+Shift+D shortcut
- Column resize: redistribute width on add/remove, double-click header to expand
- Constrain drag resize to window bounds via BoxWithConstraints
- FlowRow headers in FeedScreen/ReadsScreen to wrap on narrow columns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:38:32 +02:00
davotoula 59309c2b1d remove unused imports 2026-03-02 15:53:21 +00:00
Vitor Pamplona b523505c05 fixes spotless check 2026-02-24 18:00:04 -05:00
Vitor Pamplona b1fd450c91 Merge branch 'main' into feat/desktop-private-dms 2026-02-24 17:50:48 -05:00
nrobi144 e7239980c6 feat(desktop): add multi-column deck layout replacing NavigationRail
Replace the 80dp NavigationRail + single content area with a TweetDeck-style
multi-column deck. Default layout: Home Feed + Notifications + Messages.

New deck system:
- DeckColumnType sealed class with 12 column types
- DeckState with StateFlow-based column management
- Per-column navigation stack for in-column drill-down
- Draggable dividers for column resize (300-800dp)
- Column config persisted via Jackson JSON in DesktopPreferences
- 48dp thin sidebar with add-column and settings buttons
- AddColumnDialog for picking column types

Keyboard shortcuts:
- Cmd+T: Add column
- Cmd+W: Close focused column
- Cmd+1-9: Focus column by index
- Cmd+Shift+Left/Right: Move column left/right

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:53:31 +02:00
nrobi144 78aa7962e9 feat(desktop): add DM broadcast status banner and audit fixes
- Show relay confirmation URLs in broadcast banner
- Add relayUrls field to DmBroadcastStatus.Sent
- Wire send progress tracking with per-relay confirmations
- Fix empty chatroom Loading state transition
- Improve NewDmDialog npub metadata resolution
- Harden sendAndWaitForResponse timeout handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 06:53:53 +02:00
nrobi144 35a15f0462 feat(desktop): add DM broadcast banner and fix empty room loading
- 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>
2026-02-19 12:20:04 +02:00
nrobi144 5d983c5d27 fix(desktop): wire gift wrap broadcast for DM reactions
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>
2026-02-19 09:34:33 +02:00
nrobi144 3f5ad8f7be feat(desktop): wire NIP-17 emoji reactions in DM chat
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>
2026-02-19 07:34:53 +02:00
nrobi144 9a30b935d2 feat(desktop): wire DM sending, subscriptions, and new DM dialog
- 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>
2026-02-19 07:33:04 +02:00
Vitor Pamplona 2c3ca7f906 - Finishes the transition to EventHint objects for building events.
- Removes the "a-tag" dependency on Addressable interface because the `a` can have different names in different objects.
2026-02-18 10:45:50 -05:00
nrobi144 5d81da2486 feat(desktop): add encrypted DMs with split-pane layout (NIP-04/NIP-17)
Full desktop DM implementation with shared components extracted to commons:
- Relay layer: DM relay state, filter construction, subscription coordinator
- Shared: ChatroomFeedFilter, ChatroomFeedViewModel, ChatNewMessageState
- Shared UI: ChatBubbleLayout, ChatMessageCompose, ChatroomHeader, ChatTheme
- Desktop: split-pane (conversation list + chat), keyboard shortcuts, hover reactions
- IAccount extended with signer, sendNip04/17, chatroomList, isAcceptable

Refs: vitorpamplona/amethyst#1704

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 13:19:46 +02:00
nrobi144 5f15f0c3b1 fix: address Copilot review comments
- ChessPosition: include all fields in equals/hashCode
- AcceptedGamesRegistry: add thread safety with synchronized
- ChessEventBroadcaster: use valid filter for connection trigger
- ChessEventBroadcaster: fix misleading relayResults
- Remove println debug logging from ChessSubscription/Broadcaster
- UserProfileScreen: use proper JSON parsing via MetadataEvent

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 16:39:24 +02:00
nrobi144 8d098cf86d feat(chess): focused polling, promotion fix, and game end celebration
- Add focused game mode to ChessPollingDelegate: when viewing a game,
  only that game is polled instead of all active games
- Fix pawn promotion by parsing promotion suffix in publishMove
  (e.g., "e8q" -> "e8" + QUEEN)
- Add game end overlay with victory/defeat/draw celebration
- Remove all debug println statements for production readiness

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 12:14:34 +02:00
nrobi144 3c89c442bc feat(chess): add slim ViewModels and shared broadcast banner (Steps 7-10)
Step 7: ChessViewModelNew.kt - Slim Android ViewModel (~130 lines)
- Delegates all business logic to ChessLobbyLogic
- Exposes StateFlows from logic.state
- Platform adapter creation only

Step 8: DesktopChessViewModelNew.kt - Slim Desktop ViewModel (~120 lines)
- Same pattern as Android, delegates to ChessLobbyLogic
- UserMetadataCache for profile display
- External CoroutineScope injection

Step 9: ChessBroadcastBanner.kt - Shared Compose banner in commons
- Uses ChessBroadcastStatus from ChessLobbyState
- Works on both Android and Desktop via Compose Multiplatform
- Shows broadcasting progress, sync status, errors

Step 10: UI consumers ready for migration
- New ViewModels use ChessChallenge (enriched display data)
- Shared banner ready to replace Android-only ChessStatusBanner
- Existing screens continue to work with old ViewModel

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 12:14:34 +02:00
nrobi144 42b33ca04c feat(chess): add platform adapters and enhance lobby state (steps 5-6)
- Add ChessLobbyState with completedGames, replaceGameState(), moveToCompleted()
- Add challengerAvatarUrl to ChessChallenge
- Add CompletedGame data class for game history

Platform Adapters:
- AndroidChessAdapter: AndroidChessPublisher, AndroidRelayFetcher, AndroidMetadataProvider
- DesktopChessAdapter: DesktopChessPublisher, DesktopRelayFetcher, DesktopMetadataProvider

Shared Infrastructure:
- ChessRelayFetchHelper for one-shot relay queries
- IUserMetadataProvider interface for platform-specific metadata
- ChessFilterBuilder with simple filter methods for fetchers
- ChessSubscriptionController interface for subscription management

Fix ChessSubscription.kt to remove broken dataSources().chess reference
(subscriptions now managed by ChessLobbyLogic)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 12:14:34 +02:00
nrobi144 e0d0e33408 refactor impl 2026-02-10 12:14:05 +02:00
Vitor Pamplona eb66182211 - Updates several libraries
- Reformats code to the newest Klint
- Fixes isEmpty bug on Filters
2026-02-09 14:06:07 -05:00
Vitor Pamplona 710f15f790 - Fixes copyright using KDoc patterns instead of simpler comments
- Moves spotless and git-hooks to hidden folders
2026-02-09 13:06:41 -05:00
Vitor Pamplona 4e39a531b7 Moves metadata methods from User to UserCache object 2026-02-07 10:18:13 -05:00
Vitor Pamplona 4ced055035 Switches the metadata relay for the relay being used with the most amount of posts to be the relayhint 2026-02-04 17:38:01 -05:00
Vitor Pamplona e6f7a543cd Migrates Desktop App to the new metadata cache. 2026-02-04 15:38:16 -05:00
Vitor Pamplona c3f09987aa Merge pull request #1676 from nrobi144/nrobi144/phase-2A
Desktop: Basic Search + Bookmarks + Zaps
2026-01-26 09:53:35 -05:00
nrobi144 71e68dc35b refactor(commons): migrate from Moko to Compose Multiplatform Resources
Remove Moko Resources dependency that blocks AGP 9.0 migration.
Migrate to built-in Compose Multiplatform Resources which is compatible
with the new KMP Android plugin.

- Remove moko-resources plugin and libraries from commons module
- Move strings.xml from moko-resources/ to composeResources/values/
- Update imports from SharedRes.strings.* to Res.string.*
- Add compose.components.resources dependency to desktopApp
- Configure resource package as com.vitorpamplona.amethyst.commons.resources

Closes #1675

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 13:29:55 +02:00
nrobi144 ff47080cf1 fix: Resolve API mismatches after merge with upstream
- Fix import paths to use desktop.subscriptions instead of commons.subscriptions
- Update DesktopLocalCache to match ICacheProvider interface changes
- Use correct commons.relayClient paths for ComposeSubscriptionManager
- Add missing justConsumeMyOwnEvent and getOrCreateAddressableNote methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 06:23:58 +02:00
nrobi144 d08aed47e8 Merge upstream/main into nrobi144/phase-2A
Resolved import conflicts caused by package reorganization:
- upstream moved classes to amethyst/service/relayClient/*
- upstream moved models to commons/model/*
- kept our desktop additions (zaps, bookmarks, search)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 06:04:13 +02:00
nrobi144 8155cfee9d update metadata loading 2026-01-20 15:18:11 +02:00
nrobi144 8f6de1d304 zap updates 2026-01-19 16:32:01 +02:00
davotoula 505a6583ee remove unused imports 2026-01-15 14:20:05 +01:00
Vitor Pamplona 04ac40fa1a moves test as well 2026-01-13 16:07:03 -05:00
Vitor Pamplona 09d0f4425c Moves some of the stuff that was saved in Commons back to the desktop app because it is only used there 2026-01-13 16:04:02 -05:00
nrobi144 e1412c1f97 fix: Add proper empty states with EOSE tracking
- NotificationsScreen: Show "No notifications yet" after EOSE instead of infinite loading
- FeedScreen: Show "No notes found" after EOSE for both Global and Following feeds
- ThreadScreen: Show "Note not found" if root note missing after EOSE, "No replies yet" for empty threads

Uses existing EmptyState component from commons. Tracks EOSE (End of Stored Events) from relays to distinguish between "still loading" and "no data".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 06:52:33 +02:00
nrobi144 45207857c6 finish ThreadScreen 2026-01-12 06:23:57 +02:00
Vitor Pamplona cba4d25424 Moves follows and publish to their own packages 2026-01-07 16:16:01 -05:00
Vitor Pamplona 60dafd9267 Moves reactions to packages for their nips 2026-01-07 13:26:47 -05:00