From 44de40cf8312d045855fab4964e3b7fdcfd71c1c Mon Sep 17 00:00:00 2001 From: jinyaqiu Date: Thu, 21 Aug 2025 16:02:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=B4=E5=83=8F=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wake/Assets/.DS_Store | Bin 0 -> 6148 bytes wake/Typography.swift | 4 +- wake/View/Owner/UserInfo/AvatarPicker.swift | 84 ++++++++++++++++ wake/View/Owner/UserInfo/UserInfo.swift | 76 +++++---------- wake/Views/Utils/SVGImage.swift | 100 ++++++++++---------- wake/WakeApp.swift | 4 +- 6 files changed, 165 insertions(+), 103 deletions(-) create mode 100644 wake/Assets/.DS_Store create mode 100644 wake/View/Owner/UserInfo/AvatarPicker.swift diff --git a/wake/Assets/.DS_Store b/wake/Assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bb35e994cbebd985fe6a84d58692d4d5333cd720 GIT binary patch literal 6148 zcmeH~J!->15QX2wE(~c@y4)rQ$PE_boIn?FVQ>>1Fxd4TJ#T)RD5;GIZ(!!_%xaMI z6Xzj&u49&Rw4Ifr_HlJc>mhG^{gl0WNK?Fo#L12^lp`c+) { + 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) } }