mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
[flutter]: collpase menu
This commit is contained in:
parent
31edb66508
commit
2f4f440097
8 changed files with 93 additions and 47 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
),
|
),
|
||||||
|
|
|
@ -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"),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue