feat: 页面布局

This commit is contained in:
jinyaqiu 2025-08-25 14:09:15 +08:00
parent 2eee2486e1
commit daf8476dd4

View File

@ -9,7 +9,35 @@ struct MediaUploadView: View {
@State private var selectedIndices: Set<Int> = [] @State private var selectedIndices: Set<Int> = []
var body: some View { var body: some View {
VStack(spacing: 24) { VStack() {
//
HStack {
Button(action: {
Router.shared.pop()
}) {
Image(systemName: "chevron.left")
.font(.system(size: 17, weight: .semibold))
.foregroundColor(.themeTextMessageMain)
}
.padding(.leading, 16)
Spacer()
Text("Complete Your Profile")
.font(Typography.font(for: .title2, family: .quicksandBold))
.foregroundColor(.themeTextMessageMain)
Spacer()
//
Color.clear
.frame(width: 24, height: 24)
.padding(.trailing, 16)
}
.background(Color.themeTextWhiteSecondary)
.padding(.bottom, -24)
.zIndex(1) //
//
HStack(spacing: 20) { HStack(spacing: 20) {
Text("The upload process will take approximately 2 minutes. Thank you for your patience. ") Text("The upload process will take approximately 2 minutes. Thank you for your patience. ")
.font(Typography.font(for: .caption)) .font(Typography.font(for: .caption))
@ -28,64 +56,42 @@ struct MediaUploadView: View {
) )
) )
} }
.padding(10) .padding()
Spacer() Spacer()
.frame(height: 20)
MainUploadArea( MainUploadArea(
uploadManager: uploadManager, uploadManager: uploadManager,
showMediaPicker: $showMediaPicker, showMediaPicker: $showMediaPicker,
selectedMedia: $selectedMedia, selectedMedia: $selectedMedia,
selectedIndices: $selectedIndices selectedIndices: $selectedIndices
) )
.padding()
.id("mainUploadArea\(uploadManager.selectedMedia.count)") .id("mainUploadArea\(uploadManager.selectedMedia.count)")
Spacer() Spacer()
.frame(height: 40)
// Navigation button // Navigation button
Button(action: { Button(action: {
Router.shared.navigate(to: .avatarBox) // Router.shared.navigate(to: .avatarBox)
}) { }) {
Text("Continue") Text("Continue")
.font(.headline) .font(.headline)
.foregroundColor(.white) .foregroundColor(uploadManager.selectedMedia.isEmpty ? Color.themeTextMessage : Color.themeTextMessageMain)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 56) .frame(height: 56)
.background(Theme.Colors.primary) .background(uploadManager.selectedMedia.isEmpty ? Color.white : Color.themePrimary)
.cornerRadius(28) .cornerRadius(28)
.padding(.horizontal, 24) .padding(.horizontal, 24)
.padding(.top, 16)
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
if !uploadManager.selectedMedia.isEmpty {
ThumbnailScrollView(
uploadManager: uploadManager,
selectedIndices: $selectedIndices,
selectedMedia: $selectedMedia
)
.id("thumbnailScroll\(uploadManager.selectedMedia.count)")
}
Spacer() Spacer()
if !uploadManager.selectedMedia.isEmpty {
UploadButton(uploadManager: uploadManager)
.id("uploadButton\(uploadManager.selectedMedia.count)")
}
} }
.navigationTitle("Complete Your Profile") .background(Color.themeTextWhiteSecondary)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .navigationBarBackButtonHidden(true)
ToolbarItem(placement: .principal) {
Text("Complete Your Profile")
.font(Typography.font(for: .title2))
}
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {}) {
EmptyView()
}
}
}
.sheet(isPresented: $showMediaPicker) { .sheet(isPresented: $showMediaPicker) {
MediaPicker( MediaPicker(
selectedMedia: $uploadManager.selectedMedia, selectedMedia: $uploadManager.selectedMedia,
@ -106,6 +112,8 @@ struct MediaUploadView: View {
if !uploadManager.selectedMedia.isEmpty && selectedMedia == nil { if !uploadManager.selectedMedia.isEmpty && selectedMedia == nil {
selectedMedia = uploadManager.selectedMedia.first selectedMedia = uploadManager.selectedMedia.first
selectedIndices = [0] selectedIndices = [0]
// Start upload when media picker is dismissed with new media
uploadManager.startUpload()
} }
} }
@ -123,6 +131,11 @@ struct MediaUploadView: View {
} else if let selectedIndex = selectedIndices.first, selectedIndex < newMedia.count { } else if let selectedIndex = selectedIndices.first, selectedIndex < newMedia.count {
selectedMedia = newMedia[selectedIndex] selectedMedia = newMedia[selectedIndex]
} }
// Auto-upload when new media is added
if !newMedia.isEmpty && !uploadManager.isUploading {
uploadManager.startUpload()
}
} }
} }
@ -137,7 +150,7 @@ struct MainUploadArea: View {
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
Text("Click to upload 20 images and 5 videos to generate your next blind box.") Text("Click to upload 20 images and 5 videos to generate your next blind box.")
.font(Typography.font(for: .body, family: .quicksandRegular)) .font(Typography.font(for: .title2, family: .quicksandBold))
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(.black) .foregroundColor(.black)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@ -146,13 +159,20 @@ struct MainUploadArea: View {
if let media = selectedMedia { if let media = selectedMedia {
MediaPreview(media: media) MediaPreview(media: media)
.frame(height: 300) .frame(width: 225, height: 225)
.onTapGesture { showMediaPicker = true } .onTapGesture { showMediaPicker = true }
} else { } else {
UploadPromptView(showMediaPicker: $showMediaPicker) UploadPromptView(showMediaPicker: $showMediaPicker)
} }
if !uploadManager.selectedMedia.isEmpty {
ThumbnailScrollView(
uploadManager: uploadManager,
selectedIndices: $selectedIndices,
selectedMedia: $selectedMedia
)
.id("thumbnailScroll\(uploadManager.selectedMedia.count)")
}
} }
.padding(.horizontal)
.background(Color.white) .background(Color.white)
.cornerRadius(16) .cornerRadius(16)
} }
@ -164,25 +184,22 @@ struct UploadPromptView: View {
@Binding var showMediaPicker: Bool @Binding var showMediaPicker: Bool
var body: some View { var body: some View {
VStack(spacing: 16) { Button(action: {
showMediaPicker = true
}) {
SVGImage(svgName: "IP") SVGImage(svgName: "IP")
.frame(width: 225, height: 225) .frame(width: 225, height: 225)
.contentShape(Rectangle()) .contentShape(Rectangle())
.overlay( .overlay(
RoundedRectangle(cornerRadius: 20) RoundedRectangle(cornerRadius: 20)
.stroke(style: StrokeStyle( .stroke(style: StrokeStyle(
lineWidth: 3, lineWidth: 5,
lineCap: .round, lineCap: .round,
dash: [12, 8] dash: [12, 8]
)) ))
.foregroundColor(Color.themePrimary) .foregroundColor(Color.themePrimary)
) )
.onTapGesture {
showMediaPicker = true
}
} }
.background(Color.white)
.cornerRadius(16)
} }
} }
@ -312,26 +329,6 @@ struct AddMoreButton: View {
} }
} }
// MARK: - Upload Button
struct UploadButton: View {
@ObservedObject var uploadManager: MediaUploadManager
var body: some View {
Button(action: uploadManager.startUpload) {
Text("上传")
.font(.headline)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.frame(height: 56)
.background(Color.themePrimary)
.cornerRadius(28)
.padding(.horizontal, 40)
.padding(.bottom, 24)
}
}
}
// MARK: - Media Preview // MARK: - Media Preview
struct MediaPreview: View { struct MediaPreview: View {