// // SettingsView.swift // AIGrammar // // Created by oscar on 2024/3/27. // import SwiftUI import ToastUI import SafariServices import FirebaseAnalytics import SwiftyBeaver struct FullScreenSafariView: UIViewControllerRepresentable { let url: URL var onDismiss: (() -> Void)? func makeUIViewController(context: UIViewControllerRepresentableContext) -> SFSafariViewController { let safariViewController = SFSafariViewController(url: url) safariViewController.delegate = context.coordinator return safariViewController } func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext) { // 无需更新 } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, SFSafariViewControllerDelegate { var parent: FullScreenSafariView init(_ parent: FullScreenSafariView) { self.parent = parent } func safariViewControllerDidFinish(_ controller: SFSafariViewController) { parent.onDismiss?() } } } struct SettingsView: View { @EnvironmentObject var globalEnv: GlobalEnvironment // 引入环境对象 @State private var isLoading = false // 控制加载指示器的显示 @State private var showingToast = false // 控制是否显示toast @State private var toastText = "" @State private var showVIPPaymentView = false @EnvironmentObject var iapManager: IAPManager // 确保在上级视图中已提供 IAPManager @State private var showingFullSafari = false @State private var currentSafariURL = globalEnvironment.userTermsURL @State private var showingAdvancedSettings = false // 控制高级设置显示的状态 @State private var useSandboxEnvironment = false @State private var useDevelopmentEnvironment = false @State private var showingLogShareSheet = false @State private var logFileURL: URL? var body: some View { NavigationView { ScrollView { VStack(spacing: 0) { // Upgrade to Premium settingItem(icon: "arrow.up.circle", text: "Upgrade to Premium", isBold: true) .onTapGesture { showVIPPaymentView = true // 记录事件 Analytics.logEvent(globalAnalyticsEvents.eventEnterPurchase, parameters: [ globalAnalyticsEvents.keyPurchaseEntry: globalAnalyticsEvents.valEntrySettingsBtn as NSObject, globalAnalyticsEvents.keyDeviceID: globalEnvironment.deviceID as NSObject ]) } // Feedback settingItem(icon: "bubble.left", text: "Feedback") .onTapGesture { // Assuming there's a way to open App Store Feedback openAppStoreFeedback() } // About settingItem(icon: "info.circle", text: "Terms of Use") .onTapGesture { // Code to show About View self.showingFullSafari = true currentSafariURL = globalEnvironment.userTermsURL } // About settingItem(icon: "info.circle", text: "Privacy Policy") .onTapGesture { // Code to show About View self.showingFullSafari = true currentSafariURL = globalEnvironment.userPrivacyURL } // Restore Purchases settingItem(icon: "arrow.clockwise.circle", text: "Restore Purchases", isBold: true) .onTapGesture { restorePurchase() } } .fullScreenCover(isPresented: $showingFullSafari) { FullScreenSafariView(url: URL(string: currentSafariURL)!, onDismiss: { self.showingFullSafari = false }) } // 留出手势操作的空间,但UI上隐藏掉 gestureArea if showingAdvancedSettings { VStack { Toggle("Sandbox", isOn: $useSandboxEnvironment) Toggle("TestEnv", isOn: $useDevelopmentEnvironment) HStack { Button("View Logs") { if let logURL = getLogFileURL() { if FileManager.default.fileExists(atPath: logURL.path) { logger.info("Log file exists: \(logURL.path)") self.logFileURL = logURL self.showingLogShareSheet = true } else { logger.error("Log file does not exist.") self.toastText = "Log file not found." self.showingToast = true } } else { self.toastText = "Log file not found." self.showingToast = true } } Spacer() Button("Save") { saveSettings() showingAdvancedSettings = false } } .padding(.horizontal,15) .padding(.top, 15) } .padding(.vertical,10) .padding(.horizontal, 20) .background(Color.white) // Ensure background fills the view .cornerRadius(5) } } .background(Color.pink.opacity(0.2)) // Ensure background fills the view .navigationBarTitle("Settings", displayMode: .inline) .fullScreenCover(isPresented: $showVIPPaymentView) { VIPPaymentView() } .onDisappear { self.showingAdvancedSettings = false // 确保隐藏组件在视图消失时不显示 } } .sheet(isPresented: $showingLogShareSheet) { if let url = logFileURL { ShareSheetLog(activityItems: [url]) } } .toast(isPresented: $showingToast, dismissAfter: globalEnvironment.toastPresentMsNormal) { HStack { Image(systemName: "exclamationmark.bubble") .foregroundColor(.yellow) Text(toastText) .foregroundColor(.black) } .padding() .background(Color.white) .cornerRadius(8) .shadow(radius: 10) } // 加载指示器 if isLoading { LoadingView() } } // 定义隐藏功能 private var gestureArea: some View { Color.clear .contentShape(Rectangle()) // 为透明色定义一个矩形可命中区域 .frame(height: 50) // 可以根据需要调整手势区域的大小 .gesture( DragGesture(minimumDistance: 50, coordinateSpace: .global) .onEnded { value in // 检查水平移动距离是否足够长,同时限制垂直移动不太大 if abs(value.translation.width) > 50 && abs(value.translation.height) < 100 { // 切换高级设置的显示状态 logger.info("Advanced Settings.") showingAdvancedSettings.toggle() } } ) } // 实现保存设置的逻辑 private func saveSettings() { globalEnvironment.SetEnv(isSandBox: useSandboxEnvironment, isTestEnv: useDevelopmentEnvironment) } @ViewBuilder private func settingItem(icon: String, text: String, isBold: Bool = false) -> some View { HStack { Image(systemName: icon) // Icon on the left side .foregroundColor(.gray) Text(text) .font(.subheadline) .fontWeight(isBold ? .bold : .regular) // Conditional bold based on isBold parameter .padding(4) Spacer() } .padding() .background(Color.white) // Background for each setting item .padding(.horizontal, 0) // Add some horizontal padding // Indent divider to align with the text and extend to the edge Divider() .padding(.leading, 30) .padding(.trailing, 10) } private func openAppStoreFeedback() { let appID = globalEnvironment.APPID // 替换为您的应用ID let urlStr = "https://apps.apple.com/app/id\(appID)?action=write-review" if let url = URL(string: urlStr) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } } func restorePurchase(){ Task { await iapManager.restorePurchases() { result in switch result { case .success(_): self.toastText = "Restored Sucess!" self.showingToast = true case .failure(_): self.toastText = "Oh, something went wrong, please try again later." self.showingToast = true } } } } // 模拟加载数据 func loadData() { isLoading = true } func loadComplete(){ isLoading = false } } struct ShareSheetLog: UIViewControllerRepresentable { var activityItems: [Any] func makeUIViewController(context: Context) -> UIActivityViewController { let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) return controller } func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) { // Nothing to update here } } struct SettingsView_Previews: PreviewProvider { static var previews: some View { SettingsView() } } #Preview { SettingsView() }