Refactor sidebar state management

This commit is contained in:
Godwin Asuquo 2023-02-11 00:32:26 +02:00
parent 89fe8df459
commit bdfe070f8d
11 changed files with 140 additions and 146 deletions

View file

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 663 B

View file

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 390 B

View file

@ -19,6 +19,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart'; import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
import 'package:cake_wallet/themes/theme_list.dart'; import 'package:cake_wallet/themes/theme_list.dart';
import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_auth_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_buy_card_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart'; import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
@ -168,6 +169,7 @@ import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
final getIt = GetIt.instance; final getIt = GetIt.instance;
var _isSetupFinished = false; var _isSetupFinished = false;
@ -832,6 +834,8 @@ Future setup(
getIt.registerFactory(() => DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>())); getIt.registerFactory(() => DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>()));
getIt.registerFactory(() => DesktopSidebarViewModel());
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>( getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
=> IoniaPaymentStatusViewModel( => IoniaPaymentStatusViewModel(

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/main_actions.dart'; import 'package:cake_wallet/entities/main_actions.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_dashboard_page.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_dashboard_page.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
@ -10,6 +11,7 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.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/dashboard/desktop_sidebar_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
@ -37,6 +39,7 @@ class DashboardPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final desktopSidebarViewModel = getIt<DesktopSidebarViewModel>();
return Scaffold( return Scaffold(
body: ResponsiveLayoutUtil.instance.isMobile(context) body: ResponsiveLayoutUtil.instance.isMobile(context)
? _DashboardPageView( ? _DashboardPageView(
@ -45,7 +48,9 @@ class DashboardPage extends StatelessWidget {
addressListViewModel: addressListViewModel, addressListViewModel: addressListViewModel,
) )
: DesktopSidebarWrapper( : DesktopSidebarWrapper(
desktopSidebarViewModel: desktopSidebarViewModel,
child: DesktopDashboardPage( child: DesktopDashboardPage(
desktopSidebarViewModel: desktopSidebarViewModel,
balancePage: balancePage, balancePage: balancePage,
walletViewModel: walletViewModel, walletViewModel: walletViewModel,
addressListViewModel: addressListViewModel, addressListViewModel: addressListViewModel,

View file

@ -4,17 +4,18 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_view.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_view.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/dashboard/widgets/transactions_page.dart';
import 'package:cake_wallet/src/screens/yat_emoji_id.dart'; import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.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/dashboard/desktop_sidebar_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/main.dart';
@ -23,6 +24,7 @@ class DesktopDashboardPage extends BasePage {
required this.balancePage, required this.balancePage,
required this.walletViewModel, required this.walletViewModel,
required this.addressListViewModel, required this.addressListViewModel,
required this.desktopSidebarViewModel,
}); });
@override @override
@ -58,8 +60,9 @@ class DesktopDashboardPage extends BasePage {
@override @override
Widget trailing(BuildContext context) { Widget trailing(BuildContext context) {
final iconPath = Image.asset('assets/images/solid_desktop_menu.png', final selectedIconPath = 'assets/images/desktop_transactions_solid_icon.png';
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!); final unselectedIconPath = 'assets/images/desktop_transactions_outline_icon.png';
return InkWell( return InkWell(
onTap: () { onTap: () {
String? currentPath; String? currentPath;
@ -70,18 +73,30 @@ class DesktopDashboardPage extends BasePage {
}); });
if (currentPath == Routes.transactionsPage) { if (currentPath == Routes.transactionsPage) {
return Navigator.pop(desktopKey.currentContext!); desktopSidebarViewModel.resetSidebar();
} return;
}
desktopSidebarViewModel.onPageChange(SidebarItem.transactions);
desktopKey.currentState!.pushNamed(Routes.transactionsPage); desktopKey.currentState!.pushNamed(Routes.transactionsPage);
}, },
child: iconPath, child: Observer(
builder: (_) {
return Image.asset(
desktopSidebarViewModel.currentPage == SidebarItem.transactions
? selectedIconPath
: unselectedIconPath,
);
},
),
); );
} }
final BalancePage balancePage; final BalancePage balancePage;
final DashboardViewModel walletViewModel; final DashboardViewModel walletViewModel;
final WalletAddressListViewModel addressListViewModel; final WalletAddressListViewModel addressListViewModel;
final DesktopSidebarViewModel desktopSidebarViewModel;
bool _isEffectsInstalled = false; bool _isEffectsInstalled = false;
StreamSubscription<bool>? _onInactiveSub; StreamSubscription<bool>? _onInactiveSub;

View file

@ -1,35 +0,0 @@
import 'dart:async';
class SideMenuController {
late int _currentPage;
int get currentPage => _currentPage;
SideMenuController({int initialPage = 0}) {
_currentPage = initialPage;
}
final _streameController = StreamController<int>.broadcast();
Stream<int> get stream => _streameController.stream;
void changePage(int index) {
_currentPage = index;
_streameController.sink.add(index);
}
void dispose() {
_streameController.close();
}
void addListener(void Function(int) listener) {
_streameController.stream.listen(listener);
}
void removeListener(void Function(int) listener) {
_streameController.stream.listen(listener).cancel();
}
}
class SideMenuGlobal {
static late SideMenuController controller;
}

View file

@ -1,74 +1,39 @@
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_controller.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SideMenuItem extends StatefulWidget { class SideMenuItem extends StatelessWidget {
const SideMenuItem({ const SideMenuItem({
Key? key, Key? key,
this.onTap, required this.onTap,
required this.iconPath, required this.iconPath,
required this.priority, required this.isSelected,
}) : super(key: key); }) : super(key: key);
final void Function(int, SideMenuController)? onTap; final void Function() onTap;
final String iconPath; final String iconPath;
final int priority; final bool isSelected;
@override
_SideMenuItemState createState() => _SideMenuItemState();
}
class _SideMenuItemState extends State<SideMenuItem> {
late int currentPage = SideMenuGlobal.controller.currentPage;
void _handleChange(int page) {
if (mounted) {
setState(() {
currentPage = page;
});
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
currentPage = SideMenuGlobal.controller.currentPage;
});
if (mounted) {
SideMenuGlobal.controller.addListener(_handleChange);
}
});
}
@override
void dispose() {
SideMenuGlobal.controller.removeListener(_handleChange);
super.dispose();
}
Color _setColor() {
if (widget.priority == currentPage) {
return Theme.of(context).primaryTextTheme.headline6!.color!;
} else {
return Theme.of(context).highlightColor;
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Color _setColor() {
if (isSelected) {
return Theme.of(context).primaryTextTheme.headline6!.color!;
} else {
return Theme.of(context).highlightColor;
}
}
return InkWell( return InkWell(
child: Padding( child: Padding(
padding: EdgeInsets.all(20), padding: EdgeInsets.all(20),
child: Image.asset( child: Image.asset(
widget.iconPath, iconPath,
fit: BoxFit.cover, fit: BoxFit.cover,
height: 30, height: 30,
width: 30, width: 30,
color: _setColor(), color: _setColor(),
), ),
), ),
onTap: () => widget.onTap?.call(widget.priority, SideMenuGlobal.controller), onTap: () => onTap.call(),
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
focusColor: Colors.transparent, focusColor: Colors.transparent,
hoverColor: Colors.transparent, hoverColor: Colors.transparent,

View file

@ -1,64 +1,76 @@
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_view.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_controller.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_item.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_item.dart';
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/router.dart' as Router; import 'package:cake_wallet/router.dart' as Router;
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
class DesktopSidebarWrapper extends StatefulWidget { class DesktopSidebarWrapper extends StatelessWidget {
final Widget child; final Widget child;
final DesktopSidebarViewModel desktopSidebarViewModel;
const DesktopSidebarWrapper({required this.child}); const DesktopSidebarWrapper({required this.child, required this.desktopSidebarViewModel});
@override
State<DesktopSidebarWrapper> createState() => _DesktopSidebarWrapperState();
}
class _DesktopSidebarWrapperState extends State<DesktopSidebarWrapper> {
final page = PageController();
final sideMenu = SideMenuController();
@override
void initState() {
SideMenuGlobal.controller = sideMenu;
sideMenu.addListener((p0) {
page.jumpToPage(p0);
});
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final pageController = PageController();
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.animateToPage(
page.index,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
});
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SideMenu( Observer(builder: (_) {
topItems: [ return SideMenu(
SideMenuItem( topItems: [
iconPath: 'assets/images/wallet_outline.png', SideMenuItem(
priority: 0, iconPath: 'assets/images/wallet_outline.png',
onTap: (page, _) => sideMenu.changePage(page), isSelected: desktopSidebarViewModel.currentPage == SidebarItem.dashboard,
), onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.dashboard),
], ),
bottomItems: [ ],
SideMenuItem( bottomItems: [
iconPath: 'assets/images/support_icon.png', SideMenuItem(
priority: 1, iconPath: 'assets/images/support_icon.png',
onTap: (page, _) => sideMenu.changePage(page), isSelected: desktopSidebarViewModel.currentPage == SidebarItem.support,
), onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.support)),
SideMenuItem( SideMenuItem(
iconPath: 'assets/images/settings_outline.png', iconPath: 'assets/images/settings_outline.png',
priority: 2, isSelected: desktopSidebarViewModel.currentPage == SidebarItem.settings,
onTap: (page, _) => sideMenu.changePage(page), onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.settings),
), ),
], ],
), );
}),
Expanded( Expanded(
child: PageView( child: PageView(
controller: page, controller: pageController,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
children: [ children: [
widget.child, child,
Container( Container(
child: Navigator( child: Navigator(
initialRoute: Routes.support, initialRoute: Routes.support,

View file

@ -22,6 +22,7 @@ class TransactionsPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
color: Theme.of(context).backgroundColor,
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: 24, top: 24,
bottom: 24 bottom: 24

View file

@ -1,6 +1,5 @@
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/dashboard/desktop_widgets/desktop_sidebar/side_menu_controller.dart';
import 'package:cake_wallet/src/widgets/setting_action_button.dart'; import 'package:cake_wallet/src/widgets/setting_action_button.dart';
import 'package:cake_wallet/src/widgets/setting_actions.dart'; import 'package:cake_wallet/src/widgets/setting_actions.dart';
import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/typography.dart';
@ -17,19 +16,14 @@ class DesktopSettingsPage extends StatefulWidget {
} }
class _DesktopSettingsPageState extends State<DesktopSettingsPage> { class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
int itemCount = 0; int itemCount = SettingActions.all.length;
SideMenuController sideMenu = SideMenuController();
int? currentPage; int? currentPage;
bool isTapped = false; bool isTapped = false;
initState() { void _onItemChange(int index) {
super.initState(); setState(() {
itemCount = SettingActions.all.length; currentPage = index;
sideMenu.addListener((index) { isTapped = true;
setState(() {
isTapped = true;
currentPage = index;
});
}); });
} }
@ -67,8 +61,8 @@ class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
if (currentPage != index) { if (currentPage != index) {
final settingContext = final settingContext =
_settingsNavigatorKey.currentState?.context ?? context; _settingsNavigatorKey.currentState?.context ?? context;
sideMenu.changePage(index);
item.onTap.call(settingContext); item.onTap.call(settingContext);
_onItemChange(index);
} }
}, },
image: item.image, image: item.image,

View file

@ -0,0 +1,33 @@
import 'package:mobx/mobx.dart';
part 'desktop_sidebar_view_model.g.dart';
enum SidebarItem {
dashboard(0),
support(1),
settings(2),
transactions(3);
final int value;
const SidebarItem(this.value);
}
class DesktopSidebarViewModel = DesktopSidebarViewModelBase with _$DesktopSidebarViewModel;
abstract class DesktopSidebarViewModelBase with Store {
DesktopSidebarViewModelBase();
@observable
SidebarItem currentPage = SidebarItem.dashboard;
@action
void onPageChange(SidebarItem item) {
currentPage = item;
}
@action
void resetSidebar() {
currentPage = SidebarItem.dashboard;
}
}