Files
swiftGrammar/AIGrammar/View/IAPView.swift

201 lines
8.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// IAPView.swift
// AIGrammar
//
// Created by oscar on 2024/7/9.
//
import SwiftUI
import FirebaseAnalytics
struct VIPPaymentView: View {
@Environment(\.presentationMode) var presentationMode
@State private var showingToast = false
@State private var toastText = ""
let features = ["Grammar Check & Spelling Correction", "Words & Dictionary", "Translate"]
let freeValues = ["2 Times / Day", "2 Times / Day", "2 Times / Day"]
let premiumValues = ["Unlimited", "Unlimited", "Unlimited"]
let products = [
("Weekly", "$4.99 / week", "Billed as one payment of $4.99", "weekly", IAPProduct.premiumFeature1, "Billed Weekly"),
("Monthly", "$9.99 / month", "Billed as one payment of $9.99", "monthly", IAPProduct.premiumFeature2, "Billed Monthly"),
("Annual", "$4.16 / month", "Billed as one payment of $49.99", "yearly", IAPProduct.premiumFeature3, "Billed Yearly")
]
@State private var selectedProductIndex: Int = 1 //
@State private var selectedPlanText: String = "Billed Monthly"
@EnvironmentObject var iapManager: IAPManager // IAPManager
var body: some View {
NavigationView {
VStack {
HStack {
Text("PREMIUM")
.bold()
.foregroundColor(Color(red: 1.0, green: 0.8, blue: 0.0)) //
//.foregroundColor(.yellow)
.padding()
.background(Color.orange)
.cornerRadius(20)
Spacer()
Button("Close") {
presentationMode.wrappedValue.dismiss()
}
}
.padding()
List {
Section(header: Text("Get Premium Features").font(.headline)) {
HStack {
Text("Features")
.frame(width: 120, alignment: .leading)
Spacer()
Text("Free")
.frame(width: 120, alignment: .center)
Spacer()
Text("Premium")
.frame(width: 80, alignment: .center)
}
.font(.headline)
ForEach(Array(zip(features, zip(freeValues, premiumValues))), id: \.0) { item in
HStack {
Text(item.0)
.frame(width: 120, alignment: .leading)
Spacer()
Text(item.1.0) // Free values
.frame(width: 120, alignment: .center)
Spacer()
Text(item.1.1) // Premium values
.frame(width: 80, alignment: .center)
}
.font(.subheadline)
}
}
}
VStack(alignment: .leading) { // 使 VStack ForEach
ForEach(products.indices, id: \.self) { index in
Button(action: {
// do someting
}) {
HStack() {
Image(systemName: selectedProductIndex == index ? "checkmark.circle.fill" : "circle")
.foregroundColor(selectedProductIndex == index ? .green : .secondary)
.padding(.horizontal, 4)
VStack(alignment: .leading) {
if products[index].0 == "Annual" {
// "Premium Yearly"
Text(products[index].0) + Text(" ⚡️") + Text(" 58% off")
.bold()
.foregroundColor(.red) // 使
.font(.subheadline)
} else {
Text(products[index].0)
}
Text(products[index].1)
.font(.caption)
Text(products[index].2)
.font(.subheadline)
}
.frame(maxWidth: .infinity, alignment: .leading) // 使 HStack
}
.padding(.vertical, 10)
.background(self.selectedProductIndex == index ? Color.yellow : Color.clear)
.cornerRadius(5)
.padding(.horizontal, 20) //
.onTapGesture {
self.selectedProductIndex = index
self.selectedPlanText = products[index].5
}
}
.frame(maxWidth: .infinity, alignment: .leading) // 使 HStack
}
}
.padding(.horizontal, 5) //
Button("Purchase") {
// Handle purchase logic here
buyProduct()
}
.padding(.vertical, 15)
.padding(.horizontal, 80)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(15)
.frame(minWidth: 0, maxWidth: .infinity)
.shadow(radius: 2) //
.font(.headline) //
.padding(.top, 20)
Text((selectedPlanText ) + ", Cancel Anytime")
.font(.footnote)
.padding(.vertical, 5)
}
.navigationBarHidden(true)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(.systemBackground))
.toast(isPresented: $showingToast, dismissAfter: globalEnvironment.toastPresentMsNormal, onDismiss: {
// Toast
presentationMode.wrappedValue.dismiss() //
}) {
HStack {
Image(systemName: "exclamationmark.bubble")
.foregroundColor(.yellow)
Text(toastText)
.foregroundColor(.black)
}
.padding()
.background(Color.white)
.cornerRadius(8)
.shadow(radius: 10)
}
}
private func buyProduct() {
let productId = products[selectedProductIndex].4
logger.info("selected productId: \(productId.rawValue)")
//
Analytics.logEvent(globalAnalyticsEvents.eventPurchase, parameters: [
globalAnalyticsEvents.keyPurchaseItem: productId.rawValue as NSObject,
globalAnalyticsEvents.keyDeviceID: globalEnvironment.deviceID as NSObject
])
if let product = iapManager.products.first(where: { $0.id == productId.rawValue }) {
Task {
await iapManager.buy(product: product) { result in
switch result {
case .success(let message):
self.toastText = message
self.showingToast = true
presentationMode.wrappedValue.dismiss()
// vip
InitApp.shared.refreshUserInfo()
case .failure(let error):
self.toastText = error.localizedDescription
self.showingToast = true
}
}
}
} else {
logger.error("Product not found")
toastText = "Error loading product list, please try again later"
self.showingToast = true
}
}
}
struct VIPPaymentView_Previews: PreviewProvider {
static var previews: some View {
VIPPaymentView()
}
}