[flutter]: collpase menu

This commit is contained in:
appflowy 2021-11-05 14:23:30 +08:00
parent 31edb66508
commit 2f4f440097
8 changed files with 93 additions and 47 deletions

View file

@ -1,3 +1,4 @@
import 'package:flowy_infra/notifier.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
@ -44,20 +45,18 @@ abstract class HomeStackContext<T> with NavigationItem {
class HomeStackNotifier extends ChangeNotifier { class HomeStackNotifier extends ChangeNotifier {
HomeStackContext stackContext; HomeStackContext stackContext;
PublishNotifier<bool> collapsedNotifier = PublishNotifier();
Widget get titleWidget => stackContext.naviTitle; Widget get titleWidget => stackContext.naviTitle;
HomeStackNotifier({HomeStackContext? context}) : stackContext = context ?? BlankStackContext(); HomeStackNotifier({HomeStackContext? context}) : stackContext = context ?? BlankStackContext();
set context(HomeStackContext context) { set context(HomeStackContext context) {
notifyChange() { stackContext.isUpdated.removeListener(notifyListeners);
notifyListeners();
}
stackContext.isUpdated.removeListener(notifyChange);
stackContext.dispose(); stackContext.dispose();
stackContext = context; stackContext = context;
stackContext.isUpdated.addListener(notifyChange); stackContext.isUpdated.addListener(notifyListeners);
notifyListeners(); notifyListeners();
} }
@ -73,7 +72,9 @@ class HomeStackManager {
return _notifier.context.naviTitle; return _notifier.context.naviTitle;
} }
void setStack(HomeStackContext context) { PublishNotifier<bool> get collapsedNotifier => _notifier.collapsedNotifier;
void switchStack(HomeStackContext context) {
_notifier.context = context; _notifier.context = context;
} }

View file

@ -99,19 +99,18 @@ class HomeScreen extends StatelessWidget {
Widget _buildHomeMenu({required HomeLayout layout, required BuildContext context}) { Widget _buildHomeMenu({required HomeLayout layout, required BuildContext context}) {
final homeBloc = context.read<HomeBloc>(); final homeBloc = context.read<HomeBloc>();
Widget homeMenu = HomeMenu( final collapasedNotifier = getIt<HomeStackManager>().collapsedNotifier;
pageContextChanged: (pageContext) {
getIt<HomeStackManager>().setStack(pageContext); HomeMenu homeMenu = HomeMenu(user: user, workspaceId: workspaceId, collapsedNotifier: collapasedNotifier);
}, collapasedNotifier.addPublishListener((isCollapsed) {
isCollapseChanged: (isCollapse) { homeBloc.add(HomeEvent.forceCollapse(isCollapsed));
homeBloc.add(HomeEvent.forceCollapse(isCollapse)); });
},
user: user, homeMenu.pageContext.addPublishListener((pageContext) {
workspaceId: workspaceId, getIt<HomeStackManager>().switchStack(pageContext);
); });
homeMenu = RepaintBoundary(child: homeMenu);
homeMenu = FocusTraversalGroup(child: homeMenu); return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu));
return homeMenu;
} }
Widget _buildEditPannel({required HomeState homeState, required BuildContext context, required HomeLayout layout}) { Widget _buildEditPannel({required HomeState homeState, required BuildContext context, required HomeLayout layout}) {

View file

@ -1,5 +1,4 @@
class HomeSizes { class HomeSizes {
static double get menuTopBarHeight => 48;
static double get menuAddButtonHeight => 60; static double get menuAddButtonHeight => 60;
static double get topBarHeight => 60; static double get topBarHeight => 60;
static double get editPannelTopBarHeight => 60; static double get editPannelTopBarHeight => 60;

View file

@ -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: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/text.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
@ -9,11 +12,19 @@ typedef NaviAction = void Function();
class NavigationNotifier with ChangeNotifier { class NavigationNotifier with ChangeNotifier {
List<NavigationItem> navigationItems; List<NavigationItem> navigationItems;
NavigationNotifier({required this.navigationItems}); PublishNotifier<bool> collapasedNotifier;
NavigationNotifier({required this.navigationItems, required this.collapasedNotifier});
void update(HomeStackNotifier notifier) { void update(HomeStackNotifier notifier) {
navigationItems = notifier.context.navigationItems; bool shouldNotify = false;
notifyListeners(); 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); final notifier = Provider.of<HomeStackNotifier>(context, listen: false);
return NavigationNotifier( return NavigationNotifier(
navigationItems: notifier.context.navigationItems, navigationItems: notifier.context.navigationItems,
collapasedNotifier: notifier.collapsedNotifier,
); );
}, },
update: (_, notifier, controller) => controller!..update(notifier), update: (_, notifier, controller) => controller!..update(notifier),
child: Consumer(builder: (ctx, NavigationNotifier notifier, child) { child: Row(children: [
return Row(children: _renderChildren(notifier.navigationItems)); 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))),
]),
); );
} }
List<Widget> _renderChildren(List<NavigationItem> 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> _renderNavigationItems(List<NavigationItem> items) {
if (items.isEmpty) { if (items.isEmpty) {
return []; return [];
} }

View file

@ -1,5 +1,6 @@
import 'package:app_flowy/workspace/presentation/widgets/menu/widget/top_bar.dart'; import 'package:app_flowy/workspace/presentation/widgets/menu/widget/top_bar.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
@ -41,17 +42,16 @@ import 'widget/menu_trash.dart';
// //
class HomeMenu extends StatelessWidget { class HomeMenu extends StatelessWidget {
final Function(HomeStackContext) pageContextChanged; final PublishNotifier<HomeStackContext> pageContext = PublishNotifier();
final Function(bool) isCollapseChanged; final PublishNotifier<bool> collapsedNotifier;
final UserProfile user; final UserProfile user;
final String workspaceId; final String workspaceId;
const HomeMenu({ HomeMenu({
Key? key, Key? key,
required this.pageContextChanged,
required this.isCollapseChanged,
required this.user, required this.user,
required this.workspaceId, required this.workspaceId,
required this.collapsedNotifier,
}) : super(key: key); }) : super(key: key);
@override @override
@ -59,18 +59,22 @@ class HomeMenu extends StatelessWidget {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider<MenuBloc>( 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( child: MultiBlocListener(
listeners: [ listeners: [
BlocListener<MenuBloc, MenuState>( BlocListener<MenuBloc, MenuState>(
listenWhen: (p, c) => p.context != c.context, listenWhen: (p, c) => p.context != c.context,
listener: (context, state) => pageContextChanged(state.context), listener: (context, state) => pageContext.value = state.context,
), ),
BlocListener<MenuBloc, MenuState>( BlocListener<MenuBloc, MenuState>(
listenWhen: (p, c) => p.isCollapse != c.isCollapse, listenWhen: (p, c) => p.isCollapse != c.isCollapse,
listener: (context, state) => isCollapseChanged(state.isCollapse), listener: (context, state) => collapsedNotifier.value = state.isCollapse,
) )
], ],
child: BlocBuilder<MenuBloc, MenuState>( child: BlocBuilder<MenuBloc, MenuState>(
@ -94,7 +98,7 @@ class HomeMenu extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
_renderTopBar(context), _renderTopBar(context),
const VSpace(32), const VSpace(16),
_renderApps(context), _renderApps(context),
], ],
).padding(horizontal: Insets.l), ).padding(horizontal: Insets.l),

View file

@ -90,7 +90,7 @@ class ViewSectionNotifier with ChangeNotifier {
if (view != null) { if (view != null) {
WidgetsBinding.instance?.addPostFrameCallback((_) { WidgetsBinding.instance?.addPostFrameCallback((_) {
getIt<HomeStackManager>().setStack(view.stackContext()); getIt<HomeStackManager>().switchStack(view.stackContext());
}); });
} else { } else {
// do nothing // do nothing

View file

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

View file

@ -1,5 +1,7 @@
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart'; 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/image.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -10,18 +12,17 @@ class MenuTopBar extends StatelessWidget {
return BlocBuilder<MenuBloc, MenuState>( return BlocBuilder<MenuBloc, MenuState>(
builder: (context, state) { builder: (context, state) {
return SizedBox( return SizedBox(
height: 48, height: HomeSizes.topBarHeight,
child: Row( child: Row(
children: [ children: [
svgWithSize("flowy_logo_with_text", const Size(92, 17)), svgWithSize("flowy_logo_with_text", const Size(92, 17)),
const Spacer(), const Spacer(),
IconButton( FlowyIconButton(
iconSize: 16, width: 28,
icon: svg("home/hide_menu"),
alignment: Alignment.centerRight,
padding: EdgeInsets.zero,
onPressed: () => context.read<MenuBloc>().add(const MenuEvent.collapse()), onPressed: () => context.read<MenuBloc>().add(const MenuEvent.collapse()),
), iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
icon: svg("home/hide_menu"),
)
], ],
), ),
); );