app_widget.dart 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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_list.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_infra_ui/widget/spacing.dart';
  10. import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
  11. import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
  12. import 'package:flutter/material.dart';
  13. import 'package:flutter_bloc/flutter_bloc.dart';
  14. import 'package:dartz/dartz.dart';
  15. class AppWidgetSize {
  16. static double expandedIconSize = 24;
  17. static double expandedIconRightSpace = 8;
  18. static double scale = 1;
  19. static double get expandedPadding =>
  20. expandedIconSize * scale + expandedIconRightSpace;
  21. }
  22. class AppWidget extends MenuItem {
  23. final App app;
  24. AppWidget(this.app, {Key? key}) : super(key: ValueKey(app.id));
  25. @override
  26. Widget build(BuildContext context) {
  27. return MultiBlocProvider(
  28. providers: [
  29. BlocProvider<AppBloc>(create: (context) {
  30. final appBloc = getIt<AppBloc>(param1: app.id);
  31. appBloc.add(const AppEvent.initial());
  32. return appBloc;
  33. }),
  34. BlocProvider<AppWatchBloc>(create: (context) {
  35. final watchBloc = getIt<AppWatchBloc>(param1: app.id);
  36. watchBloc.add(const AppWatchEvent.started());
  37. return watchBloc;
  38. }),
  39. ],
  40. child: BlocBuilder<AppWatchBloc, AppWatchState>(
  41. builder: (context, state) {
  42. final child = state.map(
  43. initial: (_) => BlocBuilder<AppBloc, AppState>(
  44. builder: (context, state) {
  45. return ViewList(state.views);
  46. },
  47. ),
  48. loadViews: (s) => ViewList(some(s.views)),
  49. loadFail: (s) => FlowyErrorPage(s.error.toString()),
  50. );
  51. return expandableWrapper(context, child);
  52. },
  53. ),
  54. );
  55. }
  56. ExpandableNotifier expandableWrapper(BuildContext context, Widget child) {
  57. return ExpandableNotifier(
  58. child: ScrollOnExpand(
  59. scrollOnExpand: true,
  60. scrollOnCollapse: false,
  61. child: Column(
  62. children: <Widget>[
  63. ExpandablePanel(
  64. theme: const ExpandableThemeData(
  65. headerAlignment: ExpandablePanelHeaderAlignment.center,
  66. tapBodyToExpand: false,
  67. tapBodyToCollapse: false,
  68. iconPadding: EdgeInsets.zero,
  69. hasIcon: false,
  70. ),
  71. header: AppHeader(app),
  72. expanded: child,
  73. collapsed: const SizedBox(),
  74. ),
  75. ],
  76. ),
  77. ),
  78. );
  79. }
  80. @override
  81. MenuItemType get type => MenuItemType.app;
  82. }
  83. class AppHeader extends StatelessWidget {
  84. final App app;
  85. const AppHeader(
  86. this.app, {
  87. Key? key,
  88. }) : super(key: key);
  89. @override
  90. Widget build(BuildContext context) {
  91. return Row(
  92. mainAxisAlignment: MainAxisAlignment.center,
  93. crossAxisAlignment: CrossAxisAlignment.center,
  94. children: [
  95. ExpandableIcon(
  96. theme: ExpandableThemeData(
  97. expandIcon: Icons.arrow_drop_up,
  98. collapseIcon: Icons.arrow_drop_down,
  99. iconColor: Colors.black,
  100. iconSize: AppWidgetSize.expandedIconSize,
  101. iconPadding: EdgeInsets.zero,
  102. hasIcon: false,
  103. ),
  104. ),
  105. HSpace(AppWidgetSize.expandedIconRightSpace),
  106. Expanded(
  107. child: Text(
  108. app.name,
  109. style: const TextStyle(fontSize: 18),
  110. ),
  111. ),
  112. _renderPopupMenu(context),
  113. ],
  114. );
  115. }
  116. Widget _renderPopupMenu(BuildContext context) {
  117. return PopupMenuButton(
  118. iconSize: 20,
  119. tooltip: 'create new view',
  120. icon: const Icon(Icons.add),
  121. padding: EdgeInsets.zero,
  122. onSelected: (viewType) => _createView(viewType as ViewType, context),
  123. itemBuilder: (context) => menuItemBuilder());
  124. }
  125. List<PopupMenuEntry> menuItemBuilder() {
  126. return ViewType.values
  127. .where((element) => element != ViewType.Blank)
  128. .map((ty) {
  129. return PopupMenuItem<ViewType>(
  130. value: ty,
  131. child: Row(
  132. children: <Widget>[Text(ty.name)],
  133. ));
  134. }).toList();
  135. }
  136. void _createView(ViewType viewType, BuildContext context) {
  137. context.read<AppBloc>().add(AppEvent.createView("New view", "", viewType));
  138. }
  139. }