Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

Commit 5160177

Browse files
committed
refactor: clean up types and project structure
1 parent ed8c9bc commit 5160177

File tree

8 files changed

+151
-109
lines changed

8 files changed

+151
-109
lines changed

Example/OpenIapExample/Screens/AvailablePurchasesScreen.swift

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ struct SectionHeaderView: View {
448448

449449
// MARK: - Product List Card
450450
struct ProductListCard: View {
451-
let product: OpenIapProductData
451+
let product: OpenIapProduct
452452
let onPurchase: () -> Void
453453

454454
var body: some View {
@@ -467,7 +467,7 @@ struct ProductListCard: View {
467467
.font(.headline)
468468
.fontWeight(.semibold)
469469

470-
Text(product.description)
470+
Text(product.localizedDescription)
471471
.font(.caption)
472472
.foregroundColor(.secondary)
473473
.lineLimit(2)
@@ -477,7 +477,7 @@ struct ProductListCard: View {
477477

478478
// Price and Purchase Button
479479
VStack(spacing: 8) {
480-
Text(product.displayPrice)
480+
Text(product.localizedPrice)
481481
.font(.system(size: 16, weight: .bold))
482482
.foregroundColor(AppColors.primary)
483483

@@ -499,33 +499,33 @@ struct ProductListCard: View {
499499
}
500500

501501
private var productIcon: String {
502-
if product.id.contains("10bulbs") {
502+
if product.productId.contains("10bulbs") {
503503
return "lightbulb"
504-
} else if product.id.contains("30bulbs") {
504+
} else if product.productId.contains("30bulbs") {
505505
return "lightbulb.fill"
506-
} else if product.id.contains("premium") {
506+
} else if product.productId.contains("premium") {
507507
return "crown"
508508
} else {
509509
return "bag"
510510
}
511511
}
512512

513513
private var productTitle: String {
514-
if product.id.contains("10bulbs") {
514+
if product.productId.contains("10bulbs") {
515515
return "10 Bulbs Pack"
516-
} else if product.id.contains("30bulbs") {
516+
} else if product.productId.contains("30bulbs") {
517517
return "30 Bulbs Pack"
518-
} else if product.id.contains("premium") {
518+
} else if product.productId.contains("premium") {
519519
return "Premium Subscription"
520520
} else {
521-
return product.title
521+
return product.localizedTitle
522522
}
523523
}
524524
}
525525

526526
// MARK: - Product Grid Card (Deprecated)
527527
struct ProductGridCard: View {
528-
let product: OpenIapProductData
528+
let product: OpenIapProduct
529529
let onPurchase: () -> Void
530530

531531
var body: some View {
@@ -543,7 +543,7 @@ struct ProductGridCard: View {
543543
.multilineTextAlignment(.center)
544544
.lineLimit(2)
545545

546-
Text(product.description)
546+
Text(product.localizedDescription)
547547
.font(.caption)
548548
.foregroundColor(.secondary)
549549
.multilineTextAlignment(.center)
@@ -553,7 +553,7 @@ struct ProductGridCard: View {
553553
Spacer()
554554

555555
VStack(spacing: 8) {
556-
Text(product.displayPrice)
556+
Text(product.localizedPrice)
557557
.font(.title3)
558558
.fontWeight(.bold)
559559
.foregroundColor(AppColors.primary)
@@ -579,26 +579,26 @@ struct ProductGridCard: View {
579579
}
580580

581581
private var productIcon: String {
582-
if product.id.contains("10bulbs") {
582+
if product.productId.contains("10bulbs") {
583583
return "lightbulb"
584-
} else if product.id.contains("30bulbs") {
584+
} else if product.productId.contains("30bulbs") {
585585
return "lightbulb.fill"
586-
} else if product.id.contains("premium") {
586+
} else if product.productId.contains("premium") {
587587
return "crown"
588588
} else {
589589
return "bag"
590590
}
591591
}
592592

593593
private var productTitle: String {
594-
if product.id.contains("10bulbs") {
594+
if product.productId.contains("10bulbs") {
595595
return "10 Bulbs"
596-
} else if product.id.contains("30bulbs") {
596+
} else if product.productId.contains("30bulbs") {
597597
return "30 Bulbs"
598-
} else if product.id.contains("premium") {
598+
} else if product.productId.contains("premium") {
599599
return "Premium"
600600
} else {
601-
return product.title
601+
return product.localizedTitle
602602
}
603603
}
604604
}

Example/OpenIapExample/Screens/PurchaseFlowScreen.swift

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,26 @@ struct PurchaseFlowScreen: View {
6262
}
6363

6464
struct ProductCard: View {
65-
let product: OpenIapProductData
65+
let product: OpenIapProduct
6666
let isLoading: Bool
6767
let onPurchase: () -> Void
6868

6969
private var productIcon: String {
70-
switch product.type {
71-
case "inapp":
70+
switch product.productType {
71+
case .consumable, .nonConsumable, .nonRenewingSubscription:
7272
return "bag.fill"
73-
case "subs":
73+
case .autoRenewableSubscription:
7474
return "repeat.circle.fill"
75-
default:
76-
return "star.fill"
7775
}
7876
}
7977

8078
private var productTypeText: String {
81-
switch product.type {
82-
case "inapp":
79+
switch product.productType {
80+
case .consumable, .nonConsumable:
8381
return "In-App Purchase"
84-
case "subs":
82+
case .autoRenewableSubscription:
8583
return "Subscription"
86-
default:
84+
case .nonRenewingSubscription:
8785
return "Non-Renewing"
8886
}
8987
}
@@ -98,7 +96,7 @@ struct ProductCard: View {
9896
.frame(width: 32, height: 32)
9997

10098
VStack(alignment: .leading, spacing: 4) {
101-
Text(product.title)
99+
Text(product.localizedTitle)
102100
.font(.headline)
103101
.fontWeight(.semibold)
104102

@@ -113,7 +111,7 @@ struct ProductCard: View {
113111

114112
Spacer()
115113

116-
Text(product.displayPrice)
114+
Text(product.localizedPrice)
117115
.font(.title2)
118116
.fontWeight(.bold)
119117
.foregroundColor(AppColors.primary)
@@ -122,13 +120,13 @@ struct ProductCard: View {
122120
}
123121

124122
// Product description
125-
Text(product.description)
123+
Text(product.localizedDescription)
126124
.font(.subheadline)
127125
.foregroundColor(AppColors.secondaryText)
128126
.lineLimit(nil)
129127

130128
// Product ID (for testing)
131-
Text("ID: \(product.id)")
129+
Text("ID: \(product.productId)")
132130
.font(.caption)
133131
.font(.system(.caption, design: .monospaced))
134132
.foregroundColor(AppColors.secondaryText)
@@ -151,7 +149,7 @@ struct ProductCard: View {
151149
Spacer()
152150

153151
if !isLoading {
154-
Text(product.displayPrice)
152+
Text(product.localizedPrice)
155153
.fontWeight(.semibold)
156154
}
157155
}
@@ -412,7 +410,7 @@ struct HeaderCardView: View {
412410
struct ProductsContentView: View {
413411
@ObservedObject var store: StoreViewModel
414412

415-
var consumableProducts: [OpenIapProductData] {
413+
var consumableProducts: [OpenIapProduct] {
416414
store.products.filter { product in
417415
// Filter out premium subscription products
418416
!product.id.contains("premium") && product.type == "inapp"
@@ -432,11 +430,11 @@ struct ProductsContentView: View {
432430
ForEach(consumableProducts, id: \.id) { product in
433431
ProductCard(
434432
product: product,
435-
isLoading: store.purchasingProductIds.contains(product.id)
433+
isLoading: store.purchasingProductIds.contains(product.productId)
436434
) {
437435
store.purchaseProduct(product)
438436
}
439437
}
440438
}
441439
}
442-
}
440+
}

Example/OpenIapExample/Screens/SubscriptionFlowScreen.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ struct SubscriptionFlowScreen: View {
122122
}
123123

124124
struct SubscriptionCard: View {
125-
let product: OpenIapProductData
125+
let product: OpenIapProduct
126126
let isSubscribed: Bool
127127
let isLoading: Bool
128128
let onSubscribe: () -> Void
@@ -132,7 +132,7 @@ struct SubscriptionCard: View {
132132
HStack {
133133
VStack(alignment: .leading, spacing: 4) {
134134
HStack {
135-
Text(product.title)
135+
Text(product.localizedTitle)
136136
.font(.headline)
137137

138138
if isSubscribed {
@@ -146,7 +146,7 @@ struct SubscriptionCard: View {
146146
}
147147
}
148148

149-
Text(product.id)
149+
Text(product.productId)
150150
.font(.caption)
151151
.font(.system(.body, design: .monospaced))
152152
.foregroundColor(.secondary)
@@ -155,7 +155,7 @@ struct SubscriptionCard: View {
155155
Spacer()
156156

157157
VStack(alignment: .trailing, spacing: 2) {
158-
Text(product.displayPrice)
158+
Text(product.localizedPrice)
159159
.font(.title2)
160160
.fontWeight(.bold)
161161
.foregroundColor(isSubscribed ? AppColors.success : AppColors.secondary)
@@ -230,7 +230,7 @@ struct SubscriptionCard: View {
230230
Spacer()
231231

232232
if !isLoading {
233-
Text(product.displayPrice)
233+
Text(product.localizedPrice)
234234
.fontWeight(.semibold)
235235
}
236236
}

Example/OpenIapExample/ViewModels/StoreViewModel.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import OpenIAP
44
@MainActor
55
@available(iOS 15.0, *)
66
class StoreViewModel: ObservableObject {
7-
@Published var products: [OpenIapProductData] = []
7+
@Published var products: [OpenIapProduct] = []
88
@Published var purchases: [OpenIapPurchase] = []
99
@Published var isLoading = false
1010
@Published var showError = false
1111
@Published var errorMessage = ""
1212
@Published var purchasingProductIds: Set<String> = []
1313
@Published var showPurchaseSuccess = false
14-
@Published var lastPurchasedProduct: OpenIapProductData?
14+
@Published var lastPurchasedProduct: OpenIapProduct?
1515
@Published var isConnectionInitialized = false
1616

1717
private let iapModule = OpenIapModule.shared
@@ -100,10 +100,10 @@ class StoreViewModel: ObservableObject {
100100
purchasingProductIds.remove(productId)
101101

102102
// Find the purchased product
103-
if let purchasedProduct = products.first(where: { $0.id == productId }) {
103+
if let purchasedProduct = products.first(where: { $0.productId == productId }) {
104104
lastPurchasedProduct = purchasedProduct
105105
showPurchaseSuccess = true
106-
print("🎉 Purchase success dialog will show for: \(purchasedProduct.title)")
106+
print("🎉 Purchase success dialog will show for: \(purchasedProduct.localizedTitle)")
107107
}
108108

109109
// Reload purchases to show the new purchase
@@ -173,21 +173,21 @@ class StoreViewModel: ObservableObject {
173173
isLoading = false
174174
}
175175

176-
func purchaseProduct(_ product: OpenIapProductData) {
176+
func purchaseProduct(_ product: OpenIapProduct) {
177177
// Start loading state for this specific product
178-
purchasingProductIds.insert(product.id)
178+
purchasingProductIds.insert(product.productId)
179179

180180
print("🛒 Purchase Process Started:")
181-
print(" • Product ID: \(product.id)")
182-
print(" • Product Title: \(product.title)")
183-
print(" • Product Price: \(product.displayPrice)")
184-
print(" • Product Type: \(product.type)")
181+
print(" • Product ID: \(product.productId)")
182+
print(" • Product Title: \(product.localizedTitle)")
183+
print(" • Product Price: \(product.localizedPrice)")
184+
print(" • Product Type: \(product.productType.rawValue)")
185185

186186
Task {
187187
do {
188188
print("🔄 Calling requestPurchase API...")
189189
let transactionData = try await iapModule.requestPurchase(
190-
sku: product.id,
190+
sku: product.productId,
191191
andDangerouslyFinishTransactionAutomatically: true,
192192
appAccountToken: nil,
193193
quantity: 1,
@@ -199,15 +199,15 @@ class StoreViewModel: ObservableObject {
199199
print(" • Transaction received: \(transaction.transactionId)")
200200
print(" • Product ID: \(transaction.productId)")
201201
print(" • Purchase State: \(transaction.purchaseState)")
202-
print("✅ Purchase successful via API: \(product.title)")
202+
print("✅ Purchase successful via API: \(product.localizedTitle)")
203203
await MainActor.run {
204-
handlePurchaseSuccess(product.id)
204+
handlePurchaseSuccess(product.productId)
205205
}
206206
} else {
207207
print(" • No transaction data received")
208208
print("❌ Purchase failed: No transaction data")
209209
await MainActor.run {
210-
handlePurchaseError(OpenIapError.purchaseFailed(reason: "No transaction data received"), productId: product.id)
210+
handlePurchaseError(OpenIapError.purchaseFailed(reason: "No transaction data received"), productId: product.productId)
211211
}
212212
}
213213
} catch {

Sources/Models/AppTransaction.swift

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,27 +73,8 @@ public struct OpenIapValidationResult: Codable {
7373

7474
// MARK: - Product and Transaction serialization models
7575

76-
public struct OpenIapProductData: Codable {
77-
public let id: String
78-
public let title: String
79-
public let description: String
80-
public let price: Decimal
81-
public let displayPrice: String
82-
public let currency: String?
83-
public let type: String
84-
public let platform: String
85-
86-
public init(id: String, title: String, description: String, price: Decimal, displayPrice: String, currency: String?, type: String, platform: String = "ios") {
87-
self.id = id
88-
self.title = title
89-
self.description = description
90-
self.price = price
91-
self.displayPrice = displayPrice
92-
self.currency = currency
93-
self.type = type
94-
self.platform = platform
95-
}
96-
}
76+
// OpenIapProductData is deprecated - use OpenIapProduct instead
77+
// This type has been merged into OpenIapProduct for better API consistency
9778

9879
// IapTransactionData is deprecated - use OpenIapPurchase instead
9980
// This type has been merged into OpenIapPurchase for better API consistency

0 commit comments

Comments
 (0)