// // ResultView.swift // AIGrammar // // Created by oscar on 2024/4/1. // import SwiftUI import Foundation // 确保SingleCorrectionCard只能在本文件内访问 fileprivate struct SingleCorrectionCard: View { let correction: String var body: some View { Text(correction) .padding(.vertical, 6) .font(.system(size: UIFontMetrics.default.scaledValue(for: 15) * 4 / 5)) .background(Color.yellow.opacity(0.5)) .cornerRadius(5) } } struct GrammarDetailsCardView: View { let res: GrammarRes var body: some View { // 添加黄色虚线作为分隔 Divider() .background(Color.yellow) .frame(height: 1) .overlay( Rectangle() .stroke(style: StrokeStyle(lineWidth: 1, dash: [5])) .foregroundColor(.yellow) ) .padding(3) VStack { Text("Error: \(res.plain)") .frame(maxWidth: .infinity, alignment: .leading) // 横向铺满 .padding(.vertical, 8) // 调整高度为默认高度的2/3 .background(Color.gray.opacity(0.5)) // 设置背景色为Gray .foregroundColor(.black) .cornerRadius(5) Text("Reason: \(res.reason)") .frame(maxWidth: .infinity, alignment: .leading) // 横向铺满 Text("Correction:") .frame(maxWidth: .infinity, alignment: .leading) // 横向铺满 .padding(.top, 6) // 在Correction上方添加一些间隔 ScrollView(.horizontal, showsIndicators: false) { HStack { ForEach(Array(res.correction.enumerated()), id: \.offset) { index, correction in SingleCorrectionCard(correction: correction) } } } } .padding(.horizontal, 3) // 在卡片的底部添加一些间隔 .padding(.bottom, 3) // 在卡片的底部添加一些间隔 .background(Color.gray.opacity(0.2)) // 设置整个卡片的背景色为LightGray .cornerRadius(10) } } struct ResultView: View { // 假设的错误数据和文本内容 @Binding var textContent: String @Binding var results: [GrammarRes] @Binding var showResult : Bool @Binding var showKeyboard : Bool @State private var selectedCardIndex: Int? = 0 @State private var textRes = AttributedString() @State private var resContent: String = String("") func getColoredText(str : String, type : String, index : Int?) -> AttributedString { var text = AttributedString( str ) if(type == GrammarResType.ok.rawValue){ return text } if (type == GrammarResType.grammar.rawValue ){ text.foregroundColor = .red }else { text.backgroundColor = .yellow } text.link = URL(string: String(index!)) return text } func styledText() -> Text { var outstr = AttributedString() var index = 0 let substr: String = textContent var currentIndex = substr.startIndex for res in results { if let range = substr.range(of: res.plain, range: currentIndex.. Text { var outstr = AttributedString() var index = 0 for res in results { let tmp = getColoredText(str: res.plain, type: res.type, index: index) outstr.append(tmp) index = index + 1 } return Text(outstr) } */ var body: some View { VStack { // 为styledText提供滚动视图 ScrollView { styledText() .padding() .environment(\.openURL, OpenURLAction { url in let path = url.absoluteString print("index: \(path)") self.selectedCardIndex = Int(path) return .handled }) Spacer() // 使用Spacer确保Text组件横向拉伸 } .onTapGesture { self.showResult = false self.showKeyboard = true } .background(Color.white) // 设置背景色为Gray .frame(maxHeight: .infinity) // 限制styledText占用半个屏幕 //与上面的文本进行联动,对每个卡片设置一个index ScrollViewReader { scrollView in ScrollView { LazyVStack { ForEach(Array(results.enumerated()), id: \.offset) { index, res in if(res.type != GrammarResType.ok.rawValue){ GrammarDetailsCardView(res: res) .id(index) // 给每个CardView分配一个ID } } } } .onChange(of: selectedCardIndex) { newIndex in if let newIndex = newIndex { withAnimation { scrollView.scrollTo(newIndex, anchor: .top) } } } } .frame(maxHeight: .infinity) // 限制ErrorCard占用半个屏幕 */ } .padding() // 为所有内容添加padding .background( RoundedRectangle(cornerRadius: 10) .fill(Color.white) // 设置背景色为白色 ) .padding(5) } } struct ResultView_Preview: View { @State var input : String = "this is demo text" @State var results : [GrammarRes] @State var showResult : Bool = true @State var showKeyboard : Bool = true init() { let demoGrammarData = GrammarData.demoInstance() self.input = demoGrammarData.inputText self.results = demoGrammarData.results } var body: some View { ResultView(textContent: $input, results: $results, showResult: $showResult, showKeyboard: $showKeyboard) } } #Preview { ResultView_Preview() }