menu_bloc.dart 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import 'dart:async';
  2. import 'package:appflowy/startup/plugin/plugin.dart';
  3. import 'package:appflowy/workspace/application/view/view_ext.dart';
  4. import 'package:appflowy/workspace/application/workspace/workspace_listener.dart';
  5. import 'package:appflowy/workspace/application/workspace/workspace_service.dart';
  6. import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
  7. import 'package:dartz/dartz.dart';
  8. import 'package:appflowy_backend/log.dart';
  9. import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
  10. import 'package:appflowy_backend/protobuf/flowy-folder2/workspace.pb.dart';
  11. import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
  12. import 'package:freezed_annotation/freezed_annotation.dart';
  13. import 'package:flutter_bloc/flutter_bloc.dart';
  14. part 'menu_bloc.freezed.dart';
  15. class MenuBloc extends Bloc<MenuEvent, MenuState> {
  16. final WorkspaceService _workspaceService;
  17. final WorkspaceListener _listener;
  18. final UserProfilePB user;
  19. final WorkspacePB workspace;
  20. MenuBloc({
  21. required this.user,
  22. required this.workspace,
  23. }) : _workspaceService = WorkspaceService(workspaceId: workspace.id),
  24. _listener = WorkspaceListener(
  25. user: user,
  26. workspaceId: workspace.id,
  27. ),
  28. super(MenuState.initial(workspace)) {
  29. on<MenuEvent>((event, emit) async {
  30. await event.map(
  31. initial: (e) async {
  32. _listener.start(appsChanged: _handleAppsOrFail);
  33. await _fetchApps(emit);
  34. },
  35. openPage: (e) async {
  36. emit(state.copyWith(plugin: e.plugin));
  37. },
  38. createApp: (_CreateApp event) async {
  39. final result = await _workspaceService.createApp(
  40. name: event.name,
  41. desc: event.desc,
  42. index: 0, // default to the first index
  43. );
  44. result.fold(
  45. (app) => emit(state.copyWith(plugin: app.plugin())),
  46. (error) {
  47. Log.error(error);
  48. emit(state.copyWith(successOrFailure: right(error)));
  49. },
  50. );
  51. },
  52. didReceiveApps: (e) async {
  53. emit(
  54. e.appsOrFail.fold(
  55. (views) =>
  56. state.copyWith(views: views, successOrFailure: left(unit)),
  57. (err) => state.copyWith(successOrFailure: right(err)),
  58. ),
  59. );
  60. },
  61. moveApp: (_MoveApp value) {
  62. if (state.views.length > value.fromIndex) {
  63. final view = state.views[value.fromIndex];
  64. _workspaceService.moveApp(
  65. appId: view.id,
  66. fromIndex: value.fromIndex,
  67. toIndex: value.toIndex,
  68. );
  69. final apps = List<ViewPB>.from(state.views);
  70. apps.insert(value.toIndex, apps.removeAt(value.fromIndex));
  71. emit(state.copyWith(views: apps));
  72. }
  73. },
  74. );
  75. });
  76. }
  77. @override
  78. Future<void> close() async {
  79. await _listener.stop();
  80. return super.close();
  81. }
  82. // ignore: unused_element
  83. Future<void> _fetchApps(Emitter<MenuState> emit) async {
  84. final viewsOrError = await _workspaceService.getViews();
  85. emit(
  86. viewsOrError.fold(
  87. (views) => state.copyWith(views: views),
  88. (error) {
  89. Log.error(error);
  90. return state.copyWith(successOrFailure: right(error));
  91. },
  92. ),
  93. );
  94. }
  95. void _handleAppsOrFail(Either<List<ViewPB>, FlowyError> appsOrFail) {
  96. appsOrFail.fold(
  97. (apps) => add(MenuEvent.didReceiveApps(left(apps))),
  98. (error) => add(MenuEvent.didReceiveApps(right(error))),
  99. );
  100. }
  101. }
  102. @freezed
  103. class MenuEvent with _$MenuEvent {
  104. const factory MenuEvent.initial() = _Initial;
  105. const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
  106. const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
  107. const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
  108. const factory MenuEvent.didReceiveApps(
  109. Either<List<ViewPB>, FlowyError> appsOrFail,
  110. ) = _ReceiveApps;
  111. }
  112. @freezed
  113. class MenuState with _$MenuState {
  114. const factory MenuState({
  115. required List<ViewPB> views,
  116. required Either<Unit, FlowyError> successOrFailure,
  117. required Plugin plugin,
  118. }) = _MenuState;
  119. factory MenuState.initial(WorkspacePB workspace) => MenuState(
  120. views: workspace.views,
  121. successOrFailure: left(unit),
  122. plugin: makePlugin(pluginType: PluginType.blank),
  123. );
  124. }