diff --git a/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate b/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate index 4a53c9a..4b93d4c 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/.DS_Store b/wake/Assets/.DS_Store new file mode 100644 index 0000000..bb35e99 Binary files /dev/null and b/wake/Assets/.DS_Store differ diff --git a/wake/Typography.swift b/wake/Typography.swift index ecdc952..87d31b3 100644 --- a/wake/Typography.swift +++ b/wake/Typography.swift @@ -20,6 +20,7 @@ enum TypographyStyle { case largeTitle // 大标题 case headline // 大标题 case title // 标题 + case title2 // 标题 case body // 正文 case subtitle // 副标题 case caption // 说明文字 @@ -39,13 +40,14 @@ struct Typography { // MARK: - 配置 /// 默认字体库 - private static let defaultFontFamily: FontFamily = .quicksand + private static let defaultFontFamily: FontFamily = .quicksandRegular /// 文本样式配置表 private static let styleConfig: [TypographyStyle: TypographyConfig] = [ .largeTitle: TypographyConfig(size: 32, weight: .heavy, textStyle: .largeTitle), .headline: TypographyConfig(size: 24, weight: .bold, textStyle: .headline), .title: TypographyConfig(size: 20, weight: .semibold, textStyle: .title2), + .title2: TypographyConfig(size: 18, weight: .bold, textStyle: .title2), .body: TypographyConfig(size: 16, weight: .regular, textStyle: .body), .subtitle: TypographyConfig(size: 14, weight: .medium, textStyle: .subheadline), .caption: TypographyConfig(size: 12, weight: .regular, textStyle: .caption1), diff --git a/wake/View/Owner/UserInfo/AvatarPicker.swift b/wake/View/Owner/UserInfo/AvatarPicker.swift new file mode 100644 index 0000000..a45f35c --- /dev/null +++ b/wake/View/Owner/UserInfo/AvatarPicker.swift @@ -0,0 +1,84 @@ +import SwiftUI + +public struct AvatarPicker: View { + @StateObject private var uploadManager = MediaUploadManager() + @State private var showMediaPicker = false + @State private var isUploading = false + @Binding var selectedImage: UIImage? + + public init(selectedImage: Binding) { + self._selectedImage = selectedImage + } + + public var body: some View { + VStack(spacing: 20) { + // Avatar Image + Button(action: { + showMediaPicker = true + }) { + ZStack { + if let selectedImage = selectedImage { + Image(uiImage: selectedImage) + .resizable() + .scaledToFill() + .frame(width: 225, height: 225) + .clipShape(RoundedRectangle(cornerRadius: 20)) + } else { + // Default SVG avatar + SVGImage(svgName: "Avatar") + .frame(width: 225, height: 225) + .contentShape(Rectangle()) + } + + if isUploading { + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) + .scaleEffect(1.5) + } + } + } + + // Upload button + Button(action: { + showMediaPicker = true + }) { + Text("Upload from Gallery") + .font(Typography.font(for: .subtitle, family: .inter)) + .fontWeight(.regular) + .frame(maxWidth: .infinity) + .padding() + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(Color.themePrimaryLight) + ) + } + .frame(width: .infinity) + } + .sheet(isPresented: $showMediaPicker) { + MediaPicker( + selectedMedia: $uploadManager.selectedMedia, + imageSelectionLimit: 1, + videoSelectionLimit: 0, + allowedMediaTypes: .imagesOnly, + selectionMode: .single, + onDismiss: { + showMediaPicker = false + if !uploadManager.selectedMedia.isEmpty { + isUploading = true + uploadManager.startUpload() + } + } + ) + } + .onChange(of: uploadManager.uploadStatus) { _ in + if let firstMedia = uploadManager.selectedMedia.first, + case .image(let image) = firstMedia, + uploadManager.isAllUploaded { + selectedImage = image + isUploading = false + uploadManager.clearAllMedia() + } + } + } +} \ No newline at end of file diff --git a/wake/View/Owner/UserInfo/UserInfo.swift b/wake/View/Owner/UserInfo/UserInfo.swift index 7a49929..d172d7f 100644 --- a/wake/View/Owner/UserInfo/UserInfo.swift +++ b/wake/View/Owner/UserInfo/UserInfo.swift @@ -13,9 +13,20 @@ struct UserInfo: View { var body: some View { VStack(spacing: 0) { + HStack { + ReturnButton { + print("返回") + } + Spacer() + Text("Complete Your Profile") + .font(Typography.font(for: .title2, family: .quicksandBold)) + .foregroundColor(.themeTextMessageMain) + Spacer() + } + .padding() 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)) + .font(Typography.font(for: .caption)) .foregroundColor(.black) .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 10) @@ -31,59 +42,32 @@ struct UserInfo: View { ) ) } - .padding(.vertical, 10) + .padding(10) Spacer() VStack(spacing: 20) { // Title Text("Add Your Avatar") - .font(Typography.font(for: .title)) + .font(Typography.font(for: .body, family: .quicksandBold)) .frame(maxWidth: .infinity, alignment: .center) // Avatar ZStack { - // Show either the SVG or the uploaded image - if let avatarImage = avatarImage { - Image(uiImage: avatarImage) - .resizable() - .scaledToFill() - .frame(width: 200, height: 200) - .clipShape(Circle()) - } else { - SVGImage(svgName: "Avatar") - .frame(width: 200, height: 200) - } - - // Make sure the AvatarUploader is on top and covers the entire area - AvatarUploader(selectedImage: $avatarImage, size: 200) - .contentShape(Rectangle()) // This makes the entire area tappable - } - .frame(width: 200, height: 200) - .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)) - ) + AvatarPicker(selectedImage: $avatarImage) } + .padding(.top, 20) Button(action: { // Action for second button }) { Text("Take a Photo") + .font(Typography.font(for: .subtitle, family: .inter)) + .fontWeight(.regular) .frame(maxWidth: .infinity) .padding() .foregroundColor(.black) .background( - RoundedRectangle(cornerRadius: 25) - .fill(Color(red: 1.0, green: 0.973, blue: 0.871)) + RoundedRectangle(cornerRadius: 16) + .fill(Color.themePrimaryLight) ) } } @@ -94,30 +78,22 @@ struct UserInfo: View { Button(action: { // Action for next button }) { - Text("Next") + Text("Continue") + .font(Typography.font(for: .body)) + .fontWeight(.bold) .frame(maxWidth: .infinity) - .padding() + .padding(16) .foregroundColor(.black) .background( RoundedRectangle(cornerRadius: 25) - .fill(Color(red: 1.0, green: 0.714, blue: 0.271)) + .fill(Color.themePrimary) ) } + .padding() } .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) - } - } - } } } diff --git a/wake/Views/Utils/SVGImage.swift b/wake/Views/Utils/SVGImage.swift index 8604cfd..a16299d 100644 --- a/wake/Views/Utils/SVGImage.swift +++ b/wake/Views/Utils/SVGImage.swift @@ -11,60 +11,58 @@ struct SVGImage: UIViewRepresentable { webView.scrollView.isScrollEnabled = false webView.scrollView.contentInsetAdjustmentBehavior = .never - if let url = Bundle.main.url(forResource: svgName, withExtension: "svg") { - let htmlString = """ - - - - - - - -
- -
- - - """ - - webView.loadHTMLString(htmlString, baseURL: nil) + // 1. 获取 SVG 文件路径(注意:移除了 inDirectory 参数) + guard let path = Bundle.main.path(forResource: svgName, ofType: "svg") else { + print("❌ 无法找到 SVG 文件: \(svgName).svg") + // 打印所有可用的资源文件,用于调试 + if let resourcePath = Bundle.main.resourcePath { + print("可用的资源文件: \(try? FileManager.default.contentsOfDirectory(atPath: resourcePath))") + } + return webView } + // 2. 创建文件 URL + let fileURL = URL(fileURLWithPath: path) + + // 3. 创建 HTML 字符串 + let htmlString = """ + + + + + + + +
+ +
+ + + """ + + // 4. 加载 HTML 字符串 + webView.loadHTMLString(htmlString, baseURL: fileURL.deletingLastPathComponent()) return webView } func updateUIView(_ uiView: WKWebView, context: Context) {} -} - -// MARK: - View Modifier for SVG Image -struct SVGImageModifier: ViewModifier { - let size: CGSize - - func body(content: Content) -> some View { - content - .frame(width: size.width, height: size.height) - .aspectRatio(contentMode: .fit) - } -} - -extension View { - func svgImageStyle(size: CGSize) -> some View { - self.modifier(SVGImageModifier(size: size)) - } -} - -// Usage: -// SVGImage(svgName: "Avatar") +} \ No newline at end of file diff --git a/wake/WakeApp.swift b/wake/WakeApp.swift index 3d1766c..f603882 100644 --- a/wake/WakeApp.swift +++ b/wake/WakeApp.swift @@ -48,7 +48,9 @@ struct WakeApp: App { .environmentObject(authState) } else { // 未登录:显示登录界面 - ContentView() + // ContentView() + // .environmentObject(authState) + UserInfo() .environmentObject(authState) } }