// // PurchaseButtonView.swift // Feels // // Created by Trey Tartt on 7/7/22. // import SwiftUI import StoreKit struct PurchaseButtonView: View { enum ViewStatus: String { case needToBuy case error case success case subscribed } @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 var iapManager: IAPManager private let height: Float private let showManageSubClosure: (() -> Void)? @State var isPurchasing: Bool = false @State private var viewStatus: ViewStatus = .needToBuy { didSet { isPurchasing = false } } public init(height: Float, iapManager: IAPManager, showManageSubClosure: (() -> Void)? = nil) { self.height = height self.showManageSubClosure = showManageSubClosure self.iapManager = iapManager } var body: some View { ZStack { switch viewStatus { case .needToBuy, .error: buyOptionsView .frame(height: CGFloat(height)) .background(theme.currentTheme.secondaryBGColor) case .success: subscribedView .frame(height: CGFloat(height)) .background(theme.currentTheme.secondaryBGColor) case .subscribed: subscribedView .frame(height: CGFloat(height)) .background(theme.currentTheme.secondaryBGColor) } } .onAppear{ if let _ = iapManager.currentSubscription { viewStatus = .subscribed } } } 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) .frame(height: 50) .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 { VStack(spacing: 20) { Text(String(localized: "purchase_view_title")) .font(.body) .bold() .foregroundColor(textColor) .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) 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()) }) .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 successView: some View { HStack { Text("it worked") } .background(.green) } private var errorView: some View { HStack { Text("something broke") } .background(.red) } private var subscribedView: some View { VStack(alignment: .leading) { Text(String(localized: "purchase_view_current_subscription")) .font(.title3) .padding(.leading) 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 var purchasingView: some View { HStack { Text("purcasing") } .background(.yellow) } private func purchase(product: Product) { isPurchasing = true Task { do { if let _ = try await iapManager.purchase(product) { viewStatus = .success } } catch { viewStatus = .error } } } } struct PurchaseButtonView_Previews: PreviewProvider { static var previews: some View { PurchaseButtonView(height: 175, iapManager: IAPManager()) } }