app_widget.dart 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import 'package:app_flowy/workspace/application/app/app_bloc.dart';
  2. import 'package:app_flowy/workspace/application/app/app_watch_bloc.dart';
  3. import 'package:app_flowy/workspace/presentation/app/view_list.dart';
  4. import 'package:app_flowy/workspace/presentation/widgets/menu/menu_size.dart';
  5. import 'package:app_flowy/startup/startup.dart';
  6. import 'package:expandable/expandable.dart';
  7. import 'package:flowy_infra/size.dart';
  8. import 'package:flowy_infra_ui/widget/error_page.dart';
  9. import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
  10. import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
  11. import 'package:flutter/material.dart';
  12. import 'package:flutter_bloc/flutter_bloc.dart';
  13. import 'package:dartz/dartz.dart';
  14. class AppWidget extends StatelessWidget {
  15. final App app;
  16. const AppWidget(this.app, {Key? key}) : super(key: key);
  17. @override
  18. Widget build(BuildContext context) {
  19. return MultiBlocProvider(
  20. providers: [
  21. BlocProvider<AppBloc>(create: (context) {
  22. final appBloc = getIt<AppBloc>(param1: app.id);
  23. appBloc.add(const AppEvent.initial());
  24. return appBloc;
  25. }),
  26. BlocProvider<AppWatchBloc>(create: (context) {
  27. final watchBloc = getIt<AppWatchBloc>(param1: app.id);
  28. watchBloc.add(const AppWatchEvent.started());
  29. return watchBloc;
  30. }),
  31. ],
  32. child: BlocBuilder<AppWatchBloc, AppWatchState>(
  33. builder: (context, state) {
  34. final child = state.map(
  35. initial: (_) => BlocBuilder<AppBloc, AppState>(
  36. builder: (context, state) {
  37. return ViewList(state.views);
  38. },
  39. ),
  40. loadViews: (s) => ViewList(some(s.views)),
  41. loadFail: (s) => FlowyErrorPage(s.error.toString()),
  42. );
  43. return expandableWrapper(context, child);
  44. },
  45. ),
  46. );
  47. }
  48. ExpandableNotifier expandableWrapper(BuildContext context, Widget child) {
  49. return ExpandableNotifier(
  50. child: ScrollOnExpand(
  51. scrollOnExpand: true,
  52. scrollOnCollapse: false,
  53. child: Card(
  54. clipBehavior: Clip.antiAlias,
  55. child: Column(
  56. children: <Widget>[
  57. ExpandablePanel(
  58. theme: const ExpandableThemeData(
  59. headerAlignment: ExpandablePanelHeaderAlignment.center,
  60. tapBodyToExpand: false,
  61. tapBodyToCollapse: false,
  62. iconPadding: EdgeInsets.zero,
  63. hasIcon: false,
  64. ),
  65. header: AppHeader(app),
  66. expanded: Padding(
  67. padding: EdgeInsets.only(left: Sizes.iconMed),
  68. child: child,
  69. ),
  70. collapsed: const SizedBox(),
  71. ),
  72. ],
  73. ),
  74. ),
  75. ),
  76. );
  77. }
  78. }
  79. class AppHeader extends StatelessWidget {
  80. final App app;
  81. const AppHeader(
  82. this.app, {
  83. Key? key,
  84. }) : super(key: key);
  85. @override
  86. Widget build(BuildContext context) {
  87. return Container(
  88. color: Colors.white,
  89. child: Padding(
  90. padding: EdgeInsets.symmetric(vertical: Insets.m),
  91. child: Row(
  92. mainAxisAlignment: MainAxisAlignment.center,
  93. crossAxisAlignment: CrossAxisAlignment.center,
  94. children: [
  95. ExpandableIcon(
  96. theme: ExpandableThemeData(
  97. expandIcon: Icons.arrow_right,
  98. collapseIcon: Icons.arrow_drop_down,
  99. iconColor: Colors.black,
  100. iconSize: HomeMenuSize.collapseIconSize,
  101. iconPadding: EdgeInsets.zero,
  102. hasIcon: false,
  103. ),
  104. ),
  105. Expanded(
  106. child: Text(app.name),
  107. ),
  108. SizedBox(
  109. height: HomeMenuSize.createViewButtonSize,
  110. child: createViewPopupMenu(context),
  111. ),
  112. ],
  113. ),
  114. ),
  115. );
  116. }
  117. Widget createViewPopupMenu(BuildContext context) {
  118. return PopupMenuButton(
  119. iconSize: 24,
  120. tooltip: 'create new view',
  121. icon: const Icon(Icons.add),
  122. padding: EdgeInsets.zero,
  123. onSelected: (viewType) => _createView(viewType as ViewType, context),
  124. itemBuilder: (context) => menuItemBuilder());
  125. }
  126. List<PopupMenuEntry> menuItemBuilder() {
  127. return ViewType.values
  128. .where((element) => element != ViewType.Blank)
  129. .map((ty) {
  130. return PopupMenuItem<ViewType>(
  131. value: ty,
  132. child: Row(
  133. children: <Widget>[Text(ty.name)],
  134. ));
  135. }).toList();
  136. }
  137. void _createView(ViewType viewType, BuildContext context) {
  138. context.read<AppBloc>().add(AppEvent.createView("New view", "", viewType));
  139. }
  140. }