207 lines
6.8 KiB
Swift
207 lines
6.8 KiB
Swift
//
|
||
// 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..<substr.endIndex){
|
||
let tmpABStr = AttributedString(String(substr[currentIndex..<range.lowerBound]))
|
||
outstr.append(tmpABStr)
|
||
outstr.append(getColoredText(str: res.plain, type: res.type, index: index))
|
||
index = index + 1
|
||
currentIndex = range.upperBound
|
||
}
|
||
}
|
||
let tmpABStr = AttributedString(String(substr[currentIndex..<substr.endIndex]))
|
||
outstr.append(tmpABStr)
|
||
return Text(outstr)
|
||
}
|
||
|
||
/*
|
||
func styledText() -> 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()
|
||
}
|