Files
swiftGrammar/AIGrammar/GrammarSubView/InputView.swift
2024-08-12 10:49:20 +08:00

230 lines
9.0 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// InputView.swift
// AIGrammar
//
// Created by oscar on 2024/4/1.
//
import SwiftUI
import ToastUI
fileprivate struct ProgressBar: View {
@Binding var value: Float
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.foregroundColor(.gray.opacity(0.3))
.frame(width: geometry.size.width, height: geometry.size.height)
Rectangle()
.foregroundColor(Color.green)
.frame(width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width), height: geometry.size.height)
.animation(.linear, value: value)
}
.cornerRadius(45.0)
}
}
}
struct InputView: View {
@Binding var textInput: String
@Binding var progressValue: Float
@Binding var showKeyboard: Bool
@Binding var showBuyProView: Bool
@Binding var showResult: Bool
@Binding var results : [GrammarRes]
@Binding var isLoading: Bool //
@Binding var showingToast: Bool // toast
@Binding var toastText: String
@FocusState private var isTextEditorFocused: Bool
var body: some View {
VStack {
// TextEditor
TextEditor(text: $textInput)
.onTapGesture {
// TextEditor
self.showKeyboard = true //
self.showBuyProView = false // BuyProView
}
.focused($isTextEditorFocused)
.padding(5)
.background(Color.white)
.cornerRadius(5)
.padding(5)
.onAppear {
if showKeyboard {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.isTextEditorFocused = true
}
}
}
//Divider() // 线TextEditor
//
ProgressBar(value: $progressValue).frame(height: 3)
HStack {
Button("Clear") {
textInput = ""
progressValue = 0
}
Spacer()
Button("Check") {
//
let trimmedText = textInput.trimmingCharacters(in: .whitespacesAndNewlines)
//
if trimmedText.isEmpty {
showingToast = true
toastText = "Please enter some text."
return //
}
// 200
let MaxLen = globalEnvironment.isVip ? globalEnvironment.MaxLenGrammarCheckVIP : globalEnvironment.MaxLenGrammarCheckFree
if trimmedText.count > MaxLen {
showingToast = true
toastText = "Input too long. Please re-enter the text."
logger.info("input too lang, inputlen: \(trimmedText.count), maxlen: \(MaxLen), vip: \(globalEnvironment.isVip)")
return //
}
//
let checkRes = CommonFunc.shared.validateInputEng(input: trimmedText)
if !checkRes.isValid {
showingToast = true
toastText = checkRes.message
return
}
/*
if trimmedText.range(of: "[^a-zA-Z0-9 .,;:!?'\"@-]", options: .regularExpression) != nil {
showingToast = true
toastText = "Please enter valid characters."
return //
}
*/
loadData() //
// Send the request to the server
NetworkManager.shared.checkGrammar(inputText: trimmedText) { result in
switch result {
case .success(let results):
// Update the main UI with the results
loadComplete()
DispatchQueue.main.async {
self.results = results
self.showResult = true
self.showKeyboard = false
self.showBuyProView = false
hideKeyboard()
logger.info("grammar check succ.")
}
case .failure(let error):
loadComplete()
switch error {
case .businessError(let ret, let message):
//
logger.error("Business error - Ret: \(ret), Message: \(message)")
DispatchQueue.main.async {
showingToast = true
switch ret{
case globalEnvironment.GrammarCheckOK:
toastText = globalEnvironment.GrammarOKToast
case globalEnvironment.RetCodeFreeLimited:
toastText = globalEnvironment.FreeLimitedToast
case globalEnvironment.RetCodeDirtyInput:
toastText = globalEnvironment.DirtyInputErrToast
default:
toastText = globalEnvironment.OtherServerErrToast
}
}
case .other(let error):
logger.error("network error occurred: \(error.localizedDescription)")
DispatchQueue.main.async {
showingToast = true
toastText = globalEnvironment.NetWorkErrToast
}
}
}
}
}
.padding(.vertical, 10)
.padding(.horizontal, 40)
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(5)
.font(.subheadline) //
}
.padding(.bottom)
}
.padding() // padding
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white) //
)
.padding(5)
.onTapGesture {
//
self.isTextEditorFocused = false
showBuyProView = true
}
}
//
func loadData() {
isLoading = true
}
func loadComplete(){
isLoading = false
}
//
func toggleFocus() {
isTextEditorFocused.toggle()
}
//
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct InputView_Preview: View{
@State private var textInput: String
@State private var progressValue: Float = 0
@State private var showKeyboard: Bool = false
@State private var showBuyProView: Bool = true
@State private var showResult : Bool = false
@State private var results : [GrammarRes]
//
@State private var isLoading = false //
@State private var showingToast = false // toast
@State private var toastText = ""
init(){
let demoGrammarData = GrammarData.demoInstance()
self.textInput = demoGrammarData.inputText
self.results = demoGrammarData.results
}
var body: some View {
VStack {
InputView(textInput: $textInput, progressValue: $progressValue, showKeyboard: $showKeyboard, showBuyProView: $showBuyProView, showResult: $showResult, results: $results, isLoading: $isLoading, showingToast: $showingToast, toastText: $toastText)
}
}
}
#Preview {
InputView_Preview()
}