wake-ios/wake/View/Owner/UserInfo/UserInfo.swift
2025-08-22 18:58:08 +08:00

296 lines
14 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
struct UserInfo: View {
@Environment(\.dismiss) private var dismiss
// Sample user data - replace with your actual data model
@State private var userName = ""
@State private var userEmail = "memo@example.com"
@State private var notificationsEnabled = true
@State private var darkModeEnabled = false
@State private var showLogoutAlert = false
@State private var avatarImage: UIImage?
@State private var showUsername: Bool = false
@State private var uploadedFileId: String? // Add state for file ID
@State private var errorMessage: String = ""
@State private var showError: Bool = false
//
@State private var isKeyboardVisible = false
@FocusState private var isTextFieldFocused: Bool
private let keyboardPublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true }
.merge(with: NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false })
.receive(on: RunLoop.main)
var body: some View {
ZStack {
//
Color.themeTextWhiteSecondary
.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
//
HStack {
Button(action: {
dismiss()
}) {
Image(systemName: "chevron.left")
.font(.system(size: 17, weight: .semibold))
.foregroundColor(.themeTextMessageMain)
}
.padding(.leading, 16)
Spacer()
Text("Complete Your Profile")
.font(Typography.font(for: .title2, family: .quicksandBold))
.foregroundColor(.themeTextMessageMain)
Spacer()
//
Color.clear
.frame(width: 24, height: 24)
.padding(.trailing, 16)
}
.padding(.vertical, 12)
.background(Color.themeTextWhiteSecondary)
.zIndex(1) //
// Dynamic text that changes based on keyboard state
HStack(spacing: 20) {
Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.")
.font(Typography.font(for: .caption))
.foregroundColor(.black)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(isKeyboardVisible ? 1 : 2)
.padding(6)
.background(
LinearGradient(
gradient: Gradient(colors: [
Color(red: 1.0, green: 0.97, blue: 0.87),
.white,
Color(red: 1.0, green: 0.97, blue: 0.84)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
}
.padding(10)
.animation(.easeInOut(duration: 0.3), value: isKeyboardVisible)
.transition(.opacity)
//
GeometryReader { geometry in
ScrollView {
VStack(spacing: 0) {
// Spacer -
if !isKeyboardVisible {
Spacer(minLength: 0)
.frame(height: geometry.size.height * 0.1) // 10% of available height
}
// Content VStack
VStack(spacing: 20) {
// Title
Text(showUsername ? "Add Your Avatar" : "What's Your Name?")
.font(Typography.font(for: .body, family: .quicksandBold))
.frame(maxWidth: .infinity, alignment: .center)
// Avatar
AvatarPicker(
selectedImage: $avatarImage,
showUsername: $showUsername,
isKeyboardVisible: $isKeyboardVisible,
uploadedFileId: $uploadedFileId
)
.padding(.top, isKeyboardVisible ? 0 : 20)
if showUsername {
TextField("Username", text: $userName)
.font(Typography.font(for: .subtitle, family: .inter))
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 16)
.fill(Color.themePrimaryLight)
)
.focused($isTextFieldFocused)
.submitLabel(.done)
.onSubmit {
isTextFieldFocused = false
}
}
}
.padding()
.background(Color(.white))
.cornerRadius(20)
.padding(.horizontal)
// Spacer -
if !isKeyboardVisible {
Spacer(minLength: 0)
.frame(height: geometry.size.height * 0.1) // 10% of available height
}
// Continue Button
Button(action: {
if showUsername {
let parameters: [String: Any] = [
"username": userName,
"avatar_file_id": uploadedFileId ?? ""
]
NetworkService.shared.postWithToken(
path: "/iam/user/info",
parameters: parameters
) { (result: Result<UserInfoResponse, NetworkError>) in
DispatchQueue.main.async {
switch result {
case .success(let response):
print("✅ 用户信息更新成功")
// Update local state with the new user info
if let userData = response.data {
self.userName = userData.username
// You can update other user data here if needed
}
// Show success message or navigate back
self.dismiss()
case .failure(let error):
print("❌ 用户信息更新失败: \(error.localizedDescription)")
// Show error message to user
// You can use an @State variable to show an alert or toast
self.errorMessage = "更新失败: \(error.localizedDescription)"
self.showError = true
}
}
}
} else {
withAnimation {
showUsername = true
}
}
}) {
Text(showUsername ? "Open" : "Continue")
.font(Typography.font(for: .body))
.fontWeight(.bold)
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 25)
.fill(Color.themePrimary)
)
}
.padding(.horizontal, 32) //
.padding(.bottom, isKeyboardVisible ? 20 : 40)
.disabled(showUsername && userName.trimmingCharacters(in: .whitespaces).isEmpty)
.opacity((showUsername && userName.trimmingCharacters(in: .whitespaces).isEmpty) ? 0.6 : 1.0)
.animation(.easeInOut, value: showUsername)
.frame(maxWidth: .infinity)
//
if isKeyboardVisible {
Spacer(minLength: 0)
.frame(height: 20) //
}
}
.frame(minHeight: geometry.size.height) //
}
}
.background(Color.themeTextWhiteSecondary)
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
//
if isKeyboardVisible {
Color.black.opacity(0.001)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
//
if showError {
VStack {
Text(errorMessage)
.font(Typography.font(for: .body))
.foregroundColor(.red)
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 2)
}
.frame(maxWidth: .infinity, alignment: .center)
.padding()
}
}
.onAppear {
// Set up keyboard notifications
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in
withAnimation(.easeInOut(duration: 0.3)) {
isKeyboardVisible = true
}
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
withAnimation(.easeInOut(duration: 0.3)) {
isKeyboardVisible = false
}
}
}
.onDisappear {
// Clean up observers
NotificationCenter.default.removeObserver(self)
}
.onReceive(keyboardPublisher) { isVisible in
withAnimation(.easeInOut(duration: 0.2)) {
isKeyboardVisible = isVisible
}
}
.onChange(of: isTextFieldFocused) { newValue in
withAnimation(.easeInOut(duration: 0.2)) {
isKeyboardVisible = newValue
}
}
}
}
// MARK: - Settings Row View
struct SettingsRow: View {
let icon: String
let title: String
let color: Color
var body: some View {
HStack {
Image(systemName: icon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
.padding(6)
.background(color.opacity(0.1))
.foregroundColor(color)
.cornerRadius(6)
Text(title)
.padding(.leading, 5)
}
.padding(.vertical, 4)
}
}
// MARK: - Preview
struct UserInfo_Previews: PreviewProvider {
static var previews: some View {
UserInfo()
}
}