diff --git a/lib/src/providers/purchases.provider.dart b/lib/src/providers/purchases.provider.dart index ab6520d..2903e7d 100644 --- a/lib/src/providers/purchases.provider.dart +++ b/lib/src/providers/purchases.provider.dart @@ -187,6 +187,10 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin { } } + if (purchaseDetails.status == PurchaseStatus.error) { + await iapConnection.restorePurchases(); + } + if (purchaseDetails.pendingCompletePurchase) { await iapConnection.completePurchase(purchaseDetails); } diff --git a/lib/src/views/settings/subscription/additional_users.view.dart b/lib/src/views/settings/subscription/additional_users.view.dart index fc8331c..ed86120 100644 --- a/lib/src/views/settings/subscription/additional_users.view.dart +++ b/lib/src/views/settings/subscription/additional_users.view.dart @@ -65,12 +65,9 @@ class _AdditionalUsersViewState extends State { @override Widget build(BuildContext context) { var plusInvites = []; - var freeInvites = []; if (additionalInvites != null) { plusInvites = additionalInvites!.where((x) => x.planId == 'Plus').toList(); - freeInvites = - additionalInvites!.where((x) => x.planId == 'Free').toList(); } return Scaffold( appBar: AppBar( @@ -95,11 +92,10 @@ class _AdditionalUsersViewState extends State { ), ), if (plusInvites.isNotEmpty) - ListTile( - title: Text( - context.lang.additionalUsersPlusTokens, - style: const TextStyle(fontSize: 13), - ), + Text( + context.lang.additionalUsersPlusTokens, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), ), Padding( padding: const EdgeInsets.all(16), @@ -111,23 +107,6 @@ class _AdditionalUsersViewState extends State { children: plusInvites.map(AdditionalUserInvite.new).toList(), ), ), - if (freeInvites.isNotEmpty) - ListTile( - title: Text( - context.lang.additionalUsersFreeTokens, - style: const TextStyle(fontSize: 13), - ), - ), - Padding( - padding: const EdgeInsets.all(16), - child: GridView.count( - crossAxisCount: 2, - physics: const NeverScrollableScrollPhysics(), - childAspectRatio: 16 / 5, - shrinkWrap: true, - children: freeInvites.map(AdditionalUserInvite.new).toList(), - ), - ), ], ), ); @@ -200,7 +179,7 @@ class _AdditionalAccountState extends State { final remove = await showAlertDialog( context, 'Remove this additional user', - 'The additional user will automatically be downgraded to the preview plan after removal and you will receive a new invitation code to give to another person.', + 'The additional user will automatically be downgraded to the free plan after removal and you will receive a new invitation code to give to another person.', ); if (remove) { final res = await apiService diff --git a/lib/src/views/settings/subscription/subscription.view.dart b/lib/src/views/settings/subscription/subscription.view.dart index b54c05d..365d3df 100644 --- a/lib/src/views/settings/subscription/subscription.view.dart +++ b/lib/src/views/settings/subscription/subscription.view.dart @@ -114,6 +114,8 @@ class _SubscriptionViewState extends State { plan: SubscriptionPlan.Family, onPurchase: initAsync, ), + ], + if (currentPlan == SubscriptionPlan.Free) ...[ const SizedBox(height: 10), Center( child: Padding( @@ -174,6 +176,13 @@ class PlanCard extends StatefulWidget { State createState() => _PlanCardState(); } +String getFormattedPrice(PurchasableProduct product) { + if (product.price.contains('€')) { + return product.price.replaceAll(',00', '').replaceAll('.00', ''); + } + return product.price; +} + class _PlanCardState extends State { Future onButtonPressed(PurchasableProduct? product) async { if (widget.onPurchase == null) return; @@ -261,7 +270,7 @@ class _PlanCardState extends State { Column( children: [ Text( - '${yearlyProduct.price}/${context.lang.year}', + '${getFormattedPrice(yearlyProduct)}/${context.lang.year}', textAlign: TextAlign.center, style: const TextStyle( fontSize: 20, @@ -270,7 +279,7 @@ class _PlanCardState extends State { ), if (monthlyProduct != null) Text( - '${monthlyProduct.price}/${context.lang.month}', + '${getFormattedPrice(monthlyProduct)}/${context.lang.month}', textAlign: TextAlign.center, style: const TextStyle( fontSize: 16, @@ -282,8 +291,8 @@ class _PlanCardState extends State { if (widget.paidMonthly != null) Text( (widget.paidMonthly!) - ? '${monthlyProduct?.price}/${context.lang.month}' - : '${yearlyProduct?.price}/${context.lang.year}', + ? '${getFormattedPrice(monthlyProduct!)}/${context.lang.month}' + : '${getFormattedPrice(yearlyProduct!)}/${context.lang.year}', textAlign: TextAlign.center, style: const TextStyle( fontSize: 20, @@ -319,22 +328,21 @@ class _PlanCardState extends State { label: const Text('Manage subscription'), ), if (widget.onPurchase != null && monthlyProduct != null) - Padding( - padding: const EdgeInsets.only(right: 10), - child: OutlinedButton.icon( - onPressed: () => onButtonPressed(monthlyProduct), - label: (widget.plan == SubscriptionPlan.Free || - widget.plan == SubscriptionPlan.Plus) - ? Text(context.lang.redeemUserInviteCodeTitle) - : Text( - context.lang.upgradeToPaidPlanButton( - widget.plan.name, - ' (${context.lang.monthly})', - ), + OutlinedButton.icon( + onPressed: () => onButtonPressed(monthlyProduct), + label: (widget.plan == SubscriptionPlan.Free || + widget.plan == SubscriptionPlan.Plus) + ? Text(context.lang.redeemUserInviteCodeTitle) + : Text( + context.lang.upgradeToPaidPlanButton( + widget.plan.name, + ' (${context.lang.monthly})', ), - ), + ), ), - if (widget.onPurchase != null && yearlyProduct != null) + if (widget.onPurchase != null && + (yearlyProduct != null || + currentPlan == SubscriptionPlan.Free)) FilledButton.icon( onPressed: () => onButtonPressed(yearlyProduct), label: (widget.plan == SubscriptionPlan.Free ||