소스 검색

[flutter]: collpase menu

appflowy 3 년 전
부모
커밋
2f4f440097

+ 8 - 7
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<T> with NavigationItem {
 
 class HomeStackNotifier extends ChangeNotifier {
   HomeStackContext stackContext;
+  PublishNotifier<bool> 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<bool> get collapsedNotifier => _notifier.collapsedNotifier;
+
+  void switchStack(HomeStackContext context) {
     _notifier.context = context;
   }
 

+ 12 - 13
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<HomeBloc>();
-    Widget homeMenu = HomeMenu(
-      pageContextChanged: (pageContext) {
-        getIt<HomeStackManager>().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<HomeStackManager>().collapsedNotifier;
+
+    HomeMenu homeMenu = HomeMenu(user: user, workspaceId: workspaceId, collapsedNotifier: collapasedNotifier);
+    collapasedNotifier.addPublishListener((isCollapsed) {
+      homeBloc.add(HomeEvent.forceCollapse(isCollapsed));
+    });
+
+    homeMenu.pageContext.addPublishListener((pageContext) {
+      getIt<HomeStackManager>().switchStack(pageContext);
+    });
+
+    return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu));
   }
 
   Widget _buildEditPannel({required HomeState homeState, required BuildContext context, required HomeLayout layout}) {

+ 0 - 1
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;

+ 50 - 8
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<NavigationItem> navigationItems;
-  NavigationNotifier({required this.navigationItems});
+  PublishNotifier<bool> 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<HomeStackNotifier>(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<NavigationNotifier, PublishNotifier<bool>>(
+            selector: (context, notifier) => notifier.collapasedNotifier,
+            builder: (ctx, collapsedNotifier, child) => _renderCollapse(ctx, collapsedNotifier)),
+        Selector<NavigationNotifier, List<NavigationItem>>(
+            selector: (context, notifier) => notifier.navigationItems,
+            builder: (ctx, items, child) => Row(children: _renderNavigationItems(items))),
+      ]),
+    );
+  }
+
+  Widget _renderCollapse(BuildContext context, PublishNotifier<bool> collapsedNotifier) {
+    return ChangeNotifierProvider.value(
+      value: collapsedNotifier,
+      child: Consumer(
+        builder: (ctx, PublishNotifier<bool> 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<Widget> _renderChildren(List<NavigationItem> items) {
+  List<Widget> _renderNavigationItems(List<NavigationItem> items) {
     if (items.isEmpty) {
       return [];
     }

+ 13 - 9
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<HomeStackContext> pageContext = PublishNotifier();
+  final PublishNotifier<bool> 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<MenuBloc>(
-          create: (context) => getIt<MenuBloc>(param1: user, param2: workspaceId)..add(const MenuEvent.initial()),
+          create: (context) {
+            final menuBloc = getIt<MenuBloc>(param1: user, param2: workspaceId);
+            menuBloc.add(const MenuEvent.initial());
+            return menuBloc;
+          },
         ),
       ],
       child: MultiBlocListener(
         listeners: [
           BlocListener<MenuBloc, MenuState>(
             listenWhen: (p, c) => p.context != c.context,
-            listener: (context, state) => pageContextChanged(state.context),
+            listener: (context, state) => pageContext.value = state.context,
           ),
           BlocListener<MenuBloc, MenuState>(
             listenWhen: (p, c) => p.isCollapse != c.isCollapse,
-            listener: (context, state) => isCollapseChanged(state.isCollapse),
+            listener: (context, state) => collapsedNotifier.value = state.isCollapse,
           )
         ],
         child: BlocBuilder<MenuBloc, MenuState>(
@@ -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),

+ 1 - 1
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<HomeStackManager>().setStack(view.stackContext());
+        getIt<HomeStackManager>().switchStack(view.stackContext());
       });
     } else {
       // do nothing

+ 1 - 1
app_flowy/lib/workspace/presentation/widgets/menu/widget/menu_trash.dart

@@ -19,7 +19,7 @@ class MenuTrash extends StatelessWidget {
       child: InkWell(
         onTap: () {
           Provider.of<MenuSharedState>(context, listen: false).selectedView = null;
-          getIt<HomeStackManager>().setStack(TrashStackContext());
+          getIt<HomeStackManager>().switchStack(TrashStackContext());
         },
         child: _render(context),
       ),

+ 8 - 7
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<MenuBloc, MenuState>(
       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<MenuBloc>().add(const MenuEvent.collapse()),
-              ),
+                iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
+                icon: svg("home/hide_menu"),
+              )
             ],
           ),
         );