New version v2.3.6
This commit is contained in:
@@ -34,6 +34,7 @@ struct MessageRow: View {
|
||||
private let settings = SettingsService.shared
|
||||
|
||||
@State private var isExpanded = false
|
||||
@State private var isThinkingExpanded = true // auto-expand while streaming, collapse after
|
||||
|
||||
#if os(macOS)
|
||||
@State private var isHovering = false
|
||||
@@ -107,6 +108,27 @@ struct MessageRow: View {
|
||||
.foregroundColor(.oaiSecondary)
|
||||
}
|
||||
|
||||
// Thinking / reasoning block (collapsible)
|
||||
if let thinking = message.thinkingContent, !thinking.isEmpty {
|
||||
thinkingBlock(thinking)
|
||||
.onChange(of: message.content) { _, newContent in
|
||||
// Auto-collapse when response content starts arriving
|
||||
if !newContent.isEmpty && isThinkingExpanded && !message.isStreaming {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
isThinkingExpanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: message.isStreaming) { _, streaming in
|
||||
// Collapse when streaming finishes
|
||||
if !streaming && !message.content.isEmpty {
|
||||
withAnimation(.easeInOut(duration: 0.3)) {
|
||||
isThinkingExpanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Content
|
||||
if !message.content.isEmpty {
|
||||
messageContent
|
||||
@@ -186,6 +208,64 @@ struct MessageRow: View {
|
||||
// Close standardMessageLayout - the above closing braces close it
|
||||
// The body: some View now handles the split between compact and standard
|
||||
|
||||
// MARK: - Thinking Block
|
||||
|
||||
@ViewBuilder
|
||||
private func thinkingBlock(_ thinking: String) -> some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
// Header button
|
||||
Button(action: {
|
||||
withAnimation(.easeInOut(duration: 0.18)) { isThinkingExpanded.toggle() }
|
||||
}) {
|
||||
HStack(spacing: 6) {
|
||||
if message.isStreaming && message.content.isEmpty {
|
||||
ProgressView()
|
||||
.scaleEffect(0.5)
|
||||
.frame(width: 12, height: 12)
|
||||
Text("Thinking…")
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
Image(systemName: "brain")
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Reasoning")
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: isThinkingExpanded ? "chevron.up" : "chevron.down")
|
||||
.font(.system(size: 9, weight: .medium))
|
||||
.foregroundStyle(.secondary.opacity(0.5))
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 6)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
if isThinkingExpanded {
|
||||
Divider()
|
||||
.padding(.horizontal, 6)
|
||||
ScrollView {
|
||||
Text(thinking)
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(10)
|
||||
}
|
||||
.frame(maxHeight: 220)
|
||||
}
|
||||
}
|
||||
.background(Color.secondary.opacity(0.07))
|
||||
.cornerRadius(6)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 6)
|
||||
.strokeBorder(Color.secondary.opacity(0.15), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Compact System Message
|
||||
|
||||
@ViewBuilder
|
||||
|
||||
Reference in New Issue
Block a user