CW-148 cake pay partial redemptions (#490)

* Ionia custom redemption screen * update ionia gift card remaining amount with custom value * [NO-TASK] Fix issues with custom redeem * replace redeem * update remaining amount * fixed from code review * Add localization

Godwin Asuquo committed Sep 2, 2022 at 16:47 UTC bd25d047b2dc648ddc776b760eec2fd32c02433b
26 files changed +446 -32
lib/di.dart
+18
@@ -5,10 +5,13 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
5 import 'package:cake_wallet/ionia/ionia_category.dart';
6 import 'package:cake_wallet/ionia/ionia_gift_card.dart';
7 import 'package:cake_wallet/ionia/ionia_tip.dart';
8 +import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
9 import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
10 +import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
11 import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
12 import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
13 import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
14 +import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart';
15 import 'package:cake_wallet/view_model/ionia/ionia_filter_view_model.dart';
16 import 'package:cake_wallet/ionia/ionia_service.dart';
17 import 'package:cake_wallet/ionia/ionia_api.dart';
@@ -747,6 +750,21 @@ Future setup(
750 return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
751 });
752
753 + getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
754 + final giftCard = args.first as IoniaGiftCard;
755 +
756 + return IoniaMoreOptionsPage(giftCard);
757 + });
758 +
759 + getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard));
760 +
761 + getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
762 + final giftCard = args.first as IoniaGiftCard;
763 +
764 + return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
765 + });
766 +
767 +
768 getIt.registerFactoryParam<IoniaCustomTipPage, List, void>((List args, _) {
769 return IoniaCustomTipPage(getIt.get<IoniaCustomTipViewModel>(param1: args));
770 });
lib/ionia/ionia_gift_card.dart
+2 -1
@@ -60,10 +60,11 @@ class IoniaGiftCard {
60 final double actualAmount;
61 final double totalTransactionAmount;
62 final double totalDashTransactionAmount;
63 - final double remainingAmount;
63 + double remainingAmount;
64 final String createdDateFormatted;
65 final String lastTransactionDateFormatted;
66 final bool isActive;
67 final bool isEmpty;
68 final String logoUrl;
69 +
70 }
\ No newline at end of file
lib/router.dart
+10
@@ -6,8 +6,10 @@ import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
6 import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
7 import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart';
8 import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
9 +import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
10 import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart';
11 import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
12 +import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
13 import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
14 import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
15 import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
@@ -452,6 +454,14 @@ Route<dynamic> createRoute(RouteSettings settings) {
454 case Routes.ioniaGiftCardDetailPage:
455 final args = settings.arguments as List;
456 return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaGiftCardDetailPage>(param1: args.first));
457 +
458 + case Routes.ioniaCustomRedeemPage:
459 + final args = settings.arguments as List;
460 + return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaCustomRedeemPage>(param1: args));
461 +
462 + case Routes.ioniaMoreOptionsPage:
463 + final args = settings.arguments as List;
464 + return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaMoreOptionsPage>(param1: args));
465
466 case Routes.ioniaPaymentStatusPage:
467 final args = settings.arguments as List;
lib/routes.dart
+2
@@ -74,4 +74,6 @@ class Routes {
74 static const ioniaCustomTipPage = 'ionia_custom_tip_page';
75 static const ioniaGiftCardDetailPage = '/ionia_gift_card_detail_page';
76 static const ioniaPaymentStatusPage = '/ionia_payment_status_page';
77 + static const ioniaMoreOptionsPage = '/ionia_more_options_page';
78 + static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
79 }
lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart new
+167
@@ -0,0 +1,167 @@
1 +import 'package:cake_wallet/src/screens/base_page.dart';
2 +import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
3 +import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
4 +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
5 +import 'package:cake_wallet/src/widgets/primary_button.dart';
6 +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
7 +import 'package:cake_wallet/themes/theme_base.dart';
8 +import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart';
9 +import 'package:flutter/material.dart';
10 +import 'package:flutter/services.dart';
11 +import 'package:flutter_mobx/flutter_mobx.dart';
12 +import 'package:keyboard_actions/keyboard_actions.dart';
13 +import 'package:cake_wallet/generated/i18n.dart';
14 +
15 +class IoniaCustomRedeemPage extends BasePage {
16 + IoniaCustomRedeemPage(
17 + this.ioniaCustomRedeemViewModel,
18 + ) : _amountFieldFocus = FocusNode(),
19 + _amountController = TextEditingController() {
20 + _amountController.addListener(() {
21 + ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
22 + });
23 + }
24 +
25 + final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
26 +
27 +
28 + @override
29 + String get title => S.current.custom_redeem_amount;
30 +
31 + @override
32 + Color get titleColor => Colors.white;
33 +
34 + @override
35 + bool get extendBodyBehindAppBar => true;
36 +
37 + @override
38 + AppBarStyle get appBarStyle => AppBarStyle.transparent;
39 +
40 + Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939);
41 +
42 + final TextEditingController _amountController;
43 + final FocusNode _amountFieldFocus;
44 +
45 + @override
46 + Widget body(BuildContext context) {
47 + final _width = MediaQuery.of(context).size.width;
48 + final giftCard = ioniaCustomRedeemViewModel.giftCard;
49 + return KeyboardActions(
50 + disableScroll: true,
51 + config: KeyboardActionsConfig(
52 + keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
53 + keyboardBarColor: Theme.of(context).accentTextTheme.body2.backgroundColor,
54 + nextFocus: false,
55 + actions: [
56 + KeyboardActionsItem(
57 + focusNode: _amountFieldFocus,
58 + toolbarButtons: [(_) => KeyboardDoneButton()],
59 + ),
60 + ]),
61 + child: Container(
62 + color: Theme.of(context).backgroundColor,
63 + child: ScrollableWithBottomSection(
64 + contentPadding: EdgeInsets.zero,
65 + content: Column(
66 + children: [
67 + Container(
68 + padding: EdgeInsets.symmetric(horizontal: 25),
69 + decoration: BoxDecoration(
70 + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
71 + gradient: LinearGradient(colors: [
72 + Theme.of(context).primaryTextTheme.subhead.color,
73 + Theme.of(context).primaryTextTheme.subhead.decorationColor,
74 + ], begin: Alignment.topLeft, end: Alignment.bottomRight),
75 + ),
76 + child: Column(
77 + mainAxisSize: MainAxisSize.min,
78 + crossAxisAlignment: CrossAxisAlignment.stretch,
79 + children: [
80 + SizedBox(height: 150),
81 + BaseTextFormField(
82 + controller: _amountController,
83 + focusNode: _amountFieldFocus,
84 + keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
85 + inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
86 + hintText: '1000',
87 + placeholderTextStyle: TextStyle(
88 + color: Theme.of(context).primaryTextTheme.headline.color,
89 + fontWeight: FontWeight.w500,
90 + fontSize: 36,
91 + ),
92 + borderColor: Theme.of(context).primaryTextTheme.headline.color,
93 + textColor: Colors.white,
94 + textStyle: TextStyle(
95 + color: Colors.white,
96 + fontSize: 36,
97 + ),
98 + suffixIcon: SizedBox(
99 + width: _width / 6,
100 + ),
101 + prefixIcon: Padding(
102 + padding: EdgeInsets.only(
103 + top: 5.0,
104 + left: _width / 4,
105 + ),
106 + child: Text(
107 + 'USD: ',
108 + style: TextStyle(
109 + color: Colors.white,
110 + fontWeight: FontWeight.w900,
111 + fontSize: 36,
112 + ),
113 + ),
114 + ),
115 + ),
116 + SizedBox(height: 8),
117 + Observer(builder: (_)=>
118 + !ioniaCustomRedeemViewModel.disableRedeem ?
119 + Center(
120 + child: Text('\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.remaining} ${S.of(context).remaining}',
121 + style: TextStyle(
122 + color: Theme.of(context).primaryTextTheme.headline.color,
123 + ),),
124 + ) : SizedBox.shrink(),
125 + ),
126 + SizedBox(height: 24),
127 + ],
128 + ),
129 + ),
130 + Padding(
131 + padding: const EdgeInsets.all(24.0),
132 + child: CardItem(
133 + title: giftCard.legalName,
134 + backgroundColor: Theme.of(context).accentTextTheme.display4.backgroundColor.withOpacity(0.1),
135 + discount: giftCard.remainingAmount,
136 + isAmount: true,
137 + discountBackground: AssetImage('assets/images/red_badge_discount.png'),
138 + titleColor: Theme.of(context).accentTextTheme.display4.backgroundColor,
139 + subtitleColor: Theme.of(context).hintColor,
140 + subTitle: S.of(context).online,
141 + logoUrl: giftCard.logoUrl,
142 + ),
143 + ),
144 + ],
145 + ),
146 + bottomSection: Column(
147 + children: [
148 + Padding(
149 + padding: EdgeInsets.only(bottom: 12),
150 + child: PrimaryButton(
151 + onPressed: () {
152 + Navigator.of(context).pop(_amountController.text);
153 + },
154 + isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
155 + text: S.of(context).add_custom_redemption,
156 + color: Theme.of(context).accentTextTheme.body2.color,
157 + textColor: Colors.white,
158 + ),
159 + ),
160 + SizedBox(height: 30),
161 + ],
162 + ),
163 + ),
164 + ),
165 + );
166 + }
167 +}
lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart
+39 -15
@@ -117,7 +117,7 @@ class IoniaGiftCardDetailPage extends BasePage {
117 buildIoniaTile(
118 context,
119 title: S.of(context).amount,
120 - subTitle: viewModel.giftCard.remainingAmount.toStringAsFixed(2) ?? '0.00',
120 + subTitle: viewModel.remainingAmount.toStringAsFixed(2) ?? '0.00',
121 )),
122 Divider(height: 50),
123 TextIconButton(
@@ -127,21 +127,45 @@ class IoniaGiftCardDetailPage extends BasePage {
127 ],
128 ),
129 bottomSection: Padding(
130 - padding: EdgeInsets.only(bottom: 12),
131 - child: Observer(builder: (_) {
132 - if (!viewModel.giftCard.isEmpty) {
133 - return LoadingPrimaryButton(
134 - isLoading: viewModel.redeemState is IsExecutingState,
135 - onPressed: () => viewModel.redeem().then((_){
136 - Navigator.of(context).pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
137 - }),
138 - text: S.of(context).mark_as_redeemed,
139 - color: Theme.of(context).accentTextTheme.body2.color,
140 - textColor: Colors.white);
141 - }
130 + padding: EdgeInsets.only(bottom: 12),
131 + child: Observer(
132 + builder: (_) {
133 + if (!viewModel.giftCard.isEmpty) {
134 + return Column(
135 + children: [
136 + PrimaryButton(
137 + onPressed: () async {
138 + final amount = await Navigator.of(context)
139 + .pushNamed(Routes.ioniaMoreOptionsPage, arguments: [viewModel.giftCard]) as String;
140 + if (amount != null) {
141 + viewModel.updateRemaining(double.parse(amount));
142 + }
143 + },
144 + text: S.of(context).more_options,
145 + color: Theme.of(context).accentTextTheme.caption.color,
146 + textColor: Theme.of(context).primaryTextTheme.title.color,
147 + ),
148 + SizedBox(height: 12),
149 + LoadingPrimaryButton(
150 + isLoading: viewModel.redeemState is IsExecutingState,
151 + onPressed: () => viewModel.redeem().then(
152 + (_) {
153 + Navigator.of(context)
154 + .pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
155 + },
156 + ),
157 + text: S.of(context).mark_as_redeemed,
158 + color: Theme.of(context).accentTextTheme.body2.color,
159 + textColor: Colors.white,
160 + ),
161 + ],
162 + );
163 + }
164
143 - return Container();
144 - })),
165 + return Container();
166 + },
167 + ),
168 + ),
169 );
170 }
171
lib/src/screens/ionia/cards/ionia_more_options_page.dart new
+90
@@ -0,0 +1,90 @@
1 +import 'package:cake_wallet/ionia/ionia_gift_card.dart';
2 +import 'package:cake_wallet/routes.dart';
3 +import 'package:cake_wallet/src/screens/base_page.dart';
4 +import 'package:cake_wallet/generated/i18n.dart';
5 +import 'package:cake_wallet/typography.dart';
6 +import 'package:flutter/material.dart';
7 +
8 +
9 +class IoniaMoreOptionsPage extends BasePage {
10 + IoniaMoreOptionsPage(this.giftCard);
11 +
12 + final IoniaGiftCard giftCard;
13 +
14 + @override
15 + Widget middle(BuildContext context) {
16 + return Text(
17 + S.current.more_options,
18 + style: textMediumSemiBold(
19 + color: Theme.of(context).accentTextTheme.display4.backgroundColor,
20 + ),
21 + );
22 + }
23 +
24 + @override
25 + Widget body(BuildContext context) {
26 + return Padding(
27 + padding: const EdgeInsets.all(16.0),
28 + child: Column(
29 + 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.title.color,
34 + ),)),
35 + SizedBox(height: 40,),
36 + InkWell(
37 + onTap: () async {
38 + final amount = await Navigator.of(context).pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String;
39 + if(amount.isNotEmpty){
40 + Navigator.pop(context, amount);
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 + ),
55 + );
56 + }
57 +}
58 +
59 +class _GradiantContainer extends StatelessWidget {
60 + const _GradiantContainer({
61 + Key key,
62 + @required this.content,
63 + this.padding,
64 + this.width,
65 + }) : super(key: key);
66 +
67 + final Widget content;
68 + final EdgeInsets padding;
69 + final double width;
70 +
71 + @override
72 + Widget build(BuildContext context) {
73 + return Container(
74 + child: content,
75 + width: width,
76 + padding: padding ?? EdgeInsets.all(24),
77 + decoration: BoxDecoration(
78 + borderRadius: BorderRadius.circular(15),
79 + gradient: LinearGradient(
80 + colors: [
81 + Theme.of(context).scaffoldBackgroundColor,
82 + Theme.of(context).accentColor,
83 + ],
84 + begin: Alignment.topRight,
85 + end: Alignment.bottomLeft,
86 + ),
87 + ),
88 + );
89 + }
90 +}
lib/src/screens/ionia/widgets/card_item.dart
+3
@@ -12,6 +12,7 @@ class CardItem extends StatelessWidget {
12 this.onTap,
13 this.logoUrl,
14 this.discount,
15 + this.isAmount = false,
16 });
17
18 final VoidCallback onTap;
@@ -19,6 +20,7 @@ class CardItem extends StatelessWidget {
20 final String subTitle;
21 final String logoUrl;
22 final double discount;
23 + final bool isAmount;
24 final Color backgroundColor;
25 final Color titleColor;
26 final Color subtitleColor;
@@ -100,6 +102,7 @@ class CardItem extends StatelessWidget {
102 padding: const EdgeInsets.only(top: 20.0),
103 child: DiscountBadge(
104 percentage: discount,
105 + isAmount: isAmount,
106 discountBackground: discountBackground,
107 ),
108 ),
lib/src/widgets/discount_badge.dart
+3 -1
@@ -4,11 +4,13 @@ import 'package:cake_wallet/generated/i18n.dart';
4 class DiscountBadge extends StatelessWidget {
5 const DiscountBadge({
6 Key key,
7 + this.isAmount = false,
8 @required this.percentage,
9 this.discountBackground,
10 }) : super(key: key);
11
12 final double percentage;
13 + final bool isAmount;
14 final AssetImage discountBackground;
15
16 @override
@@ -16,7 +18,7 @@ class DiscountBadge extends StatelessWidget {
18 return Container(
19 padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
20 child: Text(
19 - S.of(context).discount(percentage.toStringAsFixed(2)),
21 + isAmount ? '\$${percentage.toStringAsFixed(2)}' : S.of(context).discount(percentage.toStringAsFixed(2)),
22 style: TextStyle(
23 color: Colors.white,
24 fontSize: 12,
lib/view_model/ionia/ionia_custom_redeem_view_model.dart new
+27
@@ -0,0 +1,27 @@
1 +import 'package:cake_wallet/ionia/ionia_gift_card.dart';
2 +import 'package:mobx/mobx.dart';
3 +part 'ionia_custom_redeem_view_model.g.dart';
4 +class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel;
5 +
6 +abstract class IoniaCustomRedeemViewModelBase with Store {
7 + IoniaCustomRedeemViewModelBase(this.giftCard){
8 + amount = 0;
9 + }
10 +
11 + final IoniaGiftCard giftCard;
12 +
13 + @observable
14 + double amount;
15 +
16 + @computed
17 + double get remaining => amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
18 +
19 + @computed
20 + bool get disableRedeem => amount > giftCard.remainingAmount;
21 +
22 + @action
23 + void updateAmount(String text){
24 + amount = text.isEmpty ? 0 : (double.parse(text.replaceAll(',', '.')) ?? 0);
25 + }
26 +
27 +}
\ No newline at end of file
lib/view_model/ionia/ionia_gift_card_details_view_model.dart
+10
@@ -12,6 +12,7 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store {
12
13 IoniaGiftCardDetailsViewModelBase({this.ioniaService, this.giftCard}) {
14 redeemState = InitialExecutionState();
15 + remainingAmount = giftCard.remainingAmount;
16 }
17
18 final IoniaService ioniaService;
@@ -20,11 +21,15 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store {
21 @observable
22 IoniaGiftCard giftCard;
23
24 + @observable
25 + double remainingAmount;
26 +
27 @observable
28 ExecutionState redeemState;
29
30 @action
31 Future<void> redeem() async {
32 + giftCard.remainingAmount = remainingAmount;
33 try {
34 redeemState = IsExecutingState();
35 await ioniaService.redeem(giftCard);
@@ -35,6 +40,11 @@ abstract class IoniaGiftCardDetailsViewModelBase with Store {
40 }
41 }
42
43 + @action
44 + void updateRemaining(double amount){
45 + remainingAmount = amount;
46 + }
47 +
48 void increaseBrightness() async {
49 brightness = await DeviceDisplayBrightness.getBrightness();
50 await DeviceDisplayBrightness.setBrightness(1.0);
res/values/strings_de.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Dieses feste Paar wird von den ausgewählten Vermittlungsstellen nicht unterstützt",
640 "variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt",
641 "none_of_selected_providers_can_exchange": "Keiner der ausgewählten Anbieter kann diesen Austausch vornehmen",
642 - "choose_one": "Wähle ein"
642 + "choose_one": "Wähle ein",
643 + "choose_from_available_options": "Wähle aus verfügbaren Optionen:",
644 + "custom_redeem_amount": "Benutzerdefinierter Einlösungsbetrag",
645 + "add_custom_redemption": "Benutzerdefinierte Einlösung hinzufügen",
646 + "remaining": "Rest"
647 }
res/values/strings_en.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "This fixed pair is not supported with the selected exchanges",
640 "variable_pair_not_supported": "This variable pair is not supported with the selected exchanges",
641 "none_of_selected_providers_can_exchange": "None of the selected providers can make this exchange",
642 - "choose_one": "Choose one"
642 + "choose_one": "Choose one",
643 + "choose_from_available_options": "Choose from the available options:",
644 + "custom_redeem_amount": "Custom Redeem Amount",
645 + "add_custom_redemption": "Add Custom Redemption",
646 + "remaining": "remaining"
647 }
res/values/strings_es.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Este par fijo no es compatible con los intercambios seleccionados",
640 "variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados",
641 "none_of_selected_providers_can_exchange": "Ninguno de los proveedores seleccionados puede realizar este intercambio",
642 - "choose_one": "Elige uno"
642 + "choose_one": "Elige uno",
643 + "choose_from_available_options": "Elija entre las opciones disponibles:",
644 + "custom_redeem_amount": "Cantidad de canje personalizada",
645 + "add_custom_redemption": "Agregar redención personalizada",
646 + "remaining": "restante"
647 }
res/values/strings_fr.arb
+5 -1
@@ -637,5 +637,9 @@
637 "fixed_pair_not_supported": "Cette paire fixe n'est pas prise en charge avec les échanges sélectionnés",
638 "variable_pair_not_supported": "Cette paire de variables n'est pas prise en charge avec les échanges sélectionnés",
639 "none_of_selected_providers_can_exchange": "Aucun des prestataires sélectionnés ne peut effectuer cet échange",
640 - "choose_one": "Choisissez-en un"
640 + "choose_one": "Choisissez-en un",
641 + "choose_from_available_options": "Choisissez parmi les options disponibles :",
642 + "custom_redeem_amount": "Montant d'échange personnalisé",
643 + "add_custom_redemption": "Ajouter un remboursement personnalisé",
644 + "remaining": "restant"
645 }
res/values/strings_hi.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "यह निश्चित जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है",
640 "variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है",
641 "none_of_selected_providers_can_exchange": "चयनित प्रदाताओं में से कोई भी इस एक्सचेंज को नहीं बना सकता",
642 - "choose_one": "एक का चयन"
642 + "choose_one": "एक का चयन",
643 + "choose_from_available_options": "उपलब्ध विकल्पों में से चुनें:",
644 + "custom_redeem_amount": "कस्टम रिडीम राशि",
645 + "add_custom_redemption": "कस्टम रिडेम्पशन जोड़ें",
646 + "remaining": "शेष"
647 }
res/values/strings_hr.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Ovaj fiksni par nije podržan s odabranim burzama",
640 "variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama",
641 "none_of_selected_providers_can_exchange": "Niti jedan od odabranih pružatelja usluga ne može izvršiti ovu razmjenu",
642 - "choose_one": "Izaberi jedan"
642 + "choose_one": "Izaberi jedan",
643 + "choose_from_available_options": "Odaberite neku od dostupnih opcija:",
644 + "custom_redeem_amount": "Prilagođeni iznos otkupa",
645 + "add_custom_redemption": "Dodaj prilagođeni otkup",
646 + "remaining": "preostalo"
647 }
res/values/strings_it.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Questa coppia fissa non è supportata con gli scambi selezionati",
640 "variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati",
641 "none_of_selected_providers_can_exchange": "Nessuno dei fornitori selezionati può effettuare questo scambio",
642 - "choose_one": "Scegline uno"
642 + "choose_one": "Scegline uno",
643 + "choose_from_available_options": "Scegli tra le opzioni disponibili:",
644 + "custom_redeem_amount": "Importo di riscatto personalizzato",
645 + "add_custom_redemption": "Aggiungi riscatto personalizzato",
646 + "remaining": "rimanente"
647 }
res/values/strings_ja.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "この固定ペアは、選択したエクスチェンジではサポートされていません",
640 "variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません",
641 "none_of_selected_providers_can_exchange": "選択したプロバイダーはいずれもこの交換を行うことができません",
642 - "choose_one": "1 つ選択してください"
642 + "choose_one": "1 つ選択してください",
643 + "choose_from_available_options": "利用可能なオプションから選択してください:",
644 + "custom_redeem_amount": "カスタム交換金額",
645 + "add_custom_redemption": "カスタム引き換えを追加",
646 + "remaining": "残り"
647 }
res/values/strings_ko.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "이 고정 쌍은 선택한 교환에서 지원되지 않습니다.",
640 "variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.",
641 "none_of_selected_providers_can_exchange": "선택한 공급자 중 누구도 이 교환을 할 수 없습니다.",
642 - "choose_one": "하나 선택"
642 + "choose_one": "하나 선택",
643 + "choose_from_available_options": "사용 가능한 옵션에서 선택:",
644 + "custom_redeem_amount": "사용자 지정 상환 금액",
645 + "add_custom_redemption": "사용자 지정 상환 추가",
646 + "remaining": "남은"
647 }
res/values/strings_nl.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Dit vaste paar wordt niet ondersteund bij de geselecteerde exchanges",
640 "variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen",
641 "none_of_selected_providers_can_exchange": "Geen van de geselecteerde providers kan deze uitwisseling maken",
642 - "choose_one": "Kies er een"
642 + "choose_one": "Kies er een",
643 + "choose_from_available_options": "Kies uit de beschikbare opties:",
644 + "custom_redeem_amount": "Aangepast inwisselbedrag",
645 + "add_custom_redemption": "Voeg aangepaste inwisseling toe",
646 + "remaining": "resterende"
647 }
res/values/strings_pl.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Ta stała para nie jest obsługiwana na wybranych giełdach",
640 "variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach",
641 "none_of_selected_providers_can_exchange": "Żaden z wybranych dostawców nie może dokonać tej wymiany",
642 - "choose_one": "Wybierz jeden"
642 + "choose_one": "Wybierz jeden",
643 + "choose_from_available_options": "Wybierz z dostępnych opcji:",
644 + "custom_redeem_amount": "Niestandardowa kwota wykorzystania",
645 + "add_custom_redemption": "Dodaj niestandardowe wykorzystanie",
646 + "remaining": "pozostałe"
647 }
res/values/strings_pt.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Este par fixo não é compatível com as exchanges selecionadas",
640 "variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas",
641 "none_of_selected_providers_can_exchange": "Nenhum dos provedores selecionados pode fazer esta troca",
642 - "choose_one": "Escolha um"
642 + "choose_one": "Escolha um",
643 + "choose_from_available_options": "Escolha entre as opções disponíveis:",
644 + "custom_redeem_amount": "Valor de resgate personalizado",
645 + "add_custom_redemption": "Adicionar resgate personalizado",
646 + "remaining": "restante"
647 }
res/values/strings_ru.arb
+5 -1
@@ -639,5 +639,9 @@
639 "fixed_pair_not_supported": "Эта фиксированная пара не поддерживается выбранными биржами.",
640 "variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.",
641 "none_of_selected_providers_can_exchange": "Ни один из выбранных провайдеров не может совершить этот обмен",
642 - "choose_one": "Выбери один"
642 + "choose_one": "Выбери один",
643 + "choose_from_available_options": "Выберите из доступных вариантов:",
644 + "custom_redeem_amount": "Пользовательская сумма погашения",
645 + "add_custom_redemption": "Добавить пользовательское погашение",
646 + "remaining": "осталось"
647 }
res/values/strings_uk.arb
+5 -1
@@ -638,5 +638,9 @@
638 "fixed_pair_not_supported": "Ця фіксована пара не підтримується вибраними біржами",
639 "variable_pair_not_supported": "Ця пара змінних не підтримується вибраними біржами",
640 "none_of_selected_providers_can_exchange": "Жоден із вибраних провайдерів не може здійснити цей обмін",
641 - "choose_one": "Вибери один"
641 + "choose_one": "Вибери один",
642 + "choose_from_available_options": "Виберіть із доступних варіантів:",
643 + "custom_redeem_amount": "Власна сума викупу",
644 + "add_custom_redemption": "Додати спеціальне погашення",
645 + "remaining": "залишилося"
646 }
res/values/strings_zh.arb
+5 -1
@@ -637,5 +637,9 @@
637 "fixed_pair_not_supported": "所选交易所不支持此固定货币对",
638 "variable_pair_not_supported": "所选交易所不支持此变量对",
639 "none_of_selected_providers_can_exchange": "选定的供应商都不能进行此交换",
640 - "choose_one": "选一个"
640 + "choose_one": "选一个",
641 + "choose_from_available_options": "从可用选项中选择:",
642 + "custom_redeem_amount": "自定义兑换金额",
643 + "add_custom_redemption": "添加自定义兑换",
644 + "remaining": "剩余"
645 }