[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: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;
}

View File

@ -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}) {

View File

@ -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;

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: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))),
]),
);
}
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) {
return [];
}

View File

@ -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),

View File

@ -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

View File

@ -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),
),

View File

@ -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"),
)
],
),
);