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> = []
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) {
Text("The upload process will take approximately 2 minutes. Thank you for your patience. ")
.font(Typography.font(for: .caption))
@ -28,64 +56,42 @@ struct MediaUploadView: View {
)
)
}
.padding(10)
.padding()
Spacer()
.frame(height: 20)
MainUploadArea(
uploadManager: uploadManager,
showMediaPicker: $showMediaPicker,
selectedMedia: $selectedMedia,
selectedIndices: $selectedIndices
)
.padding()
.id("mainUploadArea\(uploadManager.selectedMedia.count)")
Spacer()
.frame(height: 40)
// Navigation button
Button(action: {
Router.shared.navigate(to: .avatarBox)
// Router.shared.navigate(to: .avatarBox)
}) {
Text("Continue")
.font(.headline)
.foregroundColor(.white)
.foregroundColor(uploadManager.selectedMedia.isEmpty ? Color.themeTextMessage : Color.themeTextMessageMain)
.frame(maxWidth: .infinity)
.frame(height: 56)
.background(Theme.Colors.primary)
.background(uploadManager.selectedMedia.isEmpty ? Color.white : Color.themePrimary)
.cornerRadius(28)
.padding(.horizontal, 24)
.padding(.top, 16)
}
.buttonStyle(PlainButtonStyle())
if !uploadManager.selectedMedia.isEmpty {
ThumbnailScrollView(
uploadManager: uploadManager,
selectedIndices: $selectedIndices,
selectedMedia: $selectedMedia
)
.id("thumbnailScroll\(uploadManager.selectedMedia.count)")
}
Spacer()
if !uploadManager.selectedMedia.isEmpty {
UploadButton(uploadManager: uploadManager)
.id("uploadButton\(uploadManager.selectedMedia.count)")
}
}
.navigationTitle("Complete Your Profile")
.background(Color.themeTextWhiteSecondary)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Text("Complete Your Profile")
.font(Typography.font(for: .title2))
}
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {}) {
EmptyView()
}
}
}
.navigationBarBackButtonHidden(true)
.sheet(isPresented: $showMediaPicker) {
MediaPicker(
selectedMedia: $uploadManager.selectedMedia,
@ -106,6 +112,8 @@ struct MediaUploadView: View {
if !uploadManager.selectedMedia.isEmpty && selectedMedia == nil {
selectedMedia = uploadManager.selectedMedia.first
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 {
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 {
VStack(spacing: 16) {
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)
.foregroundColor(.black)
.multilineTextAlignment(.center)
@ -146,13 +159,20 @@ struct MainUploadArea: View {
if let media = selectedMedia {
MediaPreview(media: media)
.frame(height: 300)
.frame(width: 225, height: 225)
.onTapGesture { showMediaPicker = true }
} else {
UploadPromptView(showMediaPicker: $showMediaPicker)
}
if !uploadManager.selectedMedia.isEmpty {
ThumbnailScrollView(
uploadManager: uploadManager,
selectedIndices: $selectedIndices,
selectedMedia: $selectedMedia
)
.id("thumbnailScroll\(uploadManager.selectedMedia.count)")
}
}
.padding(.horizontal)
.background(Color.white)
.cornerRadius(16)
}
@ -164,25 +184,22 @@ struct UploadPromptView: View {
@Binding var showMediaPicker: Bool
var body: some View {
VStack(spacing: 16) {
Button(action: {
showMediaPicker = true
}) {
SVGImage(svgName: "IP")
.frame(width: 225, height: 225)
.contentShape(Rectangle())
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(style: StrokeStyle(
lineWidth: 3,
lineWidth: 5,
lineCap: .round,
dash: [12, 8]
))
.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
struct MediaPreview: View {