code
Clone this repository
https://tangled.org/bretton.dev/coves-mobile
git@knot.bretton.dev:bretton.dev/coves-mobile
For self-hosted knots, clone URLs may differ based on your setup.
- Pass postCid to loadComments for reply reference support
- Add onReplyTap callback to CommentThread and CommentCard
- Tapping reply icon on a comment navigates to ReplyScreen
- ReplyScreen receives parent comment for nested replies
- Show "Replying to @handle" context in reply screen
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add CommentService dependency to CommentsProvider
- Add createComment() method supporting both post and comment replies
- Store postCid alongside postUri for proper reply references
- Add input validation: 10k char limit using grapheme clusters
- Proper emoji counting (🎉 = 1 char, not 2)
- Wire up CommentService in main.dart
Reply reference logic:
- Reply to post: root=post, parent=post
- Reply to comment: root=post, parent=comment
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create auth_interceptor.dart with reusable createAuthInterceptor()
- Handles 401 responses by refreshing token and retrying once
- Sign out user if refresh fails to prevent infinite loops
- Refactor VoteService to use shared interceptor
- CommentService already uses it (from previous commit)
Eliminates ~130 lines of duplicated interceptor code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add CommentService with createComment() method that calls backend API
- Backend handles PDS writes via OAuth/DPoP (sealed token architecture)
- Add ValidationException to api_exceptions for client-side validation
- Add characters package for proper Unicode grapheme cluster counting
The comment creation flow:
Mobile → Coves Backend (sealed token) → User's PDS (DPoP)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update mock providers to remove VoteService dependency
- Add ViewerState to test fixtures for feed and comments
- Update FeedProvider tests for vote state initialization
- Update CommentsProvider tests for recursive vote state init
- Update VoteProvider tests for extractRkeyFromUri utility
- Remove obsolete vote service test methods (deleteVote, getUserVotes)
- Add generated mock files for auth service tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
main.dart:
- Remove voteService parameter from FeedProvider and CommentsProvider
CommentsProvider:
- Remove VoteService dependency - vote state from response viewer data
- Add _initializeCommentVoteState helper for recursive vote initialization
- On refresh: initialize all comments (server data is truth)
- On pagination: only initialize new comments (preserve optimistic state)
This completes the migration from VoteService.getUserVotes() to using
viewer state from API responses for both feed posts and comments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove VoteService dependency - vote state comes from feed response
- Replace getUserVotes + loadInitialVotes with per-post setInitialVoteState
- Use viewer.vote and viewer.voteUri from backend response
- Call setInitialVoteState for ALL posts to handle cross-device vote removal
This fixes the bug where votes would disappear on feed refresh:
1. Backend now populates viewer state from PDS cache
2. Feed provider initializes VoteProvider state from viewer data
3. Score adjustments are cleared to prevent double-counting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>