Download apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatTalkActivityViews.swift from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 7.3 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatTalkActivityViews.swift
- Command line
-
hf download hf://SaylorTwift/openclaw/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatTalkActivityViews.swift
-
curl -L -o ChatTalkActivityViews.swift https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatTalkActivityViews.swift
7.3 kB
| import Foundation | |
| import SwiftUI | |
| struct ChatTalkTranscriptStripModel: Equatable { | |
| let recentTranscript: [String] | |
| let partialTranscript: String | |
| init(recentTranscript: [String], partialTranscript: String, limit: Int = 20) { | |
| let finals = recentTranscript | |
| .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } | |
| .filter { !$0.isEmpty } | |
| self.recentTranscript = Array(finals.suffix(max(0, limit))) | |
| self.partialTranscript = partialTranscript.trimmingCharacters(in: .whitespacesAndNewlines) | |
| } | |
| var hasTranscript: Bool { | |
| !self.recentTranscript.isEmpty || !self.partialTranscript.isEmpty | |
| } | |
| var collapsedText: String? { | |
| if !self.partialTranscript.isEmpty { return self.partialTranscript } | |
| return self.recentTranscript.last | |
| } | |
| } | |
| struct ChatTalkActivityStrip: View { | |
| let control: OpenClawChatTalkControl | |
| private var isExpanded = false | |
| var body: some View { | |
| let model = ChatTalkTranscriptStripModel( | |
| recentTranscript: self.control.recentTranscript, | |
| partialTranscript: self.control.partialTranscript) | |
| if self.control.isEnabled { | |
| VStack(alignment: .leading, spacing: 6) { | |
| if model.hasTranscript { | |
| Button { | |
| withAnimation(.easeInOut(duration: 0.16)) { | |
| self.isExpanded.toggle() | |
| } | |
| } label: { | |
| self.header(model: model, showsDisclosure: true) | |
| } | |
| .buttonStyle(.plain) | |
| .accessibilityLabel(self.isExpanded | |
| ? String(localized: "Hide talk transcript") | |
| : String(localized: "Show talk transcript")) | |
| } else { | |
| self.header(model: model, showsDisclosure: false) | |
| } | |
| if self.isExpanded, model.hasTranscript { | |
| ScrollView { | |
| VStack(alignment: .leading, spacing: 5) { | |
| ForEach(Array(model.recentTranscript.enumerated()), id: \.offset) { _, line in | |
| Text(line) | |
| .font(OpenClawChatTypography.caption) | |
| .foregroundStyle(.primary) | |
| .frame(maxWidth: .infinity, alignment: .leading) | |
| } | |
| if !model.partialTranscript.isEmpty { | |
| Text(model.partialTranscript) | |
| .font(OpenClawChatTypography.caption.italic()) | |
| .foregroundStyle(OpenClawChatTheme.accent) | |
| .frame(maxWidth: .infinity, alignment: .leading) | |
| } | |
| } | |
| } | |
| .frame(maxHeight: 104) | |
| .transition(.opacity.combined(with: .move(edge: .top))) | |
| } | |
| } | |
| .padding(.horizontal, 10) | |
| .padding(.vertical, 7) | |
| .background( | |
| RoundedRectangle(cornerRadius: 10, style: .continuous) | |
| .fill(OpenClawChatTheme.subtleCard)) | |
| .overlay( | |
| RoundedRectangle(cornerRadius: 10, style: .continuous) | |
| .strokeBorder(OpenClawChatTheme.composerBorder, lineWidth: 1)) | |
| .padding(.horizontal, 14) | |
| .accessibilityIdentifier("chat-talk-activity") | |
| } | |
| } | |
| private func header(model: ChatTalkTranscriptStripModel, showsDisclosure: Bool) -> some View { | |
| HStack(spacing: 7) { | |
| Circle() | |
| .fill(OpenClawChatTheme.accent) | |
| .frame(width: 7, height: 7) | |
| Text(self.control.statusText) | |
| .font(OpenClawChatTypography.captionSemiBold) | |
| .lineLimit(1) | |
| if let collapsedText = model.collapsedText, !self.isExpanded { | |
| Text(collapsedText) | |
| .font(OpenClawChatTypography.caption) | |
| .foregroundStyle(model.partialTranscript.isEmpty ? .secondary : OpenClawChatTheme.accent) | |
| .italic(!model.partialTranscript.isEmpty) | |
| .lineLimit(1) | |
| } | |
| Spacer(minLength: 0) | |
| if showsDisclosure { | |
| Image(systemName: self.isExpanded ? "chevron.up" : "chevron.down") | |
| .font(.caption2.weight(.semibold)) | |
| .foregroundStyle(.secondary) | |
| } | |
| } | |
| .contentShape(Rectangle()) | |
| } | |
| } | |
| struct ChatTalkButtonGlyph: View { | |
| let control: OpenClawChatTalkControl | |
| private static let activePalette = TalkWaveformPalette( | |
| active: [.white, .white.opacity(0.78), .white.opacity(0.55)], | |
| inactive: [.white.opacity(0.65)]) | |
| var body: some View { | |
| if self.control.isEnabled { | |
| TalkWaveformView(phase: self.waveformPhase, palette: Self.activePalette) | |
| .frame(width: 23, height: 16) | |
| .allowsHitTesting(false) | |
| } else { | |
| Image(systemName: "waveform") | |
| } | |
| } | |
| private var waveformPhase: TalkWaveformPhase { | |
| if self.control.isListening { | |
| return .listening( | |
| level: self.control.level, | |
| speechActive: !self.control.partialTranscript.isEmpty) | |
| } | |
| if self.control.isSpeaking { | |
| return .speaking(level: self.control.level) | |
| } | |
| return .thinking | |
| } | |
| } | |
| private struct ChatTalkInputDeviceMenuModifier: ViewModifier { | |
| let control: OpenClawChatTalkControl | |
| func body(content: Content) -> some View { | |
| if self.control.selectInputDevice != nil { | |
| content.contextMenu { | |
| Button { | |
| self.control.selectInputDevice?(nil) | |
| } label: { | |
| self.menuLabel( | |
| String(localized: "System Default"), | |
| selected: self.control.selectedInputDeviceID == nil) | |
| } | |
| if !self.control.inputDevices.isEmpty { | |
| Divider() | |
| ForEach(self.control.inputDevices) { device in | |
| Button { | |
| self.control.selectInputDevice?(device.id) | |
| } label: { | |
| self.menuLabel( | |
| device.name, | |
| selected: self.control.selectedInputDeviceID == device.id) | |
| } | |
| } | |
| } | |
| } | |
| } else { | |
| content | |
| } | |
| } | |
| private func menuLabel(_ text: String, selected: Bool) -> some View { | |
| if selected { | |
| Label(text, systemImage: "checkmark") | |
| .font(OpenClawChatTypography.body) | |
| } else { | |
| Text(text) | |
| .font(OpenClawChatTypography.body) | |
| } | |
| } | |
| } | |
| extension View { | |
| func chatTalkInputDeviceMenu(_ control: OpenClawChatTalkControl) -> some View { | |
| self.modifier(ChatTalkInputDeviceMenuModifier(control: control)) | |
| } | |
| } | |