Merge pull request #787 from cake-tech/macos-fix-settings-create-wallet

Fix wallet create in settings
This commit is contained in:
Omar Hatem 2023-02-22 19:31:37 +02:00 committed by GitHub
commit 7a504abc01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 229 additions and 123 deletions

View file

@ -0,0 +1,9 @@
import 'package:flutter/material.dart';
class DesktopDropdownItem {
final Function() onSelected;
final Widget child;
final bool isSelected;
DesktopDropdownItem({required this.onSelected, required this.child, this.isSelected = false});
}

View file

@ -23,8 +23,11 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore,
} }
if (state == AuthenticationState.allowed) { if (state == AuthenticationState.allowed) {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); // Temporary workaround for the issue with desktopKey dispose
return; Future.delayed(Duration(milliseconds: 2), () async {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
return;
});
} }
}); });
} }

View file

@ -13,7 +13,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/router.dart' as Router; import 'package:cake_wallet/router.dart' as Router;
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
class DesktopSidebarWrapper extends BasePage { class DesktopSidebarWrapper extends BasePage {
final Widget child; final Widget child;
final DesktopSidebarViewModel desktopSidebarViewModel; final DesktopSidebarViewModel desktopSidebarViewModel;
@ -25,6 +24,8 @@ class DesktopSidebarWrapper extends BasePage {
required this.dashboardViewModel, required this.dashboardViewModel,
}); });
static Key _pageViewKey = GlobalKey();
@override @override
Color get backgroundLightColor => Color get backgroundLightColor =>
currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white; currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
@ -42,23 +43,6 @@ class DesktopSidebarWrapper extends BasePage {
double get sideMenuWidth => 76.0; double get sideMenuWidth => 76.0;
@override
Widget Function(BuildContext, Widget) get rootWrapper =>
(BuildContext context, Widget scaffold) => Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context).accentColor,
Theme.of(context).scaffoldBackgroundColor,
Theme.of(context).primaryColor,
],
begin: Alignment.topRight,
end: Alignment.bottomLeft,
),
),
child: scaffold,
);
@override @override
Widget? leading(BuildContext context) => Padding( Widget? leading(BuildContext context) => Padding(
padding: EdgeInsets.only(left: sideMenuWidth), padding: EdgeInsets.only(left: sideMenuWidth),
@ -109,24 +93,8 @@ class DesktopSidebarWrapper extends BasePage {
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
reaction<SidebarItem>((_) => desktopSidebarViewModel.currentPage, (page) { _setEffects();
String? currentPath;
DesktopDashboardPage.desktopKey.currentState?.popUntil((route) {
currentPath = route.settings.name;
return true;
});
if (page == SidebarItem.transactions) {
return;
}
if (currentPath == Routes.transactionsPage) {
Navigator.of(DesktopDashboardPage.desktopKey.currentContext!).pop();
}
pageController.jumpToPage(page.index);
});
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -155,6 +123,7 @@ class DesktopSidebarWrapper extends BasePage {
}), }),
Expanded( Expanded(
child: PageView( child: PageView(
key: _pageViewKey,
controller: pageController, controller: pageController,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
children: [ children: [
@ -186,4 +155,27 @@ class DesktopSidebarWrapper extends BasePage {
], ],
); );
} }
final desktopKey = DesktopDashboardPage.desktopKey;
void _setEffects() async {
reaction<SidebarItem>((_) => desktopSidebarViewModel.currentPage, (page) {
String? currentPath;
desktopKey.currentState?.popUntil((route) {
currentPath = route.settings.name;
return true;
});
if (page == SidebarItem.transactions) {
return;
}
if (currentPath == Routes.transactionsPage) {
Navigator.of(desktopKey.currentContext!).pop();
}
pageController.jumpToPage(page.index);
});
}
} }

View file

@ -1,14 +1,18 @@
import 'package:another_flushbar/flushbar.dart'; import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/entities/desktop_dropdown_item.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class DesktopWalletSelectionDropDown extends StatefulWidget { class DesktopWalletSelectionDropDown extends StatefulWidget {
final WalletListViewModel walletListViewModel; final WalletListViewModel walletListViewModel;
@ -25,85 +29,96 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
final litecoinIcon = Image.asset('assets/images/litecoin_icon.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 havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24); final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
Image _getNewWalletImage(BuildContext context) => Image.asset(
final double tileHeight = 60; 'assets/images/new_wallet.png',
height: 12,
width: 12,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
);
Image _getRestoreWalletImage(BuildContext context) => Image.asset(
'assets/images/restore_wallet.png',
height: 12,
width: 12,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
);
Flushbar<void>? _progressBar; Flushbar<void>? _progressBar;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final themeData = Theme.of(context); final themeData = Theme.of(context);
return DropdownButton<WalletListItem>( return Observer(builder: (context) {
items: widget.walletListViewModel.wallets final dropDownItems = [
.map((wallet) => DropdownMenuItem( ...widget.walletListViewModel.wallets
child: ConstrainedBox( .map((wallet) => DesktopDropdownItem(
constraints: BoxConstraints(maxWidth: 500), isSelected: wallet.isCurrent,
child: walletListItemTile(wallet), child: ConstrainedBox(
), constraints: BoxConstraints(maxWidth: 500),
child: DropDownItemWidget(
title: wallet.name,
image: wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon),
),
onSelected: () => _onSelectedWallet(wallet),
))
.toList(),
DesktopDropdownItem(
onSelected: () => _navigateToCreateWallet(),
child: DropDownItemWidget(
title: S.of(context).create_new,
image: _getNewWalletImage(context),
),
),
DesktopDropdownItem(
onSelected: () => _navigateToRestoreWallet(),
child: DropDownItemWidget(
title: S.of(context).restore_wallet,
image: _getRestoreWalletImage(context),
),
),
];
return DropdownButton<DesktopDropdownItem>(
items: dropDownItems
.map(
(wallet) => DropdownMenuItem<DesktopDropdownItem>(
child: wallet.child,
value: wallet, value: wallet,
)) ),
.toList(), )
onChanged: (selectedWallet) async { .toList(),
if (selectedWallet!.isCurrent || !selectedWallet.isEnabled) { onChanged: (item) {
return; item?.onSelected();
} },
dropdownColor: themeData.textTheme.bodyText1?.decorationColor,
final confirmed = await showPopUp<bool>( style: TextStyle(color: themeData.primaryTextTheme.headline6?.color),
context: context, selectedItemBuilder: (context) => dropDownItems.map((item) => item.child).toList(),
builder: (dialogContext) { value: dropDownItems.firstWhere((element) => element.isSelected),
return AlertWithTwoActions( underline: const SizedBox(),
alertTitle: S.of(context).change_wallet_alert_title, focusColor: Colors.transparent,
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name), );
leftButtonText: S.of(context).cancel, });
rightButtonText: S.of(context).change,
actionLeftButton: () => Navigator.of(context).pop(false),
actionRightButton: () => Navigator.of(context).pop(true));
}) ??
false;
if (confirmed) {
await _loadWallet(selectedWallet);
}
},
dropdownColor: themeData.textTheme.bodyText1?.decorationColor,
style: TextStyle(color: themeData.primaryTextTheme.headline6?.color),
selectedItemBuilder: (context) => widget.walletListViewModel.wallets
.map((wallet) => ConstrainedBox(
constraints: BoxConstraints(maxWidth: 500),
child: walletListItemTile(wallet),
))
.toList(),
value: widget.walletListViewModel.wallets.firstWhere((element) => element.isCurrent),
underline: const SizedBox(),
focusColor: Colors.transparent,
);
} }
Widget walletListItemTile(WalletListItem wallet) { void _onSelectedWallet(WalletListItem selectedWallet) async {
return Container( if (selectedWallet.isCurrent || !selectedWallet.isEnabled) {
height: tileHeight, return;
padding: EdgeInsets.symmetric(horizontal: 20), }
child: Row( final confirmed = await showPopUp<bool>(
crossAxisAlignment: CrossAxisAlignment.center, context: context,
mainAxisSize: MainAxisSize.min, builder: (dialogContext) {
children: <Widget>[ return AlertWithTwoActions(
wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon, alertTitle: S.of(context).change_wallet_alert_title,
SizedBox(width: 10), alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
Flexible( leftButtonText: S.of(context).cancel,
child: Text( rightButtonText: S.of(context).change,
wallet.name, actionLeftButton: () => Navigator.of(context).pop(false),
style: TextStyle( actionRightButton: () => Navigator.of(context).pop(true));
fontSize: 22, }) ??
fontWeight: FontWeight.w500, false;
color: Theme.of(context).primaryTextTheme.headline6!.color!,
), if (confirmed) {
overflow: TextOverflow.ellipsis, await _loadWallet(selectedWallet);
maxLines: 1, }
),
)
],
),
);
} }
Image _imageFor({required WalletType type}) { Image _imageFor({required WalletType type}) {
@ -152,6 +167,24 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
} }
} }
void _navigateToCreateWallet() {
if (isSingleCoin) {
Navigator.of(context)
.pushNamed(Routes.newWallet, arguments: widget.walletListViewModel.currentWalletType);
} else {
Navigator.of(context).pushNamed(Routes.newWalletType);
}
}
void _navigateToRestoreWallet() {
if (isSingleCoin) {
Navigator.of(context)
.pushNamed(Routes.restoreWallet, arguments: widget.walletListViewModel.currentWalletType);
} else {
Navigator.of(context).pushNamed(Routes.restoreWalletType);
}
}
void changeProcessText(String text) { void changeProcessText(String text) {
_progressBar = createBar<void>(text, duration: null)..show(context); _progressBar = createBar<void>(text, duration: null)..show(context);
} }

View file

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
class DropDownItemWidget extends StatelessWidget {
const DropDownItemWidget({super.key, required this.title, required this.image});
final double tileHeight = 60;
final Image image;
final String title;
@override
Widget build(BuildContext context) {
return Container(
height: tileHeight,
padding: EdgeInsets.symmetric(horizontal: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
image,
SizedBox(width: 10),
Flexible(
child: Text(
title,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
)
],
),
);
}
}

View file

@ -16,7 +16,8 @@ class DesktopSettingsPage extends StatefulWidget {
} }
class _DesktopSettingsPageState extends State<DesktopSettingsPage> { class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
final int itemCount = SettingActions.all.length; final int itemCount = SettingActions.desktopSettings.length;
int? currentPage; int? currentPage;
void _onItemChange(int index) { void _onItemChange(int index) {
@ -48,8 +49,8 @@ class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
child: ListView.separated( child: ListView.separated(
padding: EdgeInsets.only(top: 0), padding: EdgeInsets.only(top: 0),
itemBuilder: (_, index) { itemBuilder: (_, index) {
final item = SettingActions.all[index]; final item = SettingActions.desktopSettings[index];
final isLastTile = index == itemCount; final isLastTile = index == itemCount - 1;
return SettingActionButton( return SettingActionButton(
isLastTile: isLastTile, isLastTile: isLastTile,
selectionActive: currentPage != null, selectionActive: currentPage != null,

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
@ -100,9 +101,9 @@ class WalletListBodyState extends State<WalletListBody> {
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change, rightButtonText: S.of(context).change,
actionLeftButton: () => actionLeftButton: () =>
Navigator.of(context).pop(false), Navigator.of(dialogContext).pop(false),
actionRightButton: () => actionRightButton: () =>
Navigator.of(context).pop(true)); Navigator.of(dialogContext).pop(true));
}) ?? }) ??
false; false;

View file

@ -1,3 +1,6 @@
import 'dart:io';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -100,7 +103,8 @@ class AddressTextField extends StatelessWidget {
width: prefixIconWidth * options.length + width: prefixIconWidth * options.length +
(spaceBetweenPrefixIcons * options.length), (spaceBetweenPrefixIcons * options.length),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: DeviceInfo.instance.isMobile
? MainAxisAlignment.spaceBetween : MainAxisAlignment.end,
children: [ children: [
SizedBox(width: 5), SizedBox(width: 5),
if (this.options.contains(AddressTextFieldOption.paste)) ...[ if (this.options.contains(AddressTextFieldOption.paste)) ...[
@ -130,7 +134,8 @@ class AddressTextField extends StatelessWidget {
)), )),
)), )),
], ],
if (this.options.contains(AddressTextFieldOption.qrCode)) ...[ if (this.options.contains(AddressTextFieldOption.qrCode) && DeviceInfo.instance.isMobile)
...[
Container( Container(
width: prefixIconWidth, width: prefixIconWidth,
height: prefixIconHeight, height: prefixIconHeight,
@ -156,7 +161,7 @@ class AddressTextField extends StatelessWidget {
.decorationColor!, .decorationColor!,
)), )),
)) ))
], ] else SizedBox(width: 5),
if (this if (this
.options .options
.contains(AddressTextFieldOption.addressBook)) ...[ .contains(AddressTextFieldOption.addressBook)) ...[

View file

@ -24,6 +24,16 @@ class SettingActions {
supportSettingAction, supportSettingAction,
]; ];
static List<SettingActions> desktopSettings = [
connectionSettingAction,
addressBookSettingAction,
securityBackupSettingAction,
privacySettingAction,
displaySettingAction,
otherSettingAction,
supportSettingAction,
];
static SettingActions connectionSettingAction = SettingActions._( static SettingActions connectionSettingAction = SettingActions._(
name: S.current.connection_sync, name: S.current.connection_sync,
image: 'assets/images/nodes_menu.png', image: 'assets/images/nodes_menu.png',

View file

@ -0,0 +1,11 @@
import 'dart:io';
class DeviceInfo {
DeviceInfo._();
static DeviceInfo get instance => DeviceInfo._();
bool get isMobile => Platform.isAndroid || Platform.isIOS;
bool get isDesktop => Platform.isMacOS || Platform.isWindows || Platform.isLinux;
}

View file

@ -1,13 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
class WalletListItem { class WalletListItem {
const WalletListItem( const WalletListItem({
{required this.name, required this.name,
required this.type, required this.type,
required this.key, required this.key,
this.isCurrent = false, this.isCurrent = false,
this.isEnabled = true}); this.isEnabled = true,
});
final String name; final String name;
final WalletType type; final WalletType type;

View file

@ -1,5 +1,9 @@
import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
@ -22,6 +26,7 @@ abstract class WalletListViewModelBase with Store {
this._authService, this._authService,
) : wallets = ObservableList<WalletListItem>() { ) : wallets = ObservableList<WalletListItem>() {
_updateList(); _updateList();
reaction((_) => _appStore.wallet, (_) => _updateList());
} }
@observable @observable