Files
amethyst/commons/plans/2026-05-05-feed-builder-enhancements-plan.md
T
nrobi144 4010a57e68 feat(desktop): add custom feeds system with creation, pinning, and inline switching
- FeedDefinition data model with FeedSource sealed interface (Filter, Following, Global, DVM, PeopleList, InterestSet, SingleRelay)
- FeedDefinitionRepository with StateFlow, groupedFeeds, pin/unpin/reorder (max 3 pinned)
- JSON serialization via Jackson with round-trip tests (18 unit tests)
- SearchQuery.toFeedDefinition() bridge for creating feeds from search
- FeedBuilderDialog with author search (cache lookup + npub decode), hashtag/relay inputs, kind filter checkboxes, exclude authors/keywords, Cmd+S save, Enter to add
- FeedsDrawerTab in app drawer with edit/delete/pin/unpin actions
- Feeds tab in top header (FilterChips) with inline mode switching
- CustomFeedScreen + DesktopCustomFeedFilter + createCustomFeedSubscription for relay-based custom feed content
- FeedDefinitionEvent (kind 31890) in quartz for future publish/import
- Local persistence via java.util.prefs.Preferences (auto-save on change)
- DeckColumnType.CustomFeed for navigation integration
- Renamed Home to Feeds in nav rail
- Fix: AnimatedGifImage race condition (coerceIn on frame index)
- Fix: search results margins (sidePadding applied consistently)
- Fix: app drawer search includes feeds in results

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 09:59:30 +03:00

94 lines
2.9 KiB
Markdown

# Feed Builder Enhancements
**Date:** 2026-05-05
**Status:** Implementation
## Scope
Enhance `FeedBuilderDialog` with 6 items:
1. npub auto-decode (paste npub -> hex + display name)
2. Author search (type name -> search LocalCache -> pick)
3. Kind filter checkboxes (Notes, Reposts, Articles)
4. Edit + Delete feeds (CRUD completeness)
5. "Save as Feed" button in search results
6. Exclude authors field in dialog
## Implementation
### 1. npub Auto-Decode
**Where:** `FeedBuilderDialog.kt` ChipInputField for Authors
**Logic:**
- On add: if input starts with `npub1`, decode via `decodePublicKeyAsHexOrNull()`
- If decode succeeds, add hex to authors list
- Show display name in chip (resolve from LocalCache)
### 2. Author Search
**Where:** New `AuthorSearchField` composable in `FeedBuilderDialog.kt`
**Flow:**
- Replace plain text field for authors with search field
- Type >= 2 chars -> filter `DesktopLocalCache.users` by displayName/nip05
- Show dropdown with matching profiles (avatar placeholder + name + npub short)
- Click adds hex to authors list
- Still allow raw npub/hex paste (falls through to auto-decode)
**Data source:** `DesktopLocalCache.users` (already populated from metadata subscriptions)
### 3. Kind Filter Checkboxes
**Where:** `FeedBuilderDialog.kt`, new section between relays and exclude
**UI:** FlowRow of FilterChips:
- [x] Notes (kind 1)
- [x] Reposts (kind 6, 16)
- [ ] Articles (kind 30023)
- [ ] Highlights (kind 9802)
- [ ] Reactions (kind 7)
Default: Notes + Reposts checked. Maps to `FeedBuilderState.kinds`.
### 4. Edit + Delete in Drawer
**Where:** `FeedsDrawerTab.kt`
**Edit:** Add edit button on each FeedRow -> opens `FeedBuilderDialog(initial = feed)`
- On save: calls `feedRepository.update(feed)`
**Delete:** Add delete in context or as swipe action
- Confirm dialog: "Delete feed X?"
- Calls `feedRepository.delete(feed.id)`
### 5. "Save as Feed" from Search
**Where:** `SearchScreen.kt` or `SearchResultsList.kt`
**UI:** Show "Save as Feed" button when `query.canBecomeFeed()` is true
- Button appears in the header area, next to the search bar actions
- Click opens `FeedBuilderDialog` pre-filled from `query.toFeedDefinition()`
### 6. Exclude Authors in Dialog
**Where:** `FeedBuilderDialog.kt`
**UI:** Same chip input pattern as regular authors but for excludes
- Uses same author search/npub-decode logic
- Maps to `FeedBuilderState.excludeAuthors`
## File Changes
| File | Change |
|------|--------|
| `FeedBuilderDialog.kt` | Author search field, npub decode, kind checkboxes, exclude authors |
| `FeedsDrawerTab.kt` | Edit/delete buttons on feed rows |
| `SearchScreen.kt` | "Save as Feed" button |
| `FeedBuilderState.kt` | No changes needed (already has all fields) |
## Dependencies
- `decodePublicKeyAsHexOrNull` from `quartz/nip19Bech32`
- `DesktopLocalCache.users` for profile search
- `SearchQuery.canBecomeFeed()` + `toFeedDefinition()` already exist