Skip to content

Conversation

@graycreate
Copy link
Member

Summary

  • Add long-press context menu on reply items to quickly reply to a user
  • Auto-populate reply content with @username when selecting reply option
  • Automatically focus the reply input after selecting reply

Test plan

  • Open a topic with replies
  • Long-press on any reply item
  • Verify context menu appears with "回复" (Reply) option
  • Select the reply option
  • Verify reply input is focused and contains @username

🤖 Generated with Claude Code

- 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]>
Copilot AI review requested due to automatic review settings December 27, 2025 05:15
Copy link

Copilot AI left a 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

Comment on lines +121 to +122
state.replyContent = "@\(action.userName) "
state.shouldFocusReply = true
Copy link

Copilot AI Dec 27, 2025

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.

Suggested change
state.replyContent = "@\(action.userName) "
state.shouldFocusReply = true
if AccountState.isSelf(userName: action.userName) {
Toast.show("不能回复自己")
} else {
state.replyContent = "@\(action.userName) "
state.shouldFocusReply = true
}

Copilot uses AI. Check for mistakes.
.onChange(of: state.shouldFocusReply) { shouldFocus in
if shouldFocus {
replyIsFocused = true
store.appState.feedDetailStates[instanceId]?.shouldFocusReply = false
Copy link

Copilot AI Dec 27, 2025

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.

Suggested change
store.appState.feedDetailStates[instanceId]?.shouldFocusReply = false

Copilot uses AI. Check for mistakes.
Comment on lines +386 to +391
struct ReplyToUser: Action {
var target: Reducer = R
var id: String
var userName: String
}

Copy link

Copilot AI Dec 27, 2025

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.

Suggested change
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
}

Copilot uses AI. Check for mistakes.
@graycreate graycreate merged commit 4a66516 into main Dec 27, 2025
12 checks passed
@graycreate graycreate deleted the feature/long-press-reply branch December 27, 2025 05:22
@github-actions
Copy link

Code Coverage Report ❌

Current coverage: 32.9%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants