导入 XuXuCheck 工程(iOS 干化学尿液试纸分析 App)
从桌面工程复制而来,作为本仓库的 Xuxucheck/ 子目录。 为控制仓库体积做了两处删减: - 移除 Frameworks/opencv2.xcframework 下的两个 visionOS 切片 (xros-arm64、xros-arm64-simulator,合计约 106 MB),并同步删掉该 xcframework 内 Info.plist 里对应的两条 AvailableLibraries 记录, 只保留 ios-arm64 与 ios-arm64_x86_64-simulator。 - 移除全部 .DS_Store 与 xcuserdata/。 已用 xcodebuild 从本目录完整编译验证:BUILD SUCCEEDED, ProcessXCFramework 以 --platform ios 成功选中框架,产物含 3699 个 cv:: 符号 (OpenCV 确实链入),嵌入 framework 3 个,与移除无用 pod 之后的状态一致。 仓库约 206 MB,其中 OpenCV 203 MB、其余源码与依赖约 3 MB。
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Home.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct ScrollPreferenceKey: PreferenceKey {
|
||||
static var defaultValue: CGFloat = 0
|
||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||
value = nextValue()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct BlockItem: Identifiable {
|
||||
let id = UUID()
|
||||
var title: String
|
||||
var subtitle: String
|
||||
var text: String
|
||||
var image: String
|
||||
var background: String
|
||||
var logo: String
|
||||
var link: String?
|
||||
}
|
||||
|
||||
|
||||
var homeFuncblocks = [
|
||||
BlockItem(title: localizeString("Introduction"), subtitle: "-", text: "What's XuXuCheck", image: "home_intro", background: "Background 5", logo: "Logo 2",link: API.webProductIntroductionUrl + GetGeneralRequestParams()),
|
||||
BlockItem(title: localizeString("Manual"), subtitle: "-", text: "How to use XuXuCheck", image: "home_tutorial", background: "Background 4", logo: "Logo 4",link: API.webCourseUrl + GetGeneralRequestParams()),
|
||||
BlockItem(title: localizeString("ColorCard"), subtitle: "-", text: "Dry chemical Test strip's color card", image: "home_chart", background: "Background 1", logo: "Logo 1",link: API.webColorimetricCardUrl + GetGeneralRequestParams()),
|
||||
BlockItem(title: localizeString("Records"), subtitle: "-", text: "test records", image: "home_records", background: "Background 2", logo: "Logo 3",link: API.webrecordUrl + GetGeneralRequestParams())
|
||||
]
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// JS2SwiftModel.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/7/10.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
//A funny bug , the member name cannot have prefix "self".
|
||||
//if change jsSelf to selfData, compiling error will happen
|
||||
struct JS2SwiftData: Codable{
|
||||
var url: String?
|
||||
var phone_number: String?
|
||||
var redirect_url: String?
|
||||
var record_type: Int?
|
||||
var member_data: JSMember?
|
||||
var jsSelf: JSSelf?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case url,phone_number,redirect_url
|
||||
case record_type
|
||||
case member_data
|
||||
case jsSelf = "self"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct JS2SwiftModel: Codable {
|
||||
var command: String?
|
||||
var parameter: JS2SwiftData?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case command
|
||||
case parameter = "parameter"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct JSMember: Codable {
|
||||
var member_id: Int?
|
||||
var user_id: Int?
|
||||
var member_name: String?
|
||||
var member_avatar, member_birth, member_height, member_weight,member_contact,member_sex_name: String?
|
||||
var member_sex: Int?
|
||||
var member_default: Int?
|
||||
var member_main: Int?
|
||||
var created_at,updated_at: Int?
|
||||
// enum CodingKeys: String, CodingKey {
|
||||
// case member_name,member_avatar, member_birth, member_height, member_weight,member_contact,member_sex_name
|
||||
// case member_sex
|
||||
// case member_default
|
||||
// case member_main
|
||||
// case user_id
|
||||
// case member_id
|
||||
// case created_at,updated_at
|
||||
// }
|
||||
}
|
||||
|
||||
struct JSSelf: Codable{
|
||||
var user_id: Int?
|
||||
var username: String?
|
||||
var user_email, user_mobile, user_region, user_nickname: String?
|
||||
var user_avatar: String?
|
||||
var user_sex: Int?
|
||||
// enum CodingKeys: String, CodingKey {
|
||||
// case username,user_email, user_mobile, user_region, user_nickname,user_avatar
|
||||
// case user_id
|
||||
// case user_sex
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// LoginStatus.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/7/8.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@Observable
|
||||
class LoginStatus {
|
||||
var isLogin = false
|
||||
var routeToLoginView = false // set to true, tell us we need to route to LoginView()
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// MemberModel.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/17.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import ObjectMapper
|
||||
|
||||
class MemberModel: Mappable {
|
||||
var code: Int = 0
|
||||
var data: MemberData?
|
||||
var message: String?
|
||||
|
||||
required init?(map:Map) {
|
||||
|
||||
}
|
||||
|
||||
func mapping(map: Map) {
|
||||
data <- map["data"]
|
||||
code <- map["code"]
|
||||
message <- map["message"]
|
||||
}
|
||||
}
|
||||
class MemberData: Mappable{
|
||||
var usertoken: String?
|
||||
var userinfo: UserInfo?
|
||||
var defaultMember: Member?
|
||||
|
||||
required init?(map:Map) {
|
||||
|
||||
}
|
||||
|
||||
func mapping(map: Map) {
|
||||
usertoken <- map["user_token"]
|
||||
userinfo <- map["user_info"]
|
||||
defaultMember <- map["default_member"]
|
||||
}
|
||||
}
|
||||
|
||||
class UserInfo: Mappable{
|
||||
var user_id: Int = 0
|
||||
var username: String?
|
||||
var user_email, user_mobile, user_region, user_nickname: String?
|
||||
var user_avatar: String?
|
||||
var user_sex: Int?
|
||||
|
||||
required init?(map:Map) {
|
||||
|
||||
}
|
||||
|
||||
func mapping(map: Map) {
|
||||
user_id <- map["user_id"]
|
||||
username <- map["username"]
|
||||
user_email <- map["user_email"]
|
||||
user_mobile <- map["user_mobile"]
|
||||
user_region <- map["user_region"]
|
||||
user_nickname <- map["user_nickname"]
|
||||
user_avatar <- map["user_avatar"]
|
||||
user_sex <- map["user_sex"]
|
||||
}
|
||||
}
|
||||
|
||||
class Member: Mappable {
|
||||
var member_id: Int = 0
|
||||
var user_id: Int = 0
|
||||
var member_name: String?
|
||||
var member_avatar, member_birth, member_height, member_weight,member_contact,member_sex_name: String?
|
||||
var member_sex: Int?
|
||||
var member_default: Int?
|
||||
var member_main: Int?
|
||||
var created_at,updated_at: Int64?;
|
||||
|
||||
required init?(map:Map) {
|
||||
|
||||
}
|
||||
|
||||
func mapping(map: Map) {
|
||||
member_id <- map["member_id"]
|
||||
user_id <- map["user_id"]
|
||||
member_name <- map["member_name"]
|
||||
member_avatar <- map["member_avatar"]
|
||||
member_birth <- map["member_birth"]
|
||||
member_height <- map["member_height"]
|
||||
member_weight <- map["member_weight"]
|
||||
member_contact <- map["member_contact"]
|
||||
member_sex_name <- map["member_sex_name"]
|
||||
member_default <- map["member_default"]
|
||||
member_sex <- map["member_sex"]
|
||||
member_main <- map["member_main"]
|
||||
created_at <- map["created_at"]
|
||||
updated_at <- map["updated_at"]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// RecordModel.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/30.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import ObjectMapper
|
||||
|
||||
// MARK: - Welcome
|
||||
struct RecordModel: Codable {
|
||||
let usertoken: String
|
||||
let memberID: Int
|
||||
let sign: String
|
||||
let time, userid, color, items: Int
|
||||
let locator, recordType: Int
|
||||
let channel: String
|
||||
var data: [[Datum]]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case usertoken
|
||||
case memberID = "member_id"
|
||||
case sign, time, userid, color, items, locator
|
||||
case recordType = "record_type"
|
||||
case channel, data
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Datum
|
||||
struct Datum: Codable {
|
||||
let i: Int
|
||||
let v: String
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class RecordResultModel: Mappable {
|
||||
var code: Int = 0
|
||||
var data: RecordResult?
|
||||
var message: String?
|
||||
|
||||
required init?(map:Map) {
|
||||
|
||||
}
|
||||
|
||||
func mapping(map: Map) {
|
||||
data <- map["data"]
|
||||
code <- map["code"]
|
||||
message <- map["message"]
|
||||
}
|
||||
}
|
||||
class RecordResult: Mappable{
|
||||
var record_id: Int?
|
||||
|
||||
required init?(map:Map) {
|
||||
|
||||
}
|
||||
func mapping(map: Map) {
|
||||
record_id <- map["record_id"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Status.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
@Observable
|
||||
class Status {
|
||||
var showNavDetail = false
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// WebViewModel.swift
|
||||
// WKWebViewLocal
|
||||
//
|
||||
// Created by Gary Newby on 25/11/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WebKit
|
||||
|
||||
@Observable
|
||||
class WebViewModel {
|
||||
|
||||
var url: URL?
|
||||
var error: Error?
|
||||
var isLoading = false
|
||||
var backButtonIsEnabled = false
|
||||
|
||||
/// Load a file or a HTML string
|
||||
let loadFile = false
|
||||
|
||||
weak var webView: WKWebView?
|
||||
|
||||
var jsCommand: String?
|
||||
var jsParameter: JS2SwiftData?
|
||||
var hasNewCommand = false
|
||||
|
||||
func assignWebView(webView: WKWebView) {
|
||||
self.webView = webView
|
||||
|
||||
if (url != nil) {
|
||||
hasNewCommand = false
|
||||
self.webView?.load(URLRequest(url: url!))
|
||||
}else{
|
||||
if loadFile {
|
||||
loadFile(name: "index")
|
||||
} else {
|
||||
loadString(name: "index")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func loadFile(name: String) {
|
||||
guard let filePath = Bundle.main.path(forResource: name, ofType: "html", inDirectory: "Web_Assets") else {
|
||||
print("file not found:", name)
|
||||
return
|
||||
}
|
||||
let filePathURL = URL.init(fileURLWithPath: filePath)
|
||||
let fileDirectoryURL = filePathURL.deletingLastPathComponent()
|
||||
webView?.loadFileURL(filePathURL, allowingReadAccessTo: fileDirectoryURL)
|
||||
}
|
||||
|
||||
func loadString(name: String) {
|
||||
guard let filePath = Bundle.main.path(forResource: name, ofType: "html", inDirectory: "Web_Assets") else {
|
||||
print("file not found:", name)
|
||||
return
|
||||
}
|
||||
do {
|
||||
let html = try String(contentsOfFile: filePath, encoding: .utf8)
|
||||
/// baseURL needs to be set for local files to load correctly
|
||||
webView?.loadHTMLString(html, baseURL: Bundle.main.resourceURL?.appendingPathComponent("Web_Assets"))
|
||||
} catch {
|
||||
print("Error loading html")
|
||||
}
|
||||
}
|
||||
|
||||
func loadUrl(url: String){
|
||||
webView?.load(URLRequest(url: URL(string:url)!))
|
||||
}
|
||||
|
||||
func callJsImage(imageString: String){
|
||||
let script = "javascript:CallJS('SelectPhoto','data:image/jpeg;base64,\(imageString)')"
|
||||
webView?.evaluateJavaScript(script) { (result: Any?, error: Error?) in
|
||||
if let error = error {
|
||||
print("evaluateJavaScript error: \(error)")
|
||||
} else {
|
||||
print("evaluateJavaScript result: \(result ?? "")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func callJsBarcode(named: String) {
|
||||
let script = "javascript:CallJS('BarCode','\(named)')"
|
||||
webView?.evaluateJavaScript(script) { (result: Any?, error: Error?) in
|
||||
if let error = error {
|
||||
print("evaluateJavaScript error: \(error)")
|
||||
} else {
|
||||
print("evaluateJavaScript result: \(result ?? "")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isButtonVisible(_ action: String) -> Bool {
|
||||
switch action {
|
||||
case "goBack()":
|
||||
return backButtonIsEnabled
|
||||
case "changeText('hello from Swift')":
|
||||
return !backButtonIsEnabled
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// ModelProtocol.swift
|
||||
// WanAndroid_SwiftUI
|
||||
//
|
||||
// Created by zxc on 2023/6/12.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
internal protocol ModelProtocol {
|
||||
|
||||
func newJSONDecoder() -> JSONDecoder
|
||||
|
||||
func newJSONEncoder() -> JSONEncoder
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user