Apple IAP

This commit is contained in:
Hillel Coren 2022-07-13 17:25:01 +03:00
parent cb39924f19
commit ca9541026b
3 changed files with 67 additions and 49 deletions

View File

@ -61,6 +61,8 @@ PODS:
- TOCropViewController (~> 2.6.1)
- image_picker_ios (0.0.1):
- Flutter
- in_app_purchase_storekit (0.0.1):
- Flutter
- in_app_review (0.2.0):
- Flutter
- local_auth (0.0.1):
@ -108,6 +110,7 @@ DEPENDENCIES:
- google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/ios`)
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/ios`)
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
- local_auth (from `.symlinks/plugins/local_auth/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
@ -150,6 +153,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_cropper/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
in_app_purchase_storekit:
:path: ".symlinks/plugins/in_app_purchase_storekit/ios"
in_app_review:
:path: ".symlinks/plugins/in_app_review/ios"
local_auth:
@ -193,6 +198,7 @@ SPEC CHECKSUMS:
GTMSessionFetcher: 5595ec75acf5be50814f81e9189490412bad82ba
image_cropper: 60c2789d1f1a78c873235d4319ca0c34a69f2d98
image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb
in_app_purchase_storekit: d7fcf4646136ec258e237872755da8ea6c1b6096
in_app_review: 4a97249f7a2f539a0f294c2d9196b7fe35e49541
local_auth: 1740f55d7af0a2e2a8684ce225fe79d8931e808c
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62

View File

@ -11,6 +11,7 @@ import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart';
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
import 'package:invoiceninja_flutter/ui/app/upgrade_dialog.dart';
import 'package:invoiceninja_flutter/utils/app_review.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
@ -383,7 +384,7 @@ class MenuDrawer extends StatelessWidget {
},
),
),
if (state.userCompany.isOwner &&
if (true || state.userCompany.isOwner &&
state.isHosted &&
!isPaidAccount(context) &&
!isApple() &&
@ -397,15 +398,14 @@ class MenuDrawer extends StatelessWidget {
dense: true,
tileColor: Colors.green,
leading: Padding(
padding: const EdgeInsets.only(left: 9),
padding: const EdgeInsets.only(left: 6),
child: Icon(
Icons.arrow_circle_up,
size: 22,
color: Colors.white,
),
),
contentPadding:
const EdgeInsets.only(left: 12),
contentPadding: const EdgeInsets.only(left: 20),
title: state.isMenuCollapsed
? SizedBox()
: Text(
@ -419,11 +419,16 @@ class MenuDrawer extends StatelessWidget {
),
),
onTap: () {
showDialog<void>(context: context, builder: (BuildContext context) => UpgradeDialog());
/*
store.dispatch(ViewSettings(
clearFilter: true,
company: company,
user: state.user,
section: kSettingsAccountManagement));
*/
},
),
),

View File

@ -13,6 +13,7 @@ import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';
import 'package:in_app_purchase_storekit/store_kit_wrappers.dart';
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/dashboard/dashboard_chart.dart';
class UpgradeDialog extends StatefulWidget {
@override
@ -22,7 +23,6 @@ class UpgradeDialog extends StatefulWidget {
class _UpgradeDialogState extends State<UpgradeDialog> {
final InAppPurchase _inAppPurchase = InAppPurchase.instance;
StreamSubscription<List<PurchaseDetails>> _subscription;
List<String> _notFoundIds = <String>[];
List<ProductDetails> _products = <ProductDetails>[];
List<PurchaseDetails> _purchases = <PurchaseDetails>[];
bool _isAvailable = false;
@ -53,7 +53,6 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
_isAvailable = isAvailable;
_products = <ProductDetails>[];
_purchases = <PurchaseDetails>[];
_notFoundIds = <String>[];
_purchasePending = false;
_loading = false;
});
@ -75,7 +74,6 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = <PurchaseDetails>[];
_notFoundIds = productDetailResponse.notFoundIDs;
_purchasePending = false;
_loading = false;
});
@ -88,7 +86,6 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = <PurchaseDetails>[];
_notFoundIds = productDetailResponse.notFoundIDs;
_purchasePending = false;
_loading = false;
});
@ -98,7 +95,6 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
setState(() {
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_notFoundIds = productDetailResponse.notFoundIDs;
_purchasePending = false;
_loading = false;
});
@ -150,7 +146,7 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
);
}
return Stack(children: stack);
return AlertDialog(content: Stack(children: stack));
}
Card _buildConnectionCheckTile() {
@ -194,13 +190,7 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
final store = StoreProvider.of<AppState>(context);
final account = store.state.account;
if (_notFoundIds.isNotEmpty) {
productList.add(ListTile(
title: Text('[${_notFoundIds.join(", ")}] not found',
style: TextStyle(color: ThemeData.light().errorColor)),
subtitle: const Text(
'This app needs special configuration to run. Please see example/README.md for instructions.')));
}
// This loading previous purchases code is just a demo. Please do not use this as it is.
// In your app you should always verify the purchase data using the `verificationData` inside the [PurchaseDetails] object before trusting it.
@ -216,44 +206,61 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
productList.addAll(_products.map(
(ProductDetails productDetails) {
final PurchaseDetails previousPurchase = purchases[productDetails.id];
String title = productDetails.title;
String description = productDetails.description;
// TODO remove this code
// Workaround for product in app store with blank values
if (title.isEmpty && productDetails.id == kProductEnterprisePlanMonth_10) {
title = 'Enterprise - Month (6-10)';
description = 'One month of the Enterprise Plan (10 users)';
}
return ListTile(
title: Text(
productDetails.title,
title
),
subtitle: Text(
productDetails.description,
),
trailing: previousPurchase != null
? IconButton(
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
description
),
previousPurchase != null
? IconButton(
onPressed: () => confirmPriceChange(context),
icon: const Icon(Icons.upgrade))
: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.green[800],
// TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
// ignore: deprecated_member_use
primary: Colors.white,
),
onPressed: () {
PurchaseParam purchaseParam;
if (Platform.isAndroid) {
purchaseParam = GooglePlayPurchaseParam(
productDetails: productDetails,
applicationUserName: account.id);
} else {
purchaseParam = PurchaseParam(
productDetails: productDetails,
applicationUserName: account.id,
);
}
_inAppPurchase.buyNonConsumable(
purchaseParam: purchaseParam,
);
},
child: Text(productDetails.price),
: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.green[800],
// TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
// ignore: deprecated_member_use
primary: Colors.white,
),
onPressed: () {
PurchaseParam purchaseParam;
if (Platform.isAndroid) {
purchaseParam = GooglePlayPurchaseParam(
productDetails: productDetails,
applicationUserName: account.id);
} else {
purchaseParam = PurchaseParam(
productDetails: productDetails,
applicationUserName: account.id,
);
}
_inAppPurchase.buyNonConsumable(
purchaseParam: purchaseParam,
);
},
child: Text(productDetails.price),
),
SizedBox(height: 20),
],
),
);
},
));