Initial commit
8
AIGrammar/AIGrammar.entitlements
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.in-app-payments</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
80
AIGrammar/AllTabView.swift
Normal file
@ -0,0 +1,80 @@
|
||||
//
|
||||
// AllTab.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct LearningToolApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
TabView {
|
||||
GrammarCheckView()
|
||||
.tabItem {
|
||||
Image(systemName: "book.fill")
|
||||
Text("Grammar Check")
|
||||
}
|
||||
|
||||
WordsView()
|
||||
.tabItem {
|
||||
Image(systemName: "text.bubble")
|
||||
Text("Words")
|
||||
}
|
||||
|
||||
TranslateView()
|
||||
.tabItem {
|
||||
Image(systemName: "globe")
|
||||
Text("Translate")
|
||||
}
|
||||
|
||||
SettingsView()
|
||||
.tabItem {
|
||||
Image(systemName: "gear")
|
||||
Text("Settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GrammarCheckView: View {
|
||||
var body: some View {
|
||||
// Your Grammar Check View content goes here.
|
||||
Text("Grammar Check")
|
||||
}
|
||||
}
|
||||
|
||||
struct WordsView: View {
|
||||
var body: some View {
|
||||
// Your Words View content goes here.
|
||||
Text("Words")
|
||||
}
|
||||
}
|
||||
|
||||
struct TranslateView: View {
|
||||
var body: some View {
|
||||
// Your Translate View content goes here.
|
||||
Text("Translate")
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView: View {
|
||||
var body: some View {
|
||||
// Your Settings View content goes here.
|
||||
Text("Settings")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#Preview {
|
||||
AllTab()
|
||||
}
|
||||
@ -1,13 +1,120 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
"images": [
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-20@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-20@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-29@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-29@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "38x38",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-38@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "38x38",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-38@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-40@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-40@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-60@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-60@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "64x64",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-64@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "64x64",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-64@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "68x68",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-68@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-76@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "83.5x83.5",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-83.5@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "1024x1024",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-1024.png",
|
||||
"scale": "1x",
|
||||
"platform": "ios"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "icon.wuruihong.com"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-1024.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-38@2x.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-38@3x.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-64@2x.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-64@3x.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-68@2x.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
AIGrammar/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
33
AIGrammar/Assets.xcassets/vipimg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"filename" : "crown.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
AIGrammar/Assets.xcassets/vipimg.imageset/crown.png
vendored
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
18
AIGrammar/CommView/LoadingView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// LoadingView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/7/7.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LoadingView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
LoadingView()
|
||||
}
|
||||
18
AIGrammar/GrammarSubView/CameraView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// CameraView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/4/3.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CameraView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
CameraView()
|
||||
}
|
||||
18
AIGrammar/GrammarSubView/IAPTestView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// IAPTestView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/6/19.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct IAPTestView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
IAPTestView()
|
||||
}
|
||||
18
AIGrammar/GrammarSubView/InputView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// InputView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/4/1.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct InputView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
InputView()
|
||||
}
|
||||
18
AIGrammar/GrammarSubView/ResultView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// ResultView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/4/1.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ResultView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ResultView()
|
||||
}
|
||||
18
AIGrammar/GrammarSubView/RichText.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// RichText.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/4/3.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RichText: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
RichText()
|
||||
}
|
||||
18
AIGrammar/GrammarSubView/ShareSheet.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// ShareSheet.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/4/3.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ShareSheet: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ShareSheet()
|
||||
}
|
||||
18
AIGrammar/View/GrammarCheckView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// GrammarCheckView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GrammarCheckView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
GrammarCheckView()
|
||||
}
|
||||
18
AIGrammar/View/IAPView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// IAPView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/7/9.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct IAPView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
IAPView()
|
||||
}
|
||||
18
AIGrammar/View/SettingsView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// SettingsView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
SettingsView()
|
||||
}
|
||||
18
AIGrammar/View/TranslateView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// TranslateView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TranslateView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TranslateView()
|
||||
}
|
||||
18
AIGrammar/View/WordsView.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// WordsView.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct WordsView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
WordsView()
|
||||
}
|
||||
8
AIGrammar/ViewModel/Config.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// config.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/28.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
22
AIGrammar/ViewModel/GrammarData.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// DemoData.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/4/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct GrammarRes {
|
||||
var tPlain : String
|
||||
var tType : String
|
||||
var tReason : String
|
||||
var tCorrection : [String]
|
||||
}
|
||||
|
||||
struct GrammarData {
|
||||
var tInputText : String
|
||||
var tCorrectText : String
|
||||
var tResult : [GrammarRes]
|
||||
}
|
||||
|
||||
8
AIGrammar/lib/ColorToString.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// ColorToString.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/3/28.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
8
AIGrammar/lib/CommFunc.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// CommFunc.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/8/5.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
8
AIGrammar/lib/IapManager.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Iap.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/7/3.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
10
AIGrammar/lib/InitAPP.swift
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// InitAPP.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/6/26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
8
AIGrammar/lib/LogManager.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// LogManager.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/7/3.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
233
AIGrammar/lib/NetworkManager.swift
Normal file
@ -0,0 +1,233 @@
|
||||
//
|
||||
// request.swift
|
||||
// AIGrammar
|
||||
//
|
||||
// Created by oscar on 2024/6/4.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import SwiftJWT
|
||||
import SwiftyBeaver
|
||||
|
||||
struct MyClaims: Claims {
|
||||
var deviceID: String
|
||||
var gid: Int
|
||||
var exp1: Int
|
||||
}
|
||||
|
||||
struct APIResponse<T: Decodable>: Decodable {
|
||||
let ret: Int
|
||||
let message: String
|
||||
let data: T?
|
||||
}
|
||||
|
||||
struct Translation: Identifiable, Codable, Equatable {
|
||||
var id = UUID()
|
||||
var input: String
|
||||
var translation: String
|
||||
}
|
||||
|
||||
struct TranslationResponse: Codable {
|
||||
let translation: String
|
||||
}
|
||||
|
||||
struct WordDetails {
|
||||
var word: String = ""
|
||||
var explanations: [String] = []
|
||||
var phrases: [String] = []
|
||||
var synonyms: [String] = []
|
||||
}
|
||||
|
||||
struct WordDetailsResponse: Codable {
|
||||
let word: String
|
||||
let explain: [String]?
|
||||
let phrase: [String]?
|
||||
let sync: [String]?
|
||||
|
||||
// Mapping to WordDetails for use in UI
|
||||
func toWordDetails() -> WordDetails {
|
||||
return WordDetails(
|
||||
word: word,
|
||||
explanations: explain ?? [],
|
||||
phrases: phrase ?? [],
|
||||
synonyms: sync ?? []
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct VIPStatusResponse: Codable {
|
||||
let id: Int
|
||||
let userid: String
|
||||
let username: String
|
||||
let vip: Int
|
||||
}
|
||||
|
||||
|
||||
struct NetworkManager {
|
||||
static let shared = NetworkManager()
|
||||
private let jwtSecret = globalEnvironment.jwtSecret
|
||||
|
||||
// 语法检查功能
|
||||
func checkGrammar(inputText: String, completion: @escaping ([GrammarRes]?, Error?) -> Void) {
|
||||
let url = globalEnvironment.grammarURL
|
||||
let headers: HTTPHeaders = createAuthorizationHeader()
|
||||
|
||||
let parameters: [String: Any] = [
|
||||
"input": inputText,
|
||||
"lang": "eng"
|
||||
]
|
||||
AF.request(url, method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers)
|
||||
.responseDecodable(of: [GrammarRes].self) { response in
|
||||
switch response.result {
|
||||
case .success(let results):
|
||||
completion(results, nil)
|
||||
case .failure(let error):
|
||||
completion(nil, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 单词的词典功能
|
||||
func fetchWordDetails(inputText: String, lang: String = "eng", completion: @escaping (Result<WordDetails, Error>) -> Void) {
|
||||
|
||||
guard !inputText.isEmpty else { return }
|
||||
let parameters: [String: Any] = ["input": inputText, "lang": lang]
|
||||
let url = globalEnvironment.dictURL
|
||||
let headers: HTTPHeaders = createAuthorizationHeader()
|
||||
|
||||
AF.request(url, method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers)
|
||||
.responseDecodable(of: WordDetailsResponse.self) { response in
|
||||
switch response.result {
|
||||
case .success(let detailsResponse):
|
||||
print("Success: Received data for \(detailsResponse.word)")
|
||||
let details = detailsResponse.toWordDetails() // Convert here
|
||||
completion(.success(details))
|
||||
case .failure(let error):
|
||||
print("Error: \(error)")
|
||||
print("Response Data: \(String(data: response.data ?? Data(), encoding: .utf8) ?? "No data")")
|
||||
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 翻译功能
|
||||
func translate(inputText: String, lang: String = "chs", completion: @escaping (Result<Translation, Error>) -> Void) {
|
||||
|
||||
guard !inputText.isEmpty else { return }
|
||||
let url = globalEnvironment.translateURL
|
||||
let parameters: [String: Any] = ["input": inputText, "lang": lang]
|
||||
let headers: HTTPHeaders = createAuthorizationHeader()
|
||||
|
||||
AF.request(url, method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers)
|
||||
.responseDecodable(of: TranslationResponse.self) { response in
|
||||
switch response.result {
|
||||
case .success(let translationResponse):
|
||||
let newTranslation = Translation(input: inputText, translation: translationResponse.translation)
|
||||
completion(.success(newTranslation))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 翻译的点赞、点踩功能
|
||||
func sendFeedback(input: String, output: String, isPositive: Bool) {
|
||||
let url = globalEnvironment.feedbackURL
|
||||
let parameters: [String: Any] = [
|
||||
"product": "trans",
|
||||
"input": input,
|
||||
"output": output,
|
||||
"res": isPositive ? "good" : "bad"
|
||||
]
|
||||
|
||||
let headers: HTTPHeaders = createAuthorizationHeader()
|
||||
AF.request(url, method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers).response { response in
|
||||
switch response.result {
|
||||
case .success(let data):
|
||||
print("Feedback sent successfully: \(String(describing: data))")
|
||||
case .failure(let error):
|
||||
print("Error sending feedback: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 查询VIP状态
|
||||
func getUserProfile(completion: @escaping (Result<VIPStatusResponse, Error>) -> Void) {
|
||||
let url = globalEnvironment.userURL
|
||||
|
||||
let parameters: [String: Any] = [:]
|
||||
let headers: HTTPHeaders = createAuthorizationHeader()
|
||||
|
||||
performRequest(
|
||||
endpoint: url,
|
||||
parameters: parameters,
|
||||
method: .post,
|
||||
encoding: URLEncoding.httpBody,
|
||||
headers: headers, // 示例:使用JWT token
|
||||
completion: { (result: Result<VIPStatusResponse, Error>) in
|
||||
switch result {
|
||||
case .success(let vipData):
|
||||
logger.info("VIP Status: \(vipData.vip)")
|
||||
completion(.success(vipData))
|
||||
case .failure(let error):
|
||||
logger.error("Error: \(error.localizedDescription)")
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func performRequest<T: Decodable>(
|
||||
endpoint: String,
|
||||
parameters: Parameters, // 明确使用 Alamofire 的 Parameters 类型
|
||||
method: HTTPMethod = .post,
|
||||
encoding: URLEncoding = .httpBody,
|
||||
headers: HTTPHeaders? = nil,
|
||||
completion: @escaping (Result<T, Error>) -> Void
|
||||
) {
|
||||
let url = endpoint
|
||||
let defaultHeaders: HTTPHeaders = [.contentType("application/x-www-form-urlencoded")]
|
||||
let combinedHeaders = headers ?? defaultHeaders
|
||||
|
||||
// 确保参数是正确的类型
|
||||
AF.request(url, method: .post, parameters: parameters, encoding: encoding, headers: combinedHeaders).responseDecodable(of: APIResponse<T>.self) { response in
|
||||
switch response.result {
|
||||
case .success(let apiResponse):
|
||||
if apiResponse.ret == 0, let data = apiResponse.data {
|
||||
completion(.success(data))
|
||||
} else {
|
||||
let error = NSError(domain: "", code: apiResponse.ret, userInfo: [NSLocalizedDescriptionKey: apiResponse.message])
|
||||
completion(.failure(error))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func createAuthorizationHeader() -> HTTPHeaders {
|
||||
// Generate JWT and return headers
|
||||
guard let jwtToken = generateJWT(deviceID: globalEnvironment.deviceID, gID: globalEnvironment.GID, jwtSecret: jwtSecret) else {
|
||||
return [:]
|
||||
}
|
||||
return ["Authorization": "Bearer \(jwtToken)"]
|
||||
}
|
||||
|
||||
private func generateJWT(deviceID: String, gID: Int, jwtSecret: String) -> String? {
|
||||
let claims = MyClaims(deviceID: deviceID, gid: gID, exp1: Int(Date().timeIntervalSince1970) + 86400)
|
||||
var jwt = JWT(claims: claims)
|
||||
do {
|
||||
let jwtSigner = JWTSigner.hs256(key: Data(jwtSecret.utf8))
|
||||
let signedJWT = try jwt.sign(using: jwtSigner)
|
||||
return signedJWT
|
||||
} catch {
|
||||
logger.error("JWT encoding failed with error: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||