import SwiftUI import StoreKit /// Nudge sheet asking the user to support development. /// Shown automatically 3 days after first launch, then every 6 months. struct SupportNudgeView: View { @Environment(MAStoreManager.self) private var storeManager @Binding var isPresented: Bool var body: some View { NavigationStack { ScrollView { VStack(spacing: 0) { // MARK: - Hero VStack(spacing: 16) { ZStack { Circle() .fill( LinearGradient( colors: [Color.orange, Color.pink], startPoint: .topLeading, endPoint: .bottomTrailing ) ) .frame(width: 80, height: 80) .shadow(color: .orange.opacity(0.4), radius: 16, y: 6) Image(systemName: "heart.fill") .font(.system(size: 36)) .foregroundStyle(.white) } .padding(.top, 32) Text("Keep Mobile MA Growing") .font(.title2.weight(.bold)) .multilineTextAlignment(.center) Text("Mobile MA is a free, passion-driven app. If it brings music to your life, a small donation helps keep it alive and growing.") .font(.subheadline) .foregroundStyle(.secondary) .multilineTextAlignment(.center) .padding(.horizontal, 24) } .padding(.bottom, 32) // MARK: - Tiers VStack(spacing: 12) { if storeManager.products.isEmpty { ProgressView() .frame(maxWidth: .infinity) .padding(.vertical, 32) } else { ForEach(storeManager.products, id: \.id) { product in TierRow(product: product, storeManager: storeManager, isPresented: $isPresented) } } } .padding(.horizontal, 20) // MARK: - Dismiss Button { isPresented = false } label: { Text("Maybe Later") .font(.subheadline) .foregroundStyle(.secondary) .padding(.vertical, 20) } .buttonStyle(.plain) } } .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button { isPresented = false } label: { Image(systemName: "xmark.circle.fill") .foregroundStyle(.secondary) .font(.title3) } .buttonStyle(.plain) } } } .task { if storeManager.products.isEmpty { await storeManager.loadProducts() } } .presentationDetents([.medium, .large]) .presentationDragIndicator(.visible) } } // MARK: - Tier Row private struct TierRow: View { let product: Product let storeManager: MAStoreManager @Binding var isPresented: Bool private var accentColor: Color { switch product.id { case "donatesong": return .teal case "donatealbum": return .orange case "donateanthology": return .purple default: return .pink } } var body: some View { HStack(spacing: 14) { // Icon ZStack { RoundedRectangle(cornerRadius: 12) .fill(accentColor.opacity(0.15)) .frame(width: 48, height: 48) Image(systemName: storeManager.iconName(for: product)) .font(.title3) .foregroundStyle(accentColor) } // Info VStack(alignment: .leading, spacing: 2) { Text(storeManager.tierName(for: product)) .font(.body.weight(.medium)) Text(product.description) .font(.caption) .foregroundStyle(.secondary) .lineLimit(2) } Spacer() // Buy button Button { Task { await storeManager.purchase(product) if case .success = storeManager.purchaseResult { isPresented = false } } } label: { Text(product.displayPrice) .font(.subheadline.weight(.semibold)) .padding(.horizontal, 14) .padding(.vertical, 8) .background(accentColor.opacity(0.15)) .foregroundStyle(accentColor) .clipShape(Capsule()) } .buttonStyle(.plain) .disabled(storeManager.isPurchasing) } .padding(14) .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 16)) } }