feat: Haven removal flow

This commit is contained in:
Blazebrain 2023-10-03 09:09:40 +01:00
parent 82c32a0910
commit df01405cb8
11 changed files with 416 additions and 75 deletions

View file

@ -24,6 +24,8 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
import 'package:cake_wallet/src/screens/haven_removal/haven_removal_notice_page.dart';
import 'package:cake_wallet/src/screens/haven_removal/haven_removal_seed_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
@ -53,6 +55,7 @@ import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
import 'package:cake_wallet/view_model/haven_removal_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
@ -84,6 +87,7 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/core/backup_service.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cake_wallet/entities/biometric_auth.dart';
import 'package:cake_wallet/entities/contact_record.dart';
@ -1050,5 +1054,18 @@ Future<void> setup({
getIt.registerFactory<ManageNodesPage>(() => ManageNodesPage(getIt.get<NodeListViewModel>()));
getIt.registerFactory<HavenRemovalViewModel>(() => HavenRemovalViewModel(
appStore: getIt.get<AppStore>(),
walletInfoSource: _walletInfoSource,
walletLoadingService: getIt.get<WalletLoadingService>()));
getIt.registerFactoryParam<HavenRemovalNoticePage, WalletBase, void>(
(wallet, _) => HavenRemovalNoticePage(wallet, getIt.get<HavenRemovalViewModel>()),
);
getIt.registerFactoryParam<HavenRemovalSeedPage, WalletBase, HavenRemovalViewModel>(
(wallet, viewModel) => HavenRemovalSeedPage(wallet, viewModel),
);
_isSetupFinished = true;
}

View file

@ -28,7 +28,7 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
authenticationStore.installed();
}
startAuthenticationStateChange(authenticationStore, navigatorKey);
startAuthenticationStateChange(authenticationStore, navigatorKey, appStore);
startCurrentWalletChangeReaction(
appStore, settingsStore, fiatConversionStore);
startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore);

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/widgets.dart';
@ -13,8 +14,8 @@ ReactionDisposer? _onAuthenticationStateChange;
dynamic loginError;
void startAuthenticationStateChange(
AuthenticationStore authenticationStore, GlobalKey<NavigatorState> navigatorKey) {
void startAuthenticationStateChange(AuthenticationStore authenticationStore,
GlobalKey<NavigatorState> navigatorKey, AppStore appStore) {
_onAuthenticationStateChange ??= autorun(
(_) async {
final state = authenticationStore.state;
@ -25,7 +26,7 @@ void startAuthenticationStateChange(
}
if (state == AuthenticationState.allowed) {
await _navigateBasedOnWalletType(navigatorKey);
await _navigateBasedOnWalletType(navigatorKey, appStore);
}
},
);
@ -40,17 +41,19 @@ Future<void> _loadCurrentWallet() async {
}
}
Future<void> _navigateBasedOnWalletType(GlobalKey<NavigatorState> navigatorKey) async {
Future<void> _navigateBasedOnWalletType(
GlobalKey<NavigatorState> navigatorKey, AppStore appStore) async {
final typeRaw = getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType) ?? 0;
final type = deserializeFromInt(typeRaw);
if (type == WalletType.haven) {
await navigatorKey.currentState!
.pushNamedAndRemoveUntil(Routes.preSeed, (route) => false, arguments: type);
await navigatorKey.currentState!.pushNamed(Routes.seed, arguments: true);
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (route) => false);
final wallet = appStore.wallet;
await navigatorKey.currentState!.pushNamed(Routes.havenRemovalNoticePage, arguments: wallet);
return;
} else {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
return;
}
}

View file

@ -12,6 +12,8 @@ import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/webview_page.dart';
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
import 'package:cake_wallet/src/screens/haven_removal/haven_removal_notice_page.dart';
import 'package:cake_wallet/src/screens/haven_removal/haven_removal_seed_page.dart';
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
@ -47,10 +49,12 @@ import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/haven_removal_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
@ -604,6 +608,21 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.manageNodes:
return MaterialPageRoute<void>(builder: (_) => getIt.get<ManageNodesPage>());
case Routes.havenRemovalNoticePage:
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<HavenRemovalNoticePage>(param1: settings.arguments as WalletBase),
);
case Routes.havenRemovalSeedPage:
final args = settings.arguments as List;
final wallet = args.first as WalletBase;
final havenRemovalViewModel = args[1] as HavenRemovalViewModel;
return CupertinoPageRoute<void>(
builder: (_) =>
getIt.get<HavenRemovalSeedPage>(param1: wallet, param2: havenRemovalViewModel),
);
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(

View file

@ -92,4 +92,6 @@ class Routes {
static const homeSettings = '/home_settings';
static const editToken = '/edit_token';
static const manageNodes = '/manage_nodes';
static const havenRemovalNoticePage = '/haven_removal_notice_page';
static const havenRemovalSeedPage = '/haven_removal_seed_page';
}

View file

@ -0,0 +1,84 @@
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/view_model/haven_removal_view_model.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart';
class HavenRemovalNoticePage extends BasePage {
HavenRemovalNoticePage(this.wallet, this.viewModel)
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
imageDark = Image.asset('assets/images/pre_seed_dark.png');
final Image imageDark;
final Image imageLight;
final WalletBase wallet;
final HavenRemovalViewModel viewModel;
@override
Widget? leading(BuildContext context) => null;
@override
String? get title => S.current.pre_seed_title;
@override
Widget body(BuildContext context) {
final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight;
return WillPopScope(
onWillPop: () async => false,
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(24),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3),
child: AspectRatio(aspectRatio: 1, child: image),
),
Column(
children: [
Text(
S.current.havenSupportNotice,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: titleColor(context),
),
textAlign: TextAlign.center,
),
SizedBox(height: 8),
Text(
S.current.havenSupportSeedsNotice,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
],
),
PrimaryButton(
onPressed: () => Navigator.of(context)
.popAndPushNamed(Routes.havenRemovalSeedPage, arguments: [wallet, viewModel]),
text: S.of(context).pre_seed_button_text,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
)
],
),
),
),
);
}
}

View file

@ -0,0 +1,188 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/pin_code_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/clipboard_util.dart';
import 'package:cake_wallet/utils/share_util.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/haven_removal_view_model.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
class HavenRemovalSeedPage extends BasePage {
HavenRemovalSeedPage(this.wallet, this.havenRemovalViewModel);
final imageLight = Image.asset('assets/images/crypto_lock_light.png');
final imageDark = Image.asset('assets/images/crypto_lock.png');
final WalletBase wallet;
final HavenRemovalViewModel havenRemovalViewModel;
@override
String get title => S.current.seed_title;
@override
void onClose(BuildContext context) async {
await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).seed_alert_title,
alertContent: S.of(context).seed_alert_content,
leftButtonText: S.of(context).seed_alert_back,
rightButtonText: S.of(context).seed_alert_yes,
actionLeftButton: () => Navigator.of(context).pop(false),
actionRightButton: () async => await havenRemovalViewModel.onSeedsCopiedConfirmed(),
);
},
) ??
false;
// if (confirmed) {
// await havenRemovalViewModel.onSeedsCopiedConfirmed();
// }
return;
}
@override
Widget? leading(BuildContext context) => super.leading(context);
@override
Widget trailing(BuildContext context) {
return GestureDetector(
onTap: () => onClose(context),
child: Container(
width: 100,
height: 32,
alignment: Alignment.center,
margin: EdgeInsets.only(left: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
color: Theme.of(context).cardColor,
),
child: Text(
S.of(context).seed_language_next,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor,
),
),
),
);
}
@override
Widget body(BuildContext context) {
final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight;
return WillPopScope(
onWillPop: () async => false,
child: Container(
padding: EdgeInsets.all(24),
alignment: Alignment.center,
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3),
child: AspectRatio(aspectRatio: 1, child: image),
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
wallet.name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
Padding(
padding: EdgeInsets.only(top: 20, left: 16, right: 16),
child: Text(
wallet.seed ?? '',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
)
],
),
Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 43, left: 43, right: 43),
child: Text(
S.of(context).seed_reminder,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: Theme.of(context)
.extension<TransactionTradeTheme>()!
.detailsTitlesColor,
),
),
),
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Flexible(
child: Container(
padding: EdgeInsets.only(right: 8.0),
child: PrimaryButton(
onPressed: () {
ShareUtil.share(
text: wallet.seed ?? '',
context: context,
);
},
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white,
),
)),
Flexible(
child: Container(
padding: EdgeInsets.only(left: 8.0),
child: Builder(
builder: (context) => PrimaryButton(
onPressed: () {
ClipboardUtil.setSensitiveDataToClipboard(
ClipboardData(text: wallet.seed ?? ''),
);
showBar<void>(context, S.of(context).copied_to_clipboard);
},
text: S.of(context).copy,
color: Theme.of(context).extension<PinCodeTheme>()!.indicatorsColor,
textColor: Colors.white,
),
),
),
)
],
)
],
)
],
),
),
),
);
}
}

View file

@ -12,13 +12,11 @@ class PreSeedPage extends BasePage {
PreSeedPage(this.type)
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
wordsCount = _wordsCount(type),
isHavenRemovalFlow = type == WalletType.haven;
wordsCount = _wordsCount(type);
final Image imageDark;
final Image imageLight;
final WalletType type;
final bool isHavenRemovalFlow;
final int wordsCount;
@override
@ -45,46 +43,13 @@ class PreSeedPage extends BasePage {
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3),
child: AspectRatio(aspectRatio: 1, child: image),
),
Visibility(
visible: isHavenRemovalFlow,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
Text(
S.current.havenSupportNotice,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: titleColor(context),
),
textAlign: TextAlign.center,
),
SizedBox(height: 8),
Text(
S.current.havenSupportSeedsNotice,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
],
),
),
replacement: Padding(
padding: EdgeInsets.all(10),
child: Text(
S.of(context).pre_seed_description(wordsCount.toString()),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
Text(
S.of(context).pre_seed_description(wordsCount.toString()),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
PrimaryButton(

View file

@ -5,6 +5,7 @@ import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/routes.dart';
@ -246,12 +247,8 @@ class WalletListBodyState extends State<WalletListBody> {
return nonWalletTypeIcon;
}
}
Future<void> _loadWallet(WalletListItem wallet) async {
final previousListType = widget.walletListViewModel.wallets
.where((element) => element.type == widget.walletListViewModel.currentWalletType)
.toList()[0];
Future<void> _loadWallet(WalletListItem walletListItem) async {
await widget.authService.authenticateAction(
context,
onAuthSuccess: (isAuthenticatedSuccessfully) async {
@ -259,24 +256,25 @@ class WalletListBodyState extends State<WalletListBody> {
return;
}
if (walletListItem.type == WalletType.haven) {
_onHavenWalletSelected(walletListItem);
return;
}
try {
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
await widget.walletListViewModel.loadWallet(wallet);
changeProcessText(S.of(context).wallet_list_loading_wallet(walletListItem.name));
await widget.walletListViewModel.loadWallet(walletListItem);
await hideProgressText();
// only pop the wallets route in mobile as it will go back to dashboard page
// in desktop platforms the navigation tree is different
if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (wallet.type == WalletType.haven) {
_onHavenWalletSelected(previousListType);
return;
} else {
Navigator.of(context).pop();
}
Navigator.of(context).pop();
});
}
} catch (e) {
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
changeProcessText(
S.of(context).wallet_list_failed_to_load(walletListItem.name, e.toString()));
}
},
conditionToDetermineIfToUse2FA:
@ -284,11 +282,9 @@ class WalletListBodyState extends State<WalletListBody> {
);
}
Future<void> _onHavenWalletSelected(WalletListItem previousWalletListItem) async {
await Navigator.pushNamed(context, Routes.preSeed, arguments: WalletType.haven);
await Navigator.pushNamed(context, Routes.seed, arguments: true);
await widget.walletListViewModel.loadWallet(previousWalletListItem);
Future<void> _onHavenWalletSelected(WalletListItem walletListItem) async {
final wallet = await widget.walletListViewModel.loadWalletWithoutChanging(walletListItem);
await Navigator.pushNamed(context, Routes.havenRemovalNoticePage, arguments: wallet);
}
void changeProcessText(String text) {

View file

@ -0,0 +1,61 @@
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
part 'haven_removal_view_model.g.dart';
class HavenRemovalViewModel = HavenRemovalViewModelBase with _$HavenRemovalViewModel;
abstract class HavenRemovalViewModelBase with Store {
HavenRemovalViewModelBase(
{required this.appStore, required this.walletInfoSource, required this.walletLoadingService});
final AppStore appStore;
final Box<WalletInfo> walletInfoSource;
final WalletLoadingService walletLoadingService;
Future<void> onSeedsCopiedConfirmed() async {
if (walletInfoSource.length == 1) {
_navigateToWelcomePage();
return;
}
final walletInfo = _getFirstNonHavenWallet();
final wallet = await _loadWallet(walletInfo.type, walletInfo.name);
_changeWallet(wallet);
await _navigateToDashboardPage();
}
WalletInfo _getFirstNonHavenWallet() {
return walletInfoSource.values.firstWhere((element) => element.type != WalletType.haven);
}
Future<WalletBase> _loadWallet(WalletType type, String walletName) async {
final wallet = await walletLoadingService.load(type, walletName);
return wallet;
}
void _changeWallet(WalletBase wallet) {
appStore.changeCurrentWallet(wallet);
}
Future<void> _navigateToDashboardPage() async {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
return;
}
Future<void> _navigateToWelcomePage() async {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (route) => false);
return;
}
}

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/app_store.dart';
@ -43,11 +44,17 @@ abstract class WalletListViewModelBase with Store {
@action
Future<void> loadWallet(WalletListItem walletItem) async {
final wallet =
await _walletLoadingService.load(walletItem.type, walletItem.name);
final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
_appStore.changeCurrentWallet(wallet);
}
Future<WalletBase> loadWalletWithoutChanging(WalletListItem walletItem) async {
final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
return wallet;
}
@action
void updateList() {
wallets.clear();
@ -57,8 +64,7 @@ abstract class WalletListViewModelBase with Store {
name: info.name,
type: info.type,
key: info.key,
isCurrent: info.name == _appStore.wallet?.name &&
info.type == _appStore.wallet?.type,
isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
isEnabled: availableWalletTypes.contains(info.type),
),
),