diff --git a/lib/di.dart b/lib/di.dart index 90549cf6f..910feae4a 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -760,7 +760,8 @@ Future setup( return IoniaMoreOptionsPage(giftCard); }); - getIt.registerFactoryParam((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard)); + getIt.registerFactoryParam((IoniaGiftCard giftCard, _) + => IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get())); getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; diff --git a/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart b/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart index f9ce0ae88..f2702d791 100644 --- a/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart +++ b/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; @@ -18,12 +19,11 @@ class IoniaCustomRedeemPage extends BasePage { ) : _amountFieldFocus = FocusNode(), _amountController = TextEditingController() { _amountController.addListener(() { - ioniaCustomRedeemViewModel.updateAmount(_amountController.text); + ioniaCustomRedeemViewModel.updateAmount(_amountController.text); }); } final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel; - @override String get title => S.current.custom_redeem_amount; @@ -50,7 +50,7 @@ class IoniaCustomRedeemPage extends BasePage { disableScroll: true, config: KeyboardActionsConfig( keyboardActionsPlatform: KeyboardActionsPlatform.IOS, - keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!, + keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!, nextFocus: false, actions: [ KeyboardActionsItem( @@ -67,10 +67,11 @@ class IoniaCustomRedeemPage extends BasePage { Container( padding: EdgeInsets.symmetric(horizontal: 25), decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), gradient: LinearGradient(colors: [ - Theme.of(context).primaryTextTheme!.subtitle1!.color!, - Theme.of(context).primaryTextTheme!.subtitle1!.decorationColor!, + Theme.of(context).primaryTextTheme.subtitle1!.color!, + Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!, ], begin: Alignment.topLeft, end: Alignment.bottomRight), ), child: Column( @@ -85,11 +86,11 @@ class IoniaCustomRedeemPage extends BasePage { inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))], hintText: '1000', placeholderTextStyle: TextStyle( - color: Theme.of(context).primaryTextTheme!.headline5!.color!, + color: Theme.of(context).primaryTextTheme.headline5!.color!, fontWeight: FontWeight.w500, fontSize: 36, ), - borderColor: Theme.of(context).primaryTextTheme!.headline5!.color!, + borderColor: Theme.of(context).primaryTextTheme.headline5!.color!, textColor: Colors.white, textStyle: TextStyle( color: Colors.white, @@ -114,14 +115,17 @@ class IoniaCustomRedeemPage extends BasePage { ), ), SizedBox(height: 8), - Observer(builder: (_)=> - !ioniaCustomRedeemViewModel.disableRedeem ? - Center( - child: Text('\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}', - style: TextStyle( - color: Theme.of(context).primaryTextTheme!.headline5!.color!, - ),), - ) : SizedBox.shrink(), + Observer( + builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem + ? Center( + child: Text( + '\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}', + style: TextStyle( + color: Theme.of(context).primaryTextTheme.headline5!.color!, + ), + ), + ) + : SizedBox.shrink(), ), SizedBox(height: 24), ], @@ -131,30 +135,37 @@ class IoniaCustomRedeemPage extends BasePage { padding: const EdgeInsets.all(24.0), child: CardItem( title: giftCard.legalName, - backgroundColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!.withOpacity(0.1), + backgroundColor: Theme.of(context) + .accentTextTheme + .headline1! + .backgroundColor! + .withOpacity(0.1), discount: giftCard.remainingAmount, isAmount: true, discountBackground: AssetImage('assets/images/red_badge_discount.png'), - titleColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!, + titleColor: Theme.of(context).accentTextTheme.headline1!.backgroundColor!, subtitleColor: Theme.of(context).hintColor, subTitle: S.of(context).online, logoUrl: giftCard.logoUrl, ), - ), + ), ], ), bottomSection: Column( children: [ - Padding( - padding: EdgeInsets.only(bottom: 12), - child: PrimaryButton( - onPressed: () { - Navigator.of(context).pop([ioniaCustomRedeemViewModel.remaining.toString(), ioniaCustomRedeemViewModel.amount.toString()]); - }, - isDisabled: ioniaCustomRedeemViewModel.disableRedeem, - text: S.of(context).add_custom_redemption, - color: Theme.of(context).accentTextTheme!.bodyText1!.color!, - textColor: Colors.white, + Observer( + builder: (_) => Padding( + padding: EdgeInsets.only(bottom: 12), + child: LoadingPrimaryButton( + isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState, + isDisabled: ioniaCustomRedeemViewModel.disableRedeem, + text: S.of(context).add_custom_redemption, + color: Theme.of(context).accentTextTheme.bodyText1!.color!, + textColor: Colors.white, + onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) { + Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString()); + }), + ), ), ), SizedBox(height: 30), diff --git a/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart b/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart index 2e7162e40..5b3c980ec 100644 --- a/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart +++ b/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart @@ -32,7 +32,7 @@ class IoniaGiftCardDetailPage extends BasePage { final _backButton = Icon( Icons.arrow_back_ios, - color: Theme.of(context).primaryTextTheme!.headline6!.color!, + color: Theme.of(context).primaryTextTheme.headline6!.color!, size: 16, ); return Padding( @@ -43,7 +43,7 @@ class IoniaGiftCardDetailPage extends BasePage { child: ButtonTheme( minWidth: double.minPositive, child: TextButton( - // FIX-ME: Style + // FIX-ME: Style //highlightColor: Colors.transparent, //splashColor: Colors.transparent, //padding: EdgeInsets.all(0), @@ -61,7 +61,8 @@ class IoniaGiftCardDetailPage extends BasePage { Widget middle(BuildContext context) { return Text( viewModel.giftCard.legalName, - style: textMediumSemiBold(color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!), + style: + textMediumSemiBold(color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!), ); } @@ -102,20 +103,21 @@ class IoniaGiftCardDetailPage extends BasePage { title: S.of(context).gift_card_number, subTitle: viewModel.giftCard.cardNumber, ), - if (viewModel.giftCard.cardPin?.isNotEmpty ?? false) - ...[Divider(height: 30), + if (viewModel.giftCard.cardPin.isNotEmpty) ...[ + Divider(height: 30), buildIoniaTile( context, title: S.of(context).pin_number, subTitle: viewModel.giftCard.cardPin, - )], + ) + ], Divider(height: 30), - Observer(builder: (_) => - buildIoniaTile( - context, - title: S.of(context).amount, - subTitle: viewModel.remainingAmount.toStringAsFixed(2) ?? '0.00', - )), + Observer( + builder: (_) => buildIoniaTile( + context, + title: S.of(context).amount, + subTitle: viewModel.remainingAmount.toStringAsFixed(2), + )), Divider(height: 50), TextIconButton( label: S.of(context).how_to_use_card, @@ -131,24 +133,23 @@ class IoniaGiftCardDetailPage extends BasePage { return Column( children: [ PrimaryButton( - onPressed: () async { - final amount = await Navigator.of(context) - .pushNamed(Routes.ioniaMoreOptionsPage, arguments: [viewModel.giftCard]) as List?; - if (amount != null) { - viewModel.updateRemaining( balance: double.parse(amount.first), customAmount: double.parse(amount.last)); - } - }, - text: S.of(context).more_options, - color: Theme.of(context).accentTextTheme.caption!.color!, - textColor: Theme.of(context).primaryTextTheme.headline6!.color!, + onPressed: () async { + await Navigator.of(context).pushNamed( + Routes.ioniaMoreOptionsPage, + arguments: [viewModel.giftCard]) as String?; + viewModel.refeshCard(); + }, + text: S.of(context).more_options, + color: Theme.of(context).accentTextTheme.caption!.color!, + textColor: Theme.of(context).primaryTextTheme.headline6!.color!, ), SizedBox(height: 12), LoadingPrimaryButton( isLoading: viewModel.redeemState is IsExecutingState, onPressed: () => viewModel.redeem().then( (_) { - Navigator.of(context) - .pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst); + Navigator.of(context).pushNamedAndRemoveUntil( + Routes.ioniaManageCardsPage, (route) => route.isFirst); }, ), text: S.of(context).mark_as_redeemed, @@ -168,12 +169,11 @@ class IoniaGiftCardDetailPage extends BasePage { Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) { return IoniaTile( - title: title, - subTitle: subTitle, - onTap: () { - Clipboard.setData(ClipboardData(text: subTitle)); - showBar(context, - S.of(context).transaction_details_copied(title)); + title: title, + subTitle: subTitle, + onTap: () { + Clipboard.setData(ClipboardData(text: subTitle)); + showBar(context, S.of(context).transaction_details_copied(title)); }); } @@ -184,10 +184,10 @@ class IoniaGiftCardDetailPage extends BasePage { showPopUp( context: context, builder: (BuildContext context) { - return IoniaAlertModal( + return IoniaAlertModal( title: S.of(context).how_to_use_card, content: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: viewModel.giftCard.instructions .map((instruction) { return [ @@ -196,13 +196,13 @@ class IoniaGiftCardDetailPage extends BasePage { child: Text( instruction.header, style: textLargeSemiBold( - color: Theme.of(context).textTheme!.headline3!.color!, + color: Theme.of(context).textTheme.headline3!.color!, ), )), Text( instruction.body, style: textMedium( - color: Theme.of(context).textTheme!.headline3!.color!, + color: Theme.of(context).textTheme.headline3!.color!, ), ) ]; @@ -210,7 +210,7 @@ class IoniaGiftCardDetailPage extends BasePage { .expand((e) => e) .toList()), actionTitle: S.of(context).send_got_it, - ); + ); }); } } diff --git a/lib/src/screens/ionia/cards/ionia_more_options_page.dart b/lib/src/screens/ionia/cards/ionia_more_options_page.dart index d4e378f84..facdfaf32 100644 --- a/lib/src/screens/ionia/cards/ionia_more_options_page.dart +++ b/lib/src/screens/ionia/cards/ionia_more_options_page.dart @@ -5,7 +5,6 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/typography.dart'; import 'package:flutter/material.dart'; - class IoniaMoreOptionsPage extends BasePage { IoniaMoreOptionsPage(this.giftCard); @@ -16,7 +15,7 @@ class IoniaMoreOptionsPage extends BasePage { return Text( S.current.more_options, style: textMediumSemiBold( - color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!, + color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!, ), ); } @@ -27,40 +26,46 @@ class IoniaMoreOptionsPage extends BasePage { padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox(height: 10,), - Center(child: Text(S.of(context).choose_from_available_options, style: textMedium( - color: Theme.of(context).primaryTextTheme!.headline6!.color!, - ),)), - SizedBox(height: 40,), - InkWell( - onTap: () async { - final amounts = await Navigator.of(context).pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as List; - if(amounts.first.isNotEmpty){ - Navigator.pop(context, amounts); - } - }, - child: _GradiantContainer( - content: Padding( - padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50), - child: Text( - S.of(context).custom_redeem_amount, - style: textXLargeSemiBold(), - ), - ), - ), - ) - ], - ), + children: [ + SizedBox( + height: 10, + ), + Center( + child: Text( + S.of(context).choose_from_available_options, + style: textMedium( + color: Theme.of(context).primaryTextTheme.headline6!.color!, + ), + )), + SizedBox( + height: 40, + ), + InkWell( + onTap: () async { + final amount = await Navigator.of(context) + .pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?; + if (amount != null && amount.isNotEmpty) { + Navigator.pop(context); + } + }, + child: _GradiantContainer( + content: Padding( + padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50), + child: Text( + S.of(context).custom_redeem_amount, + style: textXLargeSemiBold(), + ), + ), + ), + ) + ], + ), ); } } class _GradiantContainer extends StatelessWidget { - const _GradiantContainer({ - Key? key, - required this.content - }) : super(key: key); + const _GradiantContainer({Key? key, required this.content}) : super(key: key); final Widget content; diff --git a/lib/view_model/ionia/ionia_custom_redeem_view_model.dart b/lib/view_model/ionia/ionia_custom_redeem_view_model.dart index 963604c15..6471c7378 100644 --- a/lib/view_model/ionia/ionia_custom_redeem_view_model.dart +++ b/lib/view_model/ionia/ionia_custom_redeem_view_model.dart @@ -1,29 +1,51 @@ +import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/ionia/ionia_gift_card.dart'; +import 'package:cake_wallet/ionia/ionia_service.dart'; import 'package:mobx/mobx.dart'; part 'ionia_custom_redeem_view_model.g.dart'; + class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel; abstract class IoniaCustomRedeemViewModelBase with Store { - IoniaCustomRedeemViewModelBase(this.giftCard) - : amount = 0; + IoniaCustomRedeemViewModelBase({ + required this.giftCard, + required this.ioniaService, + }) : amount = 0, + redeemState = InitialExecutionState(); final IoniaGiftCard giftCard; + final IoniaService ioniaService; + + @observable + ExecutionState redeemState; + @observable double amount; @computed - double get remaining => amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0; + double get remaining => + amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0; @computed - String get formattedRemaining => remaining.toStringAsFixed(2); + String get formattedRemaining => remaining.toStringAsFixed(2); @computed bool get disableRedeem => amount > giftCard.remainingAmount; @action - void updateAmount(String text){ - amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.')) ?? 0); + void updateAmount(String text) { + amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.'))); } -} \ No newline at end of file + @action + Future addCustomRedeem() async { + try { + redeemState = IsExecutingState(); + await ioniaService.redeem(giftCardId: giftCard.id, amount: amount); + redeemState = ExecutedSuccessfullyState(); + } catch (e) { + redeemState = FailureState(e.toString()); + } + } +} diff --git a/lib/view_model/ionia/ionia_gift_card_details_view_model.dart b/lib/view_model/ionia/ionia_gift_card_details_view_model.dart index 745f2d530..cbf5ebc78 100644 --- a/lib/view_model/ionia/ionia_gift_card_details_view_model.dart +++ b/lib/view_model/ionia/ionia_gift_card_details_view_model.dart @@ -6,30 +6,25 @@ import 'package:device_display_brightness/device_display_brightness.dart'; part 'ionia_gift_card_details_view_model.g.dart'; -class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase with _$IoniaGiftCardDetailsViewModel; +class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase + with _$IoniaGiftCardDetailsViewModel; abstract class IoniaGiftCardDetailsViewModelBase with Store { - - IoniaGiftCardDetailsViewModelBase({ - required this.ioniaService, - required this.giftCard}) - : redeemState = InitialExecutionState(), - remainingAmount = giftCard.remainingAmount, - adjustedAmount = 0, - brightness = 0; + IoniaGiftCardDetailsViewModelBase({required this.ioniaService, required this.giftCard}) + : redeemState = InitialExecutionState(), + remainingAmount = giftCard.remainingAmount, + brightness = 0; final IoniaService ioniaService; - + double brightness; - + @observable IoniaGiftCard giftCard; @observable double remainingAmount; - double adjustedAmount; - @observable ExecutionState redeemState; @@ -38,22 +33,22 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store { giftCard.remainingAmount = remainingAmount; try { redeemState = IsExecutingState(); - await ioniaService.redeem(giftCardId: giftCard.id, amount : adjustedAmount > 0 ? adjustedAmount : giftCard.remainingAmount); + await ioniaService.redeem(giftCardId: giftCard.id, amount: giftCard.remainingAmount); giftCard = await ioniaService.getGiftCard(id: giftCard.id); redeemState = ExecutedSuccessfullyState(); - } catch(e) { + } catch (e) { redeemState = FailureState(e.toString()); } } @action - void updateRemaining({required double balance, required double customAmount}) { - remainingAmount = balance; - adjustedAmount = customAmount; + Future refeshCard() async { + giftCard = await ioniaService.getGiftCard(id: giftCard.id); + remainingAmount = giftCard.remainingAmount; } void increaseBrightness() async { brightness = await DeviceDisplayBrightness.getBrightness(); await DeviceDisplayBrightness.setBrightness(1.0); } -} \ No newline at end of file +}