Skip to content

feat: add chat message list package#52

Merged
sirily11 merged 1 commit into
mainfrom
message-list
May 23, 2026
Merged

feat: add chat message list package#52
sirily11 merged 1 commit into
mainfrom
message-list

Conversation

@sirily11
Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings May 23, 2026 07:37
@vercel
Copy link
Copy Markdown

vercel Bot commented May 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
rxcode Ready Ready Preview, Comment May 23, 2026 8:05am

Request Review

Copy link
Copy Markdown

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 introduces a new reusable SwiftUI MessageList package and migrates both mobile and macOS chat transcripts to use it, aiming to centralize scroll anchoring, pinning behavior, and pagination triggers across clients.

Changes:

  • Added a new MessageList Swift Package product (with unit/UI-adjacent tests and preview/simulator harnesses).
  • Replaced bespoke transcript ScrollView logic in mobile and macOS with ChatTranscriptList (a thin adapter over MessageList).
  • Updated streaming text flush behavior in AppState to group text deltas (token-based) and force flushes at tool/result boundaries and stream lifecycle edges.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
RxCodeMobile/Views/MobileChatView.swift Switches mobile transcript rendering to ChatTranscriptList and adapts scroll-to-bottom behavior.
RxCode/App/AppState+Stream.swift Implements token-grouped text delta flushing and forces flushes before tool events / stream detaches.
RxCode/App/AppState+Project.swift Forces text flush when switching projects while streaming.
RxCode/App/AppState+Messaging.swift Forces text flush when finalizing a stream session.
RxCode/App/AppState+CrossProject.swift Forces text flush before applying tool-use cross-project handling.
RxCode/App/AppState.swift Updates documentation for the stream text buffer behavior.
Packages/Tests/MessageListTests/MessageListScrollAnchorTests.swift Adds unit tests for scroll anchor decisions.
Packages/Tests/MessageListTests/MessageListPreviewTests.swift Adds ViewInspector tests for the preview harness behavior (DEBUG-only).
Packages/Tests/MessageListTests/MessageListPinningControllerTests.swift Adds unit tests for pinning controller actions.
Packages/Sources/RxCodeChatKit/MessageListView.swift Migrates macOS message list to ChatTranscriptList and new scroll request mechanism.
Packages/Sources/RxCodeChatKit/MessageBubble.swift Adds streaming fade-in behavior for assistant markdown content.
Packages/Sources/RxCodeChatKit/ChatTranscriptList.swift Introduces ChatKit adapter types (ChatTranscriptListItem/ChatTranscriptList).
Packages/Sources/MessageList/MessageListScrollAnchor.swift Adds anchor state machine for “near bottom” + content-growth decisions.
Packages/Sources/MessageList/MessageListPreview.swift Adds a DEBUG preview harness for manual interaction testing.
Packages/Sources/MessageList/MessageListPinningController.swift Adds controller for pin/re-pin/release decisions around user-message pinning.
Packages/Sources/MessageList/MessageList.swift Adds the reusable list implementation (scroll tracking, pinning, paging triggers).
Packages/Package.swift Registers MessageList as a product/target and adds a new test target.
Packages/Examples/MessageListSimulatorApp/README.md Documents opening/building the simulator host app for manual testing.
Packages/Examples/MessageListSimulatorApp/MessageListSimulatorApp/MessageListSimulatorApp.swift Adds a small iOS host app for manual list testing.
Packages/Examples/MessageListSimulatorApp/MessageListSimulatorApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved Adds resolved package pins for the example app workspace.
Packages/Examples/MessageListSimulatorApp/MessageListSimulatorApp.xcodeproj/project.pbxproj Adds the Xcode project for the example simulator app.
Comments suppressed due to low confidence (1)

RxCodeMobile/Views/MobileChatView.swift:1016

  • After moving to ChatTranscriptList, distanceFromBottom is no longer updated anywhere, but the scroll-to-bottom button log still reports it. This makes the log data misleading; either compute/report distance using the new list’s metrics or remove the field from the log message.
        Button {
            mobileChatLogger.info(
                "[ScrollButton] tap session=\(sessionID, privacy: .public) messages=\(messages.count, privacy: .public) distance=\(Double(distanceFromBottom), privacy: .public) padding=\(Double(scrollToBottomButtonBottomPadding), privacy: .public)"
            )
            autoScrollEnabled = true

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return .releasePinAndScrollToBottom
}

mutating func releasePin() {
Comment on lines +125 to +132
scrollToBottom(proxy: proxy, animated: false)
}
}
.onChange(of: shouldScrollToBottom) { _, shouldScroll in
guard shouldScroll else { return }
guard !pinning.isPinningUserMessage else { return }
anchor.resetToBottom()
scrollToBottom(proxy: proxy, animated: true)
Comment on lines +37 to +42

if contentGrew {
return previouslyNearBottom ? .scrollToBottom : .none
}

isNearBottom = nowNearBottom
Comment on lines +108 to +121
MessageList(
messages: items,
isStreaming: isStreaming,
shouldScrollToBottom: shouldScrollToBottom,
isAtBottom: $isAtBottom,
hasMorePrevious: hasMorePrevious,
loadMorePrevious: loadMorePrevious,
onLoadError: onLoadError
) { item in
rowContent(for: item)
.padding(rowPadding)
}
.accessibilityElement(children: .contain)
.accessibilityIdentifier(accessibilityIdentifier ?? "")
Comment on lines +76 to +85
ForEach(messages) { message in
let messageID = message.id
rowContent(message)
.onGeometryChange(for: CGFloat.self) { geometry in
geometry.frame(in: .named(MessageListConstants.coordinateSpaceName)).minY
} action: { value in
guard messageID == pinning.pinnedUserMessageID else { return }
updateLatestUserMinY(value)
}
.id(messageID)
handleLastMessageChange()
}
.onChange(of: chatBridge.messages.last?.content) { _, _ in
guard isSessionReady else { return }
@sirily11 sirily11 merged commit e2a664f into main May 23, 2026
10 checks passed
@sirily11 sirily11 deleted the message-list branch May 23, 2026 08:17
@sirily11
Copy link
Copy Markdown
Contributor Author

🎉 This PR is included in version 1.11.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

enhancement New feature or request released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants