// // ResultView.swift // 划词侠 plugin // // Scrollable result text + 复制 / 重新生成 / 完成 buttons. // import SwiftUI struct ResultView: View { @ObservedObject var store: ClipperStore let actionLabel: String let output: String @State private var copyConfirmed = false var body: some View { VStack(spacing: 10) { // Action header HStack(spacing: 6) { Image(systemName: "sparkles") .font(.system(size: 11, weight: .semibold)) .foregroundColor(ClipperTheme.lime) Text(actionLabel) .font(.system(size: 12, weight: .semibold)) .foregroundColor(ClipperTheme.fgPrimary) Spacer() Text("\(output.count) 字") .font(.system(size: 10.5)) .foregroundColor(ClipperTheme.fg40) .monospacedDigit() } // Result body — scrollable. ScrollView { Text(output) .font(.system(size: 13)) .foregroundColor(ClipperTheme.fg85) .multilineTextAlignment(.leading) .frame(maxWidth: .infinity, alignment: .leading) .textSelection(.enabled) .padding(.horizontal, 12) .padding(.vertical, 10) } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) .background( RoundedRectangle(cornerRadius: 12) .fill(ClipperTheme.overlay04) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(ClipperTheme.overlay08, lineWidth: 0.5) ) ) // Action buttons HStack(spacing: 8) { resultButton(label: copyConfirmed ? "已复制" : "复制", icon: copyConfirmed ? "checkmark" : "doc.on.doc", tint: copyConfirmed ? ClipperTheme.lime : ClipperTheme.fg70) { store.copyToPasteboard(output) copyConfirmed = true Task { try? await Task.sleep(nanoseconds: 1_200_000_000) await MainActor.run { copyConfirmed = false } } } resultButton(label: "重新生成", icon: "arrow.clockwise", tint: ClipperTheme.fg70) { store.regenerate() } resultButton(label: "完成", icon: "checkmark.circle.fill", tint: Color(red: 0x0B/255, green: 0x0B/255, blue: 0x0B/255), filled: true) { store.finishResult() } } } } private func resultButton(label: String, icon: String, tint: Color, filled: Bool = false, action: @escaping () -> Void) -> some View { Button(action: action) { HStack(spacing: 6) { Image(systemName: icon) .font(.system(size: 11, weight: .semibold)) Text(label) .font(.system(size: 12, weight: .semibold)) } .foregroundColor(tint) .frame(maxWidth: .infinity) .frame(height: 32) .background( Capsule() .fill(filled ? ClipperTheme.lime : ClipperTheme.overlay06) .overlay( Capsule() .stroke(filled ? Color.clear : ClipperTheme.overlay08, lineWidth: 0.5) ) ) } .buttonStyle(.plain) } }