diff --git a/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate b/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate index 1e09284..f5a68fe 100644 Binary files a/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate and b/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/wake/Assets/Svg/Avatar.svg b/wake/Assets/Svg/Avatar.svg new file mode 100644 index 0000000..3b920fc --- /dev/null +++ b/wake/Assets/Svg/Avatar.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/wake/Typography.swift b/wake/Typography.swift index c60e934..cad7647 100644 --- a/wake/Typography.swift +++ b/wake/Typography.swift @@ -23,6 +23,7 @@ enum TypographyStyle { case subtitle // 副标题 case caption // 说明文字 case footnote // 脚注 + case small // 小号文字 } // MARK: - 字体配置结构体 @@ -41,13 +42,14 @@ struct Typography { /// 文本样式配置表 private static let styleConfig: [TypographyStyle: TypographyConfig] = [ - .headline: TypographyConfig(size: 24, weight: .bold, textStyle: .headline), - .title: TypographyConfig(size: 20, weight: .semibold, textStyle: .title2), - .body: TypographyConfig(size: 16, weight: .regular, textStyle: .body), - .subtitle: TypographyConfig(size: 14, weight: .medium, textStyle: .subheadline), - .caption: TypographyConfig(size: 12, weight: .light, textStyle: .caption1), - .footnote: TypographyConfig(size: 11, weight: .regular, textStyle: .footnote) - ] + .headline: TypographyConfig(size: 24, weight: .bold, textStyle: .headline), + .title: TypographyConfig(size: 20, weight: .semibold, textStyle: .title2), + .body: TypographyConfig(size: 16, weight: .regular, textStyle: .body), + .subtitle: TypographyConfig(size: 14, weight: .medium, textStyle: .subheadline), + .caption: TypographyConfig(size: 12, weight: .light, textStyle: .caption1), + .footnote: TypographyConfig(size: 11, weight: .regular, textStyle: .footnote), + .small: TypographyConfig(size: 10, weight: .regular, textStyle: .headline) +] // MARK: - 公共方法 diff --git a/wake/View/Components/Upload/Avatar.swift b/wake/View/Components/Upload/Avatar.swift new file mode 100644 index 0000000..e69de29 diff --git a/wake/View/Login/Login.swift b/wake/View/Login/Login.swift index 6c0dc68..7b34b71 100644 --- a/wake/View/Login/Login.swift +++ b/wake/View/Login/Login.swift @@ -7,60 +7,67 @@ import CryptoKit struct LoginView: View { // MARK: - Properties - @Environment(\.dismiss) private var dismiss @State private var isLoading = false @State private var showError = false @State private var errorMessage = "" @State private var currentNonce: String? + @State private var isLoggedIn = false // MARK: - Body var body: some View { - ZStack { - // Background - Color(red: 1.0, green: 0.67, blue: 0.15) - .edgesIgnoringSafeArea(.all) - - VStack(alignment: .leading, spacing: 4) { - Text("Hi, I'm MeMo!") - .font(.largeTitle) - .fontWeight(.semibold) - .foregroundColor(.black) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.leading, 24) - .padding(.top, 44) + NavigationStack { + ZStack { + // Background + Color(red: 1.0, green: 0.67, blue: 0.15) + .edgesIgnoringSafeArea(.all) - Text("Welcome~") - .font(.largeTitle) - .fontWeight(.semibold) - .foregroundColor(.black) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.leading, 24) - .padding(.bottom, 20) + VStack(alignment: .leading, spacing: 4) { + Text("Hi, I'm MeMo!") + .font(.largeTitle) + .fontWeight(.semibold) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.leading, 24) + .padding(.top, 44) + + Text("Welcome~") + .font(.largeTitle) + .fontWeight(.semibold) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.leading, 24) + .padding(.bottom, 20) + + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - Spacer() + VStack(spacing: 16) { + Spacer() + signInButton() + termsAndPrivacyView() + } + .padding() + .alert(isPresented: $showError) { + Alert( + title: Text("Error"), + message: Text(errorMessage), + dismissButton: .default(Text("OK")) + ) + } + + if isLoading { + loadingView() + } } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - - VStack(spacing: 16) { - Spacer() - signInButton() - termsAndPrivacyView() - } - .padding() - .alert(isPresented: $showError) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("OK")) - ) - } - - if isLoading { - loadingView() + .navigationBarHidden(true) + .fullScreenCover(isPresented: $isLoggedIn) { + NavigationStack { + UserInfo() + } } } - .navigationBarHidden(true) } // MARK: - Views @@ -140,6 +147,9 @@ struct LoginView: View { private func handleAppleSignIn(result: Result) { print("🔵 [Apple Sign In] 开始处理登录结果...") + DispatchQueue.main.async { + self.isLoggedIn = true + } switch result { case .success(let authResults): print("✅ [Apple Sign In] 登录授权成功") @@ -242,9 +252,9 @@ struct LoginView: View { // MARK: - Helpers private func handleSuccessfulAuthentication() { - print("✅ [Auth] 登录成功,准备关闭登录页面...") + print("✅ [Auth] 登录成功,准备跳转到用户信息页面...") DispatchQueue.main.async { - self.dismiss() + self.isLoggedIn = true } } @@ -257,7 +267,10 @@ struct LoginView: View { private func handleAuthenticationError(_ error: AFError) { let errorMessage = error.localizedDescription print("❌ [Auth] 认证错误: \(errorMessage)") - showError(message: "登录失败: \(errorMessage)") + DispatchQueue.main.async { + self.isLoggedIn = false + self.showError(message: "登录失败: \(errorMessage)") + } } private func showError(message: String) { diff --git a/wake/View/Owner/UserInfo/UserInfo.swift b/wake/View/Owner/UserInfo/UserInfo.swift new file mode 100644 index 0000000..74c7f9a --- /dev/null +++ b/wake/View/Owner/UserInfo/UserInfo.swift @@ -0,0 +1,146 @@ +import SwiftUI + +struct UserInfo: View { + @Environment(\.dismiss) private var dismiss + + // Sample user data - replace with your actual data model + @State private var userName = "MeMo" + @State private var userEmail = "memo@example.com" + @State private var notificationsEnabled = true + @State private var darkModeEnabled = false + @State private var showLogoutAlert = false + + var body: some View { + VStack(spacing: 0) { + HStack(spacing: 20) { + Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.") + .font(Typography.font(for: .small)) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.vertical, 10) + .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(.vertical, 10) + Spacer() + VStack(spacing: 20) { + // Title + Text("Add Your Avatar") + .font(Typography.font(for: .title)) + .frame(maxWidth: .infinity, alignment: .center) + + // Avatar + ZStack { + SVGImage(svgName: "Avatar") + .frame(width: 225, height: 225) + + // Fallback in case SVG fails to load + Image(systemName: "person.circle.fill") + .resizable() + .scaledToFit() + .frame(width: 225, height: 225) + .foregroundColor(.gray) + .opacity(0.3) + } + .padding(.vertical, 20) + + // Buttons + Button(action: { + // Action for first button + }) { + Text("Upload from Gallery") + .frame(maxWidth: .infinity) + .padding() + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 25) + .fill(Color(red: 1.0, green: 0.973, blue: 0.871)) + ) + } + + Button(action: { + // Action for second button + }) { + Text("Take a Photo") + .frame(maxWidth: .infinity) + .padding() + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 25) + .fill(Color(red: 1.0, green: 0.973, blue: 0.871)) + ) + } + } + .padding() + .background(Color(.white)) + .cornerRadius(20) + Spacer() + Button(action: { + // Action for next button + }) { + Text("Next") + .frame(maxWidth: .infinity) + .padding() + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 25) + .fill(Color(red: 1.0, green: 0.714, blue: 0.271)) + ) + } + } + .padding() + .navigationTitle("Complete Your Profile") + .navigationBarTitleDisplayMode(.inline) + .background(Color(red: 0.98, green: 0.98, blue: 0.98)) // #FAFAFA + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button(action: { + dismiss() + }) { + Image(systemName: "chevron.left") + .foregroundColor(.blue) + } + } + } + } +} + +// 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() + } +} \ No newline at end of file diff --git a/wake/Views/Utils/SVGImage.swift b/wake/Views/Utils/SVGImage.swift new file mode 100644 index 0000000..ca680cd --- /dev/null +++ b/wake/Views/Utils/SVGImage.swift @@ -0,0 +1,35 @@ +import SwiftUI +import WebKit + +struct SVGImage: UIViewRepresentable { + let svgName: String + + func makeUIView(context: Context) -> WKWebView { + let webView = WKWebView() + webView.isOpaque = false + webView.backgroundColor = .clear + webView.scrollView.isScrollEnabled = false + + // 尝试从根目录加载SVG文件 + if let url = Bundle.main.url(forResource: svgName, withExtension: "svg") { + print("SVG URL found: \(url.path)") + let request = URLRequest(url: url) + webView.load(request) + } else { + print("Error: Failed to find SVG file with name: \(svgName).svg in main bundle") + // 打印所有可用的SVG文件 + if let resourceURL = Bundle.main.resourceURL, + let files = try? FileManager.default.contentsOfDirectory(at: resourceURL, includingPropertiesForKeys: nil) { + let svgFiles = files.filter { $0.pathExtension.lowercased() == "svg" } + print("Available SVG files: \(svgFiles)") + } + } + + return webView + } + + func updateUIView(_ uiView: WKWebView, context: Context) {} +} + +// Usage: +// SVGImage(svgName: "Avatar")