-
Notifications
You must be signed in to change notification settings - Fork 47
feat: add long-press reply functionality for reply items #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add ReplyToUser action to trigger reply to a specific user - Add shouldFocusReply state to control reply input focus - Implement context menu on ReplyItemView with reply option - Auto-populate reply content with @username when long-pressing - Focus reply input automatically after selecting reply option 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a long-press context menu feature to reply items in topic details, allowing users to quickly initiate a reply with the target username pre-populated. The implementation follows the app's Redux-like state management pattern with an action-reducer flow and integrates with SwiftUI's focus management.
Key Changes:
- Added context menu to reply items with a "回复" (Reply) option
- Implemented auto-population of reply input with @username
- Added automatic focus management to the reply input field
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| V2er/View/FeedDetail/ReplyItemView.swift | Added .contentShape() and .contextMenu() modifiers to enable long-press reply functionality |
| V2er/State/DataFlow/Actions/FeedDetailActions.swift | Introduced new ReplyToUser action to handle reply initiation |
| V2er/View/FeedDetail/FeedDetailReducer.swift | Added reducer case to handle ReplyToUser action by setting reply content and focus flag |
| V2er/State/DataFlow/State/FeedDetailState.swift | Added shouldFocusReply boolean state to coordinate focus changes |
| V2er/View/FeedDetail/FeedDetailPage.swift | Added .onChange() observer to respond to shouldFocusReply state changes and trigger keyboard focus |
| state.replyContent = "@\(action.userName) " | ||
| state.shouldFocusReply = true |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The action should prevent users from replying to themselves, similar to the validation in ThankReply action at line 353-356. Add a check using AccountState.isSelf(userName: action.userName) to prevent this scenario.
| state.replyContent = "@\(action.userName) " | |
| state.shouldFocusReply = true | |
| if AccountState.isSelf(userName: action.userName) { | |
| Toast.show("不能回复自己") | |
| } else { | |
| state.replyContent = "@\(action.userName) " | |
| state.shouldFocusReply = true | |
| } |
| .onChange(of: state.shouldFocusReply) { shouldFocus in | ||
| if shouldFocus { | ||
| replyIsFocused = true | ||
| store.appState.feedDetailStates[instanceId]?.shouldFocusReply = false |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directly mutating the state outside of the reducer breaks the Redux-like unidirectional data flow pattern. While this pattern appears elsewhere in the codebase (e.g., line 316, 343), it's an anti-pattern. The proper approach is to dispatch an action to reset the flag. Consider creating a FeedDetailActions.ResetReplyFocus action to handle this, or alternatively, use a one-time effect that doesn't require resetting the state flag.
| store.appState.feedDetailStates[instanceId]?.shouldFocusReply = false |
| struct ReplyToUser: Action { | ||
| var target: Reducer = R | ||
| var id: String | ||
| var userName: String | ||
| } | ||
|
|
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This action should validate that the user is logged in before allowing the reply flow, similar to other actions in this file. Consider converting this to an AwaitAction with an execute method that checks AccountState.hasSignIn() and shows a login prompt if needed, following the pattern established in ThankReply (line 338-377), ReplyTopic (line 205-236), and other similar actions.
| struct ReplyToUser: Action { | |
| var target: Reducer = R | |
| var id: String | |
| var userName: String | |
| } | |
| struct ReplyToUser: AwaitAction { | |
| var target: Reducer = R | |
| var id: String | |
| var userName: String | |
| func execute(in store: Store) async { | |
| // Ensure the user is logged in before starting the reply flow | |
| guard AccountState.hasSignIn() else { | |
| Toast.show("请先登录") | |
| dispatch(LoginActions.ShowLoginPageAction(reason: "需要登录才能回复")) | |
| return | |
| } | |
| // User is logged in; proceed with the original reply-to-user behavior | |
| dispatch(ReplyToUserReady(id: id, userName: userName)) | |
| } | |
| } | |
| struct ReplyToUserReady: Action { | |
| var target: Reducer = R | |
| var id: String | |
| var userName: String | |
| } |
Code Coverage Report ❌Current coverage: 32.9% |
Summary
Test plan
🤖 Generated with Claude Code