Files

498 lines
20 KiB
Swift

//
// 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
}, 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()
}
.frame(height: 20)
.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
})
}
}
}