@@ -15881,11 +15881,10 @@ steps:
15881
15881
),
15882
15882
ChangeNotifierProvider<DashCounter>(create: (_) => DashCounter()),
15883
15883
ChangeNotifierProvider<DashUpgrades>(
15884
- create:
15885
- (context) => DashUpgrades(
15886
- context.read<DashCounter>(),
15887
- context.read<FirebaseNotifier>(),
15888
- ),
15884
+ create: (context) => DashUpgrades(
15885
+ context.read<DashCounter>(),
15886
+ context.read<FirebaseNotifier>(),
15887
+ ),
15889
15888
),
15890
15889
ChangeNotifierProvider<IAPRepo>(
15891
15890
create: (context) => IAPRepo(context.read<FirebaseNotifier>()),
@@ -16401,10 +16400,9 @@ steps:
16401
16400
leading: Center(widthFactor: 1, child: Text(upgrade.count.toString())),
16402
16401
title: Text(
16403
16402
title,
16404
- style:
16405
- !upgrade.purchasable
16406
- ? const TextStyle(color: Colors.redAccent)
16407
- : null,
16403
+ style: !upgrade.purchasable
16404
+ ? const TextStyle(color: Colors.redAccent)
16405
+ : null,
16408
16406
),
16409
16407
subtitle: Text('Produces ${upgrade.work} dashes per second'),
16410
16408
trailing: Text('${NumberFormat.compact().format(upgrade.cost)} dashes'),
@@ -16504,17 +16502,16 @@ steps:
16504
16502
var purchases = context.watch<DashPurchases>();
16505
16503
var products = purchases.products;
16506
16504
return Column(
16507
- children:
16508
- products
16509
- .map(
16510
- (product) => _PurchaseWidget(
16511
- product: product,
16512
- onPressed: () {
16513
- purchases.buy(product);
16514
- },
16515
- ),
16516
- )
16517
- .toList(),
16505
+ children: products
16506
+ .map(
16507
+ (product) => _PurchaseWidget(
16508
+ product: product,
16509
+ onPressed: () {
16510
+ purchases.buy(product);
16511
+ },
16512
+ ),
16513
+ )
16514
+ .toList(),
16518
16515
);
16519
16516
}
16520
16517
}
@@ -16559,11 +16556,10 @@ steps:
16559
16556
return ListView.separated(
16560
16557
shrinkWrap: true,
16561
16558
itemCount: purchases.length,
16562
- itemBuilder:
16563
- (context, index) => ListTile(
16564
- title: Text(purchases[index].title),
16565
- subtitle: Text(purchases[index].status.toString()),
16566
- ),
16559
+ itemBuilder: (context, index) => ListTile(
16560
+ title: Text(purchases[index].title),
16561
+ subtitle: Text(purchases[index].status.toString()),
16562
+ ),
16567
16563
separatorBuilder: (context, index) => const Divider(),
16568
16564
);
16569
16565
}
@@ -16622,17 +16618,15 @@ steps:
16622
16618
hasUpgrade = false;
16623
16619
return;
16624
16620
}
16625
- var purchaseStream =
16626
- _firestore
16627
- .collection('purchases')
16628
- .where('userId', isEqualTo: user.uid)
16629
- .snapshots();
16621
+ var purchaseStream = _firestore
16622
+ .collection('purchases')
16623
+ .where('userId', isEqualTo: user.uid)
16624
+ .snapshots();
16630
16625
_purchaseSubscription = purchaseStream.listen((snapshot) {
16631
- purchases =
16632
- snapshot.docs.map((document) {
16633
- var data = document.data();
16634
- return PastPurchase.fromJson(data);
16635
- }).toList();
16626
+ purchases = snapshot.docs.map((document) {
16627
+ var data = document.data();
16628
+ return PastPurchase.fromJson(data);
16629
+ }).toList();
16636
16630
16637
16631
hasActiveSubscription = purchases.any(
16638
16632
(element) =>
@@ -16916,10 +16910,9 @@ steps:
16916
16910
switch (type) {
16917
16911
case ProductType.subscription:
16918
16912
return SubscriptionPurchase(
16919
- iapSource:
16920
- e.fields!['iapSource']!.stringValue == 'googleplay'
16921
- ? IAPSource.googleplay
16922
- : IAPSource.appstore,
16913
+ iapSource: e.fields!['iapSource']!.stringValue == 'googleplay'
16914
+ ? IAPSource.googleplay
16915
+ : IAPSource.appstore,
16923
16916
orderId: e.fields!['orderId']!.stringValue!,
16924
16917
productId: e.fields!['productId']!.stringValue!,
16925
16918
userId: e.fields!['userId']!.stringValue,
@@ -16937,10 +16930,9 @@ steps:
16937
16930
);
16938
16931
case ProductType.nonSubscription:
16939
16932
return NonSubscriptionPurchase(
16940
- iapSource:
16941
- e.fields!['iapSource']!.stringValue == 'googleplay'
16942
- ? IAPSource.googleplay
16943
- : IAPSource.appstore,
16933
+ iapSource: e.fields!['iapSource']!.stringValue == 'googleplay'
16934
+ ? IAPSource.googleplay
16935
+ : IAPSource.appstore,
16944
16936
orderId: e.fields!['orderId']!.stringValue!,
16945
16937
productId: e.fields!['productId']!.stringValue!,
16946
16938
userId: e.fields!['userId']!.stringValue,
@@ -17180,7 +17172,7 @@ steps:
17180
17172
void main() {
17181
17173
runApp(const MyApp());
17182
17174
}
17183
- @@ -66 ,6 +80 ,7 @@ class _MyHomePageState extends State<MyHomePage> {
17175
+ @@ -65 ,6 +79 ,7 @@ class _MyHomePageState extends State<MyHomePage> {
17184
17176
),
17185
17177
ChangeNotifierProvider<DashPurchases>(
17186
17178
create: (context) => DashPurchases(context.read<DashCounter>()),
@@ -17374,7 +17366,7 @@ steps:
17374
17366
17375
17367
final iapConnection = IAPConnection.instance;
17376
17368
17377
- @@ -37,6 +28,26 @@ class DashPurchases extends ChangeNotifier {
17369
+ @@ -37,6 +28,27 @@ class DashPurchases extends ChangeNotifier {
17378
17370
onDone: _updateStreamOnDone,
17379
17371
onError: _updateStreamOnError,
17380
17372
);
@@ -17394,14 +17386,15 @@ steps:
17394
17386
+ storeKeyUpgrade,
17395
17387
+ };
17396
17388
+ final response = await iapConnection.queryProductDetails(ids);
17397
- + products =
17398
- + response.productDetails.map((e) => PurchasableProduct(e)).toList();
17389
+ + products = response.productDetails
17390
+ + .map((e) => PurchasableProduct(e))
17391
+ + .toList();
17399
17392
+ storeState = StoreState.available;
17400
17393
+ notifyListeners();
17401
17394
}
17402
17395
17403
17396
@override
17404
- @@ -46,18 +57 ,45 @@ class DashPurchases extends ChangeNotifier {
17397
+ @@ -46,18 +58 ,45 @@ class DashPurchases extends ChangeNotifier {
17405
17398
}
17406
17399
17407
17400
Future<void> buy(PurchasableProduct product) async {
@@ -17495,16 +17488,15 @@ steps:
17495
17488
patch-u: |
17496
17489
--- b/in_app_purchases/step_10/app/lib/main.dart
17497
17490
+++ a/in_app_purchases/step_10/app/lib/main.dart
17498
- @@ -79 ,7 +79,11 @@ class _MyHomePageState extends State<MyHomePage> {
17491
+ @@ -78 ,7 +78,10 @@ class _MyHomePageState extends State<MyHomePage> {
17499
17492
create: (context) => IAPRepo(context.read<FirebaseNotifier>()),
17500
17493
),
17501
17494
ChangeNotifierProvider<DashPurchases>(
17502
17495
- create: (context) => DashPurchases(context.read<DashCounter>()),
17503
- + create:
17504
- + (context) => DashPurchases(
17505
- + context.read<DashCounter>(),
17506
- + context.read<FirebaseNotifier>(),
17507
- + ),
17496
+ + create: (context) => DashPurchases(
17497
+ + context.read<DashCounter>(),
17498
+ + context.read<FirebaseNotifier>(),
17499
+ + ),
17508
17500
lazy: false,
17509
17501
),
17510
17502
],
@@ -17544,7 +17536,7 @@ steps:
17544
17536
final purchaseUpdated = iapConnection.purchaseStream;
17545
17537
_subscription = purchaseUpdated.listen(
17546
17538
_onPurchaseUpdate,
17547
- @@ -83 ,13 +87 ,19 @@ class DashPurchases extends ChangeNotifier {
17539
+ @@ -84 ,13 +88 ,19 @@ class DashPurchases extends ChangeNotifier {
17548
17540
17549
17541
Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async {
17550
17542
if (purchaseDetails.status == PurchaseStatus.purchased) {
@@ -17571,7 +17563,7 @@ steps:
17571
17563
}
17572
17564
}
17573
17565
17574
- @@ -98 ,6 +108 ,30 @@ class DashPurchases extends ChangeNotifier {
17566
+ @@ -99 ,6 +109 ,30 @@ class DashPurchases extends ChangeNotifier {
17575
17567
}
17576
17568
}
17577
17569
@@ -17656,7 +17648,7 @@ steps:
17656
17648
patch-u: |
17657
17649
--- b/in_app_purchases/step_10/dart-backend/bin/server.dart
17658
17650
+++ a/in_app_purchases/step_10/dart-backend/bin/server.dart
17659
- @@ -2,12 +2,111 @@
17651
+ @@ -2,12 +2,113 @@
17660
17652
// for details. All rights reserved. Use of this source code is governed by a
17661
17653
// BSD-style license that can be found in the LICENSE file.
17662
17654
@@ -17679,8 +17671,9 @@ steps:
17679
17671
+/// and their dependencies
17680
17672
+Future<Map<String, PurchaseHandler>> _createPurchaseHandlers() async {
17681
17673
+ // Configure Android Publisher API access
17682
- + final serviceAccountGooglePlay =
17683
- + File('assets/service-account-google-play.json').readAsStringSync();
17674
+ + final serviceAccountGooglePlay = File(
17675
+ + 'assets/service-account-google-play.json',
17676
+ + ).readAsStringSync();
17684
17677
+ final clientCredentialsGooglePlay = auth.ServiceAccountCredentials.fromJson(
17685
17678
+ serviceAccountGooglePlay,
17686
17679
+ );
@@ -17691,8 +17684,9 @@ steps:
17691
17684
+ final androidPublisher = ap.AndroidPublisherApi(clientGooglePlay);
17692
17685
+
17693
17686
+ // Configure Firestore API access
17694
- + final serviceAccountFirebase =
17695
- + File('assets/service-account-firebase.json').readAsStringSync();
17687
+ + final serviceAccountFirebase = File(
17688
+ + 'assets/service-account-firebase.json',
17689
+ + ).readAsStringSync();
17696
17690
+ final clientCredentialsFirebase = auth.ServiceAccountCredentials.fromJson(
17697
17691
+ serviceAccountFirebase,
17698
17692
+ );
@@ -18113,12 +18107,12 @@ steps:
18113
18107
patch-u: |
18114
18108
--- b/in_app_purchases/step_11/app/lib/main.dart
18115
18109
+++ a/in_app_purchases/step_11/app/lib/main.dart
18116
- @@ -83 ,6 +83 ,7 @@ class _MyHomePageState extends State<MyHomePage> {
18117
- (context) => DashPurchases(
18118
- context.read<DashCounter>(),
18119
- context.read<FirebaseNotifier>(),
18120
- + context.read<IAPRepo>(),
18121
- ),
18110
+ @@ -81 ,6 +81 ,7 @@ class _MyHomePageState extends State<MyHomePage> {
18111
+ create: (context) => DashPurchases(
18112
+ context.read<DashCounter>(),
18113
+ context.read<FirebaseNotifier>(),
18114
+ + context.read<IAPRepo>(),
18115
+ ),
18122
18116
lazy: false,
18123
18117
),
18124
18118
- name: Patch app/lib/logic/dash_purchases.dart
@@ -18157,15 +18151,15 @@ steps:
18157
18151
loadPurchases();
18158
18152
}
18159
18153
18160
- @@ -57 ,6 +59 ,7 @@ class DashPurchases extends ChangeNotifier {
18154
+ @@ -58 ,6 +60 ,7 @@ class DashPurchases extends ChangeNotifier {
18161
18155
@override
18162
18156
void dispose() {
18163
18157
_subscription.cancel();
18164
18158
+ iapRepo.removeListener(purchasesUpdate);
18165
18159
super.dispose();
18166
18160
}
18167
18161
18168
- @@ -139 ,4 +142,59 @@ class DashPurchases extends ChangeNotifier {
18162
+ @@ -140 ,4 +143,55 @@ class DashPurchases extends ChangeNotifier {
18169
18163
void _updateStreamOnError(dynamic error) {
18170
18164
//Handle error here
18171
18165
}
@@ -18176,16 +18170,12 @@ steps:
18176
18170
+ // Get a list of purchasable products for the subscription and upgrade.
18177
18171
+ // This should be 1 per type.
18178
18172
+ if (products.isNotEmpty) {
18179
- + subscriptions =
18180
- + products
18181
- + .where(
18182
- + (element) => element.productDetails.id == storeKeySubscription,
18183
- + )
18184
- + .toList();
18185
- + upgrades =
18186
- + products
18187
- + .where((element) => element.productDetails.id == storeKeyUpgrade)
18188
- + .toList();
18173
+ + subscriptions = products
18174
+ + .where((element) => element.productDetails.id == storeKeySubscription)
18175
+ + .toList();
18176
+ + upgrades = products
18177
+ + .where((element) => element.productDetails.id == storeKeyUpgrade)
18178
+ + .toList();
18189
18179
+ }
18190
18180
+
18191
18181
+ // Set the subscription in the counter logic and show/hide purchased on the
@@ -18248,7 +18238,7 @@ steps:
18248
18238
import 'package:googleapis_auth/auth_io.dart' as auth;
18249
18239
import 'package:shelf/shelf.dart';
18250
18240
import 'package:shelf_router/shelf_router.dart';
18251
- @@ -26 ,12 +29 ,16 @@ Future<Map<String, PurchaseHandler>> _createPurchaseHandlers() async {
18241
+ @@ -27 ,12 +30 ,16 @@ Future<Map<String, PurchaseHandler>> _createPurchaseHandlers() async {
18252
18242
final clientCredentialsGooglePlay = auth.ServiceAccountCredentials.fromJson(
18253
18243
serviceAccountGooglePlay,
18254
18244
);
@@ -18267,14 +18257,15 @@ steps:
18267
18257
+ final pubsubApi = pubsub.PubsubApi(clientGooglePlay);
18268
18258
+
18269
18259
// Configure Firestore API access
18270
- final serviceAccountFirebase =
18271
- File( 'assets/service-account-firebase.json').readAsStringSync();
18272
- @@ -47 ,9 +54,41 @@ Future<Map<String, PurchaseHandler>> _createPurchaseHandlers() async {
18260
+ final serviceAccountFirebase = File(
18261
+ 'assets/service-account-firebase.json',
18262
+ @@ -49 ,9 +56,42 @@ Future<Map<String, PurchaseHandler>> _createPurchaseHandlers() async {
18273
18263
final projectId = json['project_id'] as String;
18274
18264
final iapRepository = IapRepository(firestoreApi, projectId);
18275
18265
18276
- + final subscriptionKeyAppStore =
18277
- + File('assets/SubscriptionKey.p8').readAsStringSync();
18266
+ + final subscriptionKeyAppStore = File(
18267
+ + 'assets/SubscriptionKey.p8',
18268
+ + ).readAsStringSync();
18278
18269
+
18279
18270
+ // Configure Apple Store API access
18280
18271
+ var appStoreEnvironment = AppStoreEnvironment.sandbox(
@@ -18338,7 +18329,7 @@ steps:
18338
18329
18339
18330
final _iTunesAPI = ITunesApi(
18340
18331
ITunesHttpClient(ITunesEnvironment.sandbox(), loggingEnabled: true),
18341
- @@ -96,4 +105,53 @@ class AppStorePurchaseHandler extends PurchaseHandler {
18332
+ @@ -96,4 +105,52 @@ class AppStorePurchaseHandler extends PurchaseHandler {
18342
18333
return false;
18343
18334
}
18344
18335
}
@@ -18381,10 +18372,9 @@ steps:
18381
18372
+ ),
18382
18373
+ type: ProductType.subscription,
18383
18374
+ expiryDate: expirationDate,
18384
- + status:
18385
- + isExpired
18386
- + ? SubscriptionStatus.expired
18387
- + : SubscriptionStatus.active,
18375
+ + status: isExpired
18376
+ + ? SubscriptionStatus.expired
18377
+ + : SubscriptionStatus.active,
18388
18378
+ ),
18389
18379
+ );
18390
18380
+ }
@@ -18526,7 +18516,7 @@ steps:
18526
18516
patch-u: |
18527
18517
--- b/in_app_purchases/complete/app/lib/logic/dash_purchases.dart
18528
18518
+++ a/in_app_purchases/complete/app/lib/logic/dash_purchases.dart
18529
- @@ -192 ,8 +192 ,8 @@ class DashPurchases extends ChangeNotifier {
18519
+ @@ -189 ,8 +189 ,8 @@ class DashPurchases extends ChangeNotifier {
18530
18520
}
18531
18521
18532
18522
void _updateStatus(PurchasableProduct product, ProductStatus status) {
0 commit comments