mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Merge branch 'dashboard-desktop-view' of https://github.com/cake-tech/cake_wallet into align-create-restore-screens
This commit is contained in:
commit
28c599e68a
12 changed files with 226 additions and 104 deletions
9
lib/entities/desktop_dropdown_item.dart
Normal file
9
lib/entities/desktop_dropdown_item.dart
Normal 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});
|
||||
}
|
|
@ -23,8 +23,11 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore,
|
|||
}
|
||||
|
||||
if (state == AuthenticationState.allowed) {
|
||||
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
||||
return;
|
||||
// Temporary workaround for the issue with desktopKey dispose
|
||||
Future.delayed(Duration(milliseconds: 2), () async {
|
||||
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ class DesktopSidebarWrapper extends BasePage {
|
|||
required this.dashboardViewModel,
|
||||
});
|
||||
|
||||
static Key _pageViewKey = GlobalKey();
|
||||
|
||||
@override
|
||||
PreferredSizeWidget desktopAppBar(BuildContext context) => DesktopNavbar(
|
||||
leading: Padding(
|
||||
|
@ -97,23 +99,7 @@ class DesktopSidebarWrapper extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
reaction<SidebarItem>((_) => desktopSidebarViewModel.currentPage, (page) {
|
||||
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);
|
||||
});
|
||||
_setEffects();
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -143,6 +129,7 @@ class DesktopSidebarWrapper extends BasePage {
|
|||
}),
|
||||
Expanded(
|
||||
child: PageView(
|
||||
key: _pageViewKey,
|
||||
controller: pageController,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
|
@ -174,4 +161,25 @@ 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
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/routes.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/utils/show_bar.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_view_model.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class DesktopWalletSelectionDropDown extends StatefulWidget {
|
||||
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 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 double tileHeight = 60;
|
||||
Image _getNewWalletImage(BuildContext context) => Image.asset(
|
||||
'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;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeData = Theme.of(context);
|
||||
return DropdownButton<WalletListItem>(
|
||||
items: widget.walletListViewModel.wallets
|
||||
.map((wallet) => DropdownMenuItem(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 500),
|
||||
child: walletListItemTile(wallet),
|
||||
),
|
||||
return Observer(builder: (context) {
|
||||
final dropDownItems = [
|
||||
...widget.walletListViewModel.wallets
|
||||
.map((wallet) => DesktopDropdownItem(
|
||||
isSelected: wallet.isCurrent,
|
||||
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,
|
||||
))
|
||||
.toList(),
|
||||
onChanged: (selectedWallet) async {
|
||||
if (selectedWallet!.isCurrent || !selectedWallet.isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
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(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,
|
||||
);
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (item) {
|
||||
item?.onSelected();
|
||||
},
|
||||
dropdownColor: themeData.textTheme.bodyText1?.decorationColor,
|
||||
style: TextStyle(color: themeData.primaryTextTheme.headline6?.color),
|
||||
selectedItemBuilder: (context) => dropDownItems.map((item) => item.child).toList(),
|
||||
value: dropDownItems.firstWhere((element) => element.isSelected),
|
||||
underline: const SizedBox(),
|
||||
focusColor: Colors.transparent,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget walletListItemTile(WalletListItem wallet) {
|
||||
return Container(
|
||||
height: tileHeight,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon,
|
||||
SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Text(
|
||||
wallet.name,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
void _onSelectedWallet(WalletListItem selectedWallet) async {
|
||||
if (selectedWallet.isCurrent || !selectedWallet.isEnabled) {
|
||||
return;
|
||||
}
|
||||
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(context).pop(false),
|
||||
actionRightButton: () => Navigator.of(context).pop(true));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await _loadWallet(selectedWallet);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
_progressBar = createBar<void>(text, duration: null)..show(context);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,8 @@ class DesktopSettingsPage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
|
||||
final int itemCount = SettingActions.all.length;
|
||||
final int itemCount = SettingActions.desktopSettings.length;
|
||||
|
||||
int? currentPage;
|
||||
|
||||
void _onItemChange(int index) {
|
||||
|
@ -48,8 +49,8 @@ class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
|
|||
child: ListView.separated(
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
itemBuilder: (_, index) {
|
||||
final item = SettingActions.all[index];
|
||||
final isLastTile = index == itemCount;
|
||||
final item = SettingActions.desktopSettings[index];
|
||||
final isLastTile = index == itemCount - 1;
|
||||
return SettingActionButton(
|
||||
isLastTile: isLastTile,
|
||||
selectionActive: currentPage != null,
|
||||
|
|
|
@ -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/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
|
@ -100,9 +101,9 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(context).pop(false),
|
||||
Navigator.of(dialogContext).pop(false),
|
||||
actionRightButton: () =>
|
||||
Navigator.of(context).pop(true));
|
||||
Navigator.of(dialogContext).pop(true));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -100,7 +103,8 @@ class AddressTextField extends StatelessWidget {
|
|||
width: prefixIconWidth * options.length +
|
||||
(spaceBetweenPrefixIcons * options.length),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment: DeviceInfo.instance.isMobile
|
||||
? MainAxisAlignment.spaceBetween : MainAxisAlignment.end,
|
||||
children: [
|
||||
SizedBox(width: 5),
|
||||
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(
|
||||
width: prefixIconWidth,
|
||||
height: prefixIconHeight,
|
||||
|
@ -156,7 +161,7 @@ class AddressTextField extends StatelessWidget {
|
|||
.decorationColor!,
|
||||
)),
|
||||
))
|
||||
],
|
||||
] else SizedBox(width: 5),
|
||||
if (this
|
||||
.options
|
||||
.contains(AddressTextFieldOption.addressBook)) ...[
|
||||
|
|
|
@ -24,6 +24,16 @@ class SettingActions {
|
|||
supportSettingAction,
|
||||
];
|
||||
|
||||
static List<SettingActions> desktopSettings = [
|
||||
connectionSettingAction,
|
||||
addressBookSettingAction,
|
||||
securityBackupSettingAction,
|
||||
privacySettingAction,
|
||||
displaySettingAction,
|
||||
otherSettingAction,
|
||||
supportSettingAction,
|
||||
];
|
||||
|
||||
static SettingActions connectionSettingAction = SettingActions._(
|
||||
name: S.current.connection_sync,
|
||||
image: 'assets/images/nodes_menu.png',
|
||||
|
|
11
lib/utils/device_info.dart
Normal file
11
lib/utils/device_info.dart
Normal 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;
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class WalletListItem {
|
||||
const WalletListItem(
|
||||
{required this.name,
|
||||
required this.type,
|
||||
required this.key,
|
||||
this.isCurrent = false,
|
||||
this.isEnabled = true});
|
||||
const WalletListItem({
|
||||
required this.name,
|
||||
required this.type,
|
||||
required this.key,
|
||||
this.isCurrent = false,
|
||||
this.isEnabled = true,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final WalletType type;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import 'package:cake_wallet/core/auth_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:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
|
@ -22,6 +26,7 @@ abstract class WalletListViewModelBase with Store {
|
|||
this._authService,
|
||||
) : wallets = ObservableList<WalletListItem>() {
|
||||
_updateList();
|
||||
reaction((_) => _appStore.wallet, (_) => _updateList());
|
||||
}
|
||||
|
||||
@observable
|
||||
|
|
Loading…
Reference in a new issue