237 lines
9.9 KiB
Swift
237 lines
9.9 KiB
Swift
//
|
|
// 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())
|
|
}
|
|
}
|