导入 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,284 @@
|
||||
//
|
||||
// MineView.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/11.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MineView: View {
|
||||
@State var isDeleted = false
|
||||
@State var isPinned = false
|
||||
@State var isLoginModalPresented = false
|
||||
@State var isMyselfPresented = false
|
||||
|
||||
@Environment(LoginViewModel.self) var loginViewModel: LoginViewModel
|
||||
@Environment(LoginStatus.self) var loginStatus
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
profile
|
||||
|
||||
menu
|
||||
|
||||
setting
|
||||
}
|
||||
.listStyle(.automatic)
|
||||
.navigationTitle("Profile")
|
||||
}
|
||||
}
|
||||
|
||||
var profile: some View {
|
||||
VStack(spacing: 8) {
|
||||
|
||||
if !loginStatus.isLogin {
|
||||
Group{
|
||||
Image(systemName: "person")
|
||||
.symbolVariant(.circle.fill)
|
||||
.font(.system(size: 32))
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.blue, .blue.opacity(0.4))
|
||||
.padding()
|
||||
.background(Circle().fill(.ultraThinMaterial))
|
||||
.background(
|
||||
HexagonView()
|
||||
.offset(x: -50, y: -100)
|
||||
)
|
||||
.background(
|
||||
BlobView()
|
||||
.offset(x: 200, y: 0)
|
||||
.scaleEffect(0.6)
|
||||
)
|
||||
|
||||
Text("Sign In").font(.title.weight(.semibold))
|
||||
}.onTapGesture {
|
||||
isLoginModalPresented.toggle()
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
Group{
|
||||
//AsyncImage
|
||||
CachedAsyncImage(
|
||||
url: URL(string: API.imageUrl + Storage.shared.useravatar)
|
||||
) { image in
|
||||
image
|
||||
.resizable()
|
||||
.frame(width: 40, height: 40)
|
||||
.cornerRadius(45)
|
||||
} placeholder: {
|
||||
ZStack {
|
||||
Color.secondary.opacity(0.25)
|
||||
Image(systemName: "person")
|
||||
.imageScale(.large)
|
||||
.blendMode(.overlay)
|
||||
}
|
||||
}
|
||||
.symbolVariant(.circle.fill)
|
||||
.font(.system(size: 32))
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.blue, .blue.opacity(0.4))
|
||||
.padding()
|
||||
.background(Circle().fill(.ultraThinMaterial))
|
||||
.background(
|
||||
HexagonView()
|
||||
.offset(x: -50, y: -100)
|
||||
)
|
||||
.background(
|
||||
BlobView()
|
||||
.offset(x: 200, y: 0)
|
||||
.scaleEffect(0.6)
|
||||
)
|
||||
|
||||
Text(Storage.shared.username).font(.title.weight(.semibold))
|
||||
|
||||
Text(Storage.shared.email)
|
||||
.foregroundColor(.secondary)
|
||||
}.onTapGesture {
|
||||
isMyselfPresented.toggle()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
.fullScreenCover(isPresented: $isLoginModalPresented) { //sheet
|
||||
|
||||
if !loginStatus.isLogin {
|
||||
LoginView()
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $isMyselfPresented) { //sheet
|
||||
XuXuWebView(currentUrl: API.webMyAccountUrl + GetGeneralRequestParams())
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
}
|
||||
|
||||
@State var iScanQrPresented = false
|
||||
@State private var scannedCode: String?
|
||||
|
||||
@State var isColorPresented = false
|
||||
@State var isIntroPresented = false
|
||||
@State var isTutorPresented = false
|
||||
@State var isAboutPresented = false
|
||||
@State var isSettingPresented = false
|
||||
|
||||
// @State var isAnimating = false
|
||||
|
||||
var menu: some View {
|
||||
Section {
|
||||
//
|
||||
// Image(systemName: "face.smiling")
|
||||
// .offset(x: isAnimating ? 200 : 0)
|
||||
// .animation(.easeInOut(duration: 5).repeatForever(autoreverses: false), value: isAnimating)
|
||||
// .onAppear{
|
||||
// isAnimating.toggle()
|
||||
// }
|
||||
|
||||
|
||||
Button(
|
||||
action: {
|
||||
iScanQrPresented.toggle()
|
||||
},
|
||||
label: {
|
||||
NavigationLink(
|
||||
value: UUID(),
|
||||
label: {
|
||||
Label("qrcode", systemImage: "qrcode.viewfinder")
|
||||
}
|
||||
)
|
||||
}
|
||||
).buttonStyle(PlainButtonStyle())
|
||||
.sheet(isPresented: $iScanQrPresented) {
|
||||
CodeScannerView(codeTypes: [.qr]) { response in
|
||||
if case let .success(result) = response {
|
||||
scannedCode = result.string
|
||||
iScanQrPresented = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Text(scannedCode ?? "")
|
||||
//
|
||||
// NavigationLink {
|
||||
// //Text("Quality Control")
|
||||
// } label: {
|
||||
// Label("Quality Control", systemImage: "creditcard")
|
||||
// }.buttonStyle(PlainButtonStyle())
|
||||
|
||||
Button(
|
||||
action: {
|
||||
isColorPresented.toggle()
|
||||
},
|
||||
label: {
|
||||
NavigationLink(
|
||||
value: UUID(),
|
||||
label: {
|
||||
Label("Color Card", systemImage: "lanyardcard")
|
||||
}
|
||||
)
|
||||
}
|
||||
).buttonStyle(PlainButtonStyle())
|
||||
.fullScreenCover(isPresented: $isColorPresented) {
|
||||
XuXuWebView(currentUrl: API.webColorimetricCardUrl + GetGeneralRequestParams())
|
||||
}
|
||||
|
||||
//ImagePickerView()
|
||||
|
||||
Button(
|
||||
action: {
|
||||
isIntroPresented.toggle()
|
||||
},
|
||||
label: {
|
||||
NavigationLink(
|
||||
value: UUID(),
|
||||
label: {
|
||||
Label("Introduction", systemImage: "questionmark.folder")
|
||||
}
|
||||
)
|
||||
}
|
||||
).buttonStyle(PlainButtonStyle())
|
||||
.fullScreenCover(isPresented: $isIntroPresented) {
|
||||
XuXuWebView(currentUrl: API.webProductIntroductionUrl + GetGeneralRequestParams())
|
||||
}
|
||||
|
||||
|
||||
//UnitView()
|
||||
// Button(
|
||||
// action: {
|
||||
// isTutorPresented.toggle()
|
||||
// },
|
||||
// label: {
|
||||
// NavigationLink(
|
||||
// value: UUID(),
|
||||
// label: {
|
||||
// Label("Tutorial", systemImage: "questionmark")
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// ).buttonStyle(PlainButtonStyle())
|
||||
// .fullScreenCover(isPresented: $isTutorPresented) {
|
||||
// XuXuWebView(currentUrl: API.webManualUrl + GetGeneralRequestParams())
|
||||
// }
|
||||
|
||||
|
||||
Button(
|
||||
action: {
|
||||
isAboutPresented.toggle()
|
||||
},
|
||||
label: {
|
||||
NavigationLink(
|
||||
value: UUID(),
|
||||
label: {
|
||||
Label("About Us", systemImage: "info.circle")
|
||||
}
|
||||
)
|
||||
}
|
||||
).buttonStyle(PlainButtonStyle())
|
||||
.fullScreenCover(isPresented: $isAboutPresented) {
|
||||
XuXuWebView(currentUrl: API.webAboutUsUrl + GetGeneralRequestParams())
|
||||
}
|
||||
|
||||
}
|
||||
.accentColor(.secondary)
|
||||
.listRowSeparatorTint(.blue)
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
|
||||
var setting: some View {
|
||||
Section {
|
||||
|
||||
Button(
|
||||
action: {
|
||||
isSettingPresented.toggle()
|
||||
},
|
||||
label: {
|
||||
NavigationLink(
|
||||
value: UUID(),
|
||||
label: {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
)
|
||||
}
|
||||
).buttonStyle(PlainButtonStyle())
|
||||
.fullScreenCover(isPresented: $isSettingPresented) {
|
||||
XuXuWebView(currentUrl: API.webSettingUrl + GetGeneralRequestParams())
|
||||
|
||||
// ImagePickerView()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
.accentColor(.secondary)
|
||||
.listRowSeparatorTint(.blue)
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
MineView()
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
//
|
||||
// UnitView.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/7/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
//struct UnitView
|
||||
|
||||
struct DemoView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct MyButtonView : View {
|
||||
|
||||
@Binding var showing: Bool
|
||||
var title: String
|
||||
var hideAll: ()->()
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
self.hideAll()
|
||||
self.showing.toggle()
|
||||
}) {
|
||||
Text(title)
|
||||
.font(.system(size: 18))
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct UnitView: View {
|
||||
let bgColor = Color(hex: "E8F2F0")
|
||||
let alertColor = Color(hex: "ee6c4d")
|
||||
let topToastColor = Color(hex: "4067CC")
|
||||
let bottomToastColor = Color(hex: "bfdcae")
|
||||
let topFloatColor = Color(hex: "61A117")
|
||||
let bottomFloatColor = Color(hex: "3d5a80")
|
||||
let leftRightToastColor = Color(hex: "85adad")
|
||||
|
||||
@State var showAlert = false
|
||||
@State var showTopToast = false
|
||||
@State var showBottomToast = false
|
||||
@State var showTopFloater = false
|
||||
@State var showBottomFloater = false
|
||||
@State var showDemoView = false
|
||||
@State var showLeftToastView = false
|
||||
@State var showRightToastView = false
|
||||
|
||||
func dismissAll() {
|
||||
self.showAlert = false
|
||||
self.showTopToast = false
|
||||
self.showBottomToast = false
|
||||
self.showTopFloater = false
|
||||
self.showBottomFloater = false
|
||||
self.showLeftToastView = false
|
||||
self.showRightToastView = false
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
||||
if #available(iOS 16.0, *, macOS 13.0) {
|
||||
NavigationStack {
|
||||
content
|
||||
.navigationDestination(isPresented: $showDemoView, destination: {
|
||||
DemoView()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
NavigationView {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var content: some View {
|
||||
GeometryReader { geometryProxy in
|
||||
VStack {
|
||||
VStack(spacing: 30) {
|
||||
MyButtonView(showing: self.$showAlert, title: "Alert", hideAll: self.dismissAll)
|
||||
MyButtonView(showing: self.$showTopToast, title: "Top Toast", hideAll: self.dismissAll)
|
||||
MyButtonView(showing: self.$showBottomToast, title: "Bottom Toast", hideAll: self.dismissAll)
|
||||
MyButtonView(showing: self.$showTopFloater, title: "Top Floater", hideAll: self.dismissAll)
|
||||
MyButtonView(showing: self.$showBottomFloater, title: "Bottom Floater", hideAll: self.dismissAll)
|
||||
MyButtonView(showing: self.$showLeftToastView, title: "Left Toast", hideAll: self.dismissAll)
|
||||
MyButtonView(showing: self.$showRightToastView, title: "Right Toast", hideAll: self.dismissAll)
|
||||
}
|
||||
|
||||
|
||||
.present(isPresented: self.$showAlert, type: .alert, animation: Animation.interactiveSpring(), duration: nil, closeOnTap: false) {
|
||||
self.createAlertView()
|
||||
}
|
||||
|
||||
.present(isPresented: self.$showTopToast, type: .toast, position: .top, duration: 6.0, onTap: {
|
||||
showDemoView = true
|
||||
}, onToastDismiss: {
|
||||
print("on toast hide")
|
||||
}) {
|
||||
self.createTopToastView()
|
||||
}
|
||||
.present(isPresented: self.$showBottomToast, type: .toast, position: .bottom, onTap: {
|
||||
showDemoView = true
|
||||
}) {
|
||||
self.createBottomToastView()
|
||||
}
|
||||
.present(isPresented: self.$showTopFloater, type: .floater(), position: .top, animation: Animation.spring(), horizontalPadding: 60, onTap: {
|
||||
showDemoView = true
|
||||
}) {
|
||||
self.createTopFloaterView()
|
||||
}
|
||||
.present(isPresented: self.$showBottomFloater, type: .floater(), position: .bottom,animation: Animation.spring(), duration: 3, onTap: {
|
||||
showDemoView = true
|
||||
}) {
|
||||
self.createBottomFloaterView()
|
||||
}
|
||||
.present(isPresented: $showLeftToastView, type: .leftToastView, position: .bottom, duration: 3, onTap: {
|
||||
showDemoView = true
|
||||
}) {
|
||||
self.createLeftToastView()
|
||||
}
|
||||
|
||||
.present(isPresented: $showRightToastView, type: .rightToastView, position: .top, duration: 3, onTap: {
|
||||
showDemoView = true
|
||||
}) {
|
||||
self.createRightToastView()
|
||||
}
|
||||
|
||||
}
|
||||
NavigationLink(destination: DemoView(), isActive: $showDemoView) {
|
||||
EmptyView()
|
||||
}
|
||||
.frame(width: geometryProxy.size.width, height: geometryProxy.size.height)
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.navigationViewStyle(.automatic)
|
||||
.background(self.bgColor)
|
||||
.buttonStyle(.plain)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
||||
func createAlertView() -> some View {
|
||||
VStack(spacing: 10) {
|
||||
Image("corona")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fit)
|
||||
.frame(width: 100, height: 100)
|
||||
|
||||
Text("Hey There!!!")
|
||||
.foregroundColor(.white)
|
||||
.font(.system(size: 20))
|
||||
.fontWeight(.bold)
|
||||
|
||||
Text("Please click on dismiss to hide.")
|
||||
.font(.system(size: 16))
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
self.showAlert = false
|
||||
}) {
|
||||
Text("Dismiss")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.black)
|
||||
.fontWeight(.bold)
|
||||
}
|
||||
.frame(width: 100, height: 40)
|
||||
.background(Color.white)
|
||||
.cornerRadius(20.0)
|
||||
}
|
||||
.padding(EdgeInsets(top: 20, leading: 20, bottom: 40, trailing: 20))
|
||||
.frame(width: 300, height: 300)
|
||||
.background(self.alertColor)
|
||||
.cornerRadius(10.0)
|
||||
.shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
|
||||
}
|
||||
|
||||
func createTopToastView() -> some View {
|
||||
VStack {
|
||||
Spacer(minLength: 30)
|
||||
HStack() {
|
||||
Image("mike")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fill)
|
||||
.frame(width: 50, height: 50)
|
||||
.cornerRadius(25)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack {
|
||||
Text("Mike")
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(.white)
|
||||
.fontWeight(.bold)
|
||||
Spacer()
|
||||
Text("10:10")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
|
||||
Text("Great things never come from comfort zones.")
|
||||
.lineLimit(2)
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
}.padding(15)
|
||||
}
|
||||
.frame(height: 130)
|
||||
.background(self.topToastColor)
|
||||
}
|
||||
|
||||
func createBottomToastView() -> some View {
|
||||
VStack {
|
||||
HStack(alignment: .center) {
|
||||
Image("pizza")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fill)
|
||||
.frame(width: 50, height: 50)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Whooohoo!!")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(Color(hex: "206a5d"))
|
||||
.fontWeight(.bold)
|
||||
|
||||
Text("Your order has been placed succesfully! Sit tight we deliver the food in 20 minutes.")
|
||||
.lineLimit(2)
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(Color(hex: "206a5d"))
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(15)
|
||||
.frame(maxWidth: .infinity, maxHeight: 100)
|
||||
.background(self.bottomToastColor)
|
||||
}
|
||||
|
||||
func createTopFloaterView() -> some View {
|
||||
VStack {
|
||||
HStack() {
|
||||
Image("mike")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fill)
|
||||
.frame(width: 50, height: 50)
|
||||
.cornerRadius(25)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack {
|
||||
Text("Mike")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.white)
|
||||
.fontWeight(.bold)
|
||||
Spacer()
|
||||
Text("10:10")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
|
||||
Text("Hey, Welcome to Simform Solutions")
|
||||
.lineLimit(2)
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white)
|
||||
|
||||
}
|
||||
}.padding(15)
|
||||
}
|
||||
.frame(height: 110)
|
||||
.background(self.topFloatColor)
|
||||
.cornerRadius(15)
|
||||
}
|
||||
|
||||
func createBottomFloaterView() -> some View {
|
||||
HStack(spacing: 15) {
|
||||
Image("travel")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fill)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(10.0)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Ever thought of taking a break from work and travel?")
|
||||
.foregroundColor(.white)
|
||||
.fontWeight(.bold)
|
||||
.lineLimit(3)
|
||||
|
||||
Text("If you have ever thought of something like a career break or sabbatical, you need to realize that there will never be a perfect time.")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
}
|
||||
.padding(15)
|
||||
.frame(width: 350, height: 160)
|
||||
.background(self.bottomFloatColor)
|
||||
.cornerRadius(20.0)
|
||||
}
|
||||
|
||||
func createLeftToastView() -> some View {
|
||||
HStack {
|
||||
Text("Left Toast View!!")
|
||||
.lineLimit(2)
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(.white)
|
||||
.font(.title)
|
||||
Image("leftToastImage")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fill)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(10.0)
|
||||
}
|
||||
.frame(width: 200, height: 90)
|
||||
.background(self.leftRightToastColor)
|
||||
.cornerRadius(15)
|
||||
}
|
||||
|
||||
func createRightToastView() -> some View {
|
||||
HStack {
|
||||
Image("rightToastImage")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: ContentMode.fill)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(10.0)
|
||||
Text("Right Toast View!!")
|
||||
.lineLimit(2)
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(.white)
|
||||
.font(.title)
|
||||
}
|
||||
.frame(width: 200, height: 90)
|
||||
.background(self.leftRightToastColor)
|
||||
.cornerRadius(15)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
}
|
||||
Reference in New Issue
Block a user