Skip to content
This repository has been archived by the owner on Sep 17, 2024. It is now read-only.

Insufficient balance guidance #110

Merged
merged 11 commits into from
Oct 31, 2023
3 changes: 2 additions & 1 deletion assets/flutter_i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,5 +304,6 @@
"unable_to_launch_email_app": "Unable to launch email app",
"deposit_from_exchanges_notice": "Buy from {0}, {1} exchanges and deposit zkEVM MXC directly to AXS wallet",
"deposit_with_l3_bridge_notice": "Buy from other exchanges and use {0} to deposit ERC20 MXC to AXS wallet",
"buy_some_x_for_fee_notice": "Buy some {0} to pay for gas fee for the transaction, normally less than 2 USD when the network is not busy"
"buy_some_x_for_fee_notice": "Buy some {0} to pay for gas fee for the transaction, normally less than 2 USD when the network is not busy",
"insufficient_funds_notice": "Insufficient balance for this transaction.\n Please add funds."
}
11 changes: 11 additions & 0 deletions lib/common/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,15 @@ class Config {
static String addressExplorer(String address) {
return 'address/$address';
}

/// If error happens with these messages then we will need to show receive bottom sheet
static List<String> fundErrors = [
// User doesn't have enough to pay for native token transfer
// Zero native token balance or not enough for fee
'gas required exceeds allowance',
// Sending more than tokens balance
'execution reverted: ERC20: transfer amount exceeds balance',
// Sending more than native token balance
'insufficient funds for gas * price + value'
];
}
2 changes: 1 addition & 1 deletion lib/common/dialogs/dialogs.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export 'alert_dialog.dart';
export 'bottom_sheet.dart';
export 'warning_dialog.dart';
export 'wallet_address_dialog.dart';
export 'receive_bottom_sheet/receive_bottom_sheet.dart';
21 changes: 21 additions & 0 deletions lib/common/dialogs/receive_bottom_sheet/components/black_box.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:mxc_ui/mxc_ui.dart';

class BlackBox extends StatelessWidget {
const BlackBox({super.key, required this.child});

final Widget child;

@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(top: 16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: ColorsTheme.of(context).grey6,
borderRadius: const BorderRadius.all(Radius.circular(35)),
),
child: child,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:datadashwallet/common/common.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:mxc_ui/mxc_ui.dart';

List<TextSpan> depositFromExchangesNotice(
BuildContext context, void Function(String) launchUrl) {
final text = FlutterI18n.translate(context, 'deposit_from_exchanges_notice');
final firstSplit = text.split('{0}');
final firstPart = firstSplit[0];
final secondSplit = firstSplit[1].split('{1}');
final secondPart = secondSplit[0];
final thirdPart = secondSplit[1];
return [
TextSpan(
text: firstPart,
),
TextSpan(
text: 'OKX',
style: TextStyle(
color: ColorsTheme.of(context, listen: false).textSecondary,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
launchUrl(Urls.okx);
},
),
TextSpan(text: secondPart),
TextSpan(
text: 'Gate.io',
style: TextStyle(
color: ColorsTheme.of(context, listen: false).textSecondary,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
launchUrl(Urls.gateio);
},
),
TextSpan(text: thirdPart),
];
}

List<TextSpan> depositWithL3BridgeNotice(
BuildContext context,
VoidCallback onL3Tap,
) {
final text = FlutterI18n.translate(context, 'deposit_with_l3_bridge_notice');
final firstSplit = text.split('{0}');
final firstPart = firstSplit[0];
final secondPart = firstSplit[1];
return [
TextSpan(
text: firstPart,
),
TextSpan(
text: 'L3 bridge',
style: TextStyle(
color: ColorsTheme.of(context, listen: false).textSecondary,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()..onTap = onL3Tap,
),
TextSpan(text: secondPart),
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';

List<TextSpan> buySomeXForFeeNotice(
BuildContext context, String networkSymbol) {
String text = FlutterI18n.translate(context, 'buy_some_x_for_fee_notice');
text = text.replaceFirst('{0}', networkSymbol);
return [
TextSpan(
text: text,
),
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import 'dart:ui';

import 'package:clipboard/clipboard.dart';
import 'package:datadashwallet/common/common.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:mxc_ui/mxc_ui.dart';
import 'package:qr_flutter/qr_flutter.dart';

class ReceiveBottomSheet extends StatelessWidget {
const ReceiveBottomSheet(
{Key? key,
this.walletAddress,
required this.noticeComponents,
required this.showError})
: super(key: key);

final String? walletAddress;
final List<Widget> noticeComponents;
final bool showError;

@override
Widget build(BuildContext context) {
final formattedWalletAddress =
Formatter.formatWalletAddress(walletAddress ?? '');
bool isWalletAddressCopied = false;

return BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 20,
sigmaY: 20,
),
child: Container(
padding: const EdgeInsets.only(right: 24, left: 24, bottom: 44),
decoration: BoxDecoration(
color: ColorsTheme.of(context).cardBackground,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
MxcAppBarEvenly.title(
titleText: FlutterI18n.translate(context, 'receive'),
action: Container(
alignment: Alignment.centerRight,
child: InkWell(
child: const Icon(Icons.close),
onTap: () => Navigator.of(context).pop(false),
),
),
),
if (showError)
Text(
FlutterI18n.translate(context, 'insufficient_funds_notice'),
style: FontTheme.of(context).body1.error(),
textAlign: TextAlign.center,
),
QrImageView(
data: walletAddress ?? '',
size: 215,
dataModuleStyle: QrDataModuleStyle(
color: ColorsTheme.of(context).textPrimary,
dataModuleShape: QrDataModuleShape.square),
eyeStyle: QrEyeStyle(
color: ColorsTheme.of(context).textPrimary,
eyeShape: QrEyeShape.square),
),
const SizedBox(height: 16),
Text(
FlutterI18n.translate(context,
'scan_or_copy_address_below_to_receive_tokens_or_nfts'),
style: FontTheme.of(context).body1.secondary(),
textAlign: TextAlign.center,
),
BlackBox(
child: StatefulBuilder(builder: (_, setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
formattedWalletAddress,
style: FontTheme.of(context).subtitle1.primary(),
),
MxcChipButton(
key: const Key('copyButton'),
onTap: () async {
await FlutterClipboard.copy(walletAddress ?? '');
setState(() => isWalletAddressCopied = true);
},
title: isWalletAddressCopied
? FlutterI18n.translate(context, 'copied')
: FlutterI18n.translate(context, 'copy_address'),
iconData: Icons.check_circle_rounded,
iconSize: 16,
alignIconStart: true,
iconColor: isWalletAddressCopied
? ColorsTheme.of(context).iconBlack200
: ColorsTheme.of(context).iconPrimary,
textStyle: isWalletAddressCopied
? FontTheme.of(context).subtitle1().copyWith(
color: ColorsTheme.of(context).textBlack200)
: FontTheme.of(context).subtitle1.primary(),
backgroundColor: isWalletAddressCopied
? ColorsTheme.of(context).systemStatusActive
: null,
)
]);
}),
),
...noticeComponents
],
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export 'black_box.dart';
export 'receive_bottom_sheet.dart';
export 'mxc_notices.dart';
export 'others_notice.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'receive_bottom_sheet_utils.dart';
export 'components/receive_bottom_sheet_components.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import 'package:datadashwallet/common/common.dart';
import 'package:datadashwallet/core/core.dart';
import 'package:datadashwallet/features/dapps/dapps.dart';
import 'package:flutter/material.dart';
import 'package:mxc_ui/mxc_ui.dart';

void showReceiveBottomSheet(
BuildContext context,
String walletAddress,
int chainId,
String networkSymbol,
VoidCallback onL3Tap,
void Function(String url) launchUrlInPlatformDefault,
bool showError) {
if (Config.isMxcChains(chainId)) {
showWalletAddressDialogMXCChains(
context: context,
walletAddress: walletAddress,
onL3Tap: () => onL3Tap(),
launchUrlInPlatformDefault: launchUrlInPlatformDefault,
showError: showError);
} else {
showWalletAddressDialogOtherChains(
context: context,
walletAddress: walletAddress,
networkSymbol: networkSymbol,
showError: showError);
}
}

void showWalletAddressDialogMXCChains(
{required BuildContext context,
required String walletAddress,
required VoidCallback onL3Tap,
required Function(String) launchUrlInPlatformDefault,
required bool showError}) =>
showWalletAddressDialog(
context: context,
walletAddress: walletAddress,
noticeComponents: [
BlackBox(
child: applyTextStyle(
context,
depositFromExchangesNotice(
context, launchUrlInPlatformDefault))),
BlackBox(
child: applyTextStyle(
context, depositWithL3BridgeNotice(context, onL3Tap))),
],
showError: showError);

void showWalletAddressDialogOtherChains(
{required BuildContext context,
required String walletAddress,
required String networkSymbol,
required bool showError}) =>
showWalletAddressDialog(
context: context,
walletAddress: walletAddress,
noticeComponents: [
BlackBox(
child: applyTextStyle(
context, buySomeXForFeeNotice(context, networkSymbol)))
],
showError: showError);

void showWalletAddressDialogSimple(
{required BuildContext context,
required String walletAddress,
required bool showError}) =>
showWalletAddressDialog(
context: context,
walletAddress: walletAddress,
noticeComponents: [],
showError: showError);

void showWalletAddressDialog(
{required BuildContext context,
required String walletAddress,
required List<Widget> noticeComponents,
required bool showError}) {
showModalBottomSheet<bool>(
context: context,
useRootNavigator: true,
isScrollControlled: true,
useSafeArea: true,
backgroundColor: Colors.transparent,
builder: (BuildContext context) => ReceiveBottomSheet(
walletAddress: walletAddress,
noticeComponents: noticeComponents,
showError: showError,
),
);
}

Widget applyTextStyle(BuildContext context, List<TextSpan> children) {
return RichText(
text: TextSpan(
style: FontTheme.of(context, listen: false).body1.primary(),
children: [...children],
),
);
}
Loading