Revert changes

This commit is contained in:
Hillel Coren 2021-02-22 21:48:35 +02:00
parent 1a14f78aac
commit a8e33a39ff
4 changed files with 399 additions and 4 deletions

View File

@ -1,4 +1,20 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/web_client.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/alert_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:url_launcher/url_launcher.dart';
class UpgradeDialog extends StatefulWidget {
@override
@ -6,8 +22,234 @@ class UpgradeDialog extends StatefulWidget {
}
class _UpgradeDialogState extends State<UpgradeDialog> {
StreamSubscription<List<PurchaseDetails>> _subscription;
List<ProductDetails> _products;
List<PurchaseDetails> _purchases;
bool _showPastPurchases = false;
Future<void> loadPurchases() async {
InAppPurchaseConnection.instance
.queryPastPurchases()
.then((response) async {
if (response.pastPurchases != null && response.pastPurchases.isNotEmpty) {
setState(() {
_purchases = response.pastPurchases;
});
}
});
}
Future<void> redeemPurchase(PurchaseDetails purchase) async {
if (purchase.error != null || purchase.purchaseID == null) {
return null;
}
//Navigator.pop(context);
final localization = AppLocalization.of(context);
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final webClient = WebClient();
final data = {
'order_id': purchase.purchaseID,
'product_id': purchase.productID,
'timestamp': (int.parse(purchase.transactionDate) / 1000).floor(),
};
try {
final dynamic response = await webClient.post(
'$kAppProductionUrl/api/v1/upgrade', state.credentials.token,
data: json.encode(data));
final String message = response['message'];
if (message == 'success') {
showDialog<MessageDialog>(
context: context,
builder: (BuildContext context) {
return MessageDialog(localization.thankYouForYourPurchase,
onDismiss: () {
store.dispatch(RefreshData());
});
});
if (Platform.isIOS) {
InAppPurchaseConnection.instance.completePurchase(purchase);
}
} else {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(message);
});
}
} catch (error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
}
}
@override
void initState() {
super.initState();
final Stream purchaseUpdates =
InAppPurchaseConnection.instance.purchaseUpdatedStream;
_subscription = purchaseUpdates.listen((dynamic purchases) {
(purchases as List<PurchaseDetails>).forEach((purchase) async {
await redeemPurchase(purchase);
});
}, onDone: () {
_subscription.cancel();
_subscription = null;
}, onError: (dynamic error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
initStore();
}
void initStore() async {
final bool available = await InAppPurchaseConnection.instance.isAvailable();
if (!available) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog('Store is not available');
});
return;
}
final productIds = Set<String>.from(kProductPlans);
final ProductDetailsResponse response =
await InAppPurchaseConnection.instance.queryProductDetails(productIds);
await loadPurchases();
setState(() {
_products = response.productDetails;
});
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
void upgrade(BuildContext context, ProductDetails productDetails) {
final store = StoreProvider.of<AppState>(context);
final company = store.state.company;
InAppPurchaseConnection.instance.buyNonConsumable(
purchaseParam: PurchaseParam(
productDetails: productDetails,
applicationUserName: company.companyKey,
sandboxTesting: false,
));
}
String convertPlanToString(String plan) {
switch (plan) {
case kProductPlanPro:
return 'Pro - 1 User';
case kProductPlanEnterprise2:
return 'Enterprise - 2 Users';
case kProductPlanEnterprise5:
return 'Enterprise - 5 Users';
case kProductPlanEnterprise10:
return 'Enterprise - 10 Users';
case kProductPlanEnterprise20:
return 'Enterprise - 20 Users';
default:
return '';
}
}
@override
Widget build(BuildContext context) {
return Container();
final localization = AppLocalization.of(context);
if (_products == null) {
return LoadingIndicator(height: 50);
}
_products.sort((product1, product2) =>
parseDouble(product1.price) > parseDouble(product2.price) ? 1 : -1);
return SimpleDialog(
title: Column(
children: <Widget>[
Text(localization.annualSubscription),
if (Platform.isIOS)
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 4),
child: Text(
'Payment will be charged to iTunes Account at confirmation of purchase. Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period. Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal. Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user\'s Account Settings after purchase.',
style: TextStyle(fontSize: 12, color: Colors.grey),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
TextButton(
child: Text('Terms', style: TextStyle(fontSize: 12)),
onPressed: () => launch(kTermsOfServiceURL),
),
TextButton(
child: Text('Privacy', style: TextStyle(fontSize: 12)),
onPressed: () => launch(kPrivacyPolicyURL),
),
],
)
],
),
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
children: [
if (_showPastPurchases)
..._purchases.map((purchase) => ListTile(
title: Text(purchase.purchaseID),
subtitle: Text(formatDate(
convertTimestampToDateString(
(int.parse(purchase.transactionDate) / 1000).floor()),
context)),
onTap: () => redeemPurchase(purchase),
)),
if (_purchases != null)
AppButton(
label: _showPastPurchases
? localization.back
: localization.pastPurchases,
onPressed: () {
setState(() {
_showPastPurchases = !_showPastPurchases;
if (_showPastPurchases) {
loadPurchases();
}
});
},
),
if (!_showPastPurchases)
..._products
.map((productDetails) => ListTile(
title: Text(productDetails.title ??
convertPlanToString(productDetails.id)),
subtitle: Text(productDetails.description ?? ''),
trailing: Text(productDetails.price ?? '',
style: TextStyle(fontSize: 18)),
onTap: () => upgrade(context, productDetails),
))
.toList()
],
);
}
}

View File

@ -14,6 +14,7 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart';
import 'package:invoiceninja_flutter/ui/auth/login_view.dart';
import 'package:invoiceninja_flutter/redux/auth/auth_state.dart';
import 'package:google_sign_in/google_sign_in.dart';
class LoginScreen extends StatelessWidget {
const LoginScreen({Key key}) : super(key: key);
@ -81,6 +82,15 @@ class LoginVM {
final Function(BuildContext, Completer<Null> completer) onGoogleSignUpPressed;
static LoginVM fromStore(Store<AppState> store) {
final GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'openid',
'profile',
'https://www.googleapis.com/auth/gmail.send',
],
);
void _handleLogin({BuildContext context, bool isSignUp = false}) {
final layout = calculateLayout(context);
@ -110,9 +120,52 @@ class LoginVM {
@required String url,
@required String secret,
@required String oneTimePassword,
}) async {},
}) async {
try {
final account = await _googleSignIn.signIn();
if (account != null) {
account.authentication.then((GoogleSignInAuthentication value) {
store.dispatch(OAuthLoginRequest(
completer: completer,
idToken: value.idToken,
accessToken: value.accessToken,
serverAuthCode: value.serverAuthCode,
url: formatApiUrl(url.trim()),
secret: secret.trim(),
platform: getPlatform(context),
oneTimePassword: oneTimePassword,
));
completer.future.then((_) => _handleLogin(context: context));
});
}
} catch (error) {
completer.completeError(error);
print(error);
}
},
onGoogleSignUpPressed:
(BuildContext context, Completer<Null> completer) async {},
(BuildContext context, Completer<Null> completer) async {
try {
final account = await _googleSignIn.grantOfflineAccess();
if (account != null) {
account.authentication.then((GoogleSignInAuthentication value) {
store.dispatch(OAuthSignUpRequest(
completer: completer,
idToken: value.idToken,
accessToken: value.accessToken,
serverAuthCode: value.serverAuthCode,
));
completer.future.then(
(_) => _handleLogin(context: context, isSignUp: true));
});
}
} catch (error) {
completer.completeError(error);
print(error);
}
},
onSignUpPressed: (
BuildContext context,
Completer<Null> completer, {

View File

@ -288,6 +288,55 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.6"
firebase:
dependency: transitive
description:
name: firebase
url: "https://pub.dartlang.org"
source: hosted
version: "7.3.3"
firebase_auth:
dependency: "direct main"
description:
name: firebase_auth
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.2"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.8"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3+1"
firebase_core:
dependency: transitive
description:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.5"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+2"
fixnum:
dependency: transitive
description:
@ -403,6 +452,33 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
google_sign_in:
dependency: "direct main"
description:
path: "packages/google_sign_in/google_sign_in"
ref: master
resolved-ref: b9b7e1eabc2da8e669ea1b452d310ecce454741e
url: "https://github.com/invoiceninja/plugins.git"
source: git
version: "4.5.4"
google_sign_in_platform_interface:
dependency: "direct overridden"
description:
path: "packages/google_sign_in/google_sign_in_platform_interface"
ref: HEAD
resolved-ref: b9b7e1eabc2da8e669ea1b452d310ecce454741e
url: "https://github.com/invoiceninja/plugins.git"
source: git
version: "1.1.2"
google_sign_in_web:
dependency: "direct main"
description:
path: "packages/google_sign_in/google_sign_in_web"
ref: master
resolved-ref: b9b7e1eabc2da8e669ea1b452d310ecce454741e
url: "https://github.com/invoiceninja/plugins.git"
source: git
version: "0.9.2"
graphs:
dependency: transitive
description:
@ -466,6 +542,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
in_app_purchase:
dependency: "direct main"
description:
name: in_app_purchase
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5+1"
intl:
dependency: "direct main"
description:

View File

@ -61,10 +61,27 @@ dependencies:
extended_image: 1.3.1-dev #TODO remove
file_picker: ^2.1.1
draggable_scrollbar: ^0.0.4
in_app_purchase: ^0.3.1+1
firebase_auth: 0.15.2 #https://github.com/FirebaseExtended/flutterfire/issues/2433#issuecomment-622438185
google_sign_in:
git:
url: https://github.com/invoiceninja/plugins.git
path: packages/google_sign_in/google_sign_in
ref: master
google_sign_in_web:
git:
url: https://github.com/invoiceninja/plugins.git
path: packages/google_sign_in/google_sign_in_web
ref: master
dependency_overrides:
# https://github.com/flutter/flutter/issues/70433#issuecomment-727154345
intl: ^0.17.0-nullsafety.2
# https://github.com/flutter/flutter/issues/57712#issuecomment-703382420
google_sign_in_platform_interface:
git:
url: https://github.com/invoiceninja/plugins.git
path: packages/google_sign_in/google_sign_in_platform_interface
dev_dependencies:
#flutter_driver: # TODO Re-enable
@ -83,4 +100,4 @@ flutter:
assets:
- assets/images/logo.png
- assets/images/google-icon.png
- assets/images/payment_types/
- assets/images/payment_types/