mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-18 05:51:34 +02:00
Cw 453 (#1306)
* feat: rebase btc-addr-types, migrate to bitcoin_base * feat: allow scanning elect-rs using get_tweaks * feat: scanning and adding addresses working with getTweaks, add btc SP address type * chore: pubspec.lock * chore: pubspec.lock * fix: scan when switching, fix multiple unspents in same tx * fix: initial scan * fix: initial scan * fix: scanning issues * fix: sync, storing silent unspents * chore: deps * fix: label issues, clear spent utxo * chore: deps * fix: build * fix: missing types * feat: new electrs API & changes, fixes for last block scanning * feat: Scan Silent Payments homepage toggle * chore: build configure * feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes * fix: invalid Object in sendData * feat: improve addresses page & address book displays * feat: silent payments labeled addresses disclaimer * fix: missing i18n * chore: print * feat: single block scan, rescan by date working for btc mainnet * feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert * feat: delete silent addresses * fix: red dot in non ssl nodes * fix: inconsistent connection states, fix tx history * fix: tx & balance displays, cpfp sending * feat: new rust lib * chore: node path * fix: check node based on network * fix: missing txcount from addresses * style: padding in feature page cards * fix: restore not getting all wallet addresses by type * fix: auto switch node broken * fix: silent payment txs not being restored * feat: change scanning to subscription model, sync improvements * fix: scan re-subscription * fix: default nodes * fix: improve scanning by date, fix single block scan * refactor: common function for input tx selection * fix: nodes & build * fix: send all with multiple outs * refactor: unchanged file * Update pr_test_build.yml * chore: upgrade * chore: merge changes * refactor: unchanged files [skip ci] * fix: scan fixes, add date, allow sending while scanning * feat: sync fixes, sp settings * feat: fix resyncing * fix: date from height logic, status disconnected & chain tip get * fix: params * feat: electrum migration if using cake electrum * fix nodes update versions * re-enable tron * update sp_scanner to work on iOS [skip ci] * fix: wrong socket for old electrum nodes * Fix unchecked wallet type call * fix: double balance * feat: node domain * fix: menu name * fix: update tip on set scanning * fix: connection switching back and forth * feat: check if node is electrs, and supports sp * chore: fix build * minor enhancements * fixes and enhancements * solve conflicts with main * fix: status toggle * minor enhancement * Monero.com fixes * update sp_scanner to include windows and linux --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/main_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/cake_features_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/services_updates_widget.dart';
|
||||
@@ -12,7 +12,7 @@ import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||
@@ -330,10 +330,10 @@ class _DashboardPageView extends BasePage {
|
||||
if (dashboardViewModel.shouldShowMarketPlaceInDashboard) {
|
||||
pages.add(
|
||||
Semantics(
|
||||
label: S.of(context).market_place,
|
||||
child: MarketPlacePage(
|
||||
label: 'Cake ${S.of(context).features}',
|
||||
child: CakeFeaturesPage(
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||
cakeFeaturesViewModel: getIt.get<CakeFeaturesViewModel>(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/main_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/cake_features_page.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
@@ -74,9 +74,9 @@ class DesktopDashboardActions extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: MarketPlacePage(
|
||||
child: CakeFeaturesPage(
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||
cakeFeaturesViewModel: getIt.get<CakeFeaturesViewModel>(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -30,6 +30,7 @@ class DesktopWalletSelectionDropDown extends StatefulWidget {
|
||||
class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
|
||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
||||
@@ -68,8 +69,11 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 500),
|
||||
child: DropDownItemWidget(
|
||||
title: wallet.name,
|
||||
image: wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon),
|
||||
title: wallet.name,
|
||||
image: wallet.isEnabled
|
||||
? _imageFor(type: wallet.type, isTestnet: wallet.isTestnet)
|
||||
: nonWalletTypeIcon,
|
||||
),
|
||||
),
|
||||
onSelected: () => _onSelectedWallet(wallet),
|
||||
))
|
||||
@@ -120,16 +124,16 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_wallet_alert_title,
|
||||
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
|
||||
actionRightButton: () => Navigator.of(dialogContext).pop(true));
|
||||
}) ??
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_wallet_alert_title,
|
||||
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
|
||||
actionRightButton: () => Navigator.of(dialogContext).pop(true));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
@@ -138,9 +142,12 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
});
|
||||
}
|
||||
|
||||
Image _imageFor({required WalletType type}) {
|
||||
Image _imageFor({required WalletType type, bool? isTestnet}) {
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
if (isTestnet == true) {
|
||||
return tBitcoinIcon;
|
||||
}
|
||||
return bitcoinIcon;
|
||||
case WalletType.monero:
|
||||
return moneroIcon;
|
||||
@@ -160,7 +167,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
return polygonIcon;
|
||||
case WalletType.solana:
|
||||
return solanaIcon;
|
||||
case WalletType.tron:
|
||||
case WalletType.tron:
|
||||
return tronIcon;
|
||||
default:
|
||||
return nonWalletTypeIcon;
|
||||
@@ -168,24 +175,25 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
}
|
||||
|
||||
Future<void> _loadWallet(WalletListItem wallet) async {
|
||||
widget._authService.authenticateAction(context,
|
||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
widget._authService.authenticateAction(
|
||||
context,
|
||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (context.mounted) {
|
||||
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
|
||||
try {
|
||||
if (context.mounted) {
|
||||
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
|
||||
}
|
||||
await widget.walletListViewModel.loadWallet(wallet);
|
||||
hideProgressText();
|
||||
setState(() {});
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
||||
}
|
||||
}
|
||||
await widget.walletListViewModel.loadWallet(wallet);
|
||||
hideProgressText();
|
||||
setState(() {});
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
||||
}
|
||||
}
|
||||
},
|
||||
conditionToDetermineIfToUse2FA:
|
||||
widget.walletListViewModel.shouldRequireTOTP2FAForAccessingWallet,
|
||||
@@ -198,17 +206,16 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
context,
|
||||
route: Routes.newWallet,
|
||||
arguments: widget.walletListViewModel.currentWalletType,
|
||||
conditionToDetermineIfToUse2FA: widget
|
||||
.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||
conditionToDetermineIfToUse2FA:
|
||||
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||
);
|
||||
} else {
|
||||
widget._authService.authenticateAction(
|
||||
context,
|
||||
route: Routes.newWalletType,
|
||||
conditionToDetermineIfToUse2FA: widget
|
||||
.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||
conditionToDetermineIfToUse2FA:
|
||||
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,11 @@ class AddressPage extends BasePage {
|
||||
}
|
||||
|
||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
||||
if (bitcoin!.isBitcoinReceivePageOption(option)) {
|
||||
addressListViewModel.setAddressType(bitcoin!.getOptionToType(option));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (option) {
|
||||
case ReceivePageOption.anonPayInvoice:
|
||||
Navigator.pushNamed(
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
@@ -21,6 +24,7 @@ import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class BalancePage extends StatelessWidget {
|
||||
BalancePage({
|
||||
@@ -221,30 +225,136 @@ class CryptoBalanceWidget extends StatelessWidget {
|
||||
itemBuilder: (__, index) {
|
||||
final balance =
|
||||
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
|
||||
return BalanceRowWidget(
|
||||
availableBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
|
||||
availableBalance: balance.availableBalance,
|
||||
availableFiatBalance: balance.fiatAvailableBalance,
|
||||
additionalBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
|
||||
additionalBalance: balance.additionalBalance,
|
||||
additionalFiatBalance: balance.fiatAdditionalBalance,
|
||||
frozenBalance: balance.frozenBalance,
|
||||
frozenFiatBalance: balance.fiatFrozenBalance,
|
||||
currency: balance.asset,
|
||||
hasAdditionalBalance:
|
||||
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
|
||||
);
|
||||
return Observer(builder: (_) {
|
||||
return BalanceRowWidget(
|
||||
availableBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
|
||||
availableBalance: balance.availableBalance,
|
||||
availableFiatBalance: balance.fiatAvailableBalance,
|
||||
additionalBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
|
||||
additionalBalance: balance.additionalBalance,
|
||||
additionalFiatBalance: balance.fiatAdditionalBalance,
|
||||
frozenBalance: balance.frozenBalance,
|
||||
frozenFiatBalance: balance.fiatFrozenBalance,
|
||||
currency: balance.asset,
|
||||
hasAdditionalBalance:
|
||||
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
|
||||
isTestnet: dashboardViewModel.isTestnet,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
),
|
||||
Observer(builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
if (dashboardViewModel.showSilentPaymentsCard) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: S.of(context).silent_payments,
|
||||
subTitle: S.of(context).enable_silent_payments_scanning,
|
||||
hint: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => launchUrl(
|
||||
Uri.parse(
|
||||
"https://guides.cakewallet.com/docs/cryptos/bitcoin/#silent-payments"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).what_is_silent_payments,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
softWrap: true,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => StandardSwitch(
|
||||
value: dashboardViewModel.silentPaymentsScanningActive,
|
||||
onTaped: () => _toggleSilentPaymentsScanning(context),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => _toggleSilentPaymentsScanning(context),
|
||||
icon: Icon(
|
||||
Icons.lock,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
size: 50,
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
|
||||
final isSilentPaymentsScanningActive = dashboardViewModel.silentPaymentsScanningActive;
|
||||
final newValue = !isSilentPaymentsScanningActive;
|
||||
|
||||
dashboardViewModel.silentPaymentsScanningActive = newValue;
|
||||
|
||||
final needsToSwitch = !isSilentPaymentsScanningActive &&
|
||||
await bitcoin!.getNodeIsElectrsSPEnabled(dashboardViewModel.wallet) == false;
|
||||
|
||||
if (needsToSwitch) {
|
||||
return showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_current_node_title,
|
||||
alertContent: S.of(context).confirm_silent_payments_switch_node,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
dashboardViewModel.setSilentPaymentsScanning(newValue);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
actionLeftButton: () {
|
||||
dashboardViewModel.silentPaymentsScanningActive = isSilentPaymentsScanningActive;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
return dashboardViewModel.setSilentPaymentsScanning(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
class BalanceRowWidget extends StatelessWidget {
|
||||
@@ -259,6 +369,7 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
required this.frozenFiatBalance,
|
||||
required this.currency,
|
||||
required this.hasAdditionalBalance,
|
||||
required this.isTestnet,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -272,6 +383,7 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
final String frozenFiatBalance;
|
||||
final CryptoCurrency currency;
|
||||
final bool hasAdditionalBalance;
|
||||
final bool isTestnet;
|
||||
|
||||
// void _showBalanceDescription(BuildContext context) {
|
||||
// showPopUp<void>(
|
||||
@@ -346,14 +458,24 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.start),
|
||||
SizedBox(height: 6),
|
||||
Text('${availableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1)),
|
||||
if (isTestnet)
|
||||
Text(S.current.testnet_coins_no_value,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1)),
|
||||
if (!isTestnet)
|
||||
Text('${availableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -362,27 +484,23 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(shape: BoxShape.circle),
|
||||
child: CakeImageWidget(
|
||||
imageUrl: currency.iconPath,
|
||||
height: 40,
|
||||
width: 40,
|
||||
displayOnError: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
currency.title.substring(0, min(currency.title.length, 2)),
|
||||
style: TextStyle(fontSize: 11),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.grey.shade400,
|
||||
CakeImageWidget(
|
||||
imageUrl: currency.iconPath,
|
||||
height: 40,
|
||||
width: 40,
|
||||
displayOnError: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
currency.title.substring(0, min(currency.title.length, 2)),
|
||||
style: TextStyle(fontSize: 11),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
@@ -449,17 +567,18 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
frozenFiatBalance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
frozenFiatBalance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -493,17 +612,18 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'${additionalFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${additionalFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
+18
-44
@@ -1,23 +1,20 @@
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class MarketPlacePage extends StatelessWidget {
|
||||
MarketPlacePage({
|
||||
class CakeFeaturesPage extends StatelessWidget {
|
||||
CakeFeaturesPage({
|
||||
required this.dashboardViewModel,
|
||||
required this.marketPlaceViewModel,
|
||||
required this.cakeFeaturesViewModel,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final MarketPlaceViewModel marketPlaceViewModel;
|
||||
final CakeFeaturesViewModel cakeFeaturesViewModel;
|
||||
final _scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
@@ -37,7 +34,7 @@ class MarketPlacePage extends StatelessWidget {
|
||||
children: [
|
||||
SizedBox(height: 50),
|
||||
Text(
|
||||
S.of(context).market_place,
|
||||
'Cake ${S.of(context).features}',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -59,15 +56,21 @@ class MarketPlacePage extends StatelessWidget {
|
||||
// ),
|
||||
SizedBox(height: 20),
|
||||
DashBoardRoundedCardWidget(
|
||||
onTap: () => _launchUrl("buy.cakepay.com"),
|
||||
title: S.of(context).cake_pay_web_cards_title,
|
||||
subTitle: S.of(context).cake_pay_web_cards_subtitle,
|
||||
onTap: () => _launchMarketPlaceUrl("buy.cakepay.com"),
|
||||
svgPicture: SvgPicture.asset(
|
||||
'assets/images/cards.svg',
|
||||
height: 125,
|
||||
width: 125,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(height: 10),
|
||||
DashBoardRoundedCardWidget(
|
||||
title: "NanoGPT",
|
||||
subTitle: S.of(context).nanogpt_subtitle,
|
||||
onTap: () => _launchMarketPlaceUrl("cake.nano-gpt.com"),
|
||||
onTap: () => _launchUrl("cake.nano-gpt.com"),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -79,41 +82,12 @@ class MarketPlacePage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _launchMarketPlaceUrl(String url) async {
|
||||
void _launchUrl(String url) {
|
||||
try {
|
||||
launchUrl(
|
||||
Uri.https(url),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove ionia flow/files if we will discard it
|
||||
void _navigatorToGiftCardsPage(BuildContext context) {
|
||||
final walletType = dashboardViewModel.type;
|
||||
|
||||
switch (walletType) {
|
||||
case WalletType.haven:
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: S.of(context).gift_cards_unavailable,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
marketPlaceViewModel.isIoniaUserAuthenticated().then((value) {
|
||||
if (value) {
|
||||
Navigator.pushNamed(context, Routes.ioniaManageCardsPage);
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
|
||||
});
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/setting_action_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/setting_actions.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
@@ -180,6 +181,11 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||
|
||||
final item = SettingActions.all[index];
|
||||
|
||||
if (!widget.dashboardViewModel.hasSilentPayments &&
|
||||
item.name(context) == S.of(context).silent_payments_settings) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
final isLastTile = index == itemCount - 1;
|
||||
|
||||
return SettingActionButton(
|
||||
|
||||
@@ -10,8 +10,7 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class PresentReceiveOptionPicker extends StatelessWidget {
|
||||
PresentReceiveOptionPicker(
|
||||
{required this.receiveOptionViewModel, required this.color});
|
||||
PresentReceiveOptionPicker({required this.receiveOptionViewModel, required this.color});
|
||||
|
||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||
final Color color;
|
||||
@@ -43,17 +42,17 @@ class PresentReceiveOptionPicker extends StatelessWidget {
|
||||
Text(
|
||||
S.current.receive,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: color),
|
||||
fontSize: 18.0, fontWeight: FontWeight.bold, fontFamily: 'Lato', color: color),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Text(receiveOptionViewModel.selectedReceiveOption.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: color)))
|
||||
builder: (_) => Text(
|
||||
receiveOptionViewModel.selectedReceiveOption
|
||||
.toString()
|
||||
.replaceAll(RegExp(r'silent payments', caseSensitive: false),
|
||||
S.current.silent_payments)
|
||||
.replaceAll(
|
||||
RegExp(r'default', caseSensitive: false), S.current.string_default),
|
||||
style: TextStyle(fontSize: 10.0, fontWeight: FontWeight.w500, color: color)))
|
||||
],
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
@@ -73,65 +72,75 @@ class PresentReceiveOptionPicker extends StatelessWidget {
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children:[ AlertBackground(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Spacer(),
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 24, bottom: 24),
|
||||
child: (ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: receiveOptionViewModel.options.length,
|
||||
itemBuilder: (_, index) {
|
||||
final option = receiveOptionViewModel.options[index];
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(popUpContext);
|
||||
children: [
|
||||
AlertBackground(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Spacer(),
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 24, bottom: 24),
|
||||
child: (ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: receiveOptionViewModel.options.length,
|
||||
itemBuilder: (_, index) {
|
||||
final option = receiveOptionViewModel.options[index];
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(popUpContext);
|
||||
|
||||
receiveOptionViewModel.selectReceiveOption(option);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 24, right: 24),
|
||||
child: Observer(builder: (_) {
|
||||
final value = receiveOptionViewModel.selectedReceiveOption;
|
||||
receiveOptionViewModel.selectReceiveOption(option);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 24, right: 24),
|
||||
child: Observer(builder: (_) {
|
||||
final value = receiveOptionViewModel.selectedReceiveOption;
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(option.toString(),
|
||||
textAlign: TextAlign.left,
|
||||
style: textSmall(
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
).copyWith(
|
||||
fontWeight:
|
||||
value == option ? FontWeight.w800 : FontWeight.w500,
|
||||
)),
|
||||
RoundedCheckbox(
|
||||
value: value == option,
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, index) => SizedBox(height: 30),
|
||||
)),
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
option
|
||||
.toString()
|
||||
.replaceAll(
|
||||
RegExp(r'silent payments', caseSensitive: false),
|
||||
S.current.silent_payments)
|
||||
.replaceAll(RegExp(r'default', caseSensitive: false),
|
||||
S.current.string_default),
|
||||
textAlign: TextAlign.left,
|
||||
style: textSmall(
|
||||
color: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.titleColor,
|
||||
).copyWith(
|
||||
fontWeight:
|
||||
value == option ? FontWeight.w800 : FontWeight.w500,
|
||||
)),
|
||||
RoundedCheckbox(
|
||||
value: value == option,
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, index) => SizedBox(height: 30),
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer()
|
||||
],
|
||||
Spacer()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
AlertCloseButton(onTap: () => Navigator.of(popUpContext).pop(), bottom: 40)
|
||||
],
|
||||
),
|
||||
|
||||
@@ -67,8 +67,7 @@ class ReceivePage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
(BuildContext context, Widget scaffold) =>
|
||||
GradientBackground(scaffold: scaffold);
|
||||
(BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
@@ -99,115 +98,144 @@ class ReceivePage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: _cryptoAmountFocus,
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
)
|
||||
]),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 50, 24, 24),
|
||||
child: QRWidget(
|
||||
addressListViewModel: addressListViewModel,
|
||||
formKey: _formKey,
|
||||
heroTag: _heroTag,
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||
amountController: _amountController,
|
||||
isLight: currentTheme.type == ThemeType.light),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
padding: EdgeInsets.all(0),
|
||||
separatorBuilder: (context, _) => const HorizontalSectionDivider(),
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: addressListViewModel.items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = addressListViewModel.items[index];
|
||||
Widget cell = Container();
|
||||
|
||||
if (item is WalletAccountListHeader) {
|
||||
cell = HeaderTile(
|
||||
showTrailingButton: true,
|
||||
walletAddressListViewModel: addressListViewModel,
|
||||
trailingButtonTap: () async {
|
||||
if (addressListViewModel.type == WalletType.monero ||
|
||||
addressListViewModel.type == WalletType.haven) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => getIt.get<MoneroAccountListPage>());
|
||||
} else {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => getIt.get<NanoAccountListPage>());
|
||||
}
|
||||
},
|
||||
title: S.of(context).accounts,
|
||||
trailingIcon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
||||
));
|
||||
}
|
||||
|
||||
if (item is WalletAddressListHeader) {
|
||||
cell = HeaderTile(
|
||||
title: S.of(context).addresses,
|
||||
walletAddressListViewModel: addressListViewModel,
|
||||
showTrailingButton: !addressListViewModel.isAutoGenerateSubaddressEnabled,
|
||||
showSearchButton: true,
|
||||
trailingButtonTap: () =>
|
||||
Navigator.of(context).pushNamed(Routes.newSubaddress),
|
||||
trailingIcon: Icon(
|
||||
Icons.add,
|
||||
size: 20,
|
||||
color: Theme.of(context)
|
||||
.extension<ReceivePageTheme>()!
|
||||
.iconsColor,
|
||||
));
|
||||
}
|
||||
|
||||
if (item is WalletAddressListItem) {
|
||||
cell = Observer(builder: (_) {
|
||||
final isCurrent =
|
||||
item.address == addressListViewModel.address.address;
|
||||
final backgroundColor = isCurrent
|
||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileBackgroundColor
|
||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesBackgroundColor;
|
||||
final textColor = isCurrent
|
||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileTextColor
|
||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;
|
||||
|
||||
return AddressCell.fromItem(item,
|
||||
isCurrent: isCurrent,
|
||||
hasBalance: addressListViewModel.isElectrumWallet,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
onTap: (_) => addressListViewModel.setAddress(item),
|
||||
onEdit: () => Navigator.of(context)
|
||||
.pushNamed(Routes.newSubaddress, arguments: item));
|
||||
});
|
||||
}
|
||||
|
||||
return index != 0
|
||||
? cell
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(30),
|
||||
topRight: Radius.circular(30)),
|
||||
child: cell,
|
||||
);
|
||||
})),
|
||||
],
|
||||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: _cryptoAmountFocus,
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
)
|
||||
]),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 50, 24, 24),
|
||||
child: QRWidget(
|
||||
addressListViewModel: addressListViewModel,
|
||||
formKey: _formKey,
|
||||
heroTag: _heroTag,
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||
amountController: _amountController,
|
||||
isLight: currentTheme.type == ThemeType.light),
|
||||
),
|
||||
));
|
||||
Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
padding: EdgeInsets.all(0),
|
||||
separatorBuilder: (context, _) => const HorizontalSectionDivider(),
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: addressListViewModel.items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = addressListViewModel.items[index];
|
||||
Widget cell = Container();
|
||||
|
||||
if (item is WalletAccountListHeader) {
|
||||
cell = HeaderTile(
|
||||
showTrailingButton: true,
|
||||
walletAddressListViewModel: addressListViewModel,
|
||||
trailingButtonTap: () async {
|
||||
if (addressListViewModel.type == WalletType.monero ||
|
||||
addressListViewModel.type == WalletType.haven) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => getIt.get<MoneroAccountListPage>());
|
||||
} else {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => getIt.get<NanoAccountListPage>());
|
||||
}
|
||||
},
|
||||
title: S.of(context).accounts,
|
||||
trailingIcon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
||||
));
|
||||
}
|
||||
|
||||
if (item is WalletAddressListHeader) {
|
||||
final hasTitle = item.title != null;
|
||||
|
||||
cell = HeaderTile(
|
||||
title: hasTitle ? item.title! : S.of(context).addresses,
|
||||
walletAddressListViewModel: addressListViewModel,
|
||||
showTrailingButton:
|
||||
!addressListViewModel.isAutoGenerateSubaddressEnabled && !hasTitle,
|
||||
showSearchButton: true,
|
||||
trailingButtonTap: () =>
|
||||
Navigator.of(context).pushNamed(Routes.newSubaddress),
|
||||
trailingIcon: hasTitle
|
||||
? null
|
||||
: Icon(
|
||||
Icons.add,
|
||||
size: 20,
|
||||
color:
|
||||
Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (item is WalletAddressListItem) {
|
||||
cell = Observer(builder: (_) {
|
||||
final isCurrent = item.address == addressListViewModel.address.address;
|
||||
final backgroundColor = isCurrent
|
||||
? Theme.of(context)
|
||||
.extension<ReceivePageTheme>()!
|
||||
.currentTileBackgroundColor
|
||||
: Theme.of(context)
|
||||
.extension<ReceivePageTheme>()!
|
||||
.tilesBackgroundColor;
|
||||
final textColor = isCurrent
|
||||
? Theme.of(context)
|
||||
.extension<ReceivePageTheme>()!
|
||||
.currentTileTextColor
|
||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;
|
||||
|
||||
return AddressCell.fromItem(
|
||||
item,
|
||||
isCurrent: isCurrent,
|
||||
hasBalance: addressListViewModel.isElectrumWallet,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
onTap: item.isOneTimeReceiveAddress == true
|
||||
? null
|
||||
: (_) => addressListViewModel.setAddress(item),
|
||||
onEdit: item.isOneTimeReceiveAddress == true || item.isPrimary
|
||||
? null
|
||||
: () => Navigator.of(context)
|
||||
.pushNamed(Routes.newSubaddress, arguments: item),
|
||||
onDelete: !addressListViewModel.isSilentPayments || item.isPrimary
|
||||
? null
|
||||
: () => addressListViewModel.deleteAddress(item),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return index != 0
|
||||
? cell
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(30), topRight: Radius.circular(30)),
|
||||
child: cell,
|
||||
);
|
||||
})),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Text(
|
||||
addressListViewModel.isSilentPayments
|
||||
? S.of(context).silent_payments_disclaimer
|
||||
: S.of(context).electrum_address_disclaimer,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor)),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,22 @@ class AddressCell extends StatelessWidget {
|
||||
required this.textColor,
|
||||
this.onTap,
|
||||
this.onEdit,
|
||||
this.onDelete,
|
||||
this.txCount,
|
||||
this.balance,
|
||||
this.isChange = false,
|
||||
this.hasBalance = false});
|
||||
|
||||
factory AddressCell.fromItem(WalletAddressListItem item,
|
||||
{required bool isCurrent,
|
||||
required Color backgroundColor,
|
||||
required Color textColor,
|
||||
Function(String)? onTap,
|
||||
bool hasBalance = false,
|
||||
Function()? onEdit}) =>
|
||||
factory AddressCell.fromItem(
|
||||
WalletAddressListItem item, {
|
||||
required bool isCurrent,
|
||||
required Color backgroundColor,
|
||||
required Color textColor,
|
||||
Function(String)? onTap,
|
||||
bool hasBalance = false,
|
||||
Function()? onEdit,
|
||||
Function()? onDelete,
|
||||
}) =>
|
||||
AddressCell(
|
||||
address: item.address,
|
||||
name: item.name ?? '',
|
||||
@@ -36,6 +40,7 @@ class AddressCell extends StatelessWidget {
|
||||
textColor: textColor,
|
||||
onTap: onTap,
|
||||
onEdit: onEdit,
|
||||
onDelete: onDelete,
|
||||
txCount: item.txCount,
|
||||
balance: item.balance,
|
||||
isChange: item.isChange,
|
||||
@@ -49,6 +54,7 @@ class AddressCell extends StatelessWidget {
|
||||
final Color textColor;
|
||||
final Function(String)? onTap;
|
||||
final Function()? onEdit;
|
||||
final Function()? onDelete;
|
||||
final int? txCount;
|
||||
final String? balance;
|
||||
final bool isChange;
|
||||
@@ -64,7 +70,8 @@ class AddressCell extends StatelessWidget {
|
||||
} else {
|
||||
return formatIfCashAddr.substring(0, addressPreviewLength) +
|
||||
'...' +
|
||||
formatIfCashAddr.substring(formatIfCashAddr.length - addressPreviewLength, formatIfCashAddr.length);
|
||||
formatIfCashAddr.substring(
|
||||
formatIfCashAddr.length - addressPreviewLength, formatIfCashAddr.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +146,7 @@ class AddressCell extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Text(
|
||||
'Balance: $balance',
|
||||
'${S.of(context).balance}: $balance',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -180,7 +187,7 @@ class AddressCell extends StatelessWidget {
|
||||
|
||||
ActionPane _actionPane(BuildContext context) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: 0.3,
|
||||
extentRatio: onDelete != null ? 0.4 : 0.3,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (_) => onEdit?.call(),
|
||||
@@ -189,6 +196,14 @@ class AddressCell extends StatelessWidget {
|
||||
icon: Icons.edit,
|
||||
label: S.of(context).edit,
|
||||
),
|
||||
if (onDelete != null)
|
||||
SlidableAction(
|
||||
onPressed: (_) => onDelete!.call(),
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: Icons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/view_model/rescan_view_model.dart';
|
||||
@@ -11,7 +15,8 @@ class RescanPage extends BasePage {
|
||||
: _blockchainHeightWidgetKey = GlobalKey<BlockchainHeightState>();
|
||||
|
||||
@override
|
||||
String get title => S.current.rescan;
|
||||
String get title =>
|
||||
_rescanViewModel.isSilentPaymentsScan ? S.current.silent_payments_scanning : S.current.rescan;
|
||||
final GlobalKey<BlockchainHeightState> _blockchainHeightWidgetKey;
|
||||
final RescanViewModel _rescanViewModel;
|
||||
|
||||
@@ -19,20 +24,28 @@ class RescanPage extends BasePage {
|
||||
Widget body(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
child:
|
||||
Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
BlockchainHeightWidget(key: _blockchainHeightWidgetKey,
|
||||
onHeightOrDateEntered: (value) =>
|
||||
_rescanViewModel.isButtonEnabled = value),
|
||||
child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Observer(
|
||||
builder: (_) => BlockchainHeightWidget(
|
||||
key: _blockchainHeightWidgetKey,
|
||||
onHeightOrDateEntered: (value) => _rescanViewModel.isButtonEnabled = value,
|
||||
isSilentPaymentsScan: _rescanViewModel.isSilentPaymentsScan,
|
||||
doSingleScan: _rescanViewModel.doSingleScan,
|
||||
toggleSingleScan: () =>
|
||||
_rescanViewModel.doSingleScan = !_rescanViewModel.doSingleScan,
|
||||
)),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
isLoading:
|
||||
_rescanViewModel.state == RescanWalletState.rescaning,
|
||||
isLoading: _rescanViewModel.state == RescanWalletState.rescaning,
|
||||
text: S.of(context).rescan,
|
||||
onPressed: () async {
|
||||
await _rescanViewModel.rescanCurrentWallet(
|
||||
restoreHeight:
|
||||
_blockchainHeightWidgetKey.currentState!.height);
|
||||
if (_rescanViewModel.isSilentPaymentsScan) {
|
||||
return _toggleSilentPaymentsScanning(context);
|
||||
}
|
||||
|
||||
_rescanViewModel.rescanCurrentWallet(
|
||||
restoreHeight: _blockchainHeightWidgetKey.currentState!.height);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
color: Theme.of(context).primaryColor,
|
||||
@@ -42,4 +55,32 @@ class RescanPage extends BasePage {
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
|
||||
final height = _blockchainHeightWidgetKey.currentState!.height;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
|
||||
final needsToSwitch =
|
||||
await bitcoin!.getNodeIsElectrsSPEnabled(_rescanViewModel.wallet) == false;
|
||||
|
||||
if (needsToSwitch) {
|
||||
return showPopUp<void>(
|
||||
context: navigatorKey.currentState!.context,
|
||||
builder: (BuildContext _dialogContext) => AlertWithTwoActions(
|
||||
alertTitle: S.of(_dialogContext).change_current_node_title,
|
||||
alertContent: S.of(_dialogContext).confirm_silent_payments_switch_node,
|
||||
rightButtonText: S.of(_dialogContext).ok,
|
||||
leftButtonText: S.of(_dialogContext).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(_dialogContext).pop();
|
||||
|
||||
_rescanViewModel.rescanCurrentWallet(restoreHeight: height);
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(_dialogContext).pop(),
|
||||
));
|
||||
}
|
||||
|
||||
_rescanViewModel.rescanCurrentWallet(restoreHeight: height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
@@ -420,6 +421,10 @@ class SendPage extends BasePage {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendViewModel.isElectrumWallet) {
|
||||
bitcoin!.updateFeeRates(sendViewModel.wallet);
|
||||
}
|
||||
|
||||
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||
if (dialogContext != null && dialogContext?.mounted == true) {
|
||||
Navigator.of(dialogContext!).pop();
|
||||
|
||||
@@ -39,7 +39,9 @@ class ConnectionSyncPage extends BasePage {
|
||||
),
|
||||
if (dashboardViewModel.hasRescan) ...[
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.rescan,
|
||||
title: dashboardViewModel.hasSilentPayments
|
||||
? S.current.silent_payments_scanning
|
||||
: S.current.rescan,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
),
|
||||
if (DeviceInfo.instance.isMobile && FeatureFlag.isBackgroundSyncEnabled) ...[
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/view_model/settings/silent_payments_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class SilentPaymentsSettingsPage extends BasePage {
|
||||
SilentPaymentsSettingsPage(this._silentPaymentsSettingsViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.silent_payments_settings;
|
||||
|
||||
final SilentPaymentsSettingsViewModel _silentPaymentsSettingsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Observer(builder: (_) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.silent_payments_display_card,
|
||||
value: _silentPaymentsSettingsViewModel.silentPaymentsCardDisplay,
|
||||
onValueChange: (_, bool value) {
|
||||
_silentPaymentsSettingsViewModel.setSilentPaymentsCardDisplay(value);
|
||||
},
|
||||
),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.silent_payments_always_scan,
|
||||
value: _silentPaymentsSettingsViewModel.silentPaymentsAlwaysScan,
|
||||
onValueChange: (_, bool value) {
|
||||
_silentPaymentsSettingsViewModel.setSilentPaymentsAlwaysScan(value);
|
||||
},
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.silent_payments_scanning,
|
||||
handler: (BuildContext context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@ class UnspentCoinsListFormState extends State<UnspentCoinsListForm> {
|
||||
isSending: item.isSending,
|
||||
isFrozen: item.isFrozen,
|
||||
isChange: item.isChange,
|
||||
isSilentPayment: item.isSilentPayment,
|
||||
onCheckBoxTap: item.isFrozen
|
||||
? null
|
||||
: () async {
|
||||
|
||||
@@ -12,6 +12,7 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||
required this.isSending,
|
||||
required this.isFrozen,
|
||||
required this.isChange,
|
||||
required this.isSilentPayment,
|
||||
this.onCheckBoxTap,
|
||||
});
|
||||
|
||||
@@ -21,18 +22,16 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||
final bool isSending;
|
||||
final bool isFrozen;
|
||||
final bool isChange;
|
||||
final bool isSilentPayment;
|
||||
final Function()? onCheckBoxTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final unselectedItemColor = Theme.of(context).cardColor;
|
||||
final selectedItemColor = Theme.of(context).primaryColor;
|
||||
final itemColor = isSending
|
||||
? selectedItemColor
|
||||
: unselectedItemColor;
|
||||
final amountColor = isSending
|
||||
? Colors.white
|
||||
: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor;
|
||||
final itemColor = isSending ? selectedItemColor : unselectedItemColor;
|
||||
final amountColor =
|
||||
isSending ? Colors.white : Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor;
|
||||
final addressColor = isSending
|
||||
? Colors.white.withOpacity(0.5)
|
||||
: Theme.of(context).extension<CakeTextTheme>()!.buttonSecondaryTextColor;
|
||||
@@ -121,6 +120,23 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isSilentPayment)
|
||||
Container(
|
||||
height: 17,
|
||||
padding: EdgeInsets.only(left: 6, right: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.5)),
|
||||
color: Colors.white),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
S.of(context).silent_payments,
|
||||
style: TextStyle(
|
||||
color: itemColor,
|
||||
fontSize: 7,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -96,6 +96,7 @@ class WalletListBody extends StatefulWidget {
|
||||
class WalletListBodyState extends State<WalletListBody> {
|
||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||
@@ -162,7 +163,10 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
wallet.isEnabled
|
||||
? _imageFor(type: wallet.type)
|
||||
? _imageFor(
|
||||
type: wallet.type,
|
||||
isTestnet: wallet.isTestnet,
|
||||
)
|
||||
: nonWalletTypeIcon,
|
||||
SizedBox(width: 10),
|
||||
Flexible(
|
||||
@@ -297,9 +301,12 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||
);
|
||||
}
|
||||
|
||||
Image _imageFor({required WalletType type}) {
|
||||
Image _imageFor({required WalletType type, bool? isTestnet}) {
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
if (isTestnet == true) {
|
||||
return tBitcoinIcon;
|
||||
}
|
||||
return bitcoinIcon;
|
||||
case WalletType.monero:
|
||||
return moneroIcon;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/utils/date_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -12,13 +14,19 @@ class BlockchainHeightWidget extends StatefulWidget {
|
||||
this.onHeightChange,
|
||||
this.focusNode,
|
||||
this.onHeightOrDateEntered,
|
||||
this.hasDatePicker = true})
|
||||
: super(key: key);
|
||||
this.hasDatePicker = true,
|
||||
this.isSilentPaymentsScan = false,
|
||||
this.toggleSingleScan,
|
||||
this.doSingleScan = false,
|
||||
}) : super(key: key);
|
||||
|
||||
final Function(int)? onHeightChange;
|
||||
final Function(bool)? onHeightOrDateEntered;
|
||||
final FocusNode? focusNode;
|
||||
final bool hasDatePicker;
|
||||
final bool isSilentPaymentsScan;
|
||||
final bool doSingleScan;
|
||||
final Function()? toggleSingleScan;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => BlockchainHeightState();
|
||||
@@ -64,9 +72,10 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||
child: BaseTextFormField(
|
||||
focusNode: widget.focusNode,
|
||||
controller: restoreHeightController,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
hintText: S.of(context).widgets_restore_from_blockheight,
|
||||
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
|
||||
hintText: widget.isSilentPaymentsScan
|
||||
? S.of(context).silent_payments_scan_from_height
|
||||
: S.of(context).widgets_restore_from_blockheight,
|
||||
)))
|
||||
],
|
||||
),
|
||||
@@ -78,8 +87,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
@@ -91,22 +99,47 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||
child: IgnorePointer(
|
||||
child: BaseTextFormField(
|
||||
controller: dateController,
|
||||
hintText: S.of(context).widgets_restore_from_date,
|
||||
hintText: widget.isSilentPaymentsScan
|
||||
? S.of(context).silent_payments_scan_from_date
|
||||
: S.of(context).widgets_restore_from_date,
|
||||
)),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
if (widget.isSilentPaymentsScan)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).scan_one_block,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: StandardSwitch(
|
||||
value: widget.doSingleScan,
|
||||
onTaped: () => widget.toggleSingleScan?.call(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
|
||||
child: Text(
|
||||
S.of(context).restore_from_date_or_blockheight,
|
||||
widget.isSilentPaymentsScan
|
||||
? S.of(context).silent_payments_scan_from_date_or_blockheight
|
||||
: S.of(context).restore_from_date_or_blockheight,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).hintColor
|
||||
),
|
||||
fontSize: 12, fontWeight: FontWeight.normal, color: Theme.of(context).hintColor),
|
||||
),
|
||||
)
|
||||
]
|
||||
@@ -123,7 +156,12 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||
lastDate: now);
|
||||
|
||||
if (date != null) {
|
||||
final height = monero!.getHeightByDate(date: date);
|
||||
int height;
|
||||
if (widget.isSilentPaymentsScan) {
|
||||
height = bitcoin!.getHeightByDate(date: date);
|
||||
} else {
|
||||
height = monero!.getHeightByDate(date: date);
|
||||
}
|
||||
setState(() {
|
||||
dateController.text = DateFormat('yyyy-MM-dd').format(date);
|
||||
restoreHeightController.text = '$height';
|
||||
|
||||
@@ -2,19 +2,28 @@ import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
DashBoardRoundedCardWidget({
|
||||
required this.onTap,
|
||||
required this.title,
|
||||
required this.subTitle,
|
||||
this.hint,
|
||||
this.svgPicture,
|
||||
this.icon,
|
||||
this.onClose,
|
||||
this.customBorder,
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback? onClose;
|
||||
final String title;
|
||||
final String subTitle;
|
||||
final Widget? hint;
|
||||
final SvgPicture? svgPicture;
|
||||
final Icon? icon;
|
||||
final double? customBorder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -26,34 +35,56 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(20, 20, 40, 20),
|
||||
padding: EdgeInsets.all(20),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
borderRadius: BorderRadius.circular(customBorder ?? 20),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
softWrap: true,
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
subTitle,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.cardTextColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato'),
|
||||
softWrap: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (svgPicture != null) svgPicture!,
|
||||
if (icon != null) icon!
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
subTitle,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato'),
|
||||
)
|
||||
if (hint != null) ...[
|
||||
SizedBox(height: 10),
|
||||
hint!,
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -17,6 +17,7 @@ class SettingActions {
|
||||
connectionSettingAction,
|
||||
walletSettingAction,
|
||||
addressBookSettingAction,
|
||||
silentPaymentsSettingAction,
|
||||
securityBackupSettingAction,
|
||||
privacySettingAction,
|
||||
displaySettingAction,
|
||||
@@ -35,6 +36,15 @@ class SettingActions {
|
||||
supportSettingAction,
|
||||
];
|
||||
|
||||
static SettingActions silentPaymentsSettingAction = SettingActions._(
|
||||
name: (context) => S.of(context).silent_payments_settings,
|
||||
image: 'assets/images/bitcoin_menu.png',
|
||||
onTap: (BuildContext context) {
|
||||
Navigator.pop(context);
|
||||
Navigator.of(context).pushNamed(Routes.silentPaymentsSettings);
|
||||
},
|
||||
);
|
||||
|
||||
static SettingActions connectionSettingAction = SettingActions._(
|
||||
name: (context) => S.of(context).connection_sync,
|
||||
image: 'assets/images/nodes_menu.png',
|
||||
|
||||
Reference in New Issue
Block a user