Files
e-party-iOS/yana/Views/SettingView.swift
edwinQQQ c8ff40cac1 feat: 更新动态相关数据模型及视图组件
- 在DynamicsModels.swift中为动态响应结构和列表数据添加Sendable协议,提升并发安全性。
- 在FeedListFeature.swift中实现动态内容的加载逻辑,集成API请求以获取最新动态。
- 在FeedListView.swift中新增动态内容列表展示,优化用户交互体验。
- 在MeView.swift中添加设置按钮,支持弹出设置视图。
- 在SettingView.swift中新增COS上传测试功能,允许用户测试图片上传至腾讯云COS。
- 在OptimizedDynamicCardView.swift中实现优化的动态卡片组件,提升动态展示效果。
2025-07-22 17:17:21 +08:00

307 lines
11 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
import ComposableArchitecture
struct SettingView: View {
let store: StoreOf<SettingFeature>
@ObservedObject private var localizationManager = LocalizationManager.shared
var body: some View {
NavigationStack {
WithPerceptionTracking {
GeometryReader { geometry in
ZStack {
// - 使"bg"
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea(.all)
VStack(spacing: 0) {
// Navigation Bar
HStack {
//
Button(action: {
store.send(.dismissTapped)
}) {
Image(systemName: "chevron.left")
.font(.title2)
.foregroundColor(.white)
}
.padding(.leading, 16)
Spacer()
//
Text(NSLocalizedString("setting.title", comment: "Settings"))
.font(.custom("PingFang SC-Semibold", size: 16))
.foregroundColor(.white)
Spacer()
//
Color.clear
.frame(width: 44, height: 44)
}
.padding(.top, 8)
.padding(.horizontal)
//
ScrollView {
VStack(spacing: 24) {
UserInfoCardView(userInfo: store.userInfo, accountModel: store.accountModel)
// .padding()
.padding(.top, 32)
SettingOptionsView(
onLanguageTapped: {
// TODO:
},
onAboutTapped: {
// TODO:
}
)
Spacer(minLength: 50)
LogoutButtonView {
store.send(.logoutTapped)
}
.padding(.bottom, 50)
}
}
}
}
}
.onAppear {
store.send(.onAppear)
}
}
}
}
}
// MARK: - User Info Card View
struct UserInfoCardView: View {
let userInfo: UserInfo?
let accountModel: AccountModel?
var body: some View {
VStack(spacing: 16) {
//
Image(systemName: "person.circle.fill")
.font(.system(size: 60))
.foregroundColor(.white.opacity(0.8))
//
VStack(spacing: 8) {
if let userInfo = userInfo, let userName = userInfo.username {
Text(userName)
.font(.title2.weight(.semibold))
.foregroundColor(.white)
} else {
Text(NSLocalizedString("setting.user", comment: "User"))
.font(.title2.weight(.semibold))
.foregroundColor(.white)
}
// ID
if let userInfo = userInfo, let userId = userInfo.userId {
Text("ID: \(userId)")
.font(.caption)
.foregroundColor(.white.opacity(0.8))
} else if let accountModel = accountModel, let uid = accountModel.uid {
Text("UID: \(uid)")
.font(.caption)
.foregroundColor(.white.opacity(0.8))
}
}
}
.padding(.vertical, 24)
.padding(.horizontal, 20)
.background(Color.black.opacity(0.3))
.cornerRadius(16)
.padding(.horizontal, 24)
}
}
// MARK: - Setting Options View
// Add this new view for testing COS upload
struct TestCOSUploadView: View {
@State private var imageURL: String = "https://img.toto.im/mw600/66b3de17ly1i3mpcw0k7yj20hs0md0tf.jpg.webp"
@State private var uploadResult: String = ""
@State private var isUploading: Bool = false
@Dependency(\.apiService) private var apiService
var body: some View {
VStack(spacing: 20) {
TextField("Enter image URL", text: $imageURL)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Button(action: {
Task {
await uploadImageFromURL()
}
}) {
Text(isUploading ? "Uploading..." : "Upload to COS")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.disabled(isUploading || imageURL.isEmpty)
Text(uploadResult)
.multilineTextAlignment(.center)
.padding()
}
.navigationTitle("Test COS Upload")
}
private func uploadImageFromURL() async {
guard let url = URL(string: imageURL) else {
uploadResult = "Invalid URL"
return
}
isUploading = true
uploadResult = ""
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let cloudURL = await COSManager.shared.uploadImage(data, apiService: apiService) {
uploadResult = "Upload successful! Cloud URL: \(cloudURL)"
} else {
uploadResult = "Upload failed"
}
} catch {
uploadResult = "Download failed: \(error.localizedDescription)"
}
isUploading = false
}
}
// Modify SettingOptionsView to add the test row
struct SettingOptionsView: View {
let onLanguageTapped: () -> Void
let onAboutTapped: () -> Void
var body: some View {
VStack(spacing: 12) {
SettingRowView(
icon: "globe",
title: NSLocalizedString("setting.language", comment: "Language Settings"),
action: onLanguageTapped
)
SettingRowView(
icon: "info.circle",
title: NSLocalizedString("setting.about", comment: "About Us"),
action: onAboutTapped
)
#if DEBUG
NavigationLink(destination: TestCOSUploadView()) {
HStack {
Image(systemName: "cloud.upload")
.foregroundColor(.white.opacity(0.8))
.frame(width: 24)
Text("Test COS Upload")
.foregroundColor(.white)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.white.opacity(0.6))
.font(.caption)
}
.padding(.horizontal, 20)
.padding(.vertical, 16)
.background(Color.black.opacity(0.2))
.cornerRadius(12)
}
#endif
HStack {
Image(systemName: "app.badge")
.foregroundColor(.white.opacity(0.8))
.frame(width: 24)
Text(NSLocalizedString("setting.version", comment: "Version Info"))
.foregroundColor(.white)
Spacer()
Text("1.0.0")
.foregroundColor(.white.opacity(0.6))
.font(.caption)
}
.padding(.horizontal, 20)
.padding(.vertical, 16)
.background(Color.black.opacity(0.2))
.cornerRadius(12)
}
.padding(.horizontal, 24)
}
}
// MARK: - Logout Button View
struct LogoutButtonView: View {
let action: () -> Void
var body: some View {
Button(action: action) {
HStack {
Image(systemName: "arrow.right.square")
Text(NSLocalizedString("setting.logout", comment: "Logout"))
}
.font(.body.weight(.medium))
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(Color.red.opacity(0.7))
.cornerRadius(12)
}
.padding(.horizontal, 24)
}
}
// MARK: - Setting Row View
struct SettingRowView: View {
let icon: String
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
HStack {
Image(systemName: icon)
.foregroundColor(.white.opacity(0.8))
.frame(width: 24)
Text(title)
.foregroundColor(.white)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.white.opacity(0.6))
.font(.caption)
}
.padding(.horizontal, 20)
.padding(.vertical, 16)
.background(Color.black.opacity(0.2))
.cornerRadius(12)
}
}
}
//#Preview {
// SettingView(
// store: Store(
// initialState: SettingFeature.State()
// ) {
// SettingFeature()
// }
// )
//}