Initial commit

This commit is contained in:
oscarz
2024-08-12 10:49:20 +08:00
parent 3002510aaf
commit 00fd0adf89
331 changed files with 53210 additions and 130 deletions

View File

@ -6,13 +6,211 @@
//
import SwiftUI
import ToastUI
struct WordsView: View {
@EnvironmentObject var globalEnv: GlobalEnvironment //
@State private var searchText = ""
@State private var showingResults = false
@State private var res = WordDetails()
@State private var isLoading = false //
@State private var showingToast = false // toast
@State private var toastText = ""
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
NavigationView {
ZStack {
//
Color.pink.opacity(0.2).edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
//
HStack {
TextField("word", text: $searchText, onCommit: fetchWordData)
.padding(.horizontal, 40)
.padding(.vertical, 10)
.background(Color(.systemGray6))
.cornerRadius(8)
.font(.headline)
.overlay(
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading).padding(.leading, 8)
)
Spacer()
Button("Cancel") {
self.searchText = ""
self.showingResults = false
self.hideKeyboard()
}
}
.background(Color(.systemPink).opacity(0.2))
.cornerRadius(5) //
.shadow(radius: 2) //
.padding(8)
// 使 Spacer
if !showingResults {
Spacer()
}
if showingResults {
//
HStack {
List {
Section(header: Text("Definitions").font(.headline)) {
ForEach(res.explanations, id: \.self) { definition in
Text(definition)
.font(.system(.subheadline))
.padding(.leading, 4)
}
}
Section(header: Text("Common Phrases").font(.headline)) {
ForEach(res.phrases, id: \.self) { phrase in
Text(phrase)
.font(.system(.subheadline))
.padding(.leading, 4)
}
}
Section(header: Text("Synonyms").font(.system(size: UIFont.systemFontSize * 1.2))) {
ForEach(res.synonyms, id: \.self) { synonym in
Text(synonym)
.font(.system(.subheadline))
.padding(.leading, 4)
}
}
}
.padding(8)
.cornerRadius(5) //
.frame(maxHeight: .infinity) // ErrorCard */
}
.listStyle(GroupedListStyle()) // 使
}
}
.toast(isPresented: $showingToast, dismissAfter: globalEnvironment.toastPresentMsNormal) {
HStack {
Image(systemName: "exclamationmark.bubble")
.foregroundColor(.yellow)
Text(toastText)
.foregroundColor(.black)
}
.padding()
.background(Color.white)
.cornerRadius(8)
.shadow(radius: 10)
}
//
if isLoading {
LoadingView()
}
}
.onTapGesture {
// TextField
self.hideKeyboard()
}
.navigationBarTitle("Words", displayMode: .inline)
}
}
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
//
func loadData() {
isLoading = true
}
func loadComplete(){
isLoading = false
}
private func fetchWordData() {
//
let trimmedText = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
//
if trimmedText.isEmpty {
showingToast = true
toastText = "Please enter some text."
return //
}
// 200
if trimmedText.count > globalEnvironment.MaxLenWords {
showingToast = true
toastText = "Input too long. Please re-enter the text."
return //
}
//
let checkRes = CommonFunc.shared.validateInputEng(input: trimmedText, isSingleWord: true)
if !checkRes.isValid {
showingToast = true
toastText = checkRes.message
return
}
/*
if trimmedText.range(of: "[^a-zA-Z]", options: .regularExpression) != nil {
showingToast = true
toastText = "Please enter valid characters."
return //
}
*/
loadData() //
NetworkManager.shared.fetchWordDetails(inputText: trimmedText) { result in
switch result {
case .success(let wordDetails):
DispatchQueue.main.async {
res = wordDetails
showingResults = true
}
logger.info("fetch words succ.", context: ["word":wordDetails.word, "explanations":wordDetails.explanations, "phrases":wordDetails.phrases, "synonyms":wordDetails.synonyms])
case .failure(let error):
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.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
}
}
}
loadComplete()
}
}
}
struct WordsView_Previews: PreviewProvider {
static var previews: some View {
WordsView()
}
}
#Preview {
WordsView()
}