app_bloc.dart 4.2 KB

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