home_screen.dart 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import 'package:app_flowy/startup/plugin/plugin.dart';
  2. import 'package:app_flowy/workspace/application/home/home_bloc.dart';
  3. import 'package:app_flowy/workspace/presentation/home/hotkeys.dart';
  4. import 'package:app_flowy/workspace/application/view/view_ext.dart';
  5. import 'package:app_flowy/workspace/presentation/widgets/edit_panel/panel_animation.dart';
  6. import 'package:app_flowy/workspace/presentation/widgets/float_bubble/question_bubble.dart';
  7. import 'package:app_flowy/startup/startup.dart';
  8. import 'package:flowy_sdk/log.dart';
  9. import 'package:flowy_infra_ui/style_widget/container.dart';
  10. import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
  11. import 'package:flowy_sdk/protobuf/flowy-folder/protobuf.dart';
  12. import 'package:flutter/gestures.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:flutter_bloc/flutter_bloc.dart';
  15. import 'package:styled_widget/styled_widget.dart';
  16. import '../widgets/edit_panel/edit_panel.dart';
  17. import 'home_layout.dart';
  18. import 'home_stack.dart';
  19. import 'menu/menu.dart';
  20. class HomeScreen extends StatefulWidget {
  21. final UserProfilePB user;
  22. final CurrentWorkspaceSettingPB workspaceSetting;
  23. const HomeScreen(this.user, this.workspaceSetting, {Key? key})
  24. : super(key: key);
  25. @override
  26. State<HomeScreen> createState() => _HomeScreenState();
  27. }
  28. class _HomeScreenState extends State<HomeScreen> {
  29. ViewPB? initialView;
  30. @override
  31. void initState() {
  32. super.initState();
  33. }
  34. @override
  35. void didUpdateWidget(covariant HomeScreen oldWidget) {
  36. initialView = null;
  37. super.didUpdateWidget(oldWidget);
  38. }
  39. @override
  40. Widget build(BuildContext context) {
  41. return MultiBlocProvider(
  42. providers: [
  43. BlocProvider<HomeBloc>(
  44. create: (context) {
  45. return HomeBloc(widget.user, widget.workspaceSetting)
  46. ..add(const HomeEvent.initial());
  47. },
  48. ),
  49. ],
  50. child: HomeHotKeys(
  51. child: Scaffold(
  52. body: BlocListener<HomeBloc, HomeState>(
  53. listenWhen: (p, c) => p.unauthorized != c.unauthorized,
  54. listener: (context, state) {
  55. if (state.unauthorized) {
  56. Log.error("Push to login screen when user token was invalid");
  57. }
  58. },
  59. child: BlocBuilder<HomeBloc, HomeState>(
  60. buildWhen: (previous, current) => previous != current,
  61. builder: (context, state) {
  62. final collapsedNotifier =
  63. getIt<HomeStackManager>().collapsedNotifier;
  64. collapsedNotifier.addPublishListener((isCollapsed) {
  65. context
  66. .read<HomeBloc>()
  67. .add(HomeEvent.forceCollapse(isCollapsed));
  68. });
  69. return FlowyContainer(
  70. Theme.of(context).colorScheme.surface,
  71. // Colors.white,
  72. child: _buildBody(state),
  73. );
  74. },
  75. ),
  76. ),
  77. )),
  78. );
  79. }
  80. Widget _buildBody(HomeState state) {
  81. return LayoutBuilder(
  82. builder: (BuildContext context, BoxConstraints constraints) {
  83. final layout = HomeLayout(context, constraints, state.forceCollapse);
  84. final homeStack = HomeStack(
  85. layout: layout,
  86. );
  87. final menu = _buildHomeMenu(
  88. layout: layout,
  89. context: context,
  90. state: state,
  91. );
  92. final homeMenuResizer = _buildHomeMenuResizer(context: context);
  93. final editPanel = _buildEditPanel(
  94. homeState: state,
  95. layout: layout,
  96. context: context,
  97. );
  98. const bubble = QuestionBubble();
  99. return _layoutWidgets(
  100. layout: layout,
  101. homeStack: homeStack,
  102. homeMenu: menu,
  103. editPanel: editPanel,
  104. bubble: bubble,
  105. homeMenuResizer: homeMenuResizer,
  106. );
  107. },
  108. );
  109. }
  110. Widget _buildHomeMenu(
  111. {required HomeLayout layout,
  112. required BuildContext context,
  113. required HomeState state}) {
  114. final workspaceSetting = state.workspaceSetting;
  115. if (initialView == null && workspaceSetting.hasLatestView()) {
  116. initialView = workspaceSetting.latestView;
  117. final plugin = makePlugin(
  118. pluginType: initialView!.pluginType,
  119. data: initialView,
  120. );
  121. getIt<HomeStackManager>().setPlugin(plugin);
  122. }
  123. HomeMenu homeMenu = HomeMenu(
  124. user: widget.user,
  125. workspaceSetting: workspaceSetting,
  126. collapsedNotifier: getIt<HomeStackManager>().collapsedNotifier,
  127. );
  128. final latestView =
  129. workspaceSetting.hasLatestView() ? workspaceSetting.latestView : null;
  130. if (getIt<MenuSharedState>().latestOpenView == null) {
  131. /// AppFlowy will open the view that the last time the user opened it. The _buildHomeMenu will get called when AppFlowy's screen resizes. So we only set the latestOpenView when it's null.
  132. getIt<MenuSharedState>().latestOpenView = latestView;
  133. }
  134. return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu));
  135. }
  136. Widget _buildEditPanel(
  137. {required HomeState homeState,
  138. required BuildContext context,
  139. required HomeLayout layout}) {
  140. final homeBloc = context.read<HomeBloc>();
  141. return BlocBuilder<HomeBloc, HomeState>(
  142. buildWhen: (previous, current) =>
  143. previous.panelContext != current.panelContext,
  144. builder: (context, state) {
  145. return state.panelContext.fold(
  146. () => const SizedBox(),
  147. (panelContext) => FocusTraversalGroup(
  148. child: RepaintBoundary(
  149. child: EditPanel(
  150. panelContext: panelContext,
  151. onEndEdit: () =>
  152. homeBloc.add(const HomeEvent.dismissEditPanel()),
  153. ),
  154. ),
  155. ),
  156. );
  157. },
  158. );
  159. }
  160. Widget _buildHomeMenuResizer({
  161. required BuildContext context,
  162. }) {
  163. return MouseRegion(
  164. cursor: SystemMouseCursors.resizeLeftRight,
  165. child: GestureDetector(
  166. dragStartBehavior: DragStartBehavior.down,
  167. onPanUpdate: ((details) {
  168. context
  169. .read<HomeBloc>()
  170. .add(HomeEvent.editPanelResized(details.delta.dx));
  171. }),
  172. behavior: HitTestBehavior.translucent,
  173. child: SizedBox(
  174. width: 10,
  175. height: MediaQuery.of(context).size.height,
  176. )),
  177. );
  178. }
  179. Widget _layoutWidgets({
  180. required HomeLayout layout,
  181. required Widget homeMenu,
  182. required Widget homeStack,
  183. required Widget editPanel,
  184. required Widget bubble,
  185. required Widget homeMenuResizer,
  186. }) {
  187. return Stack(
  188. children: [
  189. homeMenu
  190. .animatedPanelX(
  191. closeX: -layout.menuWidth,
  192. isClosed: !layout.showMenu,
  193. )
  194. .positioned(
  195. left: 0,
  196. top: 0,
  197. width: layout.menuWidth,
  198. bottom: 0,
  199. animate: true)
  200. .animate(layout.animDuration, Curves.easeOut),
  201. homeStack
  202. .constrained(minWidth: 500)
  203. .positioned(
  204. left: layout.homePageLOffset,
  205. right: layout.homePageROffset,
  206. bottom: 0,
  207. top: 0,
  208. animate: true)
  209. .animate(layout.animDuration, Curves.easeOut),
  210. homeMenuResizer.positioned(left: layout.homePageLOffset - 5),
  211. bubble
  212. .positioned(
  213. right: 20,
  214. bottom: 16,
  215. animate: true,
  216. )
  217. .animate(layout.animDuration, Curves.easeOut),
  218. editPanel
  219. .animatedPanelX(
  220. duration: layout.animDuration.inMilliseconds * 0.001,
  221. closeX: layout.editPanelWidth,
  222. isClosed: !layout.showEditPanel,
  223. )
  224. .positioned(
  225. right: 0, top: 0, bottom: 0, width: layout.editPanelWidth),
  226. ],
  227. );
  228. }
  229. }