perf: reduce chat animation churn
This commit is contained in:
@@ -323,6 +323,13 @@ struct ChatTypingIndicatorBubble: View {
|
|||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
||||||
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
|
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
|
||||||
.frame(maxWidth: ChatUIConstants.bubbleMaxWidth, alignment: .leading)
|
.frame(maxWidth: ChatUIConstants.bubbleMaxWidth, alignment: .leading)
|
||||||
|
.focusable(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ChatTypingIndicatorBubble: @MainActor Equatable {
|
||||||
|
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
|
lhs.style == rhs.style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +349,7 @@ struct ChatStreamingAssistantBubble: View {
|
|||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
||||||
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
|
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
|
||||||
.frame(maxWidth: ChatUIConstants.bubbleMaxWidth, alignment: .leading)
|
.frame(maxWidth: ChatUIConstants.bubbleMaxWidth, alignment: .leading)
|
||||||
|
.focusable(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,12 +384,20 @@ struct ChatPendingToolsBubble: View {
|
|||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
||||||
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
|
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
|
||||||
.frame(maxWidth: ChatUIConstants.bubbleMaxWidth, alignment: .leading)
|
.frame(maxWidth: ChatUIConstants.bubbleMaxWidth, alignment: .leading)
|
||||||
|
.focusable(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ChatPendingToolsBubble: @MainActor Equatable {
|
||||||
|
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
|
lhs.toolCalls == rhs.toolCalls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private struct TypingDots: View {
|
private struct TypingDots: View {
|
||||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||||
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
@State private var animate = false
|
@State private var animate = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -399,10 +415,22 @@ private struct TypingDots: View {
|
|||||||
value: self.animate)
|
value: self.animate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear { self.updateAnimationState() }
|
||||||
guard !self.reduceMotion else { return }
|
.onDisappear { self.animate = false }
|
||||||
self.animate = true
|
.onChange(of: self.scenePhase) { _, _ in
|
||||||
|
self.updateAnimationState()
|
||||||
}
|
}
|
||||||
|
.onChange(of: self.reduceMotion) { _, _ in
|
||||||
|
self.updateAnimationState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateAnimationState() {
|
||||||
|
guard !self.reduceMotion, self.scenePhase == .active else {
|
||||||
|
self.animate = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.animate = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,11 +80,13 @@ public struct ClawdisChatView: View {
|
|||||||
|
|
||||||
if self.viewModel.pendingRunCount > 0 {
|
if self.viewModel.pendingRunCount > 0 {
|
||||||
ChatTypingIndicatorBubble(style: self.style)
|
ChatTypingIndicatorBubble(style: self.style)
|
||||||
|
.equatable()
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.viewModel.pendingToolCalls.isEmpty {
|
if !self.viewModel.pendingToolCalls.isEmpty {
|
||||||
ChatPendingToolsBubble(toolCalls: self.viewModel.pendingToolCalls)
|
ChatPendingToolsBubble(toolCalls: self.viewModel.pendingToolCalls)
|
||||||
|
.equatable()
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user