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")