From 2f4f440097f27236ddecb4b9b80cc893a1642e95 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 5 Nov 2021 14:23:30 +0800 Subject: [PATCH] [flutter]: collpase menu --- .../domain/page_stack/page_stack.dart | 15 ++--- .../presentation/home/home_screen.dart | 25 ++++---- .../presentation/home/home_sizes.dart | 1 - .../presentation/home/navigation.dart | 58 ++++++++++++++++--- .../presentation/widgets/menu/menu.dart | 22 ++++--- .../menu/widget/app/section/section.dart | 2 +- .../widgets/menu/widget/menu_trash.dart | 2 +- .../widgets/menu/widget/top_bar.dart | 15 ++--- 8 files changed, 93 insertions(+), 47 deletions(-) diff --git a/app_flowy/lib/workspace/domain/page_stack/page_stack.dart b/app_flowy/lib/workspace/domain/page_stack/page_stack.dart index 52ffd0e3dc..4731c4c6d2 100644 --- a/app_flowy/lib/workspace/domain/page_stack/page_stack.dart +++ b/app_flowy/lib/workspace/domain/page_stack/page_stack.dart @@ -1,3 +1,4 @@ +import 'package:flowy_infra/notifier.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:app_flowy/startup/startup.dart'; @@ -44,20 +45,18 @@ abstract class HomeStackContext with NavigationItem { class HomeStackNotifier extends ChangeNotifier { HomeStackContext stackContext; + PublishNotifier collapsedNotifier = PublishNotifier(); + Widget get titleWidget => stackContext.naviTitle; HomeStackNotifier({HomeStackContext? context}) : stackContext = context ?? BlankStackContext(); set context(HomeStackContext context) { - notifyChange() { - notifyListeners(); - } - - stackContext.isUpdated.removeListener(notifyChange); + stackContext.isUpdated.removeListener(notifyListeners); stackContext.dispose(); stackContext = context; - stackContext.isUpdated.addListener(notifyChange); + stackContext.isUpdated.addListener(notifyListeners); notifyListeners(); } @@ -73,7 +72,9 @@ class HomeStackManager { return _notifier.context.naviTitle; } - void setStack(HomeStackContext context) { + PublishNotifier get collapsedNotifier => _notifier.collapsedNotifier; + + void switchStack(HomeStackContext context) { _notifier.context = context; } diff --git a/app_flowy/lib/workspace/presentation/home/home_screen.dart b/app_flowy/lib/workspace/presentation/home/home_screen.dart index 783385c6ba..7f73b07b55 100644 --- a/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -99,19 +99,18 @@ class HomeScreen extends StatelessWidget { Widget _buildHomeMenu({required HomeLayout layout, required BuildContext context}) { final homeBloc = context.read(); - Widget homeMenu = HomeMenu( - pageContextChanged: (pageContext) { - getIt().setStack(pageContext); - }, - isCollapseChanged: (isCollapse) { - homeBloc.add(HomeEvent.forceCollapse(isCollapse)); - }, - user: user, - workspaceId: workspaceId, - ); - homeMenu = RepaintBoundary(child: homeMenu); - homeMenu = FocusTraversalGroup(child: homeMenu); - return homeMenu; + final collapasedNotifier = getIt().collapsedNotifier; + + HomeMenu homeMenu = HomeMenu(user: user, workspaceId: workspaceId, collapsedNotifier: collapasedNotifier); + collapasedNotifier.addPublishListener((isCollapsed) { + homeBloc.add(HomeEvent.forceCollapse(isCollapsed)); + }); + + homeMenu.pageContext.addPublishListener((pageContext) { + getIt().switchStack(pageContext); + }); + + return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu)); } Widget _buildEditPannel({required HomeState homeState, required BuildContext context, required HomeLayout layout}) { diff --git a/app_flowy/lib/workspace/presentation/home/home_sizes.dart b/app_flowy/lib/workspace/presentation/home/home_sizes.dart index 395ede4347..350a1e49be 100644 --- a/app_flowy/lib/workspace/presentation/home/home_sizes.dart +++ b/app_flowy/lib/workspace/presentation/home/home_sizes.dart @@ -1,5 +1,4 @@ class HomeSizes { - static double get menuTopBarHeight => 48; static double get menuAddButtonHeight => 60; static double get topBarHeight => 60; static double get editPannelTopBarHeight => 60; diff --git a/app_flowy/lib/workspace/presentation/home/navigation.dart b/app_flowy/lib/workspace/presentation/home/navigation.dart index 9b48bb78c2..f1bb6822a3 100644 --- a/app_flowy/lib/workspace/presentation/home/navigation.dart +++ b/app_flowy/lib/workspace/presentation/home/navigation.dart @@ -1,6 +1,9 @@ +import 'package:app_flowy/workspace/application/menu/menu_bloc.dart'; import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -9,11 +12,19 @@ typedef NaviAction = void Function(); class NavigationNotifier with ChangeNotifier { List navigationItems; - NavigationNotifier({required this.navigationItems}); + PublishNotifier collapasedNotifier; + NavigationNotifier({required this.navigationItems, required this.collapasedNotifier}); void update(HomeStackNotifier notifier) { - navigationItems = notifier.context.navigationItems; - notifyListeners(); + bool shouldNotify = false; + if (navigationItems != notifier.context.navigationItems) { + navigationItems = notifier.context.navigationItems; + shouldNotify = true; + } + + if (shouldNotify) { + notifyListeners(); + } } } @@ -47,16 +58,47 @@ class FlowyNavigation extends StatelessWidget { final notifier = Provider.of(context, listen: false); return NavigationNotifier( navigationItems: notifier.context.navigationItems, + collapasedNotifier: notifier.collapsedNotifier, ); }, update: (_, notifier, controller) => controller!..update(notifier), - child: Consumer(builder: (ctx, NavigationNotifier notifier, child) { - return Row(children: _renderChildren(notifier.navigationItems)); - }), + child: Row(children: [ + Selector>( + selector: (context, notifier) => notifier.collapasedNotifier, + builder: (ctx, collapsedNotifier, child) => _renderCollapse(ctx, collapsedNotifier)), + Selector>( + selector: (context, notifier) => notifier.navigationItems, + builder: (ctx, items, child) => Row(children: _renderNavigationItems(items))), + ]), ); } - List _renderChildren(List items) { + Widget _renderCollapse(BuildContext context, PublishNotifier collapsedNotifier) { + return ChangeNotifierProvider.value( + value: collapsedNotifier, + child: Consumer( + builder: (ctx, PublishNotifier notifier, child) { + if (notifier.currentValue ?? false) { + return RotationTransition( + turns: const AlwaysStoppedAnimation(180 / 360), + child: FlowyIconButton( + width: 24, + onPressed: () { + notifier.value = false; + }, + iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), + icon: svg("home/hide_menu"), + ), + ); + } else { + return Container(); + } + }, + ), + ); + } + + List _renderNavigationItems(List items) { if (items.isEmpty) { return []; } diff --git a/app_flowy/lib/workspace/presentation/widgets/menu/menu.dart b/app_flowy/lib/workspace/presentation/widgets/menu/menu.dart index 9d1b830669..654cc6a65d 100644 --- a/app_flowy/lib/workspace/presentation/widgets/menu/menu.dart +++ b/app_flowy/lib/workspace/presentation/widgets/menu/menu.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/workspace/presentation/widgets/menu/widget/top_bar.dart'; import 'package:dartz/dartz.dart'; +import 'package:flowy_infra/notifier.dart'; import 'package:flowy_infra/size.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; @@ -41,17 +42,16 @@ import 'widget/menu_trash.dart'; // └────────┘ class HomeMenu extends StatelessWidget { - final Function(HomeStackContext) pageContextChanged; - final Function(bool) isCollapseChanged; + final PublishNotifier pageContext = PublishNotifier(); + final PublishNotifier collapsedNotifier; final UserProfile user; final String workspaceId; - const HomeMenu({ + HomeMenu({ Key? key, - required this.pageContextChanged, - required this.isCollapseChanged, required this.user, required this.workspaceId, + required this.collapsedNotifier, }) : super(key: key); @override @@ -59,18 +59,22 @@ class HomeMenu extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider( - create: (context) => getIt(param1: user, param2: workspaceId)..add(const MenuEvent.initial()), + create: (context) { + final menuBloc = getIt(param1: user, param2: workspaceId); + menuBloc.add(const MenuEvent.initial()); + return menuBloc; + }, ), ], child: MultiBlocListener( listeners: [ BlocListener( listenWhen: (p, c) => p.context != c.context, - listener: (context, state) => pageContextChanged(state.context), + listener: (context, state) => pageContext.value = state.context, ), BlocListener( listenWhen: (p, c) => p.isCollapse != c.isCollapse, - listener: (context, state) => isCollapseChanged(state.isCollapse), + listener: (context, state) => collapsedNotifier.value = state.isCollapse, ) ], child: BlocBuilder( @@ -94,7 +98,7 @@ class HomeMenu extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, children: [ _renderTopBar(context), - const VSpace(32), + const VSpace(16), _renderApps(context), ], ).padding(horizontal: Insets.l), diff --git a/app_flowy/lib/workspace/presentation/widgets/menu/widget/app/section/section.dart b/app_flowy/lib/workspace/presentation/widgets/menu/widget/app/section/section.dart index 9a6fe48fe8..d734715a59 100644 --- a/app_flowy/lib/workspace/presentation/widgets/menu/widget/app/section/section.dart +++ b/app_flowy/lib/workspace/presentation/widgets/menu/widget/app/section/section.dart @@ -90,7 +90,7 @@ class ViewSectionNotifier with ChangeNotifier { if (view != null) { WidgetsBinding.instance?.addPostFrameCallback((_) { - getIt().setStack(view.stackContext()); + getIt().switchStack(view.stackContext()); }); } else { // do nothing diff --git a/app_flowy/lib/workspace/presentation/widgets/menu/widget/menu_trash.dart b/app_flowy/lib/workspace/presentation/widgets/menu/widget/menu_trash.dart index b16808d549..229187d1b8 100644 --- a/app_flowy/lib/workspace/presentation/widgets/menu/widget/menu_trash.dart +++ b/app_flowy/lib/workspace/presentation/widgets/menu/widget/menu_trash.dart @@ -19,7 +19,7 @@ class MenuTrash extends StatelessWidget { child: InkWell( onTap: () { Provider.of(context, listen: false).selectedView = null; - getIt().setStack(TrashStackContext()); + getIt().switchStack(TrashStackContext()); }, child: _render(context), ), diff --git a/app_flowy/lib/workspace/presentation/widgets/menu/widget/top_bar.dart b/app_flowy/lib/workspace/presentation/widgets/menu/widget/top_bar.dart index b39159930f..12de6c09b6 100644 --- a/app_flowy/lib/workspace/presentation/widgets/menu/widget/top_bar.dart +++ b/app_flowy/lib/workspace/presentation/widgets/menu/widget/top_bar.dart @@ -1,5 +1,7 @@ import 'package:app_flowy/workspace/application/menu/menu_bloc.dart'; +import 'package:app_flowy/workspace/presentation/home/home_sizes.dart'; import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -10,18 +12,17 @@ class MenuTopBar extends StatelessWidget { return BlocBuilder( builder: (context, state) { return SizedBox( - height: 48, + height: HomeSizes.topBarHeight, child: Row( children: [ svgWithSize("flowy_logo_with_text", const Size(92, 17)), const Spacer(), - IconButton( - iconSize: 16, - icon: svg("home/hide_menu"), - alignment: Alignment.centerRight, - padding: EdgeInsets.zero, + FlowyIconButton( + width: 28, onPressed: () => context.read().add(const MenuEvent.collapse()), - ), + iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4), + icon: svg("home/hide_menu"), + ) ], ), );