menu_bloc.dart 4.2 KB

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