add iOS
This commit is contained in:
@@ -0,0 +1,497 @@
|
||||
//
|
||||
// SideMenuView.swift
|
||||
// SFI
|
||||
//
|
||||
// Created by Mac on 2024/10/12.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import ApplicationLibrary
|
||||
import WebKit
|
||||
|
||||
import Libbox
|
||||
import Library
|
||||
|
||||
struct SideMenuView: View {
|
||||
|
||||
@Binding var isPresented: Bool
|
||||
@Binding var isLoggedIn: Bool
|
||||
|
||||
@State private var isLoading = false
|
||||
@State private var errorMessage: String?
|
||||
|
||||
@State private var plandes: SubscribeReponseClass?
|
||||
@State private var size: CGSize = .zero
|
||||
@State private var avator = UserManager.shared.getUserInfo().avator
|
||||
@State private var emailid = UserManager.shared.getUserInfo().email
|
||||
|
||||
@EnvironmentObject private var environments: ExtensionEnvironments
|
||||
@State private var alert: Alert?
|
||||
|
||||
|
||||
@State private var showAlert = false
|
||||
@State private var isInviteActive = false
|
||||
|
||||
@State private var isLogouting = false
|
||||
|
||||
|
||||
@AppStorage("paymentURLKey") private var paymentURLKey = ""
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack() {
|
||||
|
||||
// Navigation Bar
|
||||
// 用户信息区域
|
||||
ZStack{
|
||||
|
||||
HStack{
|
||||
Button(action: {
|
||||
isPresented = false // Close the side menu
|
||||
}, label: {
|
||||
|
||||
Image(systemName: "chevron.left")
|
||||
.foregroundColor(.white)
|
||||
|
||||
Text("返回")
|
||||
.foregroundColor(.white)
|
||||
}).padding(10) // 增加可点击区域
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
|
||||
Text("设置")
|
||||
.fontWeight(.bold).lineLimit(1)
|
||||
}
|
||||
.padding()
|
||||
// .padding(.top,edges.top)
|
||||
.foregroundColor(.white)
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
|
||||
// Profile Section
|
||||
VStack {
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
// AsyncImage(url: URL(string: avator)){ phase in
|
||||
// if let image = phase.image {
|
||||
// image // Displays the loaded image.
|
||||
// } else if phase.error != nil {
|
||||
// Color.red // Indicates an error.
|
||||
// } else {
|
||||
// Color.blue // Acts as a placeholder.
|
||||
// }
|
||||
// }.frame(width: 50, height: 50)
|
||||
// .clipShape(Circle())
|
||||
// Image("applogo").resizable().frame(width: 50, height: 50).clipShape(Circle())
|
||||
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("账户信息:")
|
||||
.font(.headline).fontWeight(.light)
|
||||
|
||||
Text(emailid)
|
||||
.font(.headline)
|
||||
.bold()
|
||||
|
||||
}
|
||||
Spacer()
|
||||
/*
|
||||
Spacer()
|
||||
Button {
|
||||
showAlert = true
|
||||
} label: {
|
||||
|
||||
Text("退出登录").foregroundColor(.red)
|
||||
Image(systemName: "rectangle.portrait.and.arrow.forward")
|
||||
.foregroundColor(.red)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 4, height: 4)
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
.padding()
|
||||
.background(Color.white.opacity(0.1))
|
||||
.cornerRadius(12)
|
||||
.shadow(color: .gray.opacity(0.1), radius: 5, x: 0, y: 5)
|
||||
|
||||
if (paymentURLKey.count > 3){
|
||||
HStack {
|
||||
|
||||
if isLoading {
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle())
|
||||
.padding()
|
||||
}
|
||||
|
||||
if let errorMessage = errorMessage {
|
||||
Text(errorMessage)
|
||||
.bold()
|
||||
.foregroundColor(.red)
|
||||
.multilineTextAlignment(.center) // 确保多行文本居中
|
||||
.padding()
|
||||
}else{
|
||||
|
||||
if let plandesss = self.plandes {
|
||||
if plandesss.transferEnable > 0 {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
|
||||
// Text("订阅详情:") .font(.subheadline)
|
||||
|
||||
|
||||
Text(plandesss.plan?.name ?? "")
|
||||
.font(.subheadline)
|
||||
let u = plandesss.d/1024/1024/1024
|
||||
let t = plandesss.transferEnable/1024/1024/1024
|
||||
|
||||
Spacer().frame(height: 10)
|
||||
|
||||
Text("已用: \(u) GB / 总计:\(t) GB")
|
||||
.font(.subheadline).bold()
|
||||
|
||||
HStack {
|
||||
// White bar on the left
|
||||
// RoundedRectangle(cornerRadius: 10)
|
||||
// .fill(Color.red)
|
||||
// .frame(width: 300*CGFloat(plandesss.d)/CGFloat(plandesss.transferEnable), height: 20)
|
||||
//
|
||||
Text("").frame(height: 20).frame(minWidth: (CGFloat(plandesss.d)/CGFloat(plandesss.transferEnable))<=0.1 ? 20 : 300*(CGFloat(plandesss.d)/CGFloat(plandesss.transferEnable))).background(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.fill(
|
||||
Color.red
|
||||
)
|
||||
)
|
||||
Spacer() // Fill the remaining space to push the white rectangle to the left
|
||||
}
|
||||
.frame(height: 20) // Set the total width and height for the bar
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.fill(
|
||||
Color.gray.opacity(0.5)
|
||||
)
|
||||
)
|
||||
.padding()
|
||||
|
||||
|
||||
|
||||
|
||||
// ScrollView {
|
||||
// }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||
// AttributedText(htmlContent: plan.content, size: $size)
|
||||
// .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, idealHeight: size.height, maxHeight: .infinity)
|
||||
// .background(.clear)
|
||||
|
||||
}
|
||||
Spacer()
|
||||
}else{
|
||||
Spacer()
|
||||
Text("暂无订阅")
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}.padding()
|
||||
.background(Color.white.opacity(0.1))
|
||||
.cornerRadius(12)
|
||||
.shadow(color: .gray.opacity(0.1), radius: 5, x: 0, y: 5)
|
||||
}
|
||||
} .frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.foregroundColor(.white)
|
||||
|
||||
// Menu Items
|
||||
// List {
|
||||
// NavigationLink(destination: WebShuntView()) {
|
||||
// MenuItem(icon: "globe", title: "App日志", color: .white, isNew: false)
|
||||
// }
|
||||
LazyVStack(spacing: 10, content: {
|
||||
NavigationLink(destination: SupportTicketView()) {
|
||||
MenuItem(icon: "listclipboard", title: "我的工单", color: .white, isNew: false)
|
||||
}
|
||||
Divider() // 分隔线
|
||||
|
||||
if (paymentURLKey.count > 3){
|
||||
|
||||
NavigationLink(destination: UpgradeView()) {
|
||||
MenuItem(icon: "crown.fill", title: "升级套餐", color: .yellow, isNew: true)
|
||||
}
|
||||
Divider() // 分隔线
|
||||
NavigationLink(destination: OrderListView()) {
|
||||
MenuItem(icon: "checkout", title: "我的订单", color: .white, isNew: false)
|
||||
}
|
||||
|
||||
Divider() // 分隔线
|
||||
NavigationLink(destination: InviteListView(isPresented: $isInviteActive)) {
|
||||
MenuItem(icon: "star.fill", title: "邀请中心", color: .white, isNew: false)
|
||||
}
|
||||
Divider() // 分隔线
|
||||
|
||||
|
||||
}else{
|
||||
|
||||
NavigationLink(destination: MessageCenterView()) {
|
||||
MenuItem(icon: "message.badge.circle", title: "消息通知", color: .white, isNew: false)
|
||||
}
|
||||
Divider() // 分隔线
|
||||
}
|
||||
|
||||
|
||||
NavigationLink(destination: QuestionView()) {
|
||||
MenuItem(icon: "questionmark.app", title: "问题解答", color: .white, isNew: false)
|
||||
}
|
||||
|
||||
Divider() // 分隔线
|
||||
|
||||
NavigationLink(destination: SupportView()) {
|
||||
MenuItem(icon: "headphones", title: "联系客服", color: .white, isNew: false)
|
||||
}
|
||||
Divider() // 分隔线
|
||||
NavigationLink(destination: AboutUsView()) {
|
||||
MenuItem(icon: "info.circle.fill", title: "关于我们", color: .white, isNew: false)
|
||||
}
|
||||
Divider() // 分隔线
|
||||
}).padding()
|
||||
|
||||
Button(action: {
|
||||
// Trigger the payment action
|
||||
// showAlert = true
|
||||
|
||||
alert = Alert(YesOrNOMessage: "确定退出登录吗?", {
|
||||
isLogouting=true
|
||||
UserManager.shared.clearUserData()
|
||||
//删除订阅信息
|
||||
Task {
|
||||
//await reloadSubscribe()
|
||||
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
|
||||
isLoggedIn = false
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}, label: {
|
||||
HStack {
|
||||
Image(systemName: "trash.fill")
|
||||
Text("退出登录")
|
||||
|
||||
}
|
||||
.font(.headline)
|
||||
.foregroundColor(.white)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(Color.blue)
|
||||
.cornerRadius(10)
|
||||
|
||||
}).padding()
|
||||
|
||||
}
|
||||
|
||||
// }
|
||||
// .listStyle(PlainListStyle())
|
||||
|
||||
}.background(
|
||||
BackgroundBg()
|
||||
).modifier(ActivityIndicatorModifier(isLoading: isLogouting, color: Color.black.opacity(0.8), lineWidth: 1))
|
||||
.onAppear {
|
||||
Task {
|
||||
await reloadSubscribe()
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
|
||||
}.alertBinding($alert)
|
||||
|
||||
}
|
||||
|
||||
private func writeProfilePreviewList() async throws {
|
||||
let profiles = try await ProfileManager.list()
|
||||
|
||||
for profile in profiles {
|
||||
print("detele : \(profile.path) \(profile.remoteURL ?? "" )")
|
||||
await deleteProfile(profile)
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteProfile(_ profile: Profile) async {
|
||||
do {
|
||||
_ = try await ProfileManager.delete(profile)
|
||||
} catch {
|
||||
alert = Alert(error)
|
||||
return
|
||||
}
|
||||
environments.profileUpdate.send()
|
||||
}
|
||||
|
||||
|
||||
@MainActor
|
||||
public func reloadSubscribe() async {
|
||||
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
|
||||
let userInfoUrl = URL(string: "\(UserManager.shared.baseURL())user/getSubscribe")!
|
||||
var request = URLRequest(url: userInfoUrl)
|
||||
request.httpMethod = "GET"
|
||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.addValue(UserManager.shared.getAutoData(), forHTTPHeaderField: "Authorization")
|
||||
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
|
||||
if let error = error {
|
||||
self.errorMessage = "套餐数据请求失败: \(error.localizedDescription)"
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
self.errorMessage = "套餐数据请求失败:数据为空"
|
||||
return
|
||||
}
|
||||
// Parse the user info response
|
||||
if let Subscribe = try? JSONDecoder().decode(SubscribeReponse.self, from: data) {
|
||||
|
||||
if let data = Subscribe.data {
|
||||
|
||||
plandes = data
|
||||
emailid = data.email
|
||||
|
||||
UserManager.shared.storeUserInfo(email: emailid, avator: "")
|
||||
// UserManager.shared.storeSuburlData(data: data.subscribeURL)
|
||||
|
||||
}else{
|
||||
self.errorMessage = Subscribe.message ?? ""
|
||||
}
|
||||
|
||||
|
||||
}else{
|
||||
self.errorMessage = "套餐数据请求失败"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task.resume()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Sample Destination Views for each menu item
|
||||
struct UpgradeView: View {
|
||||
@State private var isSubscriptionActive = false
|
||||
var body: some View {
|
||||
SubscriptionView(isPresented: $isSubscriptionActive)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct WebShuntView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .trailing, content: {
|
||||
LogView()
|
||||
ProfileView()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct Free30DaysView: View {
|
||||
@State private var islogined = false
|
||||
var body: some View {
|
||||
InviteView(isPresented: $islogined)
|
||||
}
|
||||
}
|
||||
|
||||
struct AboutUsView: View {
|
||||
var body: some View {
|
||||
SettingsAboutView()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct MenuItem: View {
|
||||
let icon: String
|
||||
let title: String
|
||||
let color: Color
|
||||
let isNew: Bool?
|
||||
|
||||
var body: some View {
|
||||
// Button {
|
||||
//
|
||||
// } label: {
|
||||
//
|
||||
// }
|
||||
|
||||
HStack {
|
||||
|
||||
if UIImage(systemName: icon) != nil{
|
||||
|
||||
Image(systemName: icon)
|
||||
.foregroundColor(color).tint(.white)
|
||||
.frame(width: 24, height: 24)
|
||||
|
||||
}else{
|
||||
|
||||
Image(icon).resizable()
|
||||
.foregroundColor(.white).tint(.white)
|
||||
.frame(width: 24, height: 24)
|
||||
|
||||
}
|
||||
Text(title)
|
||||
.foregroundColor(.white)
|
||||
.font(.system(size: 18))
|
||||
Spacer()
|
||||
|
||||
if isNew == true {
|
||||
Circle()
|
||||
.fill(Color.red)
|
||||
.frame(width: 8, height: 8)
|
||||
}
|
||||
}
|
||||
|
||||
.padding(.vertical, 10)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct AttributedText: UIViewRepresentable {
|
||||
let htmlContent: String
|
||||
@Binding var size: CGSize
|
||||
|
||||
private let webView = WKWebView()
|
||||
var sizeObserver: NSKeyValueObservation?
|
||||
|
||||
func makeUIView(context: Context) -> WKWebView {
|
||||
webView.scrollView.isScrollEnabled = false //<-- Here
|
||||
webView.navigationDelegate = context.coordinator
|
||||
return webView
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: WKWebView, context: Context) {
|
||||
uiView.loadHTMLString(htmlContent, baseURL: nil)
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
class Coordinator: NSObject, WKNavigationDelegate {
|
||||
let parent: AttributedText
|
||||
var sizeObserver: NSKeyValueObservation?
|
||||
|
||||
init(parent: AttributedText) {
|
||||
self.parent = parent
|
||||
sizeObserver = parent.webView.scrollView.observe(\.contentSize, options: [.new], changeHandler: { (object, change) in
|
||||
parent.size = change.newValue ?? .zero
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user