182 lines
6.7 KiB
Swift
182 lines
6.7 KiB
Swift
import SwiftUI
|
||
import UIKit
|
||
|
||
struct AboutUsView: View {
|
||
// MARK: - Properties
|
||
|
||
private let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0"
|
||
private let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1"
|
||
|
||
// MARK: - Body
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
// Background color
|
||
Color.themeTextWhiteSecondary
|
||
.edgesIgnoringSafeArea(.all)
|
||
|
||
VStack(spacing: 0) {
|
||
// Navigation Header
|
||
SimpleNaviHeader(title: "About Us") {
|
||
Router.shared.pop()
|
||
}
|
||
.padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0)
|
||
|
||
// Main Content
|
||
VStack(spacing: 0) {
|
||
// IP Address Section
|
||
VStack(spacing: 12) {
|
||
if let icon = primaryAppIconUIImage() {
|
||
Image(uiImage: icon)
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fit)
|
||
.frame(width: 102, height: 102)
|
||
.cornerRadius(18)
|
||
} else {
|
||
Image(systemName: "app.fill")
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fit)
|
||
.frame(width: 82, height: 82)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
.frame(maxWidth: .infinity)
|
||
.padding(.vertical, 32)
|
||
|
||
// Version & ICP Info
|
||
VStack(spacing: 12) {
|
||
Text("Version : 1.1.1")
|
||
.font(.system(size: 12))
|
||
.foregroundColor(.themeTextMessageMain)
|
||
|
||
Text("ICP 备案号: 京ICP备XXXXXXXX号")
|
||
.font(.system(size: 12))
|
||
.foregroundColor(.themeTextMessageMain)
|
||
}
|
||
.padding(.bottom, 32)
|
||
// Legal Links
|
||
VStack(spacing: 0) {
|
||
settingRow(
|
||
title: "Terms of Service",
|
||
action: {
|
||
withAnimation {
|
||
if let url = URL(string: "https://memorywake.com/privacy-policy") {
|
||
UIApplication.shared.open(url)
|
||
}
|
||
}
|
||
}
|
||
)
|
||
.padding()
|
||
settingRow(
|
||
title: "Privacy Policy",
|
||
action: {
|
||
withAnimation {
|
||
if let url = URL(string: "https://memorywake.com/privacy-policy") {
|
||
UIApplication.shared.open(url)
|
||
}
|
||
}
|
||
}
|
||
)
|
||
.padding()
|
||
settingRow(
|
||
title: "AI Usage Guidelines",
|
||
action: {
|
||
withAnimation {
|
||
if let url = URL(string: "https://memorywake.com/privacy-policy") {
|
||
UIApplication.shared.open(url)
|
||
}
|
||
}
|
||
}
|
||
)
|
||
.padding()
|
||
}
|
||
}
|
||
.frame(maxWidth: .infinity)
|
||
.background(Color.white)
|
||
.cornerRadius(16)
|
||
.padding()
|
||
Spacer()
|
||
}
|
||
}
|
||
.navigationBarHidden(true)
|
||
.edgesIgnoringSafeArea(.all)
|
||
}
|
||
|
||
private func settingRow(title: String, action: @escaping () -> Void) -> some View {
|
||
Button(action: action) {
|
||
HStack {
|
||
// 标题
|
||
Text(title)
|
||
.foregroundColor(.primary)
|
||
|
||
Spacer()
|
||
|
||
// 右侧箭头
|
||
Image(systemName: "chevron.right")
|
||
.font(.system(size: 14))
|
||
.foregroundColor(.gray)
|
||
}
|
||
.padding(.vertical, 12) // 增加垂直内边距
|
||
.background(Color.white)
|
||
}
|
||
.buttonStyle(PlainButtonStyle())
|
||
.listRowBackground(Color.white)
|
||
.listRowSeparator(.hidden)
|
||
}
|
||
// MARK: - Private Methods
|
||
|
||
private func primaryAppIconUIImage() -> UIImage? {
|
||
// 获取主 AppIcon 名称列表中最后一个(通常是最大尺寸)
|
||
if let iconsDictionary = Bundle.main.infoDictionary?["CFBundleIcons"] as? [String: Any],
|
||
let primaryIconsDictionary = iconsDictionary["CFBundlePrimaryIcon"] as? [String: Any],
|
||
let iconFiles = primaryIconsDictionary["CFBundleIconFiles"] as? [String],
|
||
let lastIcon = iconFiles.last,
|
||
let image = UIImage(named: lastIcon) {
|
||
return image
|
||
}
|
||
return nil
|
||
}
|
||
|
||
private func getIPAddress() -> String? {
|
||
var address: String?
|
||
var ifaddr: UnsafeMutablePointer<ifaddrs>?
|
||
|
||
if getifaddrs(&ifaddr) == 0 {
|
||
var ptr = ifaddr
|
||
while ptr != nil {
|
||
defer { ptr = ptr?.pointee.ifa_next }
|
||
|
||
let interface = ptr?.pointee
|
||
let addrFamily = interface?.ifa_addr.pointee.sa_family
|
||
|
||
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6),
|
||
let name = interface?.ifa_name,
|
||
String(cString: name) == "en0",
|
||
let addr = interface?.ifa_addr {
|
||
|
||
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
||
getnameinfo(addr, socklen_t(addr.pointee.sa_len),
|
||
&hostname, socklen_t(hostname.count),
|
||
nil, socklen_t(0),
|
||
NI_NUMERICHOST)
|
||
address = String(cString: hostname)
|
||
}
|
||
}
|
||
freeifaddrs(ifaddr)
|
||
}
|
||
|
||
return address
|
||
}
|
||
}
|
||
|
||
// MARK: - Preview
|
||
#Preview {
|
||
AboutUsView()
|
||
}
|
||
|
||
// MARK: - Dependencies
|
||
import Foundation
|
||
import SystemConfiguration
|
||
import Network
|
||
import Darwin
|