mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Merge branch 'cake-tech:dev' into dev
This commit is contained in:
@@ -336,14 +336,23 @@ class DFXBuyProvider extends BuyProvider {
|
||||
String? countryCode}) async {
|
||||
if (wallet.isHardwareWallet) {
|
||||
if (!hardwareWalletVM!.isConnected(wallet.walletInfo.type)) {
|
||||
await Navigator.of(context).pushNamed(Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
walletType: wallet.walletInfo.type,
|
||||
hardwareWalletType: wallet.walletInfo.hardwareWalletType!,
|
||||
onConnectDevice: (context, hwwVM) {
|
||||
hwwVM.initWallet(wallet);
|
||||
Navigator.of(context).pop();
|
||||
}));
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
walletType: wallet.walletInfo.type,
|
||||
hardwareWalletType: wallet.walletInfo.hardwareWalletType!,
|
||||
onConnectDevice: (context, hwwVM) {
|
||||
hwwVM.initWallet(wallet);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
isReconnect: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Recheck to handle tap-backs
|
||||
if (!hardwareWalletVM!.isConnected(wallet.walletInfo.type)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
hardwareWalletVM!.initWallet(wallet);
|
||||
}
|
||||
|
||||
@@ -174,14 +174,21 @@ class RobinhoodBuyProvider extends BuyProvider {
|
||||
String? countryCode}) async {
|
||||
if (wallet.isHardwareWallet) {
|
||||
if (!hardwareWalletVM!.isConnected(wallet.walletInfo.type)) {
|
||||
await Navigator.of(context).pushNamed(Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
walletType: wallet.walletInfo.type,
|
||||
hardwareWalletType: wallet.walletInfo.hardwareWalletType!,
|
||||
onConnectDevice: (context, hwwVM) {
|
||||
hwwVM.initWallet(wallet);
|
||||
Navigator.of(context).pop();
|
||||
}));
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
walletType: wallet.walletInfo.type,
|
||||
hardwareWalletType: wallet.walletInfo.hardwareWalletType!,
|
||||
onConnectDevice: (context, hwwVM) {
|
||||
hwwVM.initWallet(wallet);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
isReconnect: false,
|
||||
),
|
||||
);
|
||||
if (!hardwareWalletVM!.isConnected(wallet.walletInfo.type)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
hardwareWalletVM!.initWallet(wallet);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ class _AboutPageState extends State<AboutPage> {
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).about,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
content: Container(
|
||||
|
||||
@@ -128,8 +128,10 @@ class _AccountCustomizerState extends State<AccountCustomizer> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).wallet_accounts,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).maybePop,
|
||||
trailingIcon: Icon(Icons.refresh),
|
||||
trailingSemanticLabel: S.of(context).reset,
|
||||
onTrailingPressed: showResetDialog,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -105,6 +105,7 @@ class _NewAddressesPageState extends State<NewAddressesPage> {
|
||||
ModalTopBar(
|
||||
title: widget.showHidden ? S.of(context).hidden_addresses : S.of(context).addresses,
|
||||
leadingIcon: Icon(Icons.arrow_back),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
onTrailingPressed: () {}),
|
||||
Expanded(
|
||||
|
||||
@@ -116,8 +116,10 @@ class _BridgeAmountPageState extends State<BridgeAmountPage> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).enter_amount,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context, rootNavigator: true).pop(),
|
||||
trailingIcon: Icon(Icons.history),
|
||||
trailingSemanticLabel: S.of(context).history,
|
||||
onTrailingPressed: () {
|
||||
Navigator.pushNamed(context, Routes.bridgeHistoryPage,
|
||||
arguments: widget.bridgeHistoryViewModel);
|
||||
@@ -274,6 +276,7 @@ class _BridgeAmountPageState extends State<BridgeAmountPage> {
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
iconColor: theme.colorScheme.onPrimary,
|
||||
icon: Icon(Icons.arrow_forward, size: 20),
|
||||
semanticLabel: S.of(context).continue_text,
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
|
||||
@@ -87,6 +87,7 @@ class _BridgeConfirmSheetState extends State<BridgeConfirmSheet> {
|
||||
],
|
||||
),
|
||||
trailingIcon: const Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: () => Navigator.of(context).maybePop(),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@ class BridgeDetailPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: "Bridge Transfer Details",
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new, size: 18),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/pages/bridge/bridge_detail_page.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:cake_wallet/view_model/bridge/bridge_history_view_model.dart';
|
||||
@@ -25,6 +26,7 @@ class BridgeHistoryPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: "Bridge history",
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new, size: 18),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/keyboard_hide_overlay.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
@@ -30,6 +31,7 @@ class BridgeNetworkPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: 'Destination Network',
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new, size: 18),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
SizedBox(height: 48),
|
||||
|
||||
@@ -55,6 +55,7 @@ class _BridgeReceiveAddressInputPageState extends State<BridgeReceiveAddressInpu
|
||||
ModalTopBar(
|
||||
title: 'Input Receive Address',
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new, size: 18),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
SizedBox(height: 48),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/view_model/bridge/bridge_receiving_wallet_option.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/pages/bridge/bridge_confirm_sheet.dart';
|
||||
import 'package:cake_wallet/new-ui/pages/bridge/bridge_receive_address_input_page.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/keyboard_hide_overlay.dart';
|
||||
@@ -42,6 +43,7 @@ class _BridgeReceivingWalletPageState extends State<BridgeReceivingWalletPage> {
|
||||
ModalTopBar(
|
||||
title: 'Receiving Wallet',
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new, size: 18),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
|
||||
@@ -84,6 +84,7 @@ class _CardCustomizerState extends State<CardCustomizer> {
|
||||
ModalTopBar(
|
||||
title: editEnabled ? S.of(context).edit_account : S.of(context).edit_card,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
// trailingIcon: editEnabled ? Icon(Icons.delete_forever) : null,
|
||||
onLeadingPressed: () => Navigator.of(context).maybePop(),
|
||||
// onTrailingPressed: () {},
|
||||
|
||||
@@ -68,6 +68,7 @@ class _LightningUsernamePageState extends State<LightningUsernamePage> {
|
||||
ModalTopBar(
|
||||
title: "Lightning ${S.of(context).username}",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -201,6 +201,7 @@ class _NewReceivePageState extends State<NewReceivePage> {
|
||||
ModalTopBar(
|
||||
title: _largeQrMode ? "" : S.of(context).receive,
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: () {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
},
|
||||
@@ -223,6 +224,9 @@ class _NewReceivePageState extends State<NewReceivePage> {
|
||||
: widget.addressListViewModel.isRotatingAddress
|
||||
? const CupertinoActivityIndicator()
|
||||
: const Icon(Icons.refresh),
|
||||
semanticLabel: _largeQrMode
|
||||
? S.of(context).share_address
|
||||
: S.of(context).rotate_address,
|
||||
onPressed: () {
|
||||
if (_largeQrMode) {
|
||||
ShareUtil.share(
|
||||
|
||||
@@ -163,6 +163,7 @@ class _ScanPageState extends State<ScanPage> {
|
||||
},
|
||||
iconColor: buttonIconColor,
|
||||
backgroundColor: buttonColor,
|
||||
semanticLabel: S.of(context).switch_camera,
|
||||
),
|
||||
ModernButton(
|
||||
size: 36,
|
||||
@@ -171,6 +172,10 @@ class _ScanPageState extends State<ScanPage> {
|
||||
(controller.value.torchState == TorchState.on || _frontFlashMode)
|
||||
? Icons.flash_off_outlined
|
||||
: Icons.flash_on),
|
||||
semanticLabel:
|
||||
(controller.value.torchState == TorchState.on || _frontFlashMode)
|
||||
? S.of(context).turn_flash_off
|
||||
: S.of(context).turn_flash_on,
|
||||
onPressed: () {
|
||||
if (controller.value.cameraDirection == CameraFacing.front) {
|
||||
setState(() {
|
||||
@@ -194,6 +199,7 @@ class _ScanPageState extends State<ScanPage> {
|
||||
size: 36,
|
||||
iconSize: 18,
|
||||
icon: Icon(Icons.arrow_back_ios_new),
|
||||
semanticLabel: S.of(context).seed_alert_back,
|
||||
onPressed: () {
|
||||
if (_textInputMode) {
|
||||
setState(() {
|
||||
|
||||
@@ -328,6 +328,7 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
title: widget.mode.title,
|
||||
subtitle: widget.mode.description,
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
|
||||
trailingWidget: Observer(
|
||||
builder: (_) => Row(
|
||||
@@ -343,6 +344,7 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
semanticLabel: S.of(context).remove,
|
||||
onPressed: () {
|
||||
final outputIndex = _selectedOutput;
|
||||
if (_selectedOutput != 0) {
|
||||
@@ -362,6 +364,7 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
ModernButton(
|
||||
size: 36,
|
||||
icon: const Icon(Icons.add),
|
||||
semanticLabel: S.of(context).add_receiver,
|
||||
onPressed: () {
|
||||
_addInputControllers();
|
||||
widget.sendViewModel.addOutput();
|
||||
@@ -378,6 +381,7 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
semanticLabel: S.of(context).help,
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(
|
||||
CupertinoPageRoute(
|
||||
@@ -823,8 +827,15 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
widget.sendViewModel.hardwareWalletViewModel!.initWallet(widget.sendViewModel.wallet);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
isReconnect: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Recheck to handle tap-backs
|
||||
if (!widget.sendViewModel.hardwareWalletViewModel!
|
||||
.isConnected(widget.sendViewModel.walletType)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
await widget.sendViewModel.hardwareWalletViewModel!.initWallet(widget.sendViewModel.wallet);
|
||||
}
|
||||
@@ -1485,6 +1496,7 @@ class SendHelpPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: content.title,
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -152,8 +152,9 @@ class SettingsMainPage extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Column(children: [
|
||||
ModalTopBar(
|
||||
title: "Settings",
|
||||
title: S.of(context).settings_title,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
|
||||
onTrailingPressed: () {},
|
||||
),
|
||||
|
||||
@@ -472,12 +472,14 @@ class _NewSwapPageState extends State<NewSwapPage> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).swap,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).maybePop,
|
||||
trailingIcon: CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/options.svg",
|
||||
colorFilter:
|
||||
ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn),
|
||||
),
|
||||
trailingSemanticLabel: S.of(context).configure,
|
||||
onTrailingPressed: () {
|
||||
Navigator.of(context).push(CupertinoPageRoute(
|
||||
builder: (context) => Material(
|
||||
@@ -576,6 +578,7 @@ class _NewSwapPageState extends State<NewSwapPage> {
|
||||
iconSize: 24,
|
||||
svgPath: "assets/new-ui/swap_amounts.svg",
|
||||
onPressed: widget.exchangeViewModel.reverseSwapDirection,
|
||||
semanticLabel: S.of(context).swap_reverse_direction,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1174,6 +1177,7 @@ class SwapAmountBoxState extends State<SwapAmountBox> {
|
||||
size: 36,
|
||||
iconSize: 18,
|
||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
semanticLabel: S.of(context).refund_address,
|
||||
),
|
||||
if (widget.isReceiverCard &&
|
||||
widget.exchangeViewModel.receiveAddress.isEmpty) ...[
|
||||
@@ -1183,6 +1187,7 @@ class SwapAmountBoxState extends State<SwapAmountBox> {
|
||||
size: 36,
|
||||
iconSize: 20,
|
||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
semanticLabel: S.of(context).paste,
|
||||
),
|
||||
ModernButton.svg(
|
||||
svgPath: "assets/new-ui/scan.svg",
|
||||
@@ -1190,6 +1195,7 @@ class SwapAmountBoxState extends State<SwapAmountBox> {
|
||||
size: 36,
|
||||
iconSize: 20,
|
||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
semanticLabel: S.of(context).scan,
|
||||
),
|
||||
]
|
||||
],
|
||||
|
||||
@@ -107,7 +107,7 @@ class _ChangelogModalState extends State<ChangelogModal> {
|
||||
NewPrimaryButton(
|
||||
onPressed: () {
|
||||
try {
|
||||
launchUrl(Uri.https("blog.cakewallet.com"));
|
||||
launchUrl(Uri.https("docs.cakewallet.com", "/release-notes"));
|
||||
} catch (_) {}
|
||||
},
|
||||
text: S.of(context).view_more_info,
|
||||
|
||||
@@ -23,47 +23,57 @@ class CoinActionButton extends StatelessWidget {
|
||||
final size = MediaQuery.of(context).size.width * sizeFactor;
|
||||
final double effectiveSize = min(size, 80);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
width: effectiveSize,
|
||||
height: effectiveSize,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
context.customColors.cardGradientColorPrimary,
|
||||
context.customColors.cardGradientColorSecondary
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
HapticFeedback.mediumImpact();
|
||||
action();
|
||||
},
|
||||
icon: icon,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
// The caption below the circle is the accessible name, so it is excluded
|
||||
// from the semantics tree to keep this a single button node.
|
||||
return MergeSemantics(
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: label,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: effectiveSize,
|
||||
height: effectiveSize,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
context.customColors.cardGradientColorPrimary,
|
||||
context.customColors.cardGradientColorSecondary
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
label,
|
||||
),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
HapticFeedback.mediumImpact();
|
||||
action();
|
||||
},
|
||||
icon: ExcludeSemantics(child: icon),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: ExcludeSemantics(
|
||||
child: Text(
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
label,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class AssetDetailsModal extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: "",
|
||||
trailingIcon: Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).pop,
|
||||
padding: EdgeInsets.only(top: 12, right: 18),
|
||||
),
|
||||
@@ -356,17 +357,22 @@ class AssetDetailsModalBottomButton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
ModernButton.svg(
|
||||
onPressed: onPressed,
|
||||
svgPath: iconPath,
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
),
|
||||
Text(title)
|
||||
],
|
||||
// The caption is the button's accessible name, so it is excluded from the
|
||||
// semantics tree to keep the whole control a single button node.
|
||||
return MergeSemantics(
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
ModernButton.svg(
|
||||
onPressed: onPressed,
|
||||
svgPath: iconPath,
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
semanticLabel: title,
|
||||
),
|
||||
ExcludeSemantics(child: Text(title))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class HistoryFiltersPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).filters,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -25,11 +25,13 @@ class HistoryModal extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).history,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).maybePop,
|
||||
trailingIcon: CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/tx_export.svg",
|
||||
colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn),
|
||||
),
|
||||
trailingSemanticLabel: S.of(context).export_csv,
|
||||
onTrailingPressed: () =>
|
||||
CsvExportService().exportToCsv(dashboardViewModel.items, context),
|
||||
),
|
||||
|
||||
@@ -24,6 +24,7 @@ class HistorySwapProvidersPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).filter_swap_providers,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -68,6 +68,7 @@ class _TransactionDetailsModalState extends State<TransactionDetailsModal> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).transaction,
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/chain_icon.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/lightning_switcher.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart';
|
||||
@@ -53,6 +54,7 @@ class TopBar extends StatelessWidget {
|
||||
onSettingsButtonPress();
|
||||
},
|
||||
svgPath: "assets/new-ui/top-settings.svg",
|
||||
semanticLabel: S.of(context).settings_title,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -125,6 +125,7 @@ class UnconfirmedBalanceModal extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).balance_confirmation,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/modern_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
@@ -76,6 +77,7 @@ class WalletInfoBar extends StatelessWidget {
|
||||
}
|
||||
},
|
||||
svgPath: "assets/new-ui/icon-accounts.svg",
|
||||
semanticLabel: S.of(context).wallet_accounts,
|
||||
)
|
||||
]
|
||||
],
|
||||
|
||||
@@ -43,6 +43,7 @@ class CurrencyPickerSheet extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).select_asset,
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: () => Navigator.of(context).maybePop(),
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -117,6 +117,7 @@ class _FiatCurrencyPickerSheetState extends State<FiatCurrencyPickerSheet> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).select_fiat_currency_title,
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: () => Navigator.of(context).maybePop(),
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -35,6 +35,7 @@ class SelectNetworkPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).select_network_title,
|
||||
leadingIcon: const Icon(Icons.arrow_back),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).maybePop(),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
@@ -106,6 +106,7 @@ class _HardwareWalletProceedOnDeviceSheetState extends State<HardwareWalletProce
|
||||
Icons.close,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: () => showPopUp(
|
||||
context: context,
|
||||
builder: (context) => AlertWithTwoActions(
|
||||
@@ -143,6 +144,7 @@ class _HardwareWalletProceedOnDeviceSheetState extends State<HardwareWalletProce
|
||||
iconColor: Theme.of(context).colorScheme.onPrimary,
|
||||
size: 36,
|
||||
icon: Icon(Icons.arrow_forward),
|
||||
semanticLabel: S.of(context).confirm,
|
||||
onPressed: () =>
|
||||
widget.trezorConnectVM.setParingPin(_controller.text.trim()),
|
||||
),
|
||||
|
||||
@@ -32,6 +32,7 @@ class _HardwareWalletTrezorParingSheetState extends State<HardwareWalletTrezorPa
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
onTrailingPressed: () {},
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
|
||||
@@ -11,6 +11,11 @@ class ModernButton extends StatelessWidget {
|
||||
final Color? backgroundColor;
|
||||
final double? iconSize;
|
||||
final String? label;
|
||||
|
||||
/// Accessible name announced by screen readers. Falls back to [label] (the
|
||||
/// visible caption) when omitted, so one of the two is required. Must be
|
||||
/// localized by the caller.
|
||||
final String? semanticLabel;
|
||||
static const iconSvgSizeRatio = 2 / 3;
|
||||
|
||||
const ModernButton(
|
||||
@@ -21,8 +26,11 @@ class ModernButton extends StatelessWidget {
|
||||
this.iconSize,
|
||||
this.iconColor,
|
||||
this.backgroundColor,
|
||||
this.label})
|
||||
: svgPath = null;
|
||||
this.label,
|
||||
this.semanticLabel})
|
||||
: svgPath = null,
|
||||
assert(semanticLabel != null || (label != null && label != ""),
|
||||
"ModernButton needs a semanticLabel when it has no visible label");
|
||||
|
||||
const ModernButton.svg(
|
||||
{super.key,
|
||||
@@ -32,8 +40,11 @@ class ModernButton extends StatelessWidget {
|
||||
this.iconSize,
|
||||
this.iconColor,
|
||||
this.backgroundColor,
|
||||
this.label})
|
||||
: icon = null;
|
||||
this.label,
|
||||
this.semanticLabel})
|
||||
: icon = null,
|
||||
assert(semanticLabel != null || (label != null && label != ""),
|
||||
"ModernButton needs a semanticLabel when it has no visible label");
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -56,31 +67,42 @@ class ModernButton extends StatelessWidget {
|
||||
child: icon!,
|
||||
);
|
||||
|
||||
return Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: resolvedBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(size),
|
||||
),
|
||||
width: size,
|
||||
height: size,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: onPressed,
|
||||
icon: resolvedIcon,
|
||||
),
|
||||
// A single accessibility node for the whole control: the visible caption
|
||||
// duplicates the accessible name, so it is excluded to avoid a second,
|
||||
// detached stop for screen readers.
|
||||
return MergeSemantics(
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: semanticLabel ?? label,
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: resolvedBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(size),
|
||||
),
|
||||
width: size,
|
||||
height: size,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: onPressed,
|
||||
icon: ExcludeSemantics(child: resolvedIcon),
|
||||
),
|
||||
),
|
||||
if (label != null && label!.isNotEmpty)
|
||||
ExcludeSemantics(
|
||||
child: Text(
|
||||
label!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
if (label != null && label!.isNotEmpty)
|
||||
Text(
|
||||
label!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurface),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
@@ -77,6 +78,7 @@ class _NewPickerState<Item> extends State<NewPicker<Item>> {
|
||||
ModalTopBar(
|
||||
title: widget.title,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).maybePop,
|
||||
),
|
||||
Padding(
|
||||
@@ -387,6 +389,7 @@ class _PickerSliderPageState<Item> extends State<PickerSliderPage<Item>> {
|
||||
ModalTopBar(
|
||||
title: widget.title,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -25,6 +25,7 @@ class PayjoinCopyModal extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).select_address_to_copy,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
|
||||
@@ -73,6 +73,7 @@ class _ReceiveAddressTypeSelectorState extends State<ReceiveAddressTypeSelector>
|
||||
ModalTopBar(
|
||||
title: S.of(context).address_type,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
onTrailingPressed: () {}),
|
||||
SizedBox(height: 24),
|
||||
|
||||
@@ -56,6 +56,7 @@ class _ReceiveAmountModalState extends State<ReceiveAmountModal> {
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
onTrailingPressed: () {},
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
|
||||
@@ -66,6 +66,7 @@ class _ReceiveLabelModalState extends State<ReceiveLabelModal> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).label_address,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
onTrailingPressed: () {}),
|
||||
Padding(
|
||||
|
||||
@@ -14,7 +14,14 @@ class ModalTopBar extends StatelessWidget {
|
||||
this.trailingIcon,
|
||||
this.padding,
|
||||
this.leadingWidget,
|
||||
this.trailingWidget}) {
|
||||
this.trailingWidget,
|
||||
this.leadingSemanticLabel,
|
||||
this.trailingSemanticLabel})
|
||||
: assert(leadingIcon == null || (leadingSemanticLabel != null && leadingSemanticLabel != ""),
|
||||
"leadingIcon requires a non-empty leadingSemanticLabel"),
|
||||
assert(
|
||||
trailingIcon == null || (trailingSemanticLabel != null && trailingSemanticLabel != ""),
|
||||
"trailingIcon requires a non-empty trailingSemanticLabel") {
|
||||
if (leadingIcon != null && leadingWidget != null) {
|
||||
throw Exception("Cannot have both leadingIcon and leadingWidget");
|
||||
}
|
||||
@@ -33,6 +40,17 @@ class ModalTopBar extends StatelessWidget {
|
||||
final Widget? leadingWidget;
|
||||
final Widget? trailingWidget;
|
||||
|
||||
/// Accessible name for the leading chrome button. Required (and must be
|
||||
/// non-empty) whenever a [leadingIcon] is supplied, because the icon alone
|
||||
/// does not say whether it closes the modal or goes back. Must be localized
|
||||
/// by the caller.
|
||||
final String? leadingSemanticLabel;
|
||||
|
||||
/// Accessible name for the trailing chrome button. Required (and must be
|
||||
/// non-empty) whenever a [trailingIcon] is supplied. Must be localized by
|
||||
/// the caller.
|
||||
final String? trailingSemanticLabel;
|
||||
|
||||
static const buttonSize = 36.0;
|
||||
|
||||
@override
|
||||
@@ -51,10 +69,16 @@ class ModalTopBar extends StatelessWidget {
|
||||
children: [
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Text(
|
||||
title,
|
||||
child: Semantics(
|
||||
key: ValueKey(title),
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
header: title.isNotEmpty,
|
||||
// Android reads the heading from headingLevel since the
|
||||
// Flutter 3.41 engine; header: alone only covers iOS.
|
||||
headingLevel: title.isNotEmpty ? 1 : null,
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (subtitle != null && subtitle!.isNotEmpty)
|
||||
@@ -77,6 +101,7 @@ class ModalTopBar extends StatelessWidget {
|
||||
size: buttonSize,
|
||||
onPressed: onLeadingPressed,
|
||||
icon: leadingIcon!,
|
||||
semanticLabel: leadingSemanticLabel,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant)
|
||||
: leadingWidget!
|
||||
else
|
||||
@@ -90,6 +115,7 @@ class ModalTopBar extends StatelessWidget {
|
||||
size: buttonSize,
|
||||
onPressed: onTrailingPressed,
|
||||
icon: trailingIcon!,
|
||||
semanticLabel: trailingSemanticLabel,
|
||||
)
|
||||
: trailingWidget!,
|
||||
)
|
||||
|
||||
@@ -22,6 +22,7 @@ class ScanPageNetworkList extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).compatible_services,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -47,6 +47,7 @@ class FiatAmountBar extends StatelessWidget {
|
||||
svgPath: "assets/new-ui/switch.svg",
|
||||
iconSize: 18,
|
||||
onPressed: onSwitchButtonPressed,
|
||||
semanticLabel: S.of(context).switch_input_currency,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: onSwitchButtonPressed,
|
||||
|
||||
@@ -90,6 +90,7 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
|
||||
? "${S.of(context).send_from}..."
|
||||
: "${S.of(context).receive_to}...",
|
||||
leadingIcon: const Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Flexible(
|
||||
|
||||
@@ -73,6 +73,7 @@ class _L2SendExternalModalState extends State<L2SendExternalModal> {
|
||||
],
|
||||
),
|
||||
trailingIcon: Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
SafeArea(
|
||||
|
||||
@@ -161,6 +161,7 @@ class SendTransactionDetails extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
trailingIcon: Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).maybePop,
|
||||
),
|
||||
isPage
|
||||
|
||||
@@ -37,6 +37,7 @@ class ProviderOptionsPage extends StatelessWidget {
|
||||
title: S.of(context).swap_providers,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
|
||||
@@ -24,6 +24,7 @@ class ProviderSelectorPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).change_provider,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).maybePop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -44,6 +44,7 @@ class _RefundAddressModalState extends State<RefundAddressModal> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).set_refund_address,
|
||||
trailingIcon: Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
SafeArea(
|
||||
|
||||
@@ -82,6 +82,7 @@ class _SwapAddressSelectionModalState extends State<SwapAddressSelectionModal> {
|
||||
? "${S.of(context).receive_to}..."
|
||||
: "${S.of(context).send_from}...",
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Flexible(
|
||||
|
||||
@@ -47,15 +47,23 @@ class _SwapConfirmSheetState extends State<SwapConfirmSheet> {
|
||||
|
||||
if (sendVM.wallet.isHardwareWallet) {
|
||||
if (!sendVM.hardwareWalletViewModel!.isConnected(sendVM.walletType)) {
|
||||
await Navigator.of(context).pushNamed(Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
walletType: sendVM.walletType,
|
||||
hardwareWalletType: sendVM.wallet.walletInfo.hardwareWalletType!,
|
||||
onConnectDevice: (context, _) {
|
||||
sendVM.hardwareWalletViewModel!.initWallet(sendVM.wallet);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
));
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
walletType: sendVM.walletType,
|
||||
hardwareWalletType: sendVM.wallet.walletInfo.hardwareWalletType!,
|
||||
onConnectDevice: (context, _) {
|
||||
sendVM.hardwareWalletViewModel!.initWallet(sendVM.wallet);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
isReconnect: false,
|
||||
),
|
||||
);
|
||||
|
||||
// Recheck to handle tap-backs
|
||||
if (!sendVM.hardwareWalletViewModel!.isConnected(sendVM.walletType)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
sendVM.hardwareWalletViewModel!.initWallet(sendVM.wallet);
|
||||
}
|
||||
@@ -148,6 +156,7 @@ class SwapTransactionDetails extends StatelessWidget {
|
||||
fromIconPath: exchangeViewModel.depositCurrency.iconPath ?? "",
|
||||
toIconPath: exchangeViewModel.receiveCurrency.iconPath ?? ""),
|
||||
trailingIcon: Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).maybePop,
|
||||
),
|
||||
SafeArea(
|
||||
|
||||
@@ -25,6 +25,7 @@ class SwapOptionsPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).configure,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -69,6 +69,7 @@ class _SwapSendExternalModalState extends State<SwapSendExternalModal> {
|
||||
leadingWidget: SwapModalHeader(
|
||||
fromIconPath: widget.from.iconPath ?? "", toIconPath: widget.to.iconPath ?? ""),
|
||||
trailingIcon: Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -25,6 +25,7 @@ class TrocadorProvidersSettings extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: "Trocador ${S.of(context).providers}",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/animated_dropdown.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
@@ -27,6 +28,7 @@ class WalletDeprecationPopup extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -141,6 +141,7 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
|
||||
size: 36,
|
||||
icon: Icon(Icons.close),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
semanticLabel: S.of(context).close,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant)
|
||||
: Container(),
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
|
||||
@@ -36,6 +36,7 @@ class _EditBackupPasswordPageState extends State<EditBackupPasswordPage> {
|
||||
ModalTopBar(
|
||||
title: S.of(context).edit_backup_password,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -84,20 +84,16 @@ abstract class BasePage extends StatelessWidget {
|
||||
return null;
|
||||
}
|
||||
|
||||
return MergeSemantics(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: S.of(context).seed_alert_back,
|
||||
child: ModernButton(
|
||||
size: 37,
|
||||
icon: Icon(CupertinoIcons.back),
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
onPressed: () => onClose(context),
|
||||
),
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: ModernButton(
|
||||
size: 37,
|
||||
icon: Icon(CupertinoIcons.back),
|
||||
semanticLabel: S.of(context).seed_alert_back,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
onPressed: () => onClose(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@ class MoneroHardwareWalletPassphraseInputModal extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).passphrase_entry,
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -22,6 +22,7 @@ class FavoriteTokenModal extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).favorite_token,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
leadingSemanticLabel: S.of(context).close,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -59,6 +59,7 @@ class _SignPageState extends State<SignPage> {
|
||||
ModalTopBar(
|
||||
title: S.current.sign_verify_title,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -360,11 +360,9 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo
|
||||
|
||||
widget.nodeViewModel.save();
|
||||
}
|
||||
if (passphraseController.text.isNotEmpty) {
|
||||
if (_passphraseFormKey.currentState != null &&
|
||||
!_passphraseFormKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
if (_passphraseFormKey.currentState != null &&
|
||||
!_passphraseFormKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
widget.seedTypeViewModel.setPassphrase(passphraseController.text);
|
||||
|
||||
@@ -93,8 +93,10 @@ class _NodeCreateOrEditPageState extends State<NodeCreateOrEditPage> {
|
||||
ModalTopBar(
|
||||
title: widget.editingNode != null ? S.current.edit_node : S.current.node_new,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
trailingIcon: Icon(Icons.check),
|
||||
trailingSemanticLabel: S.current.save,
|
||||
onTrailingPressed: () async {
|
||||
if (_nodeFormKey.currentState != null && !_nodeFormKey.currentState!.validate()) {
|
||||
return;
|
||||
|
||||
@@ -24,6 +24,7 @@ class NodeSharePage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).share,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -75,6 +75,7 @@ class _PowNodeCreateOrEditPageState extends State<PowNodeCreateOrEditPage> {
|
||||
ModalTopBar(
|
||||
title: widget.editingNode != null ? S.current.edit_node : S.current.node_new,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
trailingIcon: CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/scan.svg",
|
||||
@@ -83,6 +84,7 @@ class _PowNodeCreateOrEditPageState extends State<PowNodeCreateOrEditPage> {
|
||||
colorFilter:
|
||||
ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn),
|
||||
),
|
||||
trailingSemanticLabel: S.current.scan,
|
||||
onTrailingPressed: () =>
|
||||
widget.nodeCreateOrEditViewModel.scanQRCodeForNewNode(context),
|
||||
),
|
||||
|
||||
@@ -22,6 +22,7 @@ class AddressListPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.of(context).accounts_subaddresses,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -114,6 +114,7 @@ class _RescanPageState extends State<RescanPage> {
|
||||
? S.current.silent_payments_scanning
|
||||
: S.current.rescan,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
|
||||
@@ -34,6 +34,7 @@ class ConnectionSyncPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop()),
|
||||
header: ModalHeader(
|
||||
iconPath: "assets/new-ui/settings_row_icons/connections.svg",
|
||||
|
||||
@@ -35,6 +35,7 @@ class DisplaySettingsPage extends StatelessWidget {
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).display,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
content: Column(
|
||||
|
||||
@@ -40,6 +40,7 @@ class _ManageNodesPageState extends State<ManageNodesPage> {
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).manage_nodes,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
trailingWidget: Row(
|
||||
spacing: 8,
|
||||
@@ -50,11 +51,13 @@ class _ManageNodesPageState extends State<ManageNodesPage> {
|
||||
icon: widget.nodeListViewModel.isTestingNodeSpeed
|
||||
? CupertinoActivityIndicator()
|
||||
: Icon(Icons.refresh),
|
||||
semanticLabel: S.of(context).test_node_speeds,
|
||||
onPressed: () => widget.nodeListViewModel.speedTestNodes()),
|
||||
),
|
||||
ModernButton(
|
||||
size: 36,
|
||||
icon: Icon(Icons.add),
|
||||
semanticLabel: S.of(context).add_new_node,
|
||||
onPressed: () async {
|
||||
final res = await Navigator.of(context)
|
||||
.pushNamed(widget.isPow ? Routes.newPowNode : Routes.newNode);
|
||||
|
||||
@@ -34,6 +34,7 @@ class _MwebNodePageState extends State<MwebNodePage> {
|
||||
topBar: ModalTopBar(
|
||||
title: S.current.litecoin_mweb_settings,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new)),
|
||||
content: Container(
|
||||
child: NewListSections(controllers: {
|
||||
|
||||
@@ -42,6 +42,7 @@ class OtherSettingsPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).other,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
// header: ModalHeader(
|
||||
|
||||
@@ -26,6 +26,7 @@ class PrivacyPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
header: ModalHeader(
|
||||
|
||||
@@ -45,6 +45,7 @@ class SecurityBackupPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop()),
|
||||
header: ModalHeader(
|
||||
iconPath: "assets/new-ui/settings_row_icons/security.svg",
|
||||
|
||||
@@ -22,6 +22,7 @@ class SilentPaymentsSettingsPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.current.silent_payments_settings,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -144,6 +144,7 @@ class _TOTPEnterCodeState extends State<TOTPEnterCode> {
|
||||
ModalTopBar(
|
||||
title: widget.isForSetup ? S.current.setup_2fa : S.current.verify_with_2fa,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -22,6 +22,7 @@ class SupportChatPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.current.settings_support,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop),
|
||||
FutureBuilder<String>(
|
||||
future: getCookie(),
|
||||
|
||||
@@ -131,6 +131,7 @@ class WalletConnectConnectionsView extends StatelessWidget {
|
||||
size: 40,
|
||||
onPressed: () => Navigator.of(context).maybePop(),
|
||||
icon: Icon(Icons.arrow_back_ios_new, size: 16),
|
||||
semanticLabel: S.of(context).seed_alert_back,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -20,6 +20,7 @@ class AddPassphraseBottomSheet extends StatefulWidget {
|
||||
class _AddPassphraseBottomSheetState extends State<AddPassphraseBottomSheet> {
|
||||
late final TextEditingController passphraseController;
|
||||
late final TextEditingController confirmPassphraseController;
|
||||
final _passphraseFormKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -112,51 +113,60 @@ class _AddPassphraseBottomSheetState extends State<AddPassphraseBottomSheet> {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
BaseTextFormField(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_passphrase_textfield_key'),
|
||||
controller: passphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12),
|
||||
hintText: S.of(context).required_passphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
obscurePassphrase ? Icons.visibility_off : Icons.visibility,
|
||||
size: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
BaseTextFormField(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_confirm_passphrase_textfield_key'),
|
||||
controller: confirmPassphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12),
|
||||
hintText: S.of(context).confirm_passphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
obscurePassphrase ? Icons.visibility_off : Icons.visibility,
|
||||
size: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
validator: (text) {
|
||||
if (text == passphraseController.text) {
|
||||
return null;
|
||||
}
|
||||
Form(
|
||||
key: _passphraseFormKey,
|
||||
child: Column(
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_passphrase_textfield_key'),
|
||||
controller: passphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12),
|
||||
hintText: S.of(context).required_passphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
obscurePassphrase ? Icons.visibility_off : Icons.visibility,
|
||||
size: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
BaseTextFormField(
|
||||
key: ValueKey(
|
||||
'add_passphrase_bottom_sheet_widget_confirm_passphrase_textfield_key',
|
||||
),
|
||||
controller: confirmPassphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12),
|
||||
hintText: S.of(context).confirm_passphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
obscurePassphrase ? Icons.visibility_off : Icons.visibility,
|
||||
size: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
validator: (text) {
|
||||
if (text == passphraseController.text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return S.of(context).passphrases_doesnt_match;
|
||||
},
|
||||
return S.of(context).passphrases_doesnt_match;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Padding(
|
||||
@@ -184,6 +194,11 @@ class _AddPassphraseBottomSheetState extends State<AddPassphraseBottomSheet> {
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_restore_button_key'),
|
||||
onPressed: () {
|
||||
if (_passphraseFormKey.currentState != null &&
|
||||
!_passphraseFormKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
widget.onRestoreButtonPressed(passphraseController.text);
|
||||
},
|
||||
|
||||
@@ -918,6 +918,7 @@
|
||||
"return_address_desc": "In the rare case of a failed swap, our partners can automatically refund your payment to the provided refund address.",
|
||||
"return_address_desc_external": "Since you chose Send From External, please set a refund address manually below.",
|
||||
"robinhood_option_description": "Buy and transfer instantly using your debit card, bank account, or Robinhood balance. USA only.",
|
||||
"rotate_address": "Get new address",
|
||||
"router_no_route": "No route defined for ${name}",
|
||||
"salary": "Salary",
|
||||
"save": "Save",
|
||||
@@ -1147,10 +1148,13 @@
|
||||
"swap_id": "Swap ID",
|
||||
"swap_provider_initial_desc": "Select the type of swap provider you prefer to use when swapping in",
|
||||
"swap_providers": "Swap providers",
|
||||
"swap_reverse_direction": "Reverse swap direction",
|
||||
"sweeping_wallet": "Sweeping wallet",
|
||||
"sweeping_wallet_alert": "This shouldn’t take long. DO NOT LEAVE THIS SCREEN OR THE SWEPT FUNDS MAY BE LOST.",
|
||||
"swipe_to_bridge": "Swipe to bridge",
|
||||
"swipe_to_send": "Swipe to send",
|
||||
"switch_camera": "Switch camera",
|
||||
"switch_input_currency": "Switch between crypto and fiat entry",
|
||||
"switch_wallet": "Switch Wallet",
|
||||
"switchToETHWallet": "Please switch to an Ethereum wallet and try again",
|
||||
"switchToWCCompatibleWallet": "Please switch to a WalletConnect compatible wallet and try again (${chains}).",
|
||||
@@ -1187,6 +1191,7 @@
|
||||
"tap_to_copy": "Tap to copy",
|
||||
"template": "Template",
|
||||
"template_name": "Template Name",
|
||||
"test_node_speeds": "Test node speeds",
|
||||
"testnet_coins_no_value": "Testnet coins have no value",
|
||||
"third_intro_content": "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!",
|
||||
"third_intro_title": "Yat plays nicely with others",
|
||||
@@ -1285,6 +1290,8 @@
|
||||
"trusted": "Trusted",
|
||||
"try_again": "Try again",
|
||||
"trying_to_spend_locked_funds": "Transaction rejected because you are trying to spend funds that have relative time lock, please wait and try again later, or disable the locked funds from coin control",
|
||||
"turn_flash_off": "Turn flash off",
|
||||
"turn_flash_on": "Turn flash on",
|
||||
"tx_commit_exception_no_dust_on_change": "The transaction is rejected with this amount. With these coins you can send ${min} without change or ${max} that returns change.",
|
||||
"tx_commit_failed": "Transaction commit failed. Please contact support.",
|
||||
"tx_commit_failed_no_peers": "Transaction failed to broadcast, please try again in a second",
|
||||
|
||||
Reference in New Issue
Block a user