feat: about us

This commit is contained in:
jinyaqiu 2025-08-31 17:27:22 +08:00
parent c9a2f760d9
commit b89b3b0cc4
6 changed files with 366 additions and 117 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -12,6 +12,8 @@ enum AppRoute: Hashable {
case memories
case subscribe
case userInfo
case account
case about
@ViewBuilder
var view: some View {
@ -36,6 +38,10 @@ enum AppRoute: Hashable {
SubscribeView()
case .userInfo:
UserInfo()
case .account:
AccountView()
case .about:
AboutUsView()
}
}
}

View File

@ -0,0 +1,157 @@
import SwiftUI
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) {
SVGImage(svgName: "AboutIP")
.frame(width: 102, height: 102)
}
.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://example.com/terms") {
UIApplication.shared.open(url)
}
}
}
)
.padding()
settingRow(
title: "Privacy Policy",
action: {
withAnimation {
if let url = URL(string: "https://example.com/terms") {
UIApplication.shared.open(url)
}
}
}
)
.padding()
settingRow(
title: "AI Usage Guidelines",
action: {
withAnimation {
if let url = URL(string: "https://example.com/terms") {
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 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

View File

@ -1,112 +0,0 @@
import SwiftUI
///
struct AccountView: View {
// MARK: -
/// - dismiss
@Environment(\.dismiss) private var dismiss
/// - /
@Binding var isAccountPresented: Bool
// MARK: -
///
private let animation = Animation.spring(
response: 0.6, //
dampingFraction: 0.9, //
blendDuration: 0.8 //
)
// MARK: -
var body: some View {
ZStack {
// Theme background color
Color.themeTextWhiteSecondary.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
//
SimpleNaviHeader(title: "Account & Security") {
withAnimation(animation) {
isAccountPresented = false
}
}
//
List {
//
settingRow(
icon: "Account",
title: "Account & Security",
action: {}
)
}
.background(Color.white)
.cornerRadius(12)
.padding()
.listStyle(PlainListStyle())
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets())
}
}
.background(Color.themeTextWhiteSecondary.edgesIgnoringSafeArea(.all))
.environment(\.horizontalSizeClass, .regular)
}
// MARK: -
/// TableView
private func configureTableView() {
// 线
UITableView.appearance().tableFooterView = UIView()
// 线
UITableView.appearance().tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNonzeroMagnitude))
// 线
UITableView.appearance().separatorInset = .zero
//
UITableView.appearance().contentInset = .zero
}
///
/// - Parameters:
/// - icon:
/// - title:
/// - action:
/// - Returns:
private func settingRow(icon: String, title: String, action: @escaping () -> Void) -> some View {
Button(action: action) {
HStack {
//
SVGImage(svgName: icon)
.frame(width: 24, height: 24)
//
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: -
#Preview {
NavigationView {
AccountView(isAccountPresented: .constant(true))
}
}

View File

@ -0,0 +1,187 @@
import SwiftUI
///
struct AccountView: View {
// MARK: -
/// - dismiss
@Environment(\.dismiss) private var dismiss
///
@State private var showDeleteConfirmation = false
// MARK: -
///
private let animation = Animation.spring(
response: 0.6, //
dampingFraction: 0.9, //
blendDuration: 0.8 //
)
// MARK: -
var body: some View {
ZStack {
// Theme background color
Color.themeTextWhiteSecondary
.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
//
SimpleNaviHeader(title: "Account & Security") {
withAnimation(animation) {
Router.shared.pop()
}
}
.padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top)
//
ScrollView {
VStack(spacing: 0) {
//
settingRow(
title: "Delete Account",
action: {
withAnimation {
showDeleteConfirmation = true
}
}
)
.padding()
}
.background(Color.white)
.cornerRadius(12)
.padding(.horizontal)
}
.background(Color.themeTextWhiteSecondary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.top)
}
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay(
//
Group {
if showDeleteConfirmation {
ZStack {
//
Color.black.opacity(0.6)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
withAnimation {
showDeleteConfirmation = false
}
}
//
VStack(spacing: 20) {
Text("Are you sure you want to delete this account?")
.font(.headline)
.font(.system(size: 14, weight: .medium))
.foregroundColor(.themeTextMessageMain)
Text("Once deleted, you cant get it back.")
.multilineTextAlignment(.center)
.font(.subheadline)
.font(.system(size: 12))
.foregroundColor(.themeTextMessage)
HStack(spacing: 20) {
Button(action: {
withAnimation {
showDeleteConfirmation = false
}
}) {
Text("Cancel")
.font(Typography.font(for: .subtitle, family: .quicksandBold))
.foregroundColor(.themeTextMessageMain)
.frame(maxWidth: .infinity)
.padding()
.background(Color.themePrimary)
.cornerRadius(32)
}
Button(action: {
//
withAnimation {
showDeleteConfirmation = false
}
// TODO: API
}) {
Text("Confirm")
.foregroundColor(.themeTextMessage)
.font(.system(size: 12))
.frame(maxWidth: .infinity)
.padding()
.background(Color.white)
.cornerRadius(32)
}
}
}
.padding()
.frame(width: 300)
.background(Color.white)
.cornerRadius(12)
.shadow(radius: 10)
}
.transition(.opacity)
}
}
)
.navigationBarBackButtonHidden(true) //
.navigationBarHidden(true) //
}
// MARK: -
/// TableView
private func configureTableView() {
// 线
UITableView.appearance().tableFooterView = UIView()
// 线
UITableView.appearance().tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNonzeroMagnitude))
// 线
UITableView.appearance().separatorInset = .zero
//
UITableView.appearance().contentInset = .zero
}
///
/// - Parameters:
/// - icon:
/// - title:
/// - action:
/// - Returns:
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: -
#Preview {
NavigationView {
AccountView()
}
}

View File

@ -9,8 +9,7 @@ struct SettingsView: View {
/// - /
@Binding var isPresented: Bool
@State private var showAccountView = false
@State private var isShowingAccountView = false
// MARK: -
@ -44,7 +43,7 @@ struct SettingsView: View {
icon: "Account",
title: "Account & Security",
action: {
// Action will be handled by NavigationLink
Router.shared.navigate(to: .account)
}
)
@ -66,7 +65,9 @@ struct SettingsView: View {
settingRow(
icon: "AboutUs",
title: "About Us",
action: {}
action: {
Router.shared.navigate(to: .about)
}
)
}
.background(Color.white)
@ -80,6 +81,7 @@ struct SettingsView: View {
Spacer()
}
}
.navigationBarHidden(true)
}
}