fix issue with custom redeem amount remaining

Godwin Asuquo committed Dec 7, 2022 at 18:12 UTC 0203f686c555581308c6bf25c05622606782d56f
6 files changed +156 -122
lib/di.dart
+2 -1
@@ -760,7 +760,8 @@ Future setup(
760 return IoniaMoreOptionsPage(giftCard);
761 });
762
763 - getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard));
763 + getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
764 + => IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
765
766 getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
767 final giftCard = args.first as IoniaGiftCard;
lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart
+40 -29
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/core/execution_state.dart';
2 import 'package:cake_wallet/src/screens/base_page.dart';
3 import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
4 import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
@@ -18,12 +19,11 @@ class IoniaCustomRedeemPage extends BasePage {
19 ) : _amountFieldFocus = FocusNode(),
20 _amountController = TextEditingController() {
21 _amountController.addListener(() {
21 - ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
22 + ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
23 });
24 }
25
26 final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
26 -
27
28 @override
29 String get title => S.current.custom_redeem_amount;
@@ -50,7 +50,7 @@ class IoniaCustomRedeemPage extends BasePage {
50 disableScroll: true,
51 config: KeyboardActionsConfig(
52 keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
53 - keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!,
53 + keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
54 nextFocus: false,
55 actions: [
56 KeyboardActionsItem(
@@ -67,10 +67,11 @@ class IoniaCustomRedeemPage extends BasePage {
67 Container(
68 padding: EdgeInsets.symmetric(horizontal: 25),
69 decoration: BoxDecoration(
70 - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
70 + borderRadius: BorderRadius.only(
71 + bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
72 gradient: LinearGradient(colors: [
72 - Theme.of(context).primaryTextTheme!.subtitle1!.color!,
73 - Theme.of(context).primaryTextTheme!.subtitle1!.decorationColor!,
73 + Theme.of(context).primaryTextTheme.subtitle1!.color!,
74 + Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!,
75 ], begin: Alignment.topLeft, end: Alignment.bottomRight),
76 ),
77 child: Column(
@@ -85,11 +86,11 @@ class IoniaCustomRedeemPage extends BasePage {
86 inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
87 hintText: '1000',
88 placeholderTextStyle: TextStyle(
88 - color: Theme.of(context).primaryTextTheme!.headline5!.color!,
89 + color: Theme.of(context).primaryTextTheme.headline5!.color!,
90 fontWeight: FontWeight.w500,
91 fontSize: 36,
92 ),
92 - borderColor: Theme.of(context).primaryTextTheme!.headline5!.color!,
93 + borderColor: Theme.of(context).primaryTextTheme.headline5!.color!,
94 textColor: Colors.white,
95 textStyle: TextStyle(
96 color: Colors.white,
@@ -114,14 +115,17 @@ class IoniaCustomRedeemPage extends BasePage {
115 ),
116 ),
117 SizedBox(height: 8),
117 - Observer(builder: (_)=>
118 - !ioniaCustomRedeemViewModel.disableRedeem ?
119 - Center(
120 - child: Text('\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
121 - style: TextStyle(
122 - color: Theme.of(context).primaryTextTheme!.headline5!.color!,
123 - ),),
124 - ) : SizedBox.shrink(),
118 + Observer(
119 + builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem
120 + ? Center(
121 + child: Text(
122 + '\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
123 + style: TextStyle(
124 + color: Theme.of(context).primaryTextTheme.headline5!.color!,
125 + ),
126 + ),
127 + )
128 + : SizedBox.shrink(),
129 ),
130 SizedBox(height: 24),
131 ],
@@ -131,30 +135,37 @@ class IoniaCustomRedeemPage extends BasePage {
135 padding: const EdgeInsets.all(24.0),
136 child: CardItem(
137 title: giftCard.legalName,
134 - backgroundColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!.withOpacity(0.1),
138 + backgroundColor: Theme.of(context)
139 + .accentTextTheme
140 + .headline1!
141 + .backgroundColor!
142 + .withOpacity(0.1),
143 discount: giftCard.remainingAmount,
144 isAmount: true,
145 discountBackground: AssetImage('assets/images/red_badge_discount.png'),
138 - titleColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!,
146 + titleColor: Theme.of(context).accentTextTheme.headline1!.backgroundColor!,
147 subtitleColor: Theme.of(context).hintColor,
148 subTitle: S.of(context).online,
149 logoUrl: giftCard.logoUrl,
150 ),
143 - ),
151 + ),
152 ],
153 ),
154 bottomSection: Column(
155 children: [
148 - Padding(
149 - padding: EdgeInsets.only(bottom: 12),
150 - child: PrimaryButton(
151 - onPressed: () {
152 - Navigator.of(context).pop([ioniaCustomRedeemViewModel.remaining.toString(), ioniaCustomRedeemViewModel.amount.toString()]);
153 - },
154 - isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
155 - text: S.of(context).add_custom_redemption,
156 - color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
157 - textColor: Colors.white,
156 + Observer(
157 + builder: (_) => Padding(
158 + padding: EdgeInsets.only(bottom: 12),
159 + child: LoadingPrimaryButton(
160 + isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState,
161 + isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
162 + text: S.of(context).add_custom_redemption,
163 + color: Theme.of(context).accentTextTheme.bodyText1!.color!,
164 + textColor: Colors.white,
165 + onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) {
166 + Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString());
167 + }),
168 + ),
169 ),
170 ),
171 SizedBox(height: 30),
lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart
+35 -35
@@ -32,7 +32,7 @@ class IoniaGiftCardDetailPage extends BasePage {
32
33 final _backButton = Icon(
34 Icons.arrow_back_ios,
35 - color: Theme.of(context).primaryTextTheme!.headline6!.color!,
35 + color: Theme.of(context).primaryTextTheme.headline6!.color!,
36 size: 16,
37 );
38 return Padding(
@@ -43,7 +43,7 @@ class IoniaGiftCardDetailPage extends BasePage {
43 child: ButtonTheme(
44 minWidth: double.minPositive,
45 child: TextButton(
46 - // FIX-ME: Style
46 + // FIX-ME: Style
47 //highlightColor: Colors.transparent,
48 //splashColor: Colors.transparent,
49 //padding: EdgeInsets.all(0),
@@ -61,7 +61,8 @@ class IoniaGiftCardDetailPage extends BasePage {
61 Widget middle(BuildContext context) {
62 return Text(
63 viewModel.giftCard.legalName,
64 - style: textMediumSemiBold(color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!),
64 + style:
65 + textMediumSemiBold(color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!),
66 );
67 }
68
@@ -102,20 +103,21 @@ class IoniaGiftCardDetailPage extends BasePage {
103 title: S.of(context).gift_card_number,
104 subTitle: viewModel.giftCard.cardNumber,
105 ),
105 - if (viewModel.giftCard.cardPin?.isNotEmpty ?? false)
106 - ...[Divider(height: 30),
106 + if (viewModel.giftCard.cardPin.isNotEmpty) ...[
107 + Divider(height: 30),
108 buildIoniaTile(
109 context,
110 title: S.of(context).pin_number,
111 subTitle: viewModel.giftCard.cardPin,
111 - )],
112 + )
113 + ],
114 Divider(height: 30),
113 - Observer(builder: (_) =>
114 - buildIoniaTile(
115 - context,
116 - title: S.of(context).amount,
117 - subTitle: viewModel.remainingAmount.toStringAsFixed(2) ?? '0.00',
118 - )),
115 + Observer(
116 + builder: (_) => buildIoniaTile(
117 + context,
118 + title: S.of(context).amount,
119 + subTitle: viewModel.remainingAmount.toStringAsFixed(2),
120 + )),
121 Divider(height: 50),
122 TextIconButton(
123 label: S.of(context).how_to_use_card,
@@ -131,24 +133,23 @@ class IoniaGiftCardDetailPage extends BasePage {
133 return Column(
134 children: [
135 PrimaryButton(
134 - onPressed: () async {
135 - final amount = await Navigator.of(context)
136 - .pushNamed(Routes.ioniaMoreOptionsPage, arguments: [viewModel.giftCard]) as List<String>?;
137 - if (amount != null) {
138 - viewModel.updateRemaining( balance: double.parse(amount.first), customAmount: double.parse(amount.last));
139 - }
140 - },
141 - text: S.of(context).more_options,
142 - color: Theme.of(context).accentTextTheme.caption!.color!,
143 - textColor: Theme.of(context).primaryTextTheme.headline6!.color!,
136 + onPressed: () async {
137 + await Navigator.of(context).pushNamed(
138 + Routes.ioniaMoreOptionsPage,
139 + arguments: [viewModel.giftCard]) as String?;
140 + viewModel.refeshCard();
141 + },
142 + text: S.of(context).more_options,
143 + color: Theme.of(context).accentTextTheme.caption!.color!,
144 + textColor: Theme.of(context).primaryTextTheme.headline6!.color!,
145 ),
146 SizedBox(height: 12),
147 LoadingPrimaryButton(
148 isLoading: viewModel.redeemState is IsExecutingState,
149 onPressed: () => viewModel.redeem().then(
150 (_) {
150 - Navigator.of(context)
151 - .pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
151 + Navigator.of(context).pushNamedAndRemoveUntil(
152 + Routes.ioniaManageCardsPage, (route) => route.isFirst);
153 },
154 ),
155 text: S.of(context).mark_as_redeemed,
@@ -168,12 +169,11 @@ class IoniaGiftCardDetailPage extends BasePage {
169
170 Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
171 return IoniaTile(
171 - title: title,
172 - subTitle: subTitle,
173 - onTap: () {
174 - Clipboard.setData(ClipboardData(text: subTitle));
175 - showBar<void>(context,
176 - S.of(context).transaction_details_copied(title));
172 + title: title,
173 + subTitle: subTitle,
174 + onTap: () {
175 + Clipboard.setData(ClipboardData(text: subTitle));
176 + showBar<void>(context, S.of(context).transaction_details_copied(title));
177 });
178 }
179
@@ -184,10 +184,10 @@ class IoniaGiftCardDetailPage extends BasePage {
184 showPopUp<void>(
185 context: context,
186 builder: (BuildContext context) {
187 - return IoniaAlertModal(
187 + return IoniaAlertModal(
188 title: S.of(context).how_to_use_card,
189 content: Column(
190 - crossAxisAlignment: CrossAxisAlignment.start,
190 + crossAxisAlignment: CrossAxisAlignment.start,
191 children: viewModel.giftCard.instructions
192 .map((instruction) {
193 return [
@@ -196,13 +196,13 @@ class IoniaGiftCardDetailPage extends BasePage {
196 child: Text(
197 instruction.header,
198 style: textLargeSemiBold(
199 - color: Theme.of(context).textTheme!.headline3!.color!,
199 + color: Theme.of(context).textTheme.headline3!.color!,
200 ),
201 )),
202 Text(
203 instruction.body,
204 style: textMedium(
205 - color: Theme.of(context).textTheme!.headline3!.color!,
205 + color: Theme.of(context).textTheme.headline3!.color!,
206 ),
207 )
208 ];
@@ -210,7 +210,7 @@ class IoniaGiftCardDetailPage extends BasePage {
210 .expand((e) => e)
211 .toList()),
212 actionTitle: S.of(context).send_got_it,
213 - );
213 + );
214 });
215 }
216 }
lib/src/screens/ionia/cards/ionia_more_options_page.dart
+36 -31
@@ -5,7 +5,6 @@ import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/typography.dart';
6 import 'package:flutter/material.dart';
7
8 -
8 class IoniaMoreOptionsPage extends BasePage {
9 IoniaMoreOptionsPage(this.giftCard);
10
@@ -16,7 +15,7 @@ class IoniaMoreOptionsPage extends BasePage {
15 return Text(
16 S.current.more_options,
17 style: textMediumSemiBold(
19 - color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!,
18 + color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!,
19 ),
20 );
21 }
@@ -27,40 +26,46 @@ class IoniaMoreOptionsPage extends BasePage {
26 padding: const EdgeInsets.all(16.0),
27 child: Column(
28 crossAxisAlignment: CrossAxisAlignment.stretch,
30 - children: [
31 - SizedBox(height: 10,),
32 - Center(child: Text(S.of(context).choose_from_available_options, style: textMedium(
33 - color: Theme.of(context).primaryTextTheme!.headline6!.color!,
34 - ),)),
35 - SizedBox(height: 40,),
36 - InkWell(
37 - onTap: () async {
38 - final amounts = await Navigator.of(context).pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as List<String>;
39 - if(amounts.first.isNotEmpty){
40 - Navigator.pop(context, amounts);
41 - }
42 - },
43 - child: _GradiantContainer(
44 - content: Padding(
45 - padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
46 - child: Text(
47 - S.of(context).custom_redeem_amount,
48 - style: textXLargeSemiBold(),
49 - ),
50 - ),
51 - ),
52 - )
53 - ],
54 - ),
29 + children: [
30 + SizedBox(
31 + height: 10,
32 + ),
33 + Center(
34 + child: Text(
35 + S.of(context).choose_from_available_options,
36 + style: textMedium(
37 + color: Theme.of(context).primaryTextTheme.headline6!.color!,
38 + ),
39 + )),
40 + SizedBox(
41 + height: 40,
42 + ),
43 + InkWell(
44 + onTap: () async {
45 + final amount = await Navigator.of(context)
46 + .pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?;
47 + if (amount != null && amount.isNotEmpty) {
48 + Navigator.pop(context);
49 + }
50 + },
51 + child: _GradiantContainer(
52 + content: Padding(
53 + padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
54 + child: Text(
55 + S.of(context).custom_redeem_amount,
56 + style: textXLargeSemiBold(),
57 + ),
58 + ),
59 + ),
60 + )
61 + ],
62 + ),
63 );
64 }
65 }
66
67 class _GradiantContainer extends StatelessWidget {
60 - const _GradiantContainer({
61 - Key? key,
62 - required this.content
63 - }) : super(key: key);
68 + const _GradiantContainer({Key? key, required this.content}) : super(key: key);
69
70 final Widget content;
71
lib/view_model/ionia/ionia_custom_redeem_view_model.dart
+29 -7
@@ -1,29 +1,51 @@
1 +import 'package:cake_wallet/core/execution_state.dart';
2 import 'package:cake_wallet/ionia/ionia_gift_card.dart';
3 +import 'package:cake_wallet/ionia/ionia_service.dart';
4 import 'package:mobx/mobx.dart';
5 part 'ionia_custom_redeem_view_model.g.dart';
6 +
7 class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel;
8
9 abstract class IoniaCustomRedeemViewModelBase with Store {
7 - IoniaCustomRedeemViewModelBase(this.giftCard)
8 - : amount = 0;
10 + IoniaCustomRedeemViewModelBase({
11 + required this.giftCard,
12 + required this.ioniaService,
13 + }) : amount = 0,
14 + redeemState = InitialExecutionState();
15
16 final IoniaGiftCard giftCard;
17
18 + final IoniaService ioniaService;
19 +
20 + @observable
21 + ExecutionState redeemState;
22 +
23 @observable
24 double amount;
25
26 @computed
16 - double get remaining => amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
27 + double get remaining =>
28 + amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
29
30 @computed
19 - String get formattedRemaining => remaining.toStringAsFixed(2);
31 + String get formattedRemaining => remaining.toStringAsFixed(2);
32
33 @computed
34 bool get disableRedeem => amount > giftCard.remainingAmount;
35
36 @action
25 - void updateAmount(String text){
26 - amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.')) ?? 0);
37 + void updateAmount(String text) {
38 + amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.')));
39 }
40
29 -}
\ No newline at end of file
41 + @action
42 + Future<void> addCustomRedeem() async {
43 + try {
44 + redeemState = IsExecutingState();
45 + await ioniaService.redeem(giftCardId: giftCard.id, amount: amount);
46 + redeemState = ExecutedSuccessfullyState();
47 + } catch (e) {
48 + redeemState = FailureState(e.toString());
49 + }
50 + }
51 +}
lib/view_model/ionia/ionia_gift_card_details_view_model.dart
+14 -19
@@ -6,30 +6,25 @@ import 'package:device_display_brightness/device_display_brightness.dart';
6
7 part 'ionia_gift_card_details_view_model.g.dart';
8
9 -class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase with _$IoniaGiftCardDetailsViewModel;
9 +class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase
10 + with _$IoniaGiftCardDetailsViewModel;
11
12 abstract class IoniaGiftCardDetailsViewModelBase with Store {
12 -
13 - IoniaGiftCardDetailsViewModelBase({
14 - required this.ioniaService,
15 - required this.giftCard})
16 - : redeemState = InitialExecutionState(),
17 - remainingAmount = giftCard.remainingAmount,
18 - adjustedAmount = 0,
19 - brightness = 0;
13 + IoniaGiftCardDetailsViewModelBase({required this.ioniaService, required this.giftCard})
14 + : redeemState = InitialExecutionState(),
15 + remainingAmount = giftCard.remainingAmount,
16 + brightness = 0;
17
18 final IoniaService ioniaService;
22 -
19 +
20 double brightness;
24 -
21 +
22 @observable
23 IoniaGiftCard giftCard;
24
25 @observable
26 double remainingAmount;
27
31 - double adjustedAmount;
32 -
28 @observable
29 ExecutionState redeemState;
30
@@ -38,22 +33,22 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store {
33 giftCard.remainingAmount = remainingAmount;
34 try {
35 redeemState = IsExecutingState();
41 - await ioniaService.redeem(giftCardId: giftCard.id, amount : adjustedAmount > 0 ? adjustedAmount : giftCard.remainingAmount);
36 + await ioniaService.redeem(giftCardId: giftCard.id, amount: giftCard.remainingAmount);
37 giftCard = await ioniaService.getGiftCard(id: giftCard.id);
38 redeemState = ExecutedSuccessfullyState();
44 - } catch(e) {
39 + } catch (e) {
40 redeemState = FailureState(e.toString());
41 }
42 }
43
44 @action
50 - void updateRemaining({required double balance, required double customAmount}) {
51 - remainingAmount = balance;
52 - adjustedAmount = customAmount;
45 + Future<void> refeshCard() async {
46 + giftCard = await ioniaService.getGiftCard(id: giftCard.id);
47 + remainingAmount = giftCard.remainingAmount;
48 }
49
50 void increaseBrightness() async {
51 brightness = await DeviceDisplayBrightness.getBrightness();
52 await DeviceDisplayBrightness.setBrightness(1.0);
53 }
59 -}
\ No newline at end of file
54 +}