@@ -74,6 +74,32 @@ steps:
7474 + </array>
7575 </dict>
7676 </plist>
77+ - name: Patch app/ios/Podfile
78+ path: steps/app/ios/Podfile
79+ patch-u: |
80+ --- b/in_app_purchases/step_00/app/ios/Podfile
81+ +++ a/in_app_purchases/step_00/app/ios/Podfile
82+ @@ -1,5 +1,5 @@
83+ -# Uncomment this line to define a global platform for your project
84+ -# platform :ios, '12.0'
85+ +# Per https://firebase.google.com/support/release-notes/ios cloud_firestore requires a minimum iOS version of 13.0
86+ +platform :ios, '13.0'
87+
88+ # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
89+ ENV['COCOAPODS_DISABLE_STATS'] = 'true'
90+ - name: Patch app/android/settings.gradle
91+ path: steps/app/android/settings.gradle
92+ patch-u: |
93+ --- b/in_app_purchases/step_00/app/android/settings.gradle
94+ +++ a/in_app_purchases/step_00/app/android/settings.gradle
95+ @@ -18,7 +18,7 @@ pluginManagement {
96+
97+ plugins {
98+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
99+ - id "com.android.application" version "8.1.0" apply false
100+ + id "com.android.application" version "8.2.1" apply false
101+ id "org.jetbrains.kotlin.android" version "1.8.22" apply false
102+ }
77103 - name: Mkdir app/assets
78104 mkdir: steps/app/assets
79105 - name: Add app/assets/dash_old.png
@@ -16838,24 +16864,24 @@ steps:
1683816864 ///
1683916865 /// [ProcessSignal.sigterm] is listened to on all platforms except Windows.
1684016866 Future<void> terminateRequestFuture() {
16841- final completer = Completer<bool>.sync ();
16867+ final completer = Completer<bool>();
1684216868
16843- // sigIntSub is copied below to avoid a race condition - ignoring this lint
16844- // ignore: cancel_subscriptions
1684516869 StreamSubscription? sigIntSub, sigTermSub;
1684616870
1684716871 Future<void> signalHandler(ProcessSignal signal) async {
1684816872 print('Received signal $signal - closing');
1684916873
16850- final subCopy = sigIntSub;
16851- if (subCopy != null) {
16852- sigIntSub = null;
16853- await subCopy.cancel();
16874+ if (sigIntSub != null) {
16875+ await sigIntSub!.cancel();
1685416876 sigIntSub = null;
16855- if (sigTermSub != null) {
16856- await sigTermSub!.cancel();
16857- sigTermSub = null;
16858- }
16877+ }
16878+
16879+ if (sigTermSub != null) {
16880+ await sigTermSub!.cancel();
16881+ sigTermSub = null;
16882+ }
16883+
16884+ if (!completer.isCompleted) {
1685916885 completer.complete(true);
1686016886 }
1686116887 }
@@ -18132,14 +18158,13 @@ steps:
1813218158 import 'dash_counter.dart';
1813318159 import 'firebase_notifier.dart';
1813418160
18135- @@ -19,19 +20,21 @@ class DashPurchases extends ChangeNotifier {
18161+ @@ -19,19 +20,20 @@ class DashPurchases extends ChangeNotifier {
1813618162 StoreState storeState = StoreState.loading;
1813718163 late StreamSubscription<List<PurchaseDetails>> _subscription;
1813818164 List<PurchasableProduct> products = [];
1813918165 + IAPRepo iapRepo;
1814018166
1814118167 bool get beautifiedDash => _beautifiedDashUpgrade;
18142- + // ignore: prefer_final_fields
1814318168 bool _beautifiedDashUpgrade = false;
1814418169 -
1814518170 final iapConnection = IAPConnection.instance;
@@ -18156,15 +18181,15 @@ steps:
1815618181 loadPurchases();
1815718182 }
1815818183
18159- @@ -57,6 +60 ,7 @@ class DashPurchases extends ChangeNotifier {
18184+ @@ -57,6 +59 ,7 @@ class DashPurchases extends ChangeNotifier {
1816018185 @override
1816118186 void dispose() {
1816218187 _subscription.cancel();
1816318188 + iapRepo.removeListener(purchasesUpdate);
1816418189 super.dispose();
1816518190 }
1816618191
18167- @@ -136,4 +140 ,54 @@ class DashPurchases extends ChangeNotifier {
18192+ @@ -136,4 +139 ,54 @@ class DashPurchases extends ChangeNotifier {
1816818193 void _updateStreamOnError(dynamic error) {
1816918194 //Handle error here
1817018195 }
@@ -18504,6 +18529,158 @@ steps:
1850418529 from: steps
1850518530 to: step_10
1850618531
18532+ - name: complete
18533+ steps:
18534+ - name: Remove complete
18535+ rmdir: complete
18536+ - name: Patch app/lib/logic/dash_purchases.dart
18537+ path: steps/app/lib/logic/dash_purchases.dart
18538+ patch-u: |
18539+ --- b/in_app_purchases/complete/app/lib/logic/dash_purchases.dart
18540+ +++ a/in_app_purchases/complete/app/lib/logic/dash_purchases.dart
18541+ @@ -1,3 +1,5 @@
18542+ +// ignore_for_file: avoid_print
18543+ +
18544+ import 'dart:async';
18545+ import 'dart:convert';
18546+
18547+ @@ -17,10 +19,10 @@ import 'firebase_notifier.dart';
18548+ class DashPurchases extends ChangeNotifier {
18549+ DashCounter counter;
18550+ FirebaseNotifier firebaseNotifier;
18551+ + IAPRepo iapRepo;
18552+ StoreState storeState = StoreState.loading;
18553+ late StreamSubscription<List<PurchaseDetails>> _subscription;
18554+ List<PurchasableProduct> products = [];
18555+ - IAPRepo iapRepo;
18556+
18557+ bool get beautifiedDash => _beautifiedDashUpgrade;
18558+ bool _beautifiedDashUpgrade = false;
18559+ @@ -44,6 +46,7 @@ class DashPurchases extends ChangeNotifier {
18560+ notifyListeners();
18561+ return;
18562+ }
18563+ +
18564+ const ids = <String>{
18565+ storeKeyConsumable,
18566+ storeKeySubscription,
18567+ @@ -58,8 +61,8 @@ class DashPurchases extends ChangeNotifier {
18568+
18569+ @override
18570+ void dispose() {
18571+ - _subscription.cancel();
18572+ iapRepo.removeListener(purchasesUpdate);
18573+ + _subscription.cancel();
18574+ super.dispose();
18575+ }
18576+
18577+ @@ -126,8 +129,10 @@ class DashPurchases extends ChangeNotifier {
18578+ headers: headers,
18579+ );
18580+ if (response.statusCode == 200) {
18581+ + print('Successfully verified purchase');
18582+ return true;
18583+ } else {
18584+ + print('failed request: ${response.statusCode} - ${response.body}');
18585+ return false;
18586+ }
18587+ }
18588+ @@ -137,7 +142,7 @@ class DashPurchases extends ChangeNotifier {
18589+ }
18590+
18591+ void _updateStreamOnError(dynamic error) {
18592+ - //Handle error here
18593+ + print(error);
18594+ }
18595+
18596+ void purchasesUpdate() {
18597+ @@ -158,21 +163,21 @@ class DashPurchases extends ChangeNotifier {
18598+ // purchases page.
18599+ if (iapRepo.hasActiveSubscription) {
18600+ counter.applyPaidMultiplier();
18601+ - for (var element in subscriptions) {
18602+ + for (final element in subscriptions) {
18603+ _updateStatus(element, ProductStatus.purchased);
18604+ }
18605+ } else {
18606+ counter.removePaidMultiplier();
18607+ - for (var element in subscriptions) {
18608+ + for (final element in subscriptions) {
18609+ _updateStatus(element, ProductStatus.purchasable);
18610+ }
18611+ }
18612+
18613+ - // Set the Dash beautifier and show/hide purchased on
18614+ + // Set the dash beautifier and show/hide purchased on
18615+ // the purchases page.
18616+ if (iapRepo.hasUpgrade != _beautifiedDashUpgrade) {
18617+ _beautifiedDashUpgrade = iapRepo.hasUpgrade;
18618+ - for (var element in upgrades) {
18619+ + for (final element in upgrades) {
18620+ _updateStatus(
18621+ element,
18622+ _beautifiedDashUpgrade
18623+ @@ -184,8 +189,8 @@ class DashPurchases extends ChangeNotifier {
18624+ }
18625+
18626+ void _updateStatus(PurchasableProduct product, ProductStatus status) {
18627+ - if (product.status != ProductStatus.purchased) {
18628+ - product.status = ProductStatus.purchased;
18629+ + if (product.status != status) {
18630+ + product.status = status;
18631+ notifyListeners();
18632+ }
18633+ }
18634+ - name: mkdir dart-backend/test
18635+ mkdir: steps/dart-backend/test
18636+ - name: Add dart-backend/test/firebase_backend_dart_test.dart
18637+ path: steps/dart-backend/test/firebase_backend_dart_test.dart
18638+ replace-contents: |
18639+ import 'package:firebase_backend_dart/google_play_purchase_handler.dart';
18640+ import 'package:firebase_backend_dart/products.dart';
18641+ import 'package:test/test.dart';
18642+
18643+ import '../bin/server.dart';
18644+
18645+ void main() {
18646+ test('extractOrderId with subscription suffix', () {
18647+ final orderId = extractOrderId('googleplay_GPA.3391-7354-8735-85865..0');
18648+ expect(orderId, 'googleplay_GPA.3391-7354-8735-85865');
18649+ });
18650+
18651+ test('extractOrderId without subscription suffix', () {
18652+ final orderId = extractOrderId('googleplay_GPA.3391-7354-8735-85865');
18653+ expect(orderId, 'googleplay_GPA.3391-7354-8735-85865');
18654+ });
18655+
18656+ test('Parse Purchase data should fail', () {
18657+ expect(() => getPurchaseData('{}'), throwsFormatException);
18658+ });
18659+
18660+ test('Parse Purchase data should succeed', () {
18661+ final (
18662+ :userId,
18663+ :source,
18664+ productData: ProductData(:productId, :type),
18665+ :token,
18666+ ) = getPurchaseData({
18667+ 'userId': 'USER_ID',
18668+ 'source': 'google_play',
18669+ 'productId': 'dash_consumable_2k',
18670+ 'verificationData': 'TOKEN',
18671+ });
18672+ expect(userId, 'USER_ID');
18673+ expect(source, 'google_play');
18674+ expect(productId, 'dash_consumable_2k');
18675+ expect(type, ProductType.nonSubscription);
18676+ expect(token, 'TOKEN');
18677+ });
18678+ }
18679+ - name: Copy to complete
18680+ copydir:
18681+ from: steps
18682+ to: complete
18683+
1850718684 - name: Cleanup
1850818685 steps:
1850918686 - name: Remove steps
0 commit comments