Files
honeyDueKMP/iosApp/iosApp/Subscription/SubscriptionPurchaseHelper.swift
T
Trey T db65db6232
Android UI Tests / ui-tests (push) Has been cancelled
i18n: complete app-wide localization (10 languages) + audit tooling
Localize all user-facing strings across iOS (SwiftUI), shared Kotlin, and
Android Compose into en/es/fr/de/pt/it/ja/ko/nl/zh:
- iOS String Catalogs: main + widget Localizable.xcstrings, InfoPlist.xcstrings
  (permissions), plural variations, ~200 new keys translated
- Shared Kotlin ClientStrings table + Android composeResources/values-* (884 keys
  ×10), routed Api/ViewModel/util error & UI strings through localization
- Backend-localized lookups/suggestions consumed via display names
- Widget extension catalog; theme names, home-profile fallbacks, validation,
  network errors, accessibility labels all localized

Add re-runnable verification gates:
- scripts/i18n_audit.py  — enumerate every literal, partition to GAP=0
- scripts/i18n_coverage.py — all 10 locales translated, format-specifier parity

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:52:28 -05:00

64 lines
2.0 KiB
Swift

import Foundation
import StoreKit
/// Shared purchase/restore logic used by FeatureComparisonView, UpgradeFeatureView, and UpgradePromptView.
/// Each view owns an instance via @StateObject and binds its published properties to the UI.
@MainActor
final class SubscriptionPurchaseHelper: ObservableObject {
@Published var isProcessing = false
@Published var errorMessage: String?
@Published var showSuccessAlert = false
@Published var selectedProduct: Product?
private var storeKit: StoreKitManager { StoreKitManager.shared }
func handlePurchase(_ product: Product) {
selectedProduct = product
isProcessing = true
errorMessage = nil
Task {
do {
let transaction = try await storeKit.purchase(product)
await MainActor.run {
isProcessing = false
if transaction != nil {
// Check if backend verification failed (purchase is valid but pending server confirmation)
if let backendError = storeKit.purchaseError {
errorMessage = backendError
} else {
showSuccessAlert = true
}
}
}
} catch {
await MainActor.run {
isProcessing = false
errorMessage = String(format: String(localized: "Purchase failed: %@"), error.localizedDescription)
}
}
}
}
func handleRestore() {
isProcessing = true
errorMessage = nil
Task {
await storeKit.restorePurchases()
await MainActor.run {
isProcessing = false
if !storeKit.purchasedProductIDs.isEmpty {
showSuccessAlert = true
} else {
errorMessage = String(localized: "No purchases found to restore")
}
}
}
}
}