292 lines
11 KiB
Swift
292 lines
11 KiB
Swift
//
|
||
// 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<FullScreenSafariView>) -> SFSafariViewController {
|
||
let safariViewController = SFSafariViewController(url: url)
|
||
safariViewController.delegate = context.coordinator
|
||
return safariViewController
|
||
}
|
||
|
||
func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext<FullScreenSafariView>) {
|
||
// 无需更新
|
||
}
|
||
|
||
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()
|
||
}
|