mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
CW-1021-Address-formatting-enhancements (#2141)
* Implement visual formatting for addresses * fix minor issues * Update transaction_details_page.dart * Update transaction_details_page.dart * fix multi recipient address formatting * Update address_cell.dart
This commit is contained in:
parent
c1e9668b1e
commit
3f25d69244
13 changed files with 292 additions and 123 deletions
|
@ -381,6 +381,7 @@ class CakePayBuyCardDetailPage extends BasePage {
|
|||
return ConfirmSendingBottomSheet(
|
||||
key: ValueKey('send_page_confirm_sending_dialog_key'),
|
||||
currentTheme: currentTheme,
|
||||
walletType: cakePayPurchaseViewModel.sendViewModel.walletType,
|
||||
paymentId: S.of(popupContext).payment_id,
|
||||
paymentIdValue: order?.orderId,
|
||||
expirationTime: cakePayPurchaseViewModel.formattedRemainingTime,
|
||||
|
|
|
@ -264,6 +264,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
return ConfirmSendingBottomSheet(
|
||||
key: ValueKey('exchange_trade_page_confirm_sending_bottom_sheet_key'),
|
||||
currentTheme: widget.currentTheme,
|
||||
walletType: widget.exchangeTradeViewModel.sendViewModel.walletType,
|
||||
titleText: S.of(bottomSheetContext).confirm_transaction,
|
||||
titleIconPath:
|
||||
widget.exchangeTradeViewModel.sendViewModel.selectedCryptoCurrency.iconPath,
|
||||
|
|
|
@ -20,6 +20,7 @@ class AddressListPage extends BasePage {
|
|||
children: <Widget>[
|
||||
AddressList(
|
||||
addressListViewModel: addressListViewModel,
|
||||
currentTheme: currentTheme,
|
||||
onSelect: (String address) async {
|
||||
Navigator.of(context).pop(address);
|
||||
},
|
||||
|
|
|
@ -124,7 +124,7 @@ class ReceivePage extends BasePage {
|
|||
isLight: currentTheme.type == ThemeType.light,
|
||||
),
|
||||
),
|
||||
AddressList(addressListViewModel: addressListViewModel),
|
||||
AddressList(addressListViewModel: addressListViewModel, currentTheme: currentTheme),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Text(
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/themes/extensions/qr_code_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/address_formatter.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
|
@ -14,6 +18,8 @@ class AddressCell extends StatelessWidget {
|
|||
required this.isPrimary,
|
||||
required this.backgroundColor,
|
||||
required this.textColor,
|
||||
required this.walletType,
|
||||
required this.currentTheme,
|
||||
this.onTap,
|
||||
this.onEdit,
|
||||
this.onHide,
|
||||
|
@ -30,6 +36,8 @@ class AddressCell extends StatelessWidget {
|
|||
required bool isCurrent,
|
||||
required Color backgroundColor,
|
||||
required Color textColor,
|
||||
required WalletType walletType,
|
||||
required ThemeBase currentTheme,
|
||||
Function(String)? onTap,
|
||||
bool hasBalance = false,
|
||||
bool hasReceived = false,
|
||||
|
@ -45,6 +53,8 @@ class AddressCell extends StatelessWidget {
|
|||
isPrimary: item.isPrimary,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
walletType: walletType,
|
||||
currentTheme: currentTheme,
|
||||
onTap: onTap,
|
||||
onEdit: onEdit,
|
||||
onHide: onHide,
|
||||
|
@ -62,6 +72,8 @@ class AddressCell extends StatelessWidget {
|
|||
final bool isPrimary;
|
||||
final Color backgroundColor;
|
||||
final Color textColor;
|
||||
final WalletType walletType;
|
||||
final ThemeBase currentTheme;
|
||||
final Function(String)? onTap;
|
||||
final Function()? onEdit;
|
||||
final Function()? onHide;
|
||||
|
@ -73,21 +85,6 @@ class AddressCell extends StatelessWidget {
|
|||
final bool hasBalance;
|
||||
final bool hasReceived;
|
||||
|
||||
static const int addressPreviewLength = 8;
|
||||
|
||||
String get formattedAddress {
|
||||
final formatIfCashAddr = address.replaceAll('bitcoincash:', '');
|
||||
|
||||
if (formatIfCashAddr.length <= (name.isNotEmpty ? 16 : 43)) {
|
||||
return formatIfCashAddr;
|
||||
} else {
|
||||
return formatIfCashAddr.substring(0, addressPreviewLength) +
|
||||
'...' +
|
||||
formatIfCashAddr.substring(
|
||||
formatIfCashAddr.length - addressPreviewLength, formatIfCashAddr.length);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Widget cell = InkWell(
|
||||
|
@ -139,16 +136,14 @@ class AddressCell extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
Flexible(
|
||||
child: AutoSizeText(
|
||||
responsiveLayoutUtil.shouldRenderTabletUI ? address : formattedAddress,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
child: AddressFormatter.buildSegmentedAddress(
|
||||
address: address,
|
||||
walletType: walletType,
|
||||
shouldTruncate: name.isNotEmpty || address.length > 43 ,
|
||||
evenTextStyle: TextStyle(
|
||||
fontSize: isChange ? 10 : 14,
|
||||
color: textColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
color: textColor
|
||||
))),
|
||||
],
|
||||
),
|
||||
if (hasBalance || hasReceived)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -9,6 +7,7 @@ import 'package:cake_wallet/src/screens/receive/widgets/address_cell.dart';
|
|||
import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart';
|
||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/list_item.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_account_list_header.dart';
|
||||
|
@ -20,16 +19,17 @@ import 'package:cw_core/wallet_type.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class AddressList extends StatefulWidget {
|
||||
const AddressList({
|
||||
super.key,
|
||||
required this.addressListViewModel,
|
||||
required this.currentTheme,
|
||||
this.onSelect,
|
||||
});
|
||||
|
||||
final WalletAddressListViewModel addressListViewModel;
|
||||
final ThemeBase currentTheme;
|
||||
final Function(String)? onSelect;
|
||||
|
||||
@override
|
||||
|
@ -161,6 +161,8 @@ class _AddressListState extends State<AddressList> {
|
|||
return AddressCell.fromItem(
|
||||
item,
|
||||
isCurrent: isCurrent,
|
||||
currentTheme: widget.currentTheme,
|
||||
walletType: widget.addressListViewModel.type,
|
||||
hasBalance: widget.addressListViewModel.isBalanceAvailable,
|
||||
hasReceived: widget.addressListViewModel.isReceivedAvailable,
|
||||
// hasReceived:
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/routes.dart';
|
|||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/address_formatter.dart';
|
||||
import 'package:cake_wallet/utils/brightness_util.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
|
@ -160,16 +161,15 @@ class QRWidget extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
addressUri.address,
|
||||
child: AddressFormatter.buildSegmentedAddress(
|
||||
address: addressUri.address,
|
||||
walletType: addressListViewModel.type,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
evenTextStyle: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.textColor),
|
||||
),
|
||||
),
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.textColor))),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
|
|
|
@ -558,6 +558,7 @@ class SendPage extends BasePage {
|
|||
key: ValueKey('send_page_confirm_sending_dialog_key'),
|
||||
titleText: S.of(bottomSheetContext).confirm_transaction,
|
||||
currentTheme: currentTheme,
|
||||
walletType: sendViewModel.walletType,
|
||||
titleIconPath: sendViewModel.selectedCryptoCurrency.iconPath,
|
||||
currency: sendViewModel.selectedCryptoCurrency,
|
||||
amount: S.of(bottomSheetContext).send_amount,
|
||||
|
|
|
@ -190,6 +190,7 @@ class RBFDetailsPage extends BasePage {
|
|||
key: ValueKey('rbf_confirm_sending_bottom_sheet'),
|
||||
titleText: S.of(bottomSheetContext).confirm_transaction,
|
||||
currentTheme: currentTheme,
|
||||
walletType: transactionDetailsViewModel.sendViewModel.walletType,
|
||||
titleIconPath: transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency.iconPath,
|
||||
currency: transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency,
|
||||
amount: S.of(bottomSheetContext).send_amount,
|
||||
|
|
|
@ -9,8 +9,11 @@ import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.
|
|||
import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/utils/address_formatter.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -39,13 +42,28 @@ class TransactionDetailsPage extends BasePage {
|
|||
final item = transactionDetailsViewModel.items[index];
|
||||
|
||||
if (item is StandartListItem) {
|
||||
Widget? addressTextWidget;
|
||||
|
||||
if (item.title.toLowerCase() == 'recipient addresses' ||
|
||||
item.title.toLowerCase() == 'source address') {
|
||||
addressTextWidget = getFormattedAddress(
|
||||
context: context,
|
||||
value: item.value,
|
||||
walletType: transactionDetailsViewModel.sendViewModel.walletType,
|
||||
);
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
key: item.key,
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
showBar<void>(context, S.of(context).transaction_details_copied(item.title));
|
||||
},
|
||||
child: ListRow(title: '${item.title}:', value: item.value),
|
||||
child: ListRow(
|
||||
title: '${item.title}:',
|
||||
value: item.value,
|
||||
textWidget: addressTextWidget,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -91,4 +109,80 @@ class TransactionDetailsPage extends BasePage {
|
|||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget getFormattedAddress({
|
||||
required BuildContext context,
|
||||
required String value,
|
||||
required WalletType walletType,
|
||||
}) {
|
||||
final textStyle = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
);
|
||||
final List<Widget> children = [];
|
||||
final bool hasDoubleNewline = value.contains('\n\n');
|
||||
|
||||
if (hasDoubleNewline) {
|
||||
final blocks = value
|
||||
.split('\n\n')
|
||||
.map((b) => b.trim())
|
||||
.where((b) => b.isNotEmpty)
|
||||
.toList();
|
||||
for (final block in blocks) {
|
||||
final lines = block
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.where((l) => l.isNotEmpty)
|
||||
.toList();
|
||||
if (lines.length > 1) {
|
||||
children.add(Text(lines.first, style: textStyle));
|
||||
for (int i = 1; i < lines.length; i++) {
|
||||
children.add(
|
||||
AddressFormatter.buildSegmentedAddress(
|
||||
address: lines[i],
|
||||
walletType: walletType,
|
||||
evenTextStyle: textStyle,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
children.add(
|
||||
AddressFormatter.buildSegmentedAddress(
|
||||
address: lines.first,
|
||||
walletType: walletType,
|
||||
evenTextStyle: textStyle,
|
||||
),
|
||||
);
|
||||
}
|
||||
children.add(SizedBox(height: 8));
|
||||
}
|
||||
} else {
|
||||
final lines = value
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.where((l) => l.isNotEmpty)
|
||||
.toList();
|
||||
bool firstLineIsContactName = (lines.length > 1 && lines.first.length < 20);
|
||||
int startIndex = 0;
|
||||
if (firstLineIsContactName) {
|
||||
children.add(Text(lines.first, style: textStyle));
|
||||
startIndex = 1;
|
||||
}
|
||||
for (int i = startIndex; i < lines.length; i++) {
|
||||
children.add(
|
||||
AddressFormatter.buildSegmentedAddress(
|
||||
address: lines[i],
|
||||
walletType: walletType,
|
||||
evenTextStyle: textStyle,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,12 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
|||
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/address_formatter.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.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 'dart:math' as math;
|
||||
|
||||
import 'base_bottom_sheet_widget.dart';
|
||||
|
||||
|
@ -27,6 +28,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
|||
final String feeFiatAmount;
|
||||
final List<Output> outputs;
|
||||
final VoidCallback onSlideComplete;
|
||||
final WalletType walletType;
|
||||
final PendingChange? change;
|
||||
final bool isOpenCryptoPay;
|
||||
|
||||
|
@ -46,6 +48,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
|||
required this.feeFiatAmount,
|
||||
required this.outputs,
|
||||
required this.onSlideComplete,
|
||||
required this.walletType,
|
||||
this.change,
|
||||
this.isOpenCryptoPay = false,
|
||||
Key? key,
|
||||
|
@ -91,6 +94,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
|||
itemTitle: paymentId!,
|
||||
currentTheme: currentTheme,
|
||||
itemTitleTextStyle: itemTitleTextStyle,
|
||||
walletType: walletType,
|
||||
isBatchSending: false,
|
||||
amount: '',
|
||||
address: paymentIdValue!,
|
||||
|
@ -139,6 +143,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
|||
name: isBatchSending ? batchContactTitle : contactName,
|
||||
address: _address,
|
||||
amount: _amount,
|
||||
walletType: walletType,
|
||||
isBatchSending: isBatchSending,
|
||||
itemTitleTextStyle: itemTitleTextStyle,
|
||||
itemSubTitleTextStyle: itemSubTitleTextStyle,
|
||||
|
@ -149,6 +154,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
|||
currentTheme: currentTheme,
|
||||
itemTitleTextStyle: itemTitleTextStyle,
|
||||
isBatchSending: isBatchSending,
|
||||
walletType: walletType,
|
||||
amount: _amount,
|
||||
address: _address,
|
||||
itemSubTitleTextStyle: itemSubTitleTextStyle,
|
||||
|
@ -166,6 +172,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
|||
address: change!.address,
|
||||
amount: change!.amount + ' ${currency.title}',
|
||||
isBatchSending: true,
|
||||
walletType: walletType,
|
||||
itemTitleTextStyle: itemTitleTextStyle,
|
||||
itemSubTitleTextStyle: itemSubTitleTextStyle,
|
||||
tileBackgroundColor: tileBackgroundColor,
|
||||
|
@ -275,6 +282,7 @@ class AddressTile extends StatelessWidget {
|
|||
required this.address,
|
||||
required this.itemSubTitleTextStyle,
|
||||
required this.tileBackgroundColor,
|
||||
required this.walletType,
|
||||
});
|
||||
|
||||
final String itemTitle;
|
||||
|
@ -285,18 +293,10 @@ class AddressTile extends StatelessWidget {
|
|||
final String address;
|
||||
final TextStyle itemSubTitleTextStyle;
|
||||
final Color tileBackgroundColor;
|
||||
final WalletType walletType;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final addressTextStyle = TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: currentTheme.type == ThemeType.bright
|
||||
? Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.5)
|
||||
: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
);
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
|
@ -313,41 +313,20 @@ class AddressTile extends StatelessWidget {
|
|||
if (isBatchSending) Text(amount, style: itemTitleTextStyle),
|
||||
],
|
||||
),
|
||||
buildSegmentedAddress(
|
||||
AddressFormatter.buildSegmentedAddress(
|
||||
address: address,
|
||||
evenTextStyle: addressTextStyle,
|
||||
oddTextStyle: itemSubTitleTextStyle,
|
||||
walletType: walletType,
|
||||
evenTextStyle: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none)
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSegmentedAddress({
|
||||
required String address,
|
||||
int chunkSize = 6,
|
||||
required TextStyle evenTextStyle,
|
||||
required TextStyle oddTextStyle,
|
||||
}) {
|
||||
final spans = <TextSpan>[];
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < address.length; i += chunkSize) {
|
||||
final chunk = address.substring(i, math.min(i + chunkSize, address.length));
|
||||
final style = (index % 2 == 0) ? evenTextStyle : oddTextStyle;
|
||||
|
||||
spans.add(
|
||||
TextSpan(text: '$chunk ', style: style),
|
||||
);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return RichText(
|
||||
text: TextSpan(children: spans, style: evenTextStyle),
|
||||
overflow: TextOverflow.visible,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AddressExpansionTile extends StatelessWidget {
|
||||
|
@ -362,6 +341,7 @@ class AddressExpansionTile extends StatelessWidget {
|
|||
required this.itemTitleTextStyle,
|
||||
required this.itemSubTitleTextStyle,
|
||||
required this.tileBackgroundColor,
|
||||
required this.walletType,
|
||||
});
|
||||
|
||||
final String contactType;
|
||||
|
@ -373,19 +353,10 @@ class AddressExpansionTile extends StatelessWidget {
|
|||
final TextStyle itemTitleTextStyle;
|
||||
final TextStyle itemSubTitleTextStyle;
|
||||
final Color tileBackgroundColor;
|
||||
final WalletType walletType;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final addressTextStyle = TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: currentTheme.type == ThemeType.bright
|
||||
? Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.5)
|
||||
: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
);
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||
|
@ -420,10 +391,15 @@ class AddressExpansionTile extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: buildSegmentedAddress(
|
||||
child: AddressFormatter.buildSegmentedAddress(
|
||||
address: address,
|
||||
evenTextStyle: addressTextStyle,
|
||||
oddTextStyle: itemSubTitleTextStyle,
|
||||
walletType: walletType,
|
||||
evenTextStyle: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none)
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -434,30 +410,4 @@ class AddressExpansionTile extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSegmentedAddress({
|
||||
required String address,
|
||||
int chunkSize = 6,
|
||||
required TextStyle evenTextStyle,
|
||||
required TextStyle oddTextStyle,
|
||||
}) {
|
||||
final spans = <TextSpan>[];
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < address.length; i += chunkSize) {
|
||||
final chunk = address.substring(i, math.min(i + chunkSize, address.length));
|
||||
final style = (index % 2 == 0) ? evenTextStyle : oddTextStyle;
|
||||
|
||||
spans.add(
|
||||
TextSpan(text: '$chunk ', style: style),
|
||||
);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return RichText(
|
||||
text: TextSpan(children: spans, style: evenTextStyle),
|
||||
overflow: TextOverflow.visible,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ class ListRow extends StatelessWidget {
|
|||
this.padding,
|
||||
this.color,
|
||||
this.hintTextColor,
|
||||
this.mainTextColor
|
||||
this.mainTextColor,
|
||||
this.textWidget
|
||||
});
|
||||
|
||||
final String title;
|
||||
|
@ -24,6 +25,16 @@ class ListRow extends StatelessWidget {
|
|||
final Color? color;
|
||||
final Color? hintTextColor;
|
||||
final Color? mainTextColor;
|
||||
final Widget? textWidget;
|
||||
|
||||
Widget _getTextWidget (BuildContext context) => textWidget ?? Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: mainTextColor ?? Theme.of(context).extension<CakeTextTheme>()!.titleColor
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -49,12 +60,7 @@ class ListRow extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(value,
|
||||
style: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: mainTextColor ?? Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
|
||||
),
|
||||
child: _getTextWidget(context)),
|
||||
image != null
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
|
|
117
lib/utils/address_formatter.dart
Normal file
117
lib/utils/address_formatter.dart
Normal file
|
@ -0,0 +1,117 @@
|
|||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
class AddressFormatter {
|
||||
static Widget buildSegmentedAddress({
|
||||
required String address,
|
||||
required WalletType walletType,
|
||||
required TextStyle evenTextStyle,
|
||||
TextStyle? oddTextStyle,
|
||||
TextAlign? textAlign,
|
||||
bool shouldTruncate = false,
|
||||
}) {
|
||||
if (shouldTruncate) {
|
||||
return _buildTruncatedAddress(
|
||||
address: address,
|
||||
walletType: walletType,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle ?? evenTextStyle.copyWith(color: evenTextStyle.color!.withAlpha(150)),
|
||||
textAlign: textAlign,
|
||||
);
|
||||
} else {
|
||||
return _buildFullSegmentedAddress(
|
||||
address: address,
|
||||
walletType: walletType,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle ?? evenTextStyle.copyWith(color: evenTextStyle.color!.withAlpha(128)),
|
||||
textAlign: textAlign,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static Widget _buildFullSegmentedAddress({
|
||||
required String address,
|
||||
required WalletType walletType,
|
||||
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);
|
||||
}
|
||||
|
||||
final spans = <TextSpan>[];
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
final style = (i % 2 == 0) ? evenTextStyle : oddTextStyle;
|
||||
spans.add(TextSpan(text: '${chunks[i]} ', style: style));
|
||||
}
|
||||
|
||||
return RichText(
|
||||
text: TextSpan(children: spans),
|
||||
textAlign: textAlign ?? TextAlign.start,
|
||||
overflow: TextOverflow.visible,
|
||||
);
|
||||
}
|
||||
|
||||
static Widget _buildTruncatedAddress({
|
||||
required String address,
|
||||
required WalletType walletType,
|
||||
required TextStyle evenTextStyle,
|
||||
required TextStyle oddTextStyle,
|
||||
TextAlign? textAlign,
|
||||
}) {
|
||||
|
||||
final cleanAddress = address.replaceAll('bitcoincash:', '');
|
||||
|
||||
final int digitCount = (walletType == WalletType.monero ||
|
||||
walletType == WalletType.wownero ||
|
||||
walletType == WalletType.zano)
|
||||
? 6
|
||||
: 4;
|
||||
|
||||
if (cleanAddress.length <= 2 * digitCount) {
|
||||
return _buildFullSegmentedAddress(
|
||||
address: cleanAddress,
|
||||
walletType: walletType,
|
||||
evenTextStyle: evenTextStyle,
|
||||
oddTextStyle: oddTextStyle,
|
||||
textAlign: textAlign,
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
switch (walletType) {
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
case WalletType.zano:
|
||||
return 6;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue