home_screen.dart 7.7 KB

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