Files
suixinkan_ios_new/suixinkan/Features/TravelAlbum/Views/CreateTravelAlbumSheet.swift
汉秋 d2fe5d71e4 Add TravelAlbum, ProfileSpace, and wired camera transfer modules.
Introduce travel album entry with Sony PTP tethering pipeline, profile space settings page, home routing updates, Launch Screen storyboard, and related tests/docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 09:41:05 +08:00

159 lines
7.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// CreateTravelAlbumSheet.swift
// suixinkan
//
// Created by Codex on 2026/6/29.
//
import SwiftUI
///
struct CreateTravelAlbumSheet: View {
let orders: [TravelAlbumAvailableOrder]
let isCreating: Bool
let onConfirm: (Int, String, String, String, TravelAlbumAvailableOrder?) -> Void
@Environment(\.dismiss) private var dismiss
@State private var mode = TravelAlbumEntryViewModel.modePreShoot
@State private var freeCount = ""
@State private var singlePrice = ""
@State private var packagePrice = ""
@State private var selectedOrder: TravelAlbumAvailableOrder?
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: AppMetrics.Spacing.medium) {
modeCard(
title: "先拍再买",
description: "拍完后分享给用户,用户在小程序上选择性购买",
selected: mode == TravelAlbumEntryViewModel.modePreShoot
) {
mode = TravelAlbumEntryViewModel.modePreShoot
}
modeCard(
title: "买了再拍",
description: "用户已在小程序下单,绑定订单后用户可直接选片",
selected: mode == TravelAlbumEntryViewModel.modePreOrder
) {
mode = TravelAlbumEntryViewModel.modePreOrder
}
if mode == TravelAlbumEntryViewModel.modePreShoot {
preShootFields
} else {
preOrderFields
}
}
.padding(AppMetrics.Spacing.pageHorizontal)
.padding(.vertical, AppMetrics.Spacing.medium)
}
.background(Color(hex: 0xF5F7FA))
.navigationTitle("新建相册任务")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("取消") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button(isCreating ? "创建中" : "确认创建") {
onConfirm(mode, freeCount, singlePrice, packagePrice, selectedOrder)
}
.disabled(isCreating)
}
}
}
}
private var preShootFields: some View {
VStack(spacing: AppMetrics.Spacing.small) {
fieldRow(title: "免费张数", placeholder: "请输入免费张数", text: $freeCount, keyboard: .numberPad)
fieldRow(title: "单张价格(元)", placeholder: "请输入单张照片价格", text: $singlePrice, keyboard: .decimalPad)
fieldRow(title: "打包价(元)", placeholder: "可选", text: $packagePrice, keyboard: .decimalPad)
}
}
private var preOrderFields: some View {
VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
Text("选择绑定订单")
.font(.system(size: AppMetrics.FontSize.subheadline, weight: .medium))
.foregroundStyle(AppDesign.textSecondary)
if orders.isEmpty {
Text("暂无可绑定订单")
.foregroundStyle(AppDesign.placeholder)
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
} else {
ForEach(orders) { order in
Button {
selectedOrder = order
} label: {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text(order.projectName)
.font(.system(size: AppMetrics.FontSize.body, weight: .medium))
.foregroundStyle(AppDesign.textPrimary)
Text("\(order.orderNumber) · \(order.userPhone)")
.font(.system(size: AppMetrics.FontSize.caption))
.foregroundStyle(AppDesign.textSecondary)
}
Spacer()
Image(systemName: selectedOrder?.orderNumber == order.orderNumber ? "checkmark.circle.fill" : "circle")
.foregroundStyle(selectedOrder?.orderNumber == order.orderNumber ? AppDesign.primary : AppDesign.placeholder)
}
.padding(AppMetrics.Spacing.medium)
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
}
.buttonStyle(.plain)
}
}
}
}
private func modeCard(title: String, description: String, selected: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
HStack(alignment: .top, spacing: AppMetrics.Spacing.medium) {
Image(systemName: selected ? "largecircle.fill.circle" : "circle")
.foregroundStyle(selected ? AppDesign.primary : AppDesign.placeholder)
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
.foregroundStyle(AppDesign.textPrimary)
Text(description)
.font(.system(size: AppMetrics.FontSize.caption))
.foregroundStyle(AppDesign.textSecondary)
.multilineTextAlignment(.leading)
}
Spacer()
}
.padding(AppMetrics.Spacing.large)
.background(Color.white)
.overlay(
RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card)
.stroke(selected ? AppDesign.primary : Color.clear, lineWidth: 1.5)
)
.clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
}
.buttonStyle(.plain)
}
private func fieldRow(title: String, placeholder: String, text: Binding<String>, keyboard: UIKeyboardType) -> some View {
VStack(alignment: .leading, spacing: 6) {
Text(title)
.font(.system(size: AppMetrics.FontSize.caption))
.foregroundStyle(AppDesign.textSecondary)
TextField(placeholder, text: text)
.keyboardType(keyboard)
.padding(AppMetrics.Spacing.medium)
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
}
}
}