wake-ios/wake/View/Subscribe/Components/PlanSelector.swift
2025-09-01 18:35:57 +08:00

136 lines
4.6 KiB
Swift

//
// PlanSelector.swift
// wake
//
// Created by fairclip on 2025/8/19.
//
import SwiftUI
// MARK: -
struct PlanSelector: View {
@Binding var selectedPlan: SubscriptionPlan?
let onPlanSelected: (SubscriptionPlan) -> Void
private let plans: [SubscriptionPlan] = [.free, .pioneer]
init(
selectedPlan: Binding<SubscriptionPlan?>,
onPlanSelected: @escaping (SubscriptionPlan) -> Void = { _ in }
) {
self._selectedPlan = selectedPlan
self.onPlanSelected = onPlanSelected
}
var body: some View {
HStack(spacing: Theme.Spacing.md) {
ForEach(plans, id: \.self) { plan in
PlanCard(
plan: plan,
isSelected: selectedPlan == plan,
onTap: {
selectedPlan = plan
onPlanSelected(plan)
}
)
}
}
}
}
// MARK: -
struct PlanCard: View {
let plan: SubscriptionPlan
let isSelected: Bool
let onTap: () -> Void
var body: some View {
Button(action: onTap) {
ZStack {
//
VStack(spacing: Theme.Spacing.sm) {
// Popular
if plan.isPopular {
VStack {
HStack {
Spacer()
Text("Popular")
.font(Typography.font(for: .caption, family: .quicksandRegular))
.foregroundColor(Color.white)
.padding(.horizontal, Theme.Spacing.sm)
.padding(.vertical, Theme.Spacing.xs)
.background(Color.black)
.cornerRadius(Theme.CornerRadius.round, corners: [.bottomLeft])
}
Spacer()
VStack {
//
Text(plan.displayName)
.font(Typography.font(for: .title, family: .quicksandBold, size: 18))
.foregroundColor(plan == .pioneer ? Theme.Colors.textPrimary: Theme.Colors.textTertiary )
//
if plan == .pioneer {
Text(plan.price)
.font(Typography.font(for: .body, family: .quicksandBold, size: 20))
.foregroundColor(Theme.Colors.textPrimary)
}
}
Spacer()
Spacer()
}
}
else {
//
Text(plan.displayName)
.font(Typography.font(for: .title, family: .quicksandBold, size: 18))
.foregroundColor(plan == .pioneer ? Theme.Colors.textPrimary: Theme.Colors.textTertiary )
//
if plan == .pioneer {
Text(plan.price)
.font(Typography.font(for: .body, family: .quicksandBold, size: 20))
.foregroundColor(Theme.Colors.textPrimary)
}
}
}
.frame(maxWidth: .infinity)
.frame(height: 120)
.background(
plan == .pioneer ?
Theme.Colors.primary :
Theme.Colors.surfaceTertiary
)
.overlay(
RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)
.stroke(
isSelected ? Theme.Colors.borderDark : Theme.Colors.border,
lineWidth: 2
)
)
.cornerRadius(Theme.CornerRadius.medium)
}
}
.buttonStyle(PlainButtonStyle())
}
}
// MARK: -
#Preview("Plan Selector") {
@State var selectedPlan: SubscriptionPlan? = .pioneer
VStack(spacing: 20) {
PlanSelector(
selectedPlan: $selectedPlan,
onPlanSelected: { plan in
print("Selected plan: \(plan.displayName)")
}
)
}
.padding()
.background(Color(.systemGroupedBackground))
}