Fix subscription screen: use product IDs and add close button

- Switch from groupID to productIDs for more reliable product loading
- Add dismiss button overlay so users aren't trapped if products fail to load
- Make productIdentifiers static for shared access

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-28 11:13:01 -06:00
parent f614487057
commit 6ce7c508ed
3 changed files with 20 additions and 4 deletions

View File

@@ -3848,6 +3848,10 @@
} }
} }
}, },
"Close" : {
"comment" : "An accessibility label for the button that dismisses the view.",
"isCommentAutoGenerated" : true
},
"content_view_delete_entry" : { "content_view_delete_entry" : {
"extractionState" : "manual", "extractionState" : "manual",
"localizations" : { "localizations" : {

View File

@@ -49,7 +49,7 @@ class IAPManager: ObservableObject {
static let subscriptionGroupID = "21951685" static let subscriptionGroupID = "21951685"
private let productIdentifiers: Set<String> = [ static let productIdentifiers: Set<String> = [
"com.88oakapps.reflect.IAP.subscriptions.monthly", "com.88oakapps.reflect.IAP.subscriptions.monthly",
"com.88oakapps.reflect.IAP.subscriptions.yearly" "com.88oakapps.reflect.IAP.subscriptions.yearly"
] ]
@@ -267,7 +267,7 @@ class IAPManager: ObservableObject {
private func loadProducts() async { private func loadProducts() async {
do { do {
let products = try await Product.products(for: productIdentifiers) let products = try await Product.products(for: Self.productIdentifiers)
availableProducts = products.filter { $0.type == .autoRenewable } availableProducts = products.filter { $0.type == .autoRenewable }
} catch { } catch {
AppLogger.iap.error("Failed to load products: \(error.localizedDescription)") AppLogger.iap.error("Failed to load products: \(error.localizedDescription)")
@@ -284,7 +284,7 @@ class IAPManager: ObservableObject {
if transaction.revocationDate != nil { continue } if transaction.revocationDate != nil { continue }
// Check if this is one of our subscription products // Check if this is one of our subscription products
guard productIdentifiers.contains(transaction.productID) else { continue } guard Self.productIdentifiers.contains(transaction.productID) else { continue }
// Get the product for this transaction // Get the product for this transaction
currentProduct = availableProducts.first { $0.id == transaction.productID } currentProduct = availableProducts.first { $0.id == transaction.productID }

View File

@@ -27,13 +27,25 @@ struct ReflectSubscriptionStoreView: View {
} }
var body: some View { var body: some View {
SubscriptionStoreView(groupID: IAPManager.subscriptionGroupID) { SubscriptionStoreView(productIDs: IAPManager.productIdentifiers) {
marketingContent marketingContent
} }
.subscriptionStoreControlStyle(.prominentPicker) .subscriptionStoreControlStyle(.prominentPicker)
.storeButton(.visible, for: .restorePurchases) .storeButton(.visible, for: .restorePurchases)
.subscriptionStoreButtonLabel(.multiline) .subscriptionStoreButtonLabel(.multiline)
.tint(tintColor) .tint(tintColor)
.overlay(alignment: .topTrailing) {
Button {
dismiss()
} label: {
Image(systemName: "xmark.circle.fill")
.font(.title2)
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.secondary)
}
.padding(16)
.accessibilityLabel("Close")
}
.onAppear { .onAppear {
AnalyticsManager.shared.trackPaywallViewed(source: source) AnalyticsManager.shared.trackPaywallViewed(source: source)
} }