import Cocoa final class PremiumPlansWindowController: NSWindowController { init() { let viewController = PremiumPlansViewController() let window = NSWindow(contentViewController: viewController) window.title = "Premium Plans" window.styleMask = [.titled, .closable, .miniaturizable, .resizable] window.setContentSize(NSSize(width: 1160, height: 760)) window.minSize = NSSize(width: 980, height: 680) window.center() super.init(window: window) } @available(*, unavailable) required init?(coder: NSCoder) { nil } } private final class PremiumPlansViewController: NSViewController { private struct Plan { let id: String let title: String let subtitle: String let price: String let period: String let billedPill: String let billedLine: String let crossedPrice: String? let savingsText: String? let features: [String] let iconName: String let iconTint: NSColor let highlight: Bool } private enum Theme { static let pageStart = NSColor(srgbRed: 249 / 255, green: 252 / 255, blue: 255 / 255, alpha: 1) static let pageEnd = NSColor(srgbRed: 238 / 255, green: 244 / 255, blue: 255 / 255, alpha: 1) static let cardBackground = NSColor.white static let primaryText = NSColor(srgbRed: 27 / 255, green: 38 / 255, blue: 79 / 255, alpha: 1) static let secondaryText = NSColor(srgbRed: 108 / 255, green: 120 / 255, blue: 157 / 255, alpha: 1) static let cardBorder = NSColor(srgbRed: 198 / 255, green: 216 / 255, blue: 255 / 255, alpha: 1) static let accent = NSColor(srgbRed: 55 / 255, green: 128 / 255, blue: 255 / 255, alpha: 1) static let accentHover = NSColor(srgbRed: 38 / 255, green: 108 / 255, blue: 232 / 255, alpha: 1) static let mutedButtonFill = NSColor(srgbRed: 238 / 255, green: 243 / 255, blue: 252 / 255, alpha: 1) static let bottomStrip = NSColor(srgbRed: 244 / 255, green: 248 / 255, blue: 255 / 255, alpha: 1) static let divider = NSColor(srgbRed: 218 / 255, green: 228 / 255, blue: 247 / 255, alpha: 1) static let successText = NSColor(srgbRed: 21 / 255, green: 154 / 255, blue: 220 / 255, alpha: 1) static let iconTint = NSColor(srgbRed: 47 / 255, green: 136 / 255, blue: 255 / 255, alpha: 1) } private let plans: [Plan] = [ Plan( id: "weekly", title: "Weekly", subtitle: "Flexible and commitment-free", price: "$9.99", period: "/ week", billedPill: "", billedLine: "", crossedPrice: nil, savingsText: nil, features: [ "All premium features", "Perfect for short-term goals", "Cancel anytime" ], iconName: "paperplane.fill", iconTint: Theme.iconTint, highlight: false ), Plan( id: "monthly", title: "Monthly", subtitle: "Balanced for regular productivity", price: "$19.99", period: "/ month", billedPill: "Most Popular", billedLine: "", crossedPrice: nil, savingsText: nil, features: [ "All premium features", "Best value for regular users", "Priority support" ], iconName: "bolt.fill", iconTint: Theme.accent, highlight: true ), Plan( id: "yearly", title: "Yearly", subtitle: "Best value for long-term users", price: "$39.99", period: "/ year", billedPill: "3-day free trial", billedLine: "", crossedPrice: nil, savingsText: nil, features: [ "All premium features", "Lowest effective monthly cost", "Ideal for long-term use" ], iconName: "crown.fill", iconTint: Theme.successText, highlight: false ) ] private let pageGradient = CAGradientLayer() private lazy var popularGradient: CAGradientLayer = { let layer = CAGradientLayer() layer.colors = [ NSColor(srgbRed: 189 / 255, green: 52 / 255, blue: 255 / 255, alpha: 1).cgColor, NSColor(srgbRed: 73 / 255, green: 153 / 255, blue: 255 / 255, alpha: 1).cgColor ] layer.startPoint = CGPoint(x: 0, y: 0.5) layer.endPoint = CGPoint(x: 1, y: 0.5) return layer }() override func viewDidLayout() { super.viewDidLayout() pageGradient.frame = view.bounds popularGradient.frame = CGRect(x: 0, y: 0, width: 160, height: 22) } override func loadView() { view = NSView() view.wantsLayer = true pageGradient.colors = [Theme.pageStart.cgColor, Theme.pageEnd.cgColor] pageGradient.startPoint = CGPoint(x: 0, y: 1) pageGradient.endPoint = CGPoint(x: 1, y: 0) view.layer?.addSublayer(pageGradient) setupLayout() } private func setupLayout() { let crownIcon = NSImageView() crownIcon.translatesAutoresizingMaskIntoConstraints = false crownIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 18, weight: .semibold) crownIcon.image = NSImage(systemSymbolName: "crown.fill", accessibilityDescription: nil) crownIcon.contentTintColor = NSColor(srgbRed: 254 / 255, green: 214 / 255, blue: 92 / 255, alpha: 1) let title = NSTextField(labelWithString: "Upgrade to Pro") title.font = .systemFont(ofSize: 52, weight: .bold) title.textColor = Theme.primaryText title.alignment = .center let subtitle = NSTextField(labelWithString: "Unlock unlimited access to premium tools and boost your productivity.") subtitle.font = .systemFont(ofSize: 15, weight: .medium) subtitle.textColor = Theme.secondaryText subtitle.alignment = .center let cardsRow = NSStackView(views: plans.map(makePricingCard(_:))) cardsRow.orientation = .horizontal cardsRow.spacing = 14 cardsRow.alignment = .top cardsRow.distribution = .fillEqually cardsRow.translatesAutoresizingMaskIntoConstraints = false let trustRow = makeTrustRow() let footerRow = makeFooterRow() let root = NSStackView(views: [crownIcon, title, subtitle, cardsRow, trustRow, footerRow]) root.orientation = .vertical root.spacing = 18 root.alignment = .centerX root.translatesAutoresizingMaskIntoConstraints = false view.addSubview(root) NSLayoutConstraint.activate([ root.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24), root.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24), root.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), root.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16), cardsRow.widthAnchor.constraint(equalTo: root.widthAnchor), cardsRow.heightAnchor.constraint(equalToConstant: 420), trustRow.widthAnchor.constraint(equalTo: root.widthAnchor), footerRow.widthAnchor.constraint(equalTo: root.widthAnchor), crownIcon.heightAnchor.constraint(equalToConstant: 20) ]) } private func makePricingCard(_ plan: Plan) -> NSView { let card = NSView() card.translatesAutoresizingMaskIntoConstraints = false card.wantsLayer = true card.layer?.backgroundColor = Theme.cardBackground.cgColor card.layer?.cornerRadius = 16 card.layer?.borderWidth = plan.highlight ? 2 : 1 card.layer?.borderColor = (plan.highlight ? Theme.accent : Theme.cardBorder).cgColor let iconWell = NSView() iconWell.translatesAutoresizingMaskIntoConstraints = false iconWell.wantsLayer = true iconWell.layer?.cornerRadius = 10 iconWell.layer?.backgroundColor = Theme.bottomStrip.cgColor iconWell.widthAnchor.constraint(equalToConstant: 24).isActive = true iconWell.heightAnchor.constraint(equalToConstant: 24).isActive = true let icon = NSImageView() icon.translatesAutoresizingMaskIntoConstraints = false icon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 11, weight: .bold) icon.image = NSImage(systemSymbolName: plan.iconName, accessibilityDescription: nil) icon.contentTintColor = plan.iconTint iconWell.addSubview(icon) NSLayoutConstraint.activate([ icon.centerXAnchor.constraint(equalTo: iconWell.centerXAnchor), icon.centerYAnchor.constraint(equalTo: iconWell.centerYAnchor) ]) let titleLabel = NSTextField(labelWithString: plan.title) titleLabel.font = .systemFont(ofSize: 44, weight: .bold) titleLabel.textColor = Theme.primaryText titleLabel.alignment = .center let subtitleLabel = NSTextField(labelWithString: plan.subtitle) subtitleLabel.font = .systemFont(ofSize: 13, weight: .medium) subtitleLabel.textColor = Theme.secondaryText subtitleLabel.alignment = .center let billingPill = pillLabel(text: plan.billedPill, tint: Theme.bottomStrip, textColor: Theme.iconTint) billingPill.isHidden = plan.billedPill.isEmpty let priceLabel = NSTextField(labelWithString: plan.price) priceLabel.font = .systemFont(ofSize: 40, weight: .bold) priceLabel.textColor = Theme.primaryText let periodLabel = NSTextField(labelWithString: plan.period) periodLabel.font = .systemFont(ofSize: 30, weight: .semibold) periodLabel.textColor = Theme.secondaryText let priceRow = NSStackView(views: [priceLabel, periodLabel]) priceRow.orientation = .horizontal priceRow.spacing = 4 priceRow.alignment = .firstBaseline let billingLabel = NSTextField(labelWithString: plan.billedLine) billingLabel.font = .systemFont(ofSize: 13, weight: .medium) billingLabel.textColor = Theme.secondaryText billingLabel.isHidden = plan.billedLine.isEmpty let inlinePriceInfo = inlinePriceInfoLabel(oldPrice: plan.crossedPrice, newPrice: plan.savingsText) inlinePriceInfo.isHidden = (plan.crossedPrice == nil || plan.savingsText == nil) let divider = NSBox() divider.boxType = .separator divider.translatesAutoresizingMaskIntoConstraints = false divider.borderColor = Theme.divider let featuresStack = NSStackView(views: plan.features.map(makeFeatureRow(_:))) featuresStack.orientation = .vertical featuresStack.spacing = 9 featuresStack.alignment = .leading let selectButton = NSButton(title: "Get \(plan.title)", target: self, action: #selector(didTapSelectPlan)) selectButton.identifier = NSUserInterfaceItemIdentifier(plan.id) selectButton.isBordered = false selectButton.bezelStyle = .rounded selectButton.font = .systemFont(ofSize: 15, weight: .bold) selectButton.contentTintColor = plan.highlight ? .white : Theme.primaryText selectButton.wantsLayer = true selectButton.layer?.cornerRadius = 12 selectButton.layer?.borderWidth = 1 selectButton.layer?.borderColor = (plan.highlight ? Theme.accent : Theme.divider).cgColor selectButton.layer?.backgroundColor = (plan.highlight ? NSColor(srgbRed: 189 / 255, green: 52 / 255, blue: 255 / 255, alpha: 1) : Theme.mutedButtonFill).cgColor selectButton.translatesAutoresizingMaskIntoConstraints = false selectButton.heightAnchor.constraint(equalToConstant: 58).isActive = true let spacer = NSView() spacer.setContentHuggingPriority(.defaultLow, for: .vertical) let content = NSStackView(views: [iconWell, titleLabel, subtitleLabel, billingPill, priceRow, billingLabel, inlinePriceInfo, divider, featuresStack, spacer, selectButton]) content.orientation = .vertical content.spacing = 10 content.alignment = .centerX content.translatesAutoresizingMaskIntoConstraints = false card.addSubview(content) NSLayoutConstraint.activate([ divider.widthAnchor.constraint(equalTo: content.widthAnchor), content.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 18), content.trailingAnchor.constraint(equalTo: card.trailingAnchor, constant: -18), content.topAnchor.constraint(equalTo: card.topAnchor, constant: 14), content.bottomAnchor.constraint(equalTo: card.bottomAnchor, constant: -16), selectButton.widthAnchor.constraint(equalTo: content.widthAnchor) ]) if plan.highlight { let badgeHost = NSView() badgeHost.translatesAutoresizingMaskIntoConstraints = false badgeHost.wantsLayer = true badgeHost.layer?.cornerRadius = 14 badgeHost.layer?.masksToBounds = true badgeHost.layer?.addSublayer(popularGradient) let sparkle = NSImageView() sparkle.translatesAutoresizingMaskIntoConstraints = false sparkle.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 10, weight: .semibold) sparkle.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: nil) sparkle.contentTintColor = .white let badge = NSTextField(labelWithString: "Most Popular") badge.font = .systemFont(ofSize: 12, weight: .bold) badge.textColor = .white badgeHost.addSubview(sparkle) badgeHost.addSubview(badge) card.addSubview(badgeHost) NSLayoutConstraint.activate([ badgeHost.trailingAnchor.constraint(equalTo: card.trailingAnchor, constant: -14), badgeHost.topAnchor.constraint(equalTo: card.topAnchor, constant: 10), badgeHost.widthAnchor.constraint(equalToConstant: 160), badgeHost.heightAnchor.constraint(equalToConstant: 22), sparkle.leadingAnchor.constraint(equalTo: badgeHost.leadingAnchor, constant: 14), sparkle.centerYAnchor.constraint(equalTo: badgeHost.centerYAnchor), badge.leadingAnchor.constraint(equalTo: sparkle.trailingAnchor, constant: 6), badge.centerYAnchor.constraint(equalTo: badgeHost.centerYAnchor) ]) } return card } private func makeFeatureRow(_ text: String) -> NSView { let icon = NSImageView() icon.translatesAutoresizingMaskIntoConstraints = false icon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 11, weight: .bold) icon.image = NSImage(systemSymbolName: "checkmark.circle.fill", accessibilityDescription: nil) icon.contentTintColor = Theme.iconTint icon.widthAnchor.constraint(equalToConstant: 14).isActive = true let label = NSTextField(labelWithString: text) label.font = .systemFont(ofSize: 16, weight: .semibold) label.textColor = Theme.primaryText let row = NSStackView(views: [icon, label]) row.orientation = .horizontal row.spacing = 8 row.alignment = .centerY row.distribution = .fill return row } private func inlinePriceInfoLabel(oldPrice: String?, newPrice: String?) -> NSTextField { guard let oldPrice, let newPrice else { return NSTextField(labelWithString: "") } let full = NSMutableAttributedString() let oldAttributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 12, weight: .semibold), .foregroundColor: Theme.secondaryText, .strikethroughStyle: NSUnderlineStyle.single.rawValue ] let newAttributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 12, weight: .bold), .foregroundColor: Theme.successText ] full.append(NSAttributedString(string: "\(oldPrice) ", attributes: oldAttributes)) full.append(NSAttributedString(string: newPrice, attributes: newAttributes)) let label = NSTextField(labelWithAttributedString: full) return label } private func pillLabel(text: String, tint: NSColor, textColor: NSColor) -> NSTextField { let pill = NSTextField(labelWithString: text) pill.font = .systemFont(ofSize: 10, weight: .semibold) pill.textColor = textColor pill.alignment = .center pill.wantsLayer = true pill.layer?.backgroundColor = tint.cgColor pill.layer?.cornerRadius = 9 pill.translatesAutoresizingMaskIntoConstraints = false pill.heightAnchor.constraint(equalToConstant: 18).isActive = true pill.widthAnchor.constraint(greaterThanOrEqualToConstant: 95).isActive = true return pill } private func makeTrustRow() -> NSView { let badges = NSStackView(views: [ trustBadge(icon: "shield.fill", title: "Secure Payments", subtitle: "Your payment is 100% secure."), trustBadge(icon: "arrow.counterclockwise", title: "Cancel Anytime", subtitle: "No commitment, cancel anytime."), trustBadge(icon: "headphones", title: "24/7 Support", subtitle: "We're here to help you anytime."), trustBadge(icon: "lock.fill", title: "Privacy First", subtitle: "Your data is safe with us.") ]) badges.orientation = .horizontal badges.alignment = .centerY badges.distribution = .fillEqually badges.spacing = 12 badges.edgeInsets = NSEdgeInsets(top: 0, left: 8, bottom: 0, right: 8) badges.translatesAutoresizingMaskIntoConstraints = false badges.wantsLayer = true badges.layer?.backgroundColor = Theme.bottomStrip.cgColor badges.layer?.borderColor = Theme.divider.cgColor badges.layer?.borderWidth = 1 badges.layer?.cornerRadius = 10 badges.setHuggingPriority(.defaultLow, for: .horizontal) badges.heightAnchor.constraint(equalToConstant: 72).isActive = true return badges } private func makeFooterRow() -> NSView { let items = [ "Manage Subscription", "Restore Purchase", "Privacy Policy", "Terms of Services", "Support" ] let cells = items.enumerated().map { index, text in footerCell(text: text, showsTrailingDivider: index < items.count - 1) } let links = NSStackView(views: cells) links.orientation = .horizontal links.distribution = .fillEqually links.spacing = 0 links.alignment = .centerY links.translatesAutoresizingMaskIntoConstraints = false return links } private func footerCell(text: String, showsTrailingDivider: Bool) -> NSView { let container = NSView() container.translatesAutoresizingMaskIntoConstraints = false let label = footerLink(text) label.translatesAutoresizingMaskIntoConstraints = false label.alignment = .center container.addSubview(label) var constraints = [ label.centerXAnchor.constraint(equalTo: container.centerXAnchor), label.centerYAnchor.constraint(equalTo: container.centerYAnchor) ] if showsTrailingDivider { let divider = footerDivider() container.addSubview(divider) constraints.append(contentsOf: [ divider.trailingAnchor.constraint(equalTo: container.trailingAnchor), divider.centerYAnchor.constraint(equalTo: container.centerYAnchor) ]) } NSLayoutConstraint.activate(constraints) return container } private func trustBadge(icon: String, title: String, subtitle: String) -> NSView { let image = NSImageView() image.translatesAutoresizingMaskIntoConstraints = false image.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold) image.image = NSImage(systemSymbolName: icon, accessibilityDescription: nil) image.contentTintColor = Theme.primaryText let titleLabel = NSTextField(labelWithString: title) titleLabel.font = .systemFont(ofSize: 12, weight: .bold) titleLabel.textColor = Theme.primaryText let subtitleLabel = NSTextField(labelWithString: subtitle) subtitleLabel.font = .systemFont(ofSize: 10, weight: .medium) subtitleLabel.textColor = Theme.secondaryText let textStack = NSStackView(views: [titleLabel, subtitleLabel]) textStack.orientation = .vertical textStack.spacing = 2 textStack.alignment = .leading let stack = NSStackView(views: [image, textStack]) stack.orientation = .horizontal stack.spacing = 8 stack.alignment = .leading stack.edgeInsets = NSEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) stack.wantsLayer = true stack.layer?.backgroundColor = NSColor.clear.cgColor return stack } private func footerLink(_ text: String) -> NSTextField { let label = NSTextField(labelWithString: text) label.font = .systemFont(ofSize: 12, weight: .medium) label.textColor = Theme.secondaryText return label } private func footerDivider() -> NSBox { let divider = NSBox() divider.boxType = .separator divider.borderColor = Theme.divider divider.translatesAutoresizingMaskIntoConstraints = false divider.widthAnchor.constraint(equalToConstant: 1).isActive = true divider.heightAnchor.constraint(equalToConstant: 14).isActive = true return divider } @objc private func didTapSelectPlan(_ sender: NSButton) { sender.layer?.backgroundColor = Theme.accentHover.cgColor let selectedPlan = sender.identifier?.rawValue ?? sender.title let alert = NSAlert() alert.messageText = "Premium checkout coming soon" alert.informativeText = "Plan selected: \(selectedPlan.capitalized). Payment flow can be connected next." alert.alertStyle = .informational alert.addButton(withTitle: "OK") if let window = view.window { alert.beginSheetModal(for: window) } else { alert.runModal() } } }