// // PurchaseButtonView.swift // Feels // // Created by Trey Tartt on 7/7/22. // import SwiftUI import StoreKit struct PurchaseButtonView: View { @AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor @AppStorage(UserDefaultsStore.Keys.firstLaunchDate.rawValue, store: GroupUserDefaults.groupDefaults) private var firstLaunchDate = Date() var iapManager: IAPManager private let showCountdownTimer: Bool private let showManageSubClosure: (() -> Void)? public init(iapManager: IAPManager, showManageSubClosure: (() -> Void)? = nil, showCountdownTimer: Bool = false) { self.showManageSubClosure = showManageSubClosure self.iapManager = iapManager self.showCountdownTimer = showCountdownTimer } var body: some View { ZStack { // if we should show the iap warning that means no purchase which means // we should show buy options switch iapManager.showIAPWarning { case true: VStack { buyOptionsView .background(theme.currentTheme.secondaryBGColor) } case false: subscribedView .background(theme.currentTheme.secondaryBGColor) } } } private var buyOptionsSetingsView: some View { GeometryReader { metrics in VStack(spacing: 20) { Text(String(localized: "purchase_view_title")) .foregroundColor(textColor) .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) .padding([.leading, .trailing]) VStack(alignment: .leading) { ForEach(iapManager.sortedSubscriptionKeysByPriceOptions, id: \.self) { product in HStack { Button(action: { purchase(product: product) }, label: { Text("\(product.displayPrice)\n\(product.displayName)") .foregroundColor(.white) .bold() .frame(maxWidth: .infinity) .contentShape(Rectangle()) }) .frame(maxWidth: .infinity) .frame(height: 50) .padding() .background(RoundedRectangle(cornerRadius: 10).fill(iapManager.colorForIAPButton(iapIdentifier: product.id))) } } } .padding([.leading, .leading]) } } } private var buyOptionsView: some View { VStack { ZStack { theme.currentTheme.secondaryBGColor if iapManager.isLoadingSubscriptions { VStack(spacing: 20) { Text(String(localized: "purchase_view_loading")) .font(.body) .bold() .frame(minWidth: 0, maxWidth: .infinity, alignment: .center) ProgressView() } } else { VStack(spacing: 20) { Text(String(localized: "purchase_view_title")) .font(.body) .bold() .foregroundColor(textColor) .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) .padding(.top) if showCountdownTimer { if let date = Calendar.current.date(byAdding: .day, value: 30, to: firstLaunchDate) { HStack { if iapManager.daysLeftBeforeIAP > 0 { Text(String(localized: "purchase_view_current_subscription_expires_in")) .font(.body) .bold() .foregroundColor(textColor) Text(date, style: .relative) .font(.body) .bold() .foregroundColor(textColor) } else { Text(String(localized: "purchase_view_current_subscription_expired_on")) .font(.body) .bold() .foregroundColor(textColor) Text(date, style: .date) .font(.body) .bold() .foregroundColor(textColor) } } .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) } Text(String(localized: "purchase_view_current_why_subscribe")) .font(.body) .bold() .foregroundColor(textColor) } HStack { ForEach(iapManager.sortedSubscriptionKeysByPriceOptions) { product in Button(action: { purchase(product: product) }, label: { Text("\(product.displayPrice)\n\(product.displayName)") .foregroundColor(.white) .bold() .frame(maxWidth: .infinity) .contentShape(Rectangle()) .frame(height: 65) }) .padding() .frame(maxWidth: .infinity) .background(RoundedRectangle(cornerRadius: 10).fill(iapManager.colorForIAPButton(iapIdentifier: product.id))) } } } .padding([.leading, .trailing]) .frame(minWidth: 0, maxWidth: .infinity) } } } .background(.ultraThinMaterial) .frame(minWidth: 0, maxWidth: .infinity) .background(.clear) } private var subscribedView: some View { VStack(alignment: .leading) { Text(String(localized: "purchase_view_current_subscription")) .font(.title3) .padding([.leading, .top]) Divider() if let currentProduct = iapManager.currentSubscription, let value = iapManager.subscriptions[currentProduct] { HStack { VStack (alignment: .leading, spacing: 10) { Text(currentProduct.displayName) .font(.title3) Text(currentProduct.displayPrice) .font(.title3) }.padding([.leading, .trailing]) ForEach(value!.status, id: \.self) { singleStatus in StatusInfoView(product: currentProduct, status: singleStatus) .padding([.leading]) .font(.body) } } } Button(action: { showManageSubClosure?() }, label: { Text(String(localized: "purchase_view_cancel")) .foregroundColor(.red) }) .frame(maxWidth: .infinity) .padding([.bottom]) .multilineTextAlignment(.center) Divider() showOtherSubOptions } } private var showOtherSubOptions: some View { VStack (spacing: 10) { HStack { ForEach(iapManager.sortedSubscriptionKeysByPriceOptions, id: \.self) { product in if product.id != iapManager.nextRenewllOption?.id { Button(action: { purchase(product: product) }, label: { Text("\(product.displayPrice)\n\(product.displayName)") .foregroundColor(.white) .font(.headline) }) .contentShape(Rectangle()) .padding() .frame(maxWidth: .infinity) .background(RoundedRectangle(cornerRadius: 10).fill(iapManager.colorForIAPButton(iapIdentifier: product.id))) } } } } .padding([.leading, .trailing]) } private func purchase(product: Product) { Task { try await iapManager.purchase(product) } } } struct PurchaseButtonView_Previews: PreviewProvider { static var previews: some View { PurchaseButtonView(iapManager: IAPManager()) } }