mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
cw-1584-ironwood-migration-modal (#3481)
* ironwood migration modal * auto-show when migration begins * remove restricted import * new condition * string fix * only activate if ironwood is active * reaction safeguards * migration*
This commit is contained in:
@@ -1214,6 +1214,23 @@ abstract class ZcashWalletBase
|
||||
return migratable;
|
||||
}
|
||||
|
||||
Future<bool> hasOrchardMigratableBalance() async {
|
||||
|
||||
final (active, migratableOrchard) = await runWithCoin(
|
||||
accountId: accountId,
|
||||
func: (final coin) async => (
|
||||
await zkool_network.isIronwoodActive(c: coin),
|
||||
await _migratableOrchardTotal(coin),
|
||||
),
|
||||
);
|
||||
|
||||
if(!active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return migratableOrchard > BigInt.zero;
|
||||
}
|
||||
|
||||
Future<void> _$autoShield() async {
|
||||
if (syncStatus is! SyncedSyncStatus) {
|
||||
return;
|
||||
|
||||
@@ -145,4 +145,5 @@ class PreferencesKey {
|
||||
static const backgroundImage = 'background_image';
|
||||
static const mwebAdDismissed = "mweb_ad_dismissed";
|
||||
static const balanceHideCounter = "balance_hide_counter";
|
||||
static const zcashMigrationModalViewed = "zcash_migration_modal_viewed";
|
||||
}
|
||||
|
||||
@@ -13,10 +13,14 @@ import 'package:cake_wallet/new-ui/widgets/coins_page/mweb_ad.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/top_bar.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/unconfirmed_balance_widget.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/wallet_info.dart';
|
||||
import "package:cake_wallet/new-ui/widgets/coins_page/zcash_migration_modal.dart";
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||
import "package:cw_core/amount/money.dart";
|
||||
import "package:cw_core/crypto_currency.dart";
|
||||
import "package:cw_core/transaction_direction.dart";
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -48,6 +52,24 @@ class _NewHomePageState extends State<NewHomePage> {
|
||||
_lightningMode = false;
|
||||
});
|
||||
});
|
||||
|
||||
reaction((_) => widget.dashboardViewModel.isMigratingToIronwood, (val) {
|
||||
if (val && !widget.dashboardViewModel.settingsStore.zcashMigrationModalViewed) {
|
||||
if(!context.mounted) {
|
||||
return;
|
||||
}
|
||||
widget.dashboardViewModel.settingsStore.zcashMigrationModalViewed = true;
|
||||
showMaterialModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) => ZcashMigrationModal(
|
||||
hasContinue: true,
|
||||
balance: widget.dashboardViewModel.wallet.balance.values.first.unavailable
|
||||
.toStringWithSymbol(),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _setAccountViewModel() {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import "package:cake_wallet/new-ui/widgets/coins_page/zcash_migration_modal.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';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import "package:flutter/cupertino.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
@@ -21,6 +23,7 @@ class UnconfirmedBalanceWidget extends StatelessWidget {
|
||||
return Observer(builder: (_) {
|
||||
final show = dashboardViewModel.balanceViewModel
|
||||
.hasAdditionalBalance(dashboardViewModel.wallet.currency);
|
||||
final isIronwoodMigration = dashboardViewModel.isMigratingToIronwood;
|
||||
|
||||
return AnimatedSize(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
@@ -44,13 +47,17 @@ class UnconfirmedBalanceWidget extends StatelessWidget {
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
final modal = isIronwoodMigration
|
||||
? ZcashMigrationModal(
|
||||
hasContinue: false, balance: "${balance} ${currency.symbol}")
|
||||
: UnconfirmedBalanceModal(
|
||||
balance: balance.toStringWithSymbol(),
|
||||
currencyIconPath: currency.iconPath ?? "",
|
||||
);
|
||||
showMaterialModalBottomSheet(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
builder: (context) => UnconfirmedBalanceModal(
|
||||
balance: balance.toStringWithSymbol(),
|
||||
currencyIconPath: currency.iconPath ?? "",
|
||||
));
|
||||
builder: (context) => modal);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
@@ -63,8 +70,12 @@ class UnconfirmedBalanceWidget extends StatelessWidget {
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
child: isIronwoodMigration
|
||||
? CupertinoActivityIndicator(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primary.withAlpha(50),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
@@ -80,7 +91,7 @@ class UnconfirmedBalanceWidget extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Text(S.of(context).confirming),
|
||||
Text(isIronwoodMigration ? S.of(context).migrating_to_ironwood : S.of(context).confirming),
|
||||
],
|
||||
)
|
||||
],
|
||||
@@ -172,3 +183,4 @@ class UnconfirmedBalanceModal extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
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";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:url_launcher/url_launcher.dart";
|
||||
|
||||
class ZcashMigrationModal extends StatelessWidget {
|
||||
const ZcashMigrationModal({required this.hasContinue, required this.balance, super.key});
|
||||
|
||||
final String balance;
|
||||
final bool hasContinue;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SafeArea(
|
||||
bottom: false,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Column(
|
||||
children: [
|
||||
ModalTopBar(
|
||||
title: S.of(context).zcash_network_upgrade,
|
||||
trailingIcon: const Icon(Icons.close),
|
||||
onTrailingPressed: Navigator.of(context).pop,
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
spacing: 40,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 146,
|
||||
height: 79,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Positioned(
|
||||
left: 67,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/ironwood_migration.svg",
|
||||
width: 75,
|
||||
height: 75,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
child: Container(
|
||||
width: 79,
|
||||
height: 79,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(99999999),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
width: 4,),),
|
||||
child: const CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/crypto_full_icons/zcash.svg",
|
||||
height: 75,
|
||||
width: 75,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(
|
||||
balance,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,),
|
||||
),
|
||||
Text(S.of(context).is_currently_being_migrated),
|
||||
],
|
||||
),
|
||||
),),
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "${S.of(context).zcash_network_upgrade_desc_1}\n\n",
|
||||
style: Theme.of(context).textTheme.bodyMedium,),
|
||||
TextSpan(
|
||||
text: "${S.of(context).zcash_network_upgrade_desc_2}\n\n",
|
||||
style: Theme.of(context).textTheme.bodyMedium,),
|
||||
TextSpan(
|
||||
text: "${S.of(context).zcash_network_upgrade_desc_3}\n\n",
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: const Color(0xFFF9C03C),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
spacing: 12,
|
||||
children: [
|
||||
NewPrimaryButton(
|
||||
onPressed: _launchDocs,
|
||||
text: S.of(context).learn_more,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
textColor: Theme.of(context).colorScheme.primary,),
|
||||
if (hasContinue)
|
||||
NewPrimaryButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
text: S.of(context).continue_text,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
void _launchDocs() {
|
||||
try {
|
||||
launchUrl(Uri.parse("https://docs.cakewallet.com/cryptos/zcash/ironwood-migration"));
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,7 @@ abstract class SettingsStoreBase with Store {
|
||||
required this.mwebNodeUri,
|
||||
required this.mwebAdDismissed,
|
||||
required this.balanceHideCounter,
|
||||
required this.zcashMigrationModalViewed,
|
||||
required bool initialEnableAutomaticNodeSwitching,
|
||||
required String initialBackgroundImage,
|
||||
TransactionPriority? initialBitcoinTransactionPriority,
|
||||
@@ -766,6 +767,9 @@ abstract class SettingsStoreBase with Store {
|
||||
(int balanceHideCounter) =>
|
||||
_sharedPreferences.setInt(PreferencesKey.balanceHideCounter, balanceHideCounter));
|
||||
|
||||
reaction((_) => zcashMigrationModalViewed,
|
||||
(val) => _sharedPreferences.setBool(PreferencesKey.zcashMigrationModalViewed, val));
|
||||
|
||||
this.nodes.observe((change) {
|
||||
if (change.newValue != null && change.key != null) {
|
||||
_saveCurrentNode(change.newValue!, change.key!);
|
||||
@@ -1075,6 +1079,9 @@ abstract class SettingsStoreBase with Store {
|
||||
@observable
|
||||
bool mwebAdDismissed;
|
||||
|
||||
@observable
|
||||
bool zcashMigrationModalViewed;
|
||||
|
||||
final SecureStorage _secureStorage;
|
||||
final SharedPreferences _sharedPreferences;
|
||||
|
||||
@@ -1350,6 +1357,7 @@ abstract class SettingsStoreBase with Store {
|
||||
final enableAutomaticNodeSwitching =
|
||||
sharedPreferences.getBool(PreferencesKey.enableAutomaticNodeSwitching) ?? true;
|
||||
final backgroundImage = sharedPreferences.getString(PreferencesKey.backgroundImage) ?? '';
|
||||
final zcashMigrationModalViewed = sharedPreferences.getBool(PreferencesKey.zcashMigrationModalViewed) ?? false;
|
||||
|
||||
// If no value
|
||||
if (pinLength == null || pinLength == 0) {
|
||||
@@ -1762,6 +1770,7 @@ abstract class SettingsStoreBase with Store {
|
||||
initialBuiltinTor: builtinTor,
|
||||
mwebAdDismissed: mwebAdDismissed,
|
||||
balanceHideCounter: balanceHideCounter,
|
||||
zcashMigrationModalViewed: zcashMigrationModalViewed
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ abstract class DashboardViewModelBase with Store {
|
||||
isShowFirstYatIntroduction = false,
|
||||
isShowSecondYatIntroduction = false,
|
||||
isShowThirdYatIntroduction = false,
|
||||
isMigratingToIronwood = false,
|
||||
filterItems = [],
|
||||
exchangeFilterItems = [],
|
||||
subname = '',
|
||||
@@ -250,6 +251,8 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
reaction((_) => tradesStore.trades, (_) => tradeMonitor.monitorActiveTrades(wallet.id));
|
||||
|
||||
addZcashMigrationReaction();
|
||||
|
||||
tradeMonitor.monitorActiveTrades(wallet.id);
|
||||
}
|
||||
|
||||
@@ -374,6 +377,22 @@ abstract class DashboardViewModelBase with Store {
|
||||
);
|
||||
}
|
||||
|
||||
@observable
|
||||
ReactionDisposer? zcashMigrationReactionDisposer;
|
||||
|
||||
@action
|
||||
void addZcashMigrationReaction() {
|
||||
zcashMigrationReactionDisposer?.reaction.dispose();
|
||||
zcashMigrationReactionDisposer = null;
|
||||
|
||||
if (wallet.type == WalletType.zcash) {
|
||||
zcashMigrationReactionDisposer = reaction((_) => wallet.balance.values.first, (_) async {
|
||||
isMigratingToIronwood =
|
||||
wallet.type == WalletType.zcash && await zcash!.hasOrchardMigratableBalance(wallet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get isSyncHeavy {
|
||||
if ([
|
||||
@@ -1270,6 +1289,8 @@ abstract class DashboardViewModelBase with Store {
|
||||
name = wallet.name;
|
||||
loadFilterItems();
|
||||
|
||||
addZcashMigrationReaction();
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
subname = monero!.getCurrentAccount(wallet).label;
|
||||
|
||||
@@ -1551,6 +1572,9 @@ abstract class DashboardViewModelBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
@observable
|
||||
bool isMigratingToIronwood;
|
||||
|
||||
String getTransactionType(TransactionInfo tx) {
|
||||
if (wallet.type == WalletType.bitcoin) {
|
||||
if (tx.isReplaced == true) return ' (replaced)';
|
||||
|
||||
@@ -213,6 +213,11 @@ class CWZcash extends Zcash {
|
||||
bool ironwoodActive(WalletAddresses walletAddresses) {
|
||||
return (walletAddresses as ZcashWalletAddresses).ironwoodActive;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> hasOrchardMigratableBalance(WalletBase wallet) {
|
||||
return (wallet as ZcashWallet).hasOrchardMigratableBalance();
|
||||
}
|
||||
}
|
||||
|
||||
const wordList = [
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="75" height="75" viewBox="0 0 75 75" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.7438 43.75H18.9104C19.391 39.6528 21.258 36.1979 24.5115 33.3854C27.7642 30.5729 31.6076 29.1667 36.0417 29.1667C38.8625 29.1667 41.8701 30.0736 45.0646 31.8875C48.259 33.7007 50.8979 36.266 52.9812 39.5833H43.4292V43.75H60.0958V27.0833H55.9292V36.5865C53.3868 32.6656 50.2767 29.7542 46.599 27.8521C42.9205 25.9507 39.4014 25 36.0417 25C30.4062 25 25.5944 26.8083 21.6063 30.425C17.6188 34.041 15.3313 38.4826 14.7438 43.75ZM37.5135 75C32.3281 75 27.4528 74.016 22.8875 72.0479C18.3229 70.0799 14.3521 67.409 10.975 64.0354C7.59792 60.6618 4.92465 56.6944 2.95521 52.1333C0.985069 47.5729 0 42.6997 0 37.5135C0 32.3281 0.984027 27.4528 2.95208 22.8875C4.92014 18.3229 7.59097 14.3521 10.9646 10.975C14.3382 7.59792 18.3056 4.92465 22.8667 2.95521C27.4271 0.985069 32.3003 0 37.4865 0C42.6719 0 47.5472 0.984031 52.1125 2.95209C56.6771 4.92014 60.6479 7.59097 64.025 10.9646C67.4021 14.3382 70.0753 18.3056 72.0448 22.8667C74.0149 27.4271 75 32.3003 75 37.4865C75 42.6719 74.016 47.5472 72.0479 52.1125C70.0799 56.6771 67.409 60.6479 64.0354 64.025C60.6618 67.4021 56.6944 70.0753 52.1333 72.0448C47.5729 74.0149 42.6997 75 37.5135 75Z" fill="#8C9FBB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -571,6 +571,7 @@
|
||||
"invalid_input": "Invalid input",
|
||||
"invalid_password": "Invalid password",
|
||||
"invoice_details": "Invoice details",
|
||||
"is_currently_being_migrated": "is currently being migrated",
|
||||
"is_percentage": "is",
|
||||
"keys": "Keys",
|
||||
"label": "Label",
|
||||
@@ -646,6 +647,7 @@
|
||||
"messages": "Messages",
|
||||
"method": "Method",
|
||||
"methods": "Methods",
|
||||
"migrating_to_ironwood": "migrating to Ironwood",
|
||||
"min_amount": "Min: ${value}",
|
||||
"min_value": "Min: ${value} ${currency}",
|
||||
"mining": "Mining",
|
||||
@@ -1476,5 +1478,9 @@
|
||||
"zcash_card_enable_later": "You can always enable this card later in settings",
|
||||
"zcash_card_missing_funds": "Missing funds?",
|
||||
"zcash_card_scan": "Scan",
|
||||
"zcash_card_warning": "Do not close the app until the procedure completes, if you do so this process will need to restart from scratch."
|
||||
"zcash_card_warning": "Do not close the app until the procedure completes, if you do so this process will need to restart from scratch.",
|
||||
"zcash_network_upgrade": "Zcash Network Upgrade",
|
||||
"zcash_network_upgrade_desc_1": "Zcash has undergone a network upgrade called Ironwood that requires migration of funds before they can be spent. This migration is automatic, privacy-preserving, and starts as soon as you open your Zcash wallet.",
|
||||
"zcash_network_upgrade_desc_2": "When the migration finishes, your Available Balance will return to normal, and you can continue to send and receive Zcash as usual.",
|
||||
"zcash_network_upgrade_desc_3": "Please allow your Zcash wallet to finishing syncing, and then leave the app open until migration finishes which can take a few minutes depending on the balance."
|
||||
}
|
||||
|
||||
@@ -1770,6 +1770,7 @@ abstract class Zcash {
|
||||
bool showMissingFundsCard(WalletBase wallet);
|
||||
Future<void> rescanInternalChange(WalletBase wallet);
|
||||
bool ironwoodActive(WalletAddresses walletAddresses);
|
||||
Future<bool> hasOrchardMigratableBalance(WalletBase wallet);
|
||||
}
|
||||
""";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user