mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Address-formatting-enhancements-MWEB (#2189)
* apply formatting to address book and MWEB * fix wallet type exception * Update cw_core/lib/wallet_type.dart [skip ci] * Update lib/src/screens/contact/contact_list_page.dart [skip ci] * Update lib/src/screens/contact/contact_list_page.dart [skip ci] * Update lib/utils/address_formatter.dart [skip ci] * Update lib/utils/address_formatter.dart [skip ci] * Update lib/utils/address_formatter.dart --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
2f28ea3fb7
commit
a7376c3225
5 changed files with 173 additions and 84 deletions
|
@ -247,3 +247,38 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
|
|||
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
|
||||
}
|
||||
}
|
||||
|
||||
WalletType? cryptoCurrencyToWalletType(CryptoCurrency type) {
|
||||
switch (type) {
|
||||
case CryptoCurrency.xmr:
|
||||
return WalletType.monero;
|
||||
case CryptoCurrency.btc:
|
||||
return WalletType.bitcoin;
|
||||
case CryptoCurrency.ltc:
|
||||
return WalletType.litecoin;
|
||||
case CryptoCurrency.xhv:
|
||||
return WalletType.haven;
|
||||
case CryptoCurrency.eth:
|
||||
return WalletType.ethereum;
|
||||
case CryptoCurrency.bch:
|
||||
return WalletType.bitcoinCash;
|
||||
case CryptoCurrency.nano:
|
||||
return WalletType.nano;
|
||||
case CryptoCurrency.banano:
|
||||
return WalletType.banano;
|
||||
case CryptoCurrency.maticpoly:
|
||||
return WalletType.polygon;
|
||||
case CryptoCurrency.sol:
|
||||
return WalletType.solana;
|
||||
case CryptoCurrency.trx:
|
||||
return WalletType.tron;
|
||||
case CryptoCurrency.wow:
|
||||
return WalletType.wownero;
|
||||
case CryptoCurrency.zano:
|
||||
return WalletType.zano;
|
||||
case CryptoCurrency.dcr:
|
||||
return WalletType.decred;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,11 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
|||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/address_formatter.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -235,7 +237,7 @@ class _ContactPageBodyState extends State<ContactPageBody> with SingleTickerProv
|
|||
return;
|
||||
}
|
||||
|
||||
final isCopied = await showNameAndAddressDialog(context, contact.name, contact.address);
|
||||
final isCopied = await DialogService.showNameAndAddressDialog(context, contact);
|
||||
|
||||
if (isCopied) {
|
||||
await Clipboard.setData(ClipboardData(text: contact.address));
|
||||
|
@ -280,21 +282,6 @@ class _ContactPageBodyState extends State<ContactPageBody> with SingleTickerProv
|
|||
? Image.asset(image, height: 24, width: 24)
|
||||
: const SizedBox(height: 24, width: 24);
|
||||
}
|
||||
|
||||
Future<bool> showNameAndAddressDialog(BuildContext context, String name, String address) async {
|
||||
return await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: name,
|
||||
alertContent: address,
|
||||
rightButtonText: S.of(context).copy,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.of(context).pop(true),
|
||||
actionLeftButton: () => Navigator.of(context).pop(false));
|
||||
}) ??
|
||||
false;
|
||||
}
|
||||
}
|
||||
|
||||
class ContactListBody extends StatefulWidget {
|
||||
|
@ -357,7 +344,7 @@ class _ContactListBodyState extends State<ContactListBody> {
|
|||
}
|
||||
|
||||
final isCopied =
|
||||
await showNameAndAddressDialog(context, contact.name, contact.address);
|
||||
await DialogService.showNameAndAddressDialog(context, contact);
|
||||
|
||||
if (isCopied) {
|
||||
await Clipboard.setData(ClipboardData(text: contact.address));
|
||||
|
@ -434,7 +421,7 @@ class _ContactListBodyState extends State<ContactListBody> {
|
|||
),
|
||||
SlidableAction(
|
||||
onPressed: (_) async {
|
||||
final isDelete = await showAlertDialog(context);
|
||||
final isDelete = await DialogService.showAlertDialog(context);
|
||||
|
||||
if (isDelete) {
|
||||
await widget.contactListViewModel.delete(contact);
|
||||
|
@ -494,33 +481,49 @@ class _ContactListBodyState extends State<ContactListBody> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<bool> showAlertDialog(BuildContext context) async {
|
||||
}
|
||||
|
||||
class DialogService {
|
||||
static Future<bool> showAlertDialog(BuildContext context) async {
|
||||
return await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).address_remove_contact,
|
||||
alertContent: S.of(context).address_remove_content,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.of(context).pop(true),
|
||||
actionLeftButton: () => Navigator.of(context).pop(false));
|
||||
}) ??
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).address_remove_contact,
|
||||
alertContent: S.of(context).address_remove_content,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.of(context).pop(true),
|
||||
actionLeftButton: () => Navigator.of(context).pop(false));
|
||||
}) ??
|
||||
false;
|
||||
}
|
||||
|
||||
Future<bool> showNameAndAddressDialog(BuildContext context, String name, String address) async {
|
||||
static Future<bool> showNameAndAddressDialog(BuildContext context,ContactBase contact) async {
|
||||
return await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: name,
|
||||
alertContent: address,
|
||||
rightButtonText: S.of(context).copy,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.of(context).pop(true),
|
||||
actionLeftButton: () => Navigator.of(context).pop(false));
|
||||
}) ??
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: contact.name,
|
||||
alertContent: contact.address,
|
||||
alertContentTextWidget: AddressFormatter.buildSegmentedAddress(
|
||||
address: contact.address,
|
||||
textAlign: TextAlign.center,
|
||||
walletType: cryptoCurrencyToWalletType(contact.type),
|
||||
evenTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
rightButtonText: S.of(context).copy,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.of(context).pop(true),
|
||||
actionLeftButton: () => Navigator.of(context).pop(false));
|
||||
}) ??
|
||||
false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
|||
AlertWithTwoActions({
|
||||
required this.alertTitle,
|
||||
required this.alertContent,
|
||||
this.alertContentTextWidget,
|
||||
required this.leftButtonText,
|
||||
required this.rightButtonText,
|
||||
required this.actionLeftButton,
|
||||
|
@ -21,6 +22,7 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
|||
|
||||
final String alertTitle;
|
||||
final String alertContent;
|
||||
final Widget? alertContentTextWidget;
|
||||
final String leftButtonText;
|
||||
final String rightButtonText;
|
||||
final VoidCallback actionLeftButton;
|
||||
|
@ -38,6 +40,8 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
|||
@override
|
||||
String get contentText => alertContent;
|
||||
@override
|
||||
Widget? get contentTextWidget => alertContentTextWidget;
|
||||
@override
|
||||
String get leftActionButtonText => leftButtonText;
|
||||
@override
|
||||
String get rightActionButtonText => rightButtonText;
|
||||
|
|
|
@ -13,6 +13,8 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
|
||||
String get contentText => '';
|
||||
|
||||
Widget? get contentTextWidget => null;
|
||||
|
||||
String get leftActionButtonText => '';
|
||||
|
||||
String get rightActionButtonText => '';
|
||||
|
@ -79,7 +81,8 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
contentTextWidget ??
|
||||
Text(
|
||||
contentText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
|
|
|
@ -5,24 +5,31 @@ import 'dart:math' as math;
|
|||
class AddressFormatter {
|
||||
static Widget buildSegmentedAddress({
|
||||
required String address,
|
||||
required WalletType walletType,
|
||||
WalletType? walletType,
|
||||
required TextStyle evenTextStyle,
|
||||
TextStyle? oddTextStyle,
|
||||
TextAlign? textAlign,
|
||||
bool shouldTruncate = false,
|
||||
}) {
|
||||
|
||||
final cleanAddress = address.replaceAll('bitcoincash:', '');
|
||||
final isMWEB = address.startsWith('ltcmweb');
|
||||
final chunkSize = walletType != null ? _getChunkSize(walletType) : 4;
|
||||
|
||||
if (shouldTruncate) {
|
||||
return _buildTruncatedAddress(
|
||||
address: address,
|
||||
walletType: walletType,
|
||||
address: cleanAddress,
|
||||
isMWEB: isMWEB,
|
||||
chunkSize: chunkSize,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle ?? evenTextStyle.copyWith(color: evenTextStyle.color!.withAlpha(150)),
|
||||
textAlign: textAlign,
|
||||
);
|
||||
} else {
|
||||
return _buildFullSegmentedAddress(
|
||||
address: address,
|
||||
walletType: walletType,
|
||||
address: cleanAddress,
|
||||
isMWEB: isMWEB,
|
||||
chunkSize: chunkSize,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle ?? evenTextStyle.copyWith(color: evenTextStyle.color!.withAlpha(128)),
|
||||
textAlign: textAlign,
|
||||
|
@ -32,19 +39,34 @@ class AddressFormatter {
|
|||
|
||||
static Widget _buildFullSegmentedAddress({
|
||||
required String address,
|
||||
required WalletType walletType,
|
||||
required bool isMWEB,
|
||||
required int chunkSize,
|
||||
required TextStyle evenTextStyle,
|
||||
required TextStyle oddTextStyle,
|
||||
TextAlign? textAlign,
|
||||
}) {
|
||||
|
||||
final cleanAddress = address.replaceAll('bitcoincash:', '');
|
||||
final chunkSize = _getChunkSize(walletType);
|
||||
final chunks = <String>[];
|
||||
|
||||
for (int i = 0; i < cleanAddress.length; i += chunkSize) {
|
||||
final chunk = cleanAddress.substring(i, math.min(i + chunkSize, cleanAddress.length));
|
||||
chunks.add(chunk);
|
||||
if (isMWEB) {
|
||||
const mwebDisplayPrefix = 'ltcmweb';
|
||||
chunks.add(mwebDisplayPrefix);
|
||||
final startIndex = mwebDisplayPrefix.length;
|
||||
for (int i = startIndex; i < address.length; i += chunkSize) {
|
||||
final chunk = address.substring(
|
||||
i,
|
||||
math.min(i + chunkSize, address.length),
|
||||
);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < address.length; i += chunkSize) {
|
||||
final chunk = address.substring(
|
||||
i,
|
||||
math.min(i + chunkSize, address.length),
|
||||
);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
final spans = <TextSpan>[];
|
||||
|
@ -62,46 +84,68 @@ class AddressFormatter {
|
|||
|
||||
static Widget _buildTruncatedAddress({
|
||||
required String address,
|
||||
required WalletType walletType,
|
||||
required bool isMWEB,
|
||||
required int chunkSize,
|
||||
required TextStyle evenTextStyle,
|
||||
required TextStyle oddTextStyle,
|
||||
TextAlign? textAlign,
|
||||
}) {
|
||||
|
||||
final cleanAddress = address.replaceAll('bitcoincash:', '');
|
||||
if (isMWEB) {
|
||||
const fixedPrefix = 'ltcmweb';
|
||||
final secondChunkStart = fixedPrefix.length;
|
||||
const chunkSize = 4;
|
||||
final secondChunk = address.substring(
|
||||
secondChunkStart,
|
||||
math.min(secondChunkStart + chunkSize, address.length),
|
||||
);
|
||||
final lastChunk = address.substring(address.length - chunkSize);
|
||||
|
||||
final int digitCount = (walletType == WalletType.monero ||
|
||||
walletType == WalletType.wownero ||
|
||||
walletType == WalletType.zano)
|
||||
? 6
|
||||
: 4;
|
||||
final spans = <TextSpan>[
|
||||
TextSpan(text: '$fixedPrefix ', style: evenTextStyle),
|
||||
TextSpan(text: '$secondChunk ', style: oddTextStyle),
|
||||
TextSpan(text: '... ', style: oddTextStyle),
|
||||
TextSpan(text: lastChunk, style: evenTextStyle),
|
||||
];
|
||||
|
||||
if (cleanAddress.length <= 2 * digitCount) {
|
||||
return _buildFullSegmentedAddress(
|
||||
address: cleanAddress,
|
||||
walletType: walletType,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle,
|
||||
textAlign: textAlign,
|
||||
return RichText(
|
||||
text: TextSpan(children: spans),
|
||||
textAlign: textAlign ?? TextAlign.start,
|
||||
overflow: TextOverflow.visible,
|
||||
);
|
||||
} else {
|
||||
final int digitCount = chunkSize;
|
||||
|
||||
if (address.length <= 2 * digitCount) {
|
||||
return _buildFullSegmentedAddress(
|
||||
address: address,
|
||||
isMWEB: isMWEB,
|
||||
chunkSize: chunkSize,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle,
|
||||
textAlign: textAlign,
|
||||
);
|
||||
}
|
||||
|
||||
final String firstPart = address.substring(0, digitCount);
|
||||
final String secondPart =
|
||||
address.substring(digitCount, digitCount * 2);
|
||||
final String lastPart =
|
||||
address.substring(address.length - digitCount);
|
||||
|
||||
final spans = <TextSpan>[
|
||||
TextSpan(text: '$firstPart ', style: evenTextStyle),
|
||||
TextSpan(text: '$secondPart ', style: oddTextStyle),
|
||||
TextSpan(text: '... ', style: oddTextStyle),
|
||||
TextSpan(text: lastPart, style: evenTextStyle),
|
||||
];
|
||||
|
||||
return RichText(
|
||||
text: TextSpan(children: spans),
|
||||
textAlign: textAlign ?? TextAlign.start,
|
||||
overflow: TextOverflow.visible,
|
||||
);
|
||||
}
|
||||
|
||||
final String firstPart = cleanAddress.substring(0, digitCount);
|
||||
final String secondPart = cleanAddress.substring(digitCount, digitCount * 2);
|
||||
final String lastPart = cleanAddress.substring(cleanAddress.length - digitCount);
|
||||
|
||||
final spans = <TextSpan>[
|
||||
TextSpan(text: '$firstPart ', style: evenTextStyle),
|
||||
TextSpan(text: '$secondPart ', style: oddTextStyle),
|
||||
TextSpan(text: '... ', style: oddTextStyle),
|
||||
TextSpan(text: lastPart, style: evenTextStyle),
|
||||
];
|
||||
|
||||
return RichText(
|
||||
text: TextSpan(children: spans),
|
||||
textAlign: textAlign ?? TextAlign.start,
|
||||
overflow: TextOverflow.visible,
|
||||
);
|
||||
}
|
||||
|
||||
static int _getChunkSize(WalletType walletType) {
|
||||
|
@ -114,4 +158,4 @@ class AddressFormatter {
|
|||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue