diff --git a/wake/Assets/Svg/IP1.svg b/wake/Assets/Svg/IP1.svg new file mode 100644 index 0000000..256a92a --- /dev/null +++ b/wake/Assets/Svg/IP1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/wake/Assets/Svg/JoinList.svg b/wake/Assets/Svg/JoinList.svg new file mode 100644 index 0000000..9893af9 --- /dev/null +++ b/wake/Assets/Svg/JoinList.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/wake/Typography.swift b/wake/Typography.swift index c9cab9e..e625504 100644 --- a/wake/Typography.swift +++ b/wake/Typography.swift @@ -26,6 +26,7 @@ enum TypographyStyle { case largeTitle // 大标题 case smallLargeTitle // 小大标题 case headline // 大标题 + case headline1 // 大标题1 case title // 标题 case title2 // 标题 case title3 // 标题 @@ -54,6 +55,7 @@ struct Typography { private static let styleConfig: [TypographyStyle: TypographyConfig] = [ .largeTitle: TypographyConfig(size: 32, weight: .heavy, textStyle: .largeTitle), .smallLargeTitle: TypographyConfig(size: 30, weight: .heavy, textStyle: .largeTitle), + .headline1: TypographyConfig(size: 26, weight: .bold, textStyle: .headline), .headline: TypographyConfig(size: 24, weight: .bold, textStyle: .headline), .title3: TypographyConfig(size: 22, weight: .semibold, textStyle: .title2), .title: TypographyConfig(size: 20, weight: .semibold, textStyle: .title2), diff --git a/wake/View/Blind/Apng.swift b/wake/View/Blind/Apng.swift deleted file mode 100644 index 3b6a755..0000000 --- a/wake/View/Blind/Apng.swift +++ /dev/null @@ -1,38 +0,0 @@ -import SwiftUI -import UIKit - -// 包装UIImageView以支持APNG动画 -struct APNGView: UIViewRepresentable { - let imageName: String - @Binding var isAnimating: Bool - - func makeUIView(context: Context) -> UIImageView { - let imageView = UIImageView() - - // 从资源加载APNG - if let image = UIImage(named: imageName) { - imageView.image = image - // 启用动画 - imageView.animationImages = image.images - // 设置动画时长(根据实际帧数调整) - imageView.animationDuration = image.duration - // 根据isAnimating状态决定是否开始动画 - if isAnimating { - imageView.startAnimating() - } - } - - return imageView - } - - func updateUIView(_ uiView: UIImageView, context: Context) { - // 根据isAnimating状态控制动画 - if isAnimating { - if !uiView.isAnimating { - uiView.startAnimating() - } - } else { - uiView.stopAnimating() - } - } -} \ No newline at end of file diff --git a/wake/View/Blind/BlindOutCome.swift b/wake/View/Blind/BlindOutCome.swift index b30d28b..50c3f04 100644 --- a/wake/View/Blind/BlindOutCome.swift +++ b/wake/View/Blind/BlindOutCome.swift @@ -8,6 +8,7 @@ struct BlindOutcomeView: View { @Environment(\.presentationMode) var presentationMode @State private var isFullscreen = false @State private var isPlaying = false + @State private var showIPListModal = false var body: some View { NavigationView { @@ -99,9 +100,11 @@ struct BlindOutcomeView: View { // Button below media VStack(spacing: 16) { Button(action: { - // 如果携带的类型是video跳转到contentview + // 如果携带的类型是video显示弹窗 if case .video = media { - // Router.shared.navigate(to: .mediaUpload) + withAnimation { + showIPListModal = true + } } else { Router.shared.navigate(to: .mediaUpload) } @@ -130,6 +133,9 @@ struct BlindOutcomeView: View { FullscreenMediaView(media: media, isPresented: $isFullscreen, isPlaying: $isPlaying, player: nil) } } + .overlay( + JoinModal(isPresented: $showIPListModal) + ) } .navigationViewStyle(StackNavigationViewStyle()) // 确保在iPad上也能正确显示 .navigationBarHidden(true) // 额外确保隐藏导航栏 diff --git a/wake/View/Blind/JoinModal.swift b/wake/View/Blind/JoinModal.swift new file mode 100644 index 0000000..e215707 --- /dev/null +++ b/wake/View/Blind/JoinModal.swift @@ -0,0 +1,220 @@ +import SwiftUI + +struct JoinModal: View { + @Binding var isPresented: Bool + + var body: some View { + ZStack(alignment: .bottom) { + // Semi-transparent background + if isPresented { + Color.black.opacity(0.4) + .edgesIgnoringSafeArea(.all) + .onTapGesture { + withAnimation { + isPresented = false + } + } + } + + // Modal content + if isPresented { + VStack(spacing: 0) { + // IP Image peeking from top + HStack { + // Make sure you have an image named "IP" in your assets + SVGImage(svgName: "IP1") + .frame(width: 116, height: 65) + .offset(x: 30) + Spacer() + } + .frame(height: 65) + + VStack(spacing: 0) { + // Close button on the right + HStack { + Spacer() + Button(action: { + withAnimation { + isPresented = false + } + }) { + Image(systemName: "xmark") + .font(.system(size: 20, weight: .medium)) + .foregroundColor(.themeTextMessageMain) + .padding(12) + } + .padding(.trailing, 16) + } + + // 文本 + VStack(spacing: 8) { + Text("Join us!") + .font(Typography.font(for: .headline1, family: .quicksandBold)) + .foregroundColor(.themeTextMessageMain) + Text("Join us to get more exclusive benefits.") + .font(.system(size: 14, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + .padding(.vertical, 12) + // List content + VStack (alignment: .leading) { + HStack { + SVGImage(svgName: "JoinList") + .frame(width: 32, height: 32) + HStack (alignment: .top){ + Text("Unlimited") + .font(.system(size: 16, weight: .bold)) + .foregroundColor(.themeTextMessageMain) + Text(" blind box purchases.") + .font(.system(size: 16, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + } + .padding(.vertical, 12) + .padding(.leading,12) + HStack (alignment: .center) { + SVGImage(svgName: "JoinList") + .frame(width: 32, height: 32) + VStack (alignment: .leading,spacing: 4) { + HStack { + Text("Freely") + .font(.system(size: 16, weight: .bold)) + .foregroundColor(.themeTextMessageMain) + Text(" upload image and video") + .font(.system(size: 16, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + Text(" materials.") + .font(.system(size: 16, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + } + .padding(.vertical, 12) + .padding(.leading,12) + + HStack(alignment: .top) { + SVGImage(svgName: "JoinList") + .frame(width: 32, height: 32) + VStack (alignment: .leading,spacing: 4) { + HStack { + Text("500") + .font(.system(size: 16, weight: .bold)) + .foregroundColor(.themeTextMessageMain) + Text(" credits daily,") + .font(.system(size: 16, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + HStack(alignment: .top) { + VStack (alignment: .leading, spacing: 4) { + HStack { + Text("5000") + .font(.system(size: 16, weight: .bold)) + .foregroundColor(.themeTextMessageMain) + Text(" permanent credits on your first") + .font(.system(size: 16, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + Text(" purchase!") + .font(.system(size: 16, weight: .regular)) + .foregroundColor(.themeTextMessageMain) + } + } + } + } + .padding(.top, 12) + .padding(.leading,12) + HStack { + Spacer() // This will push the button to the right + Button(action: { + // 点击跳转到会员页面 + Router.shared.navigate(to: .subscribe) + }) { + HStack { + Text("See More") + .font(.system(size: 16)) + Image(systemName: "chevron.right") + .font(.system(size: 14)) + } + .foregroundColor(.themeTextMessageMain) + .padding(.vertical, 12) + .padding(.horizontal, 24) + .cornerRadius(20) + } + } + .padding(.trailing, 16) // Add some right padding to match the design + Button(action: { + // 点击跳转到会员页面 + Router.shared.navigate(to: .subscribe) + }) { + HStack { + Text("Subscribe") + .font(Typography.font(for: .body, family: .quicksandBold)) + Spacer() + Text("$1.00/Mon") + .font(Typography.font(for: .body, family: .quicksandBold)) + } + .foregroundColor(.themeTextMessageMain) + .padding(.vertical, 12) + .padding(.horizontal, 30) + .background(Color.themePrimary) + .cornerRadius(20) + } + .padding(.top, 16) + // 协议条款 + HStack(alignment: .center) { + Button(action: { + // Action for Terms of Service + }) { + Text("Terms of Service") + .font(.system(size: 12, weight: .regular)) + .foregroundColor(.themeTextMessage) + .underline() // Add underline + } + Rectangle() + .fill(Color.gray.opacity(0.5)) + .frame(width: 1, height: 16) + .padding(.vertical, 4) + Button(action: { + // Action for Privacy Policy + }) { + Text("Privacy Policy") + .font(.system(size: 12, weight: .regular)) + .foregroundColor(.themeTextMessage) + .underline() // Add underline + } + Rectangle() + .fill(Color.gray.opacity(0.5)) + .frame(width: 1, height: 16) + .padding(.vertical, 4) + Button(action: { + // Action for Restore Purchase + }) { + Text("Restore Purchase") + .font(.system(size: 12, weight: .regular)) + .foregroundColor(.themeTextMessage) + .underline() // Add underline + } + } + .padding(.bottom, 24) + .frame(maxWidth: .infinity, alignment: .center) + } + .padding(.horizontal, 16) + } + .background(Color.white) + .cornerRadius(20, corners: [.topLeft, .topRight]) + } + .frame(height: nil) + .transition(.move(edge: .bottom)) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) + .edgesIgnoringSafeArea(.all) + .animation(.easeInOut, value: isPresented) + } +} + +struct JoinModal_Previews: PreviewProvider { + static var previews: some View { + JoinModal(isPresented: .constant(true)) + } +} diff --git a/wake/View/Upload/MediaUploadView.swift b/wake/View/Upload/MediaUploadView.swift index 633e2e5..5ef72a4 100644 --- a/wake/View/Upload/MediaUploadView.swift +++ b/wake/View/Upload/MediaUploadView.swift @@ -167,7 +167,7 @@ struct MediaUploadView: View { } // 开始上传 - uploadManager.startUpload() + // uploadManager.startUpload() } else { print("ℹ️ 没有新文件需要添加,所有选择的文件都已存在") } @@ -249,7 +249,7 @@ struct MediaUploadView: View { } // 开始上传新添加的媒体 - uploadManager.startUpload() + // uploadManager.startUpload() print("媒体添加完成,总数量: \(uploadManager.selectedMedia.count)") } } diff --git a/wake/WakeApp.swift b/wake/WakeApp.swift index 894aea3..ec8f291 100644 --- a/wake/WakeApp.swift +++ b/wake/WakeApp.swift @@ -46,7 +46,7 @@ struct WakeApp: App { // 根据登录状态显示不同视图 if authState.isAuthenticated { // 已登录:显示userInfo页面 - LoginView() + MediaUploadView() .environmentObject(authState) // ContentView() // .environmentObject(authState)