menu_bloc.dart 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. );
  43. result.fold(
  44. (app) => emit(state.copyWith(plugin: app.plugin())),
  45. (error) {
  46. Log.error(error);
  47. emit(state.copyWith(successOrFailure: right(error)));
  48. },
  49. );
  50. },
  51. didReceiveApps: (e) async {
  52. emit(
  53. e.appsOrFail.fold(
  54. (views) =>
  55. state.copyWith(views: views, successOrFailure: left(unit)),
  56. (err) => state.copyWith(successOrFailure: right(err)),
  57. ),
  58. );
  59. },
  60. moveApp: (_MoveApp value) {
  61. if (state.views.length > value.fromIndex) {
  62. final view = state.views[value.fromIndex];
  63. _workspaceService.moveApp(
  64. appId: view.id,
  65. fromIndex: value.fromIndex,
  66. toIndex: value.toIndex,
  67. );
  68. final apps = List<ViewPB>.from(state.views);
  69. apps.insert(value.toIndex, apps.removeAt(value.fromIndex));
  70. emit(state.copyWith(views: apps));
  71. }
  72. },
  73. );
  74. });
  75. }
  76. @override
  77. Future<void> close() async {
  78. await _listener.stop();
  79. return super.close();
  80. }
  81. // ignore: unused_element
  82. Future<void> _fetchApps(Emitter<MenuState> emit) async {
  83. final viewsOrError = await _workspaceService.getViews();
  84. emit(
  85. viewsOrError.fold(
  86. (views) => state.copyWith(views: views),
  87. (error) {
  88. Log.error(error);
  89. return state.copyWith(successOrFailure: right(error));
  90. },
  91. ),
  92. );
  93. }
  94. void _handleAppsOrFail(Either<List<ViewPB>, FlowyError> appsOrFail) {
  95. appsOrFail.fold(
  96. (apps) => add(MenuEvent.didReceiveApps(left(apps))),
  97. (error) => add(MenuEvent.didReceiveApps(right(error))),
  98. );
  99. }
  100. }
  101. @freezed
  102. class MenuEvent with _$MenuEvent {
  103. const factory MenuEvent.initial() = _Initial;
  104. const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
  105. const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
  106. const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
  107. const factory MenuEvent.didReceiveApps(
  108. Either<List<ViewPB>, FlowyError> appsOrFail,
  109. ) = _ReceiveApps;
  110. }
  111. @freezed
  112. class MenuState with _$MenuState {
  113. const factory MenuState({
  114. required List<ViewPB> views,
  115. required Either<Unit, FlowyError> successOrFailure,
  116. required Plugin plugin,
  117. }) = _MenuState;
  118. factory MenuState.initial(WorkspacePB workspace) => MenuState(
  119. views: workspace.views,
  120. successOrFailure: left(unit),
  121. plugin: makePlugin(pluginType: PluginType.blank),
  122. );
  123. }