mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-23 06:38:35 +02:00
CW-1069-implement-deuro-dapp-support (#2304)
* feat: started dEuro Savings integration * fix: merge conflict regarding theming * feat: Add dEuro Savings Screen * feat: Change DEuro Savings UI * feat: Complete DEuro Savings integration with UI enhancements and transaction support * style: remove forgotten print statements * feat: localize dEuro subtitle * feat: add approval flow and priority handling to DEuro Savings integration - Introduced approval flow for DEuro Savings to enable token approvals. - Added priority handling for deposit and withdrawal operations. - Updated UI to support approval state and interactions. - Localized new strings for multiple languages. - Enhanced transaction handling with separate approval and commit actions. * feat: add support for ERC20 token approval transactions - Introduced `signApprovalTransaction` and `createApprovalTransaction` methods. - Added handling for infinite approvals. - Implemented encoding for approval transaction data. - Enhanced transaction creation flow with approval-specific functionality. * Update UI * feat: enhance DEuro Savings logic and UI with computed property and fix gradient background * feat: localize transaction confirmation content for DEuro Savings * feat: enable interest collection for DEuro Savings with localized support * fix reformatting [skip ci] --------- Co-authored-by: tuxsudo <tuxsudo@tux.pizza> Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
tuxsudo
OmarHatem
parent
150becb679
commit
edaf485993
@@ -5,15 +5,16 @@ import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class CakeFeaturesPage extends StatelessWidget {
|
||||
CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel});
|
||||
CakeFeaturesPage(
|
||||
{required this.dashboardViewModel, required this.cakeFeaturesViewModel});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final CakeFeaturesViewModel cakeFeaturesViewModel;
|
||||
@@ -58,6 +59,23 @@ class CakeFeaturesPage extends StatelessWidget {
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
if (dashboardViewModel.type == WalletType.ethereum) ...[
|
||||
DashBoardRoundedCardWidget(
|
||||
isDarkTheme: dashboardViewModel.isDarkTheme,
|
||||
shadowBlur: dashboardViewModel.getShadowBlur(),
|
||||
shadowSpread: dashboardViewModel.getShadowSpread(),
|
||||
onTap: () =>
|
||||
Navigator.of(context).pushNamed(Routes.dEuroSavings),
|
||||
title: S.of(context).deuro_savings,
|
||||
subTitle: S.of(context).deuro_savings_subtitle,
|
||||
image: Image.asset(
|
||||
'assets/images/deuro_icon.png',
|
||||
height: 80,
|
||||
width: 80,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
],
|
||||
DashBoardRoundedCardWidget(
|
||||
isDarkTheme: dashboardViewModel.isDarkTheme,
|
||||
shadowBlur: dashboardViewModel.getShadowBlur(),
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/integrations/deuro/widgets/interest_card_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/integrations/deuro/widgets/savings_card_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/integrations/deuro/widgets/savings_edit_sheet.dart';
|
||||
import 'package:cake_wallet/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/view_model/integrations/deuro_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class DEuroSavingsPage extends BasePage {
|
||||
final DEuroViewModel _dEuroViewModel;
|
||||
|
||||
DEuroSavingsPage(this._dEuroViewModel);
|
||||
|
||||
@override
|
||||
bool get gradientBackground => true;
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
(context, scaffold) => GradientBackground(scaffold: scaffold);
|
||||
|
||||
@override
|
||||
String get title => S.current.deuro_savings;
|
||||
|
||||
Widget trailing(BuildContext context) => MergeSemantics(
|
||||
child: SizedBox(
|
||||
height: 37,
|
||||
width: 37,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: "Refresh",
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Theme.of(context).colorScheme.onSurface,
|
||||
overlayColor: WidgetStateColor.resolveWith(
|
||||
(states) => Colors.transparent),
|
||||
),
|
||||
onPressed: _dEuroViewModel.reloadSavingsUserData,
|
||||
child: Icon(
|
||||
Icons.refresh,
|
||||
color: pageIconColor(context),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _setReactions(context, _dEuroViewModel));
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Observer(
|
||||
builder: (_) => SavingsCard(
|
||||
isDarkTheme: currentTheme.isDark,
|
||||
interestRate: "${_dEuroViewModel.interestRate}%",
|
||||
savingsBalance: _dEuroViewModel.savingsBalance,
|
||||
currency: CryptoCurrency.deuro,
|
||||
onAddSavingsPressed: () => _onSavingsAdd(context),
|
||||
onRemoveSavingsPressed: () => _onSavingsRemove(context),
|
||||
onApproveSavingsPressed: _dEuroViewModel.prepareApproval,
|
||||
isEnabled: _dEuroViewModel.isEnabled,
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => InterestCardWidget(
|
||||
isDarkTheme: currentTheme.isDark,
|
||||
title: S.of(context).deuro_savings_collect_interest,
|
||||
collectedInterest: _dEuroViewModel.accruedInterest,
|
||||
onCollectInterest: _dEuroViewModel.prepareCollectInterest,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSavingsAdd(BuildContext context) async {
|
||||
final amount = await Navigator.of(context).push(MaterialPageRoute<String>(
|
||||
builder: (BuildContext context) => SavingEditPage(isAdding: true)));
|
||||
if (amount != null) _dEuroViewModel.prepareSavingsEdit(amount, true);
|
||||
}
|
||||
|
||||
Future<void> _onSavingsRemove(BuildContext context) async {
|
||||
final amount = await Navigator.of(context).push(MaterialPageRoute<String>(
|
||||
builder: (BuildContext context) => SavingEditPage(isAdding: false)));
|
||||
if (amount != null) _dEuroViewModel.prepareSavingsEdit(amount, false);
|
||||
}
|
||||
|
||||
bool _isReactionsSet = false;
|
||||
|
||||
void _setReactions(BuildContext context, DEuroViewModel dEuroViewModel) {
|
||||
if (_isReactionsSet) return;
|
||||
|
||||
reaction((_) => dEuroViewModel.transaction, (PendingTransaction? tx) async {
|
||||
if (tx == null) return;
|
||||
final result = await showModalBottomSheet<bool>(
|
||||
context: context,
|
||||
isDismissible: false,
|
||||
isScrollControlled: true,
|
||||
builder: (BuildContext bottomSheetContext) => ConfirmSendingBottomSheet(
|
||||
key: ValueKey('savings_page_confirm_sending_dialog_key'),
|
||||
titleText: S.of(bottomSheetContext).confirm_transaction,
|
||||
currentTheme: currentTheme,
|
||||
walletType: WalletType.ethereum,
|
||||
titleIconPath: CryptoCurrency.deuro.iconPath,
|
||||
currency: CryptoCurrency.deuro,
|
||||
amount: S.of(bottomSheetContext).send_amount,
|
||||
amountValue: tx.amountFormatted,
|
||||
fiatAmountValue: "",
|
||||
fee: S.of(bottomSheetContext).send_estimated_fee,
|
||||
feeValue: tx.feeFormatted,
|
||||
feeFiatAmount: "",
|
||||
outputs: [],
|
||||
onSlideComplete: () async {
|
||||
Navigator.of(bottomSheetContext).pop(true);
|
||||
dEuroViewModel.commitTransaction();
|
||||
},
|
||||
change: tx.change,
|
||||
),
|
||||
);
|
||||
|
||||
if (result == null) dEuroViewModel.dismissTransaction();
|
||||
});
|
||||
|
||||
reaction((_) => dEuroViewModel.approvalTransaction, (PendingTransaction? tx) async {
|
||||
if (tx == null) return;
|
||||
final result = await showModalBottomSheet<bool>(
|
||||
context: context,
|
||||
isDismissible: false,
|
||||
isScrollControlled: true,
|
||||
builder: (BuildContext bottomSheetContext) => ConfirmSendingBottomSheet(
|
||||
key: ValueKey('savings_page_confirm_approval_dialog_key'),
|
||||
titleText: S.of(bottomSheetContext).approve_tokens,
|
||||
currentTheme: currentTheme,
|
||||
walletType: WalletType.ethereum,
|
||||
titleIconPath: CryptoCurrency.deuro.iconPath,
|
||||
currency: CryptoCurrency.deuro,
|
||||
amount: S.of(bottomSheetContext).send_amount,
|
||||
amountValue: tx.amountFormatted,
|
||||
fiatAmountValue: "",
|
||||
fee: S.of(bottomSheetContext).send_estimated_fee,
|
||||
feeValue: tx.feeFormatted,
|
||||
feeFiatAmount: "",
|
||||
outputs: [],
|
||||
onSlideComplete: () {
|
||||
Navigator.of(bottomSheetContext).pop(true);
|
||||
dEuroViewModel.commitApprovalTransaction();
|
||||
},
|
||||
change: tx.change,
|
||||
),
|
||||
);
|
||||
|
||||
if (result == null) dEuroViewModel.dismissTransaction();
|
||||
});
|
||||
|
||||
reaction((_) => dEuroViewModel.state, (ExecutionState state) async {
|
||||
if (state is TransactionCommitted) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!context.mounted) return;
|
||||
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isDismissible: false,
|
||||
builder: (BuildContext bottomSheetContext) => InfoBottomSheet(
|
||||
currentTheme: currentTheme,
|
||||
titleText: S.of(bottomSheetContext).transaction_sent,
|
||||
contentImage: 'assets/images/birthday_cake.png',
|
||||
content: S.of(bottomSheetContext).deuro_tx_commited_content,
|
||||
actionButtonText: S.of(bottomSheetContext).close,
|
||||
actionButtonKey: ValueKey('send_page_sent_dialog_ok_button_key'),
|
||||
actionButton: () => Navigator.of(bottomSheetContext).pop(),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_isReactionsSet = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/bottom_sheet/base_bottom_sheet_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/view_model/integrations/deuro_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EditSavingsBottomSheet extends BaseBottomSheet {
|
||||
EditSavingsBottomSheet(this.dEuroViewModel, {required super.titleText});
|
||||
|
||||
final _amountController = TextEditingController();
|
||||
final DEuroViewModel dEuroViewModel;
|
||||
|
||||
@override
|
||||
Widget contentWidget(BuildContext context) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: CurrencyAmountTextField(
|
||||
hasUnderlineBorder: true,
|
||||
borderWidth: 1.0,
|
||||
selectedCurrency: CryptoCurrency.deuro.name.toUpperCase(),
|
||||
amountFocusNode: null,
|
||||
amountController: _amountController,
|
||||
tag: CryptoCurrency.deuro.tag,
|
||||
isAmountEditable: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
Widget footerWidget(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 34),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () => dEuroViewModel.prepareSavingsEdit(_amountController.text, true),
|
||||
text: S.of(context).confirm,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
isLoading: false,
|
||||
isDisabled: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/integrations/deuro/widgets/savings_card_widget.dart';
|
||||
import 'package:cake_wallet/themes/utils/custom_theme_colors.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class InterestCardWidget extends StatelessWidget {
|
||||
InterestCardWidget({
|
||||
required this.title,
|
||||
required this.collectedInterest,
|
||||
super.key,
|
||||
required this.isDarkTheme,
|
||||
required this.onCollectInterest,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String collectedInterest;
|
||||
final bool isDarkTheme;
|
||||
final VoidCallback onCollectInterest;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(children: [
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 16),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
isDarkTheme
|
||||
? CustomThemeColors.cardGradientColorPrimaryDark
|
||||
: CustomThemeColors.cardGradientColorPrimaryLight,
|
||||
isDarkTheme
|
||||
? CustomThemeColors.cardGradientColorSecondaryDark
|
||||
: CustomThemeColors.cardGradientColorSecondaryLight,
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
SavingsCard.getAssetBalanceRow(
|
||||
context,
|
||||
title: title,
|
||||
subtitle: collectedInterest,
|
||||
currency: CryptoCurrency.deuro,
|
||||
hideSymbol: true,
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SavingsCard.getButton(
|
||||
context,
|
||||
label: S.of(context).deuro_collect_interest,
|
||||
onPressed: onCollectInterest,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class NumberPad extends StatelessWidget {
|
||||
final VoidCallback? onDecimalPressed;
|
||||
final VoidCallback onDeletePressed;
|
||||
final void Function(int index) onNumberPressed;
|
||||
final FocusNode focusNode;
|
||||
|
||||
const NumberPad({
|
||||
super.key,
|
||||
required this.onNumberPressed,
|
||||
required this.onDeletePressed,
|
||||
required this.focusNode,
|
||||
this.onDecimalPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => KeyboardListener(
|
||||
focusNode: focusNode,
|
||||
onKeyEvent: (keyEvent) {
|
||||
if (keyEvent is KeyDownEvent) {
|
||||
if (keyEvent.logicalKey.keyLabel == "Backspace") {
|
||||
return onDeletePressed();
|
||||
}
|
||||
|
||||
if ([".", ","].contains(keyEvent.logicalKey.keyLabel) &&
|
||||
onDecimalPressed != null) {
|
||||
return onDecimalPressed!();
|
||||
}
|
||||
|
||||
int? number = int.tryParse(keyEvent.character ?? '');
|
||||
if (number != null) return onNumberPressed(number);
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 300,
|
||||
child: GridView.count(
|
||||
childAspectRatio: 2,
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: List.generate(12, (index) {
|
||||
if (index == 9) {
|
||||
if (onDecimalPressed == null) return Container();
|
||||
return InkWell(
|
||||
onTap: onDecimalPressed,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'.',
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 30,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (index == 10) {
|
||||
index = 0;
|
||||
} else if (index == 11) {
|
||||
return MergeSemantics(
|
||||
child: Container(
|
||||
child: Semantics(
|
||||
label: S.of(context).delete,
|
||||
button: true,
|
||||
onTap: onDeletePressed,
|
||||
child: TextButton(
|
||||
onPressed: onDeletePressed,
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor:
|
||||
Colors.transparent,
|
||||
shape: CircleBorder(),
|
||||
),
|
||||
child: Image.asset(
|
||||
'assets/images/delete_icon.png',
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
|
||||
return InkWell(
|
||||
onTap: () => onNumberPressed(index),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'$index',
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 30,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/themes/utils/custom_theme_colors.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SavingsCard extends StatelessWidget {
|
||||
final bool isDarkTheme;
|
||||
final bool isEnabled;
|
||||
final String interestRate;
|
||||
final String savingsBalance;
|
||||
final CryptoCurrency currency;
|
||||
final VoidCallback onAddSavingsPressed;
|
||||
final VoidCallback onRemoveSavingsPressed;
|
||||
final VoidCallback onApproveSavingsPressed;
|
||||
|
||||
const SavingsCard({
|
||||
super.key,
|
||||
required this.isDarkTheme,
|
||||
required this.interestRate,
|
||||
required this.savingsBalance,
|
||||
required this.currency,
|
||||
required this.onAddSavingsPressed,
|
||||
required this.onRemoveSavingsPressed,
|
||||
required this.onApproveSavingsPressed,
|
||||
this.isEnabled = true,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
margin: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
isDarkTheme
|
||||
? CustomThemeColors.cardGradientColorPrimaryDark
|
||||
: CustomThemeColors.cardGradientColorPrimaryLight,
|
||||
isDarkTheme
|
||||
? CustomThemeColors.cardGradientColorSecondaryDark
|
||||
: CustomThemeColors.cardGradientColorSecondaryLight,
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
getAssetBalanceRow(context,
|
||||
title: S.of(context).deuro_savings_balance,
|
||||
subtitle: savingsBalance,
|
||||
currency: currency),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Current APR',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
softWrap: true,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
interestRate,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
softWrap: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: isEnabled
|
||||
? [
|
||||
Expanded(
|
||||
child: getButton(
|
||||
context,
|
||||
label: S.of(context).deuro_savings_add,
|
||||
imagePath: 'assets/images/received.png',
|
||||
onPressed: onAddSavingsPressed,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: getButton(
|
||||
context,
|
||||
label: S.of(context).deuro_savings_remove,
|
||||
imagePath: 'assets/images/upload.png',
|
||||
onPressed: onRemoveSavingsPressed,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.surface,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
]
|
||||
: [
|
||||
Expanded(
|
||||
child: getButton(
|
||||
context,
|
||||
label: S.of(context).deuro_savings_set_approval,
|
||||
onPressed: onApproveSavingsPressed,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
static Widget getButton(
|
||||
BuildContext context, {
|
||||
required String label,
|
||||
String? imagePath,
|
||||
required VoidCallback onPressed,
|
||||
required Color backgroundColor,
|
||||
required Color color,
|
||||
}) =>
|
||||
Semantics(
|
||||
label: label,
|
||||
child: OutlinedButton(
|
||||
onPressed: onPressed,
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: backgroundColor,
|
||||
side: BorderSide(
|
||||
color: Theme.of(context).colorScheme.outlineVariant.withAlpha(0),
|
||||
width: 0,
|
||||
),
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (imagePath != null) ...[
|
||||
Image.asset(
|
||||
imagePath,
|
||||
height: 30,
|
||||
width: 30,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Text(
|
||||
label,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
static Widget getAssetBalanceRow(
|
||||
BuildContext context, {
|
||||
required String title,
|
||||
required String subtitle,
|
||||
required CryptoCurrency currency,
|
||||
bool hideSymbol = true,
|
||||
}) =>
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 6),
|
||||
AutoSizeText(
|
||||
subtitle,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 24,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
//width: min(MediaQuery.of(context).size.width * 0.2, 100),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
CakeImageWidget(
|
||||
imageUrl: currency.iconPath,
|
||||
height: 40,
|
||||
width: 40,
|
||||
errorWidget: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
currency.title
|
||||
.substring(0, min(currency.title.length, 2)),
|
||||
style:
|
||||
Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontSize: 11,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!hideSymbol) ...[
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
currency.title,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/integrations/deuro/widgets/numpad.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SavingEditPage extends BasePage {
|
||||
final bool isAdding;
|
||||
|
||||
SavingEditPage({required this.isAdding});
|
||||
|
||||
String get title =>
|
||||
isAdding ? S.current.deuro_savings_add : S.current.deuro_savings_remove;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => _SavingsEditBody();
|
||||
}
|
||||
|
||||
class _SavingsEditBody extends StatefulWidget {
|
||||
const _SavingsEditBody();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _SavingsEditBodyState();
|
||||
}
|
||||
|
||||
class _SavingsEditBodyState extends State<_SavingsEditBody> {
|
||||
@override
|
||||
void initState() {
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _numpadFocusNode.requestFocus());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_numpadFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
String amount = '0';
|
||||
final FocusNode _numpadFocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SafeArea(
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 26, right: 26, top: 10),
|
||||
child: AutoSizeText(
|
||||
"${amount.toString()} dEuro",
|
||||
maxLines: 1,
|
||||
maxFontSize: 60,
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 60,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
)),
|
||||
NumberPad(
|
||||
focusNode: _numpadFocusNode,
|
||||
onNumberPressed: (i) => setState(
|
||||
() => amount = amount == '0' ? i.toString() : '${amount}${i}',
|
||||
),
|
||||
onDeletePressed: () => setState(
|
||||
() => amount = amount.length > 1
|
||||
? amount.substring(0, amount.length - 1)
|
||||
: '0',
|
||||
),
|
||||
onDecimalPressed: () =>
|
||||
setState(() => amount = '${amount.replaceAll('.', '')}.'),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 34),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () => Navigator.pop(context, amount),
|
||||
text: S.of(context).confirm,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
isLoading: false,
|
||||
isDisabled: false,
|
||||
),
|
||||
)
|
||||
]),
|
||||
);
|
||||
}
|
||||
@@ -109,6 +109,7 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(left: 10)),
|
||||
if (image != null) image! else if (svgPicture != null) svgPicture!,
|
||||
if (icon != null) icon!
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user