app_bloc.dart 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import 'package:app_flowy/plugin/plugin.dart';
  2. import 'package:app_flowy/workspace/application/app/app_listener.dart';
  3. import 'package:app_flowy/workspace/application/app/app_service.dart';
  4. import 'package:flowy_sdk/log.dart';
  5. import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
  6. import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
  7. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  8. import 'package:freezed_annotation/freezed_annotation.dart';
  9. import 'package:flutter_bloc/flutter_bloc.dart';
  10. import 'package:dartz/dartz.dart';
  11. part 'app_bloc.freezed.dart';
  12. class AppBloc extends Bloc<AppEvent, AppState> {
  13. final App app;
  14. final AppService service;
  15. final AppListener listener;
  16. AppBloc({required this.app, required this.service, required this.listener}) : super(AppState.initial(app)) {
  17. on<AppEvent>((event, emit) async {
  18. await event.map(initial: (e) async {
  19. listener.start(
  20. viewsChanged: _handleViewsChanged,
  21. appUpdated: (app) => add(AppEvent.appDidUpdate(app)),
  22. );
  23. await _fetchViews(emit);
  24. }, createView: (CreateView value) async {
  25. final viewOrFailed = await service.createView(
  26. appId: app.id,
  27. name: value.name,
  28. desc: value.desc,
  29. dataType: value.dataType,
  30. pluginType: value.pluginType,
  31. );
  32. viewOrFailed.fold(
  33. (view) => emit(state.copyWith(
  34. latestCreatedView: view,
  35. successOrFailure: left(unit),
  36. )),
  37. (error) {
  38. Log.error(error);
  39. emit(state.copyWith(successOrFailure: right(error)));
  40. },
  41. );
  42. }, didReceiveViews: (e) async {
  43. await handleDidReceiveViews(e.views, emit);
  44. }, delete: (e) async {
  45. final result = await service.delete(appId: app.id);
  46. result.fold(
  47. (unit) => emit(state.copyWith(successOrFailure: left(unit))),
  48. (error) => emit(state.copyWith(successOrFailure: right(error))),
  49. );
  50. }, rename: (e) async {
  51. final result = await service.updateApp(appId: app.id, name: e.newName);
  52. result.fold(
  53. (l) => emit(state.copyWith(successOrFailure: left(unit))),
  54. (error) => emit(state.copyWith(successOrFailure: right(error))),
  55. );
  56. }, appDidUpdate: (e) async {
  57. emit(state.copyWith(app: e.app));
  58. });
  59. });
  60. }
  61. @override
  62. Future<void> close() async {
  63. await listener.close();
  64. return super.close();
  65. }
  66. void _handleViewsChanged(Either<List<View>, FlowyError> result) {
  67. result.fold(
  68. (views) => add(AppEvent.didReceiveViews(views)),
  69. (error) {
  70. Log.error(error);
  71. },
  72. );
  73. }
  74. Future<void> handleDidReceiveViews(List<View> views, Emitter<AppState> emit) async {
  75. final latestCreatedView = state.latestCreatedView;
  76. AppState newState = state.copyWith(views: views);
  77. if (latestCreatedView != null) {
  78. final index = views.indexWhere((element) => element.id == latestCreatedView.id);
  79. if (index == -1) {
  80. newState = newState.copyWith(latestCreatedView: null);
  81. }
  82. }
  83. emit(newState);
  84. }
  85. Future<void> _fetchViews(Emitter<AppState> emit) async {
  86. final viewsOrFailed = await service.getViews(appId: app.id);
  87. viewsOrFailed.fold(
  88. (apps) => emit(state.copyWith(views: apps)),
  89. (error) {
  90. Log.error(error);
  91. emit(state.copyWith(successOrFailure: right(error)));
  92. },
  93. );
  94. }
  95. }
  96. @freezed
  97. class AppEvent with _$AppEvent {
  98. const factory AppEvent.initial() = Initial;
  99. const factory AppEvent.createView(
  100. String name,
  101. String desc,
  102. PluginDataType dataType,
  103. PluginType pluginType,
  104. ) = CreateView;
  105. const factory AppEvent.delete() = Delete;
  106. const factory AppEvent.rename(String newName) = Rename;
  107. const factory AppEvent.didReceiveViews(List<View> views) = ReceiveViews;
  108. const factory AppEvent.appDidUpdate(App app) = AppDidUpdate;
  109. }
  110. @freezed
  111. class AppState with _$AppState {
  112. const factory AppState({
  113. required App app,
  114. required bool isLoading,
  115. required List<View>? views,
  116. View? latestCreatedView,
  117. required Either<Unit, FlowyError> successOrFailure,
  118. }) = _AppState;
  119. factory AppState.initial(App app) => AppState(
  120. app: app,
  121. isLoading: false,
  122. views: null,
  123. latestCreatedView: null,
  124. successOrFailure: left(unit),
  125. );
  126. }