From 39392618ecfeb89576387b0229fd1ebee6229946 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Thu, 11 Jun 2026 15:59:12 +0200
Subject: [PATCH] fix(iap): align PurchaseService with the live store products
---
lib/services/purchase_service.dart | 33 +++++++++++++++++++++------------
1 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/lib/services/purchase_service.dart b/lib/services/purchase_service.dart
index a611657..d6dbe83 100644
--- a/lib/services/purchase_service.dart
+++ b/lib/services/purchase_service.dart
@@ -5,13 +5,15 @@
import 'package:shared_preferences/shared_preferences.dart';
/// Product ID for the one-time full-access purchase.
-const String kFullAccessProductId = 'com.tekmidian.pailot.fullaccess';
+/// Matches the IAPs registered in App Store Connect (Apple ID 6779190925)
+/// and Google Play Console (one-time product `com.tekmidian.pailot.pro`).
+const String kFullAccessProductId = 'com.tekmidian.pailot.pro';
/// Maximum sessions allowed on the free tier.
const int kFreeTierMaxSessions = 2;
-/// Maximum message age for free-tier users (15 minutes).
-const Duration kFreeTierMessageTtl = Duration(minutes: 15);
+/// Maximum message age for free-tier users.
+const Duration kFreeTierMessageTtl = Duration(minutes: 30);
/// Shared preference key for caching purchase status locally.
const String _kProCacheKey = 'pailot_is_pro';
@@ -51,20 +53,27 @@
/// Initialize the service. Call once at app startup.
Future<void> initialize() async {
- // Restore cached value immediately so UI doesn't flicker.
- // Default to true for dev/sideloaded builds (no StoreKit configured).
+ // Hydrate from local cache first so UI doesn't flash "Free" before the
+ // store reply lands. The cache is authoritative for offline / cold-start
+ // rendering; restorePurchases() reconciles it with the platform stores.
final prefs = await SharedPreferences.getInstance();
- // Force pro for now — clear any stale false value from earlier testing
- _isPro = true;
- await prefs.setBool(_kProCacheKey, true);
+ _isPro = prefs.getBool(_kProCacheKey) ?? false;
notifyListeners();
- // Check if IAP is available — may not be on dev/sideloaded builds
+ // If the platform IAP layer isn't available (sideloaded dev build, no
+ // network, simulator without StoreKit config), keep the cached value as-is
+ // and skip the store dance. In debug, default to Pro so dev testing isn't
+ // blocked by the paywall — but never override in release builds.
final available = await InAppPurchase.instance.isAvailable();
if (!available) {
- debugPrint('[IAP] StoreKit not available — assuming pro (dev build)');
- _isPro = true;
- notifyListeners();
+ if (kDebugMode && !_isPro) {
+ debugPrint('[IAP] Store unavailable in debug build — granting Pro for dev testing');
+ _isPro = true;
+ await prefs.setBool(_kProCacheKey, true);
+ notifyListeners();
+ } else {
+ debugPrint('[IAP] Store unavailable; using cached isPro=$_isPro');
+ }
return;
}
--
Gitblit v1.3.1