doc_bloc.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import 'dart:convert';
  2. import 'package:app_flowy/workspace/infrastructure/repos/trash_repo.dart';
  3. import 'package:app_flowy/workspace/infrastructure/repos/view_repo.dart';
  4. import 'package:flowy_sdk/protobuf/flowy-folder-data-model/trash.pb.dart';
  5. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  6. import 'package:flutter_quill/flutter_quill.dart' show Document, Delta;
  7. import 'package:flowy_sdk/log.dart';
  8. import 'package:flutter_bloc/flutter_bloc.dart';
  9. import 'package:freezed_annotation/freezed_annotation.dart';
  10. import 'package:dartz/dartz.dart';
  11. import 'dart:async';
  12. part 'doc_bloc.freezed.dart';
  13. typedef FlutterQuillDocument = Document;
  14. class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
  15. final ViewRepository repo;
  16. final ViewListener listener;
  17. final TrashRepo trashRepo;
  18. late FlutterQuillDocument document;
  19. StreamSubscription? _subscription;
  20. DocumentBloc({
  21. required this.repo,
  22. required this.listener,
  23. required this.trashRepo,
  24. }) : super(DocumentState.initial()) {
  25. on<DocumentEvent>((event, emit) async {
  26. await event.map(
  27. initial: (Initial value) async {
  28. await _initial(value, emit);
  29. },
  30. deleted: (Deleted value) async {
  31. emit(state.copyWith(isDeleted: true));
  32. },
  33. restore: (Restore value) async {
  34. emit(state.copyWith(isDeleted: false));
  35. },
  36. deletePermanently: (DeletePermanently value) async {
  37. final result = await trashRepo.deleteViews([Tuple2(repo.view.id, TrashType.TrashView)]);
  38. final newState = result.fold((l) => state.copyWith(forceClose: true), (r) => state);
  39. emit(newState);
  40. },
  41. restorePage: (RestorePage value) async {
  42. final result = await trashRepo.putback(repo.view.id);
  43. final newState = result.fold((l) => state.copyWith(isDeleted: false), (r) => state);
  44. emit(newState);
  45. },
  46. );
  47. });
  48. }
  49. @override
  50. Future<void> close() async {
  51. await listener.close();
  52. if (_subscription != null) {
  53. await _subscription?.cancel();
  54. }
  55. repo.closeDocument();
  56. return super.close();
  57. }
  58. Future<void> _initial(Initial value, Emitter<DocumentState> emit) async {
  59. listener.deletedNotifier.addPublishListener((result) {
  60. result.fold(
  61. (view) => add(const DocumentEvent.deleted()),
  62. (error) {},
  63. );
  64. });
  65. listener.restoredNotifier.addPublishListener((result) {
  66. result.fold(
  67. (view) => add(const DocumentEvent.restore()),
  68. (error) {},
  69. );
  70. });
  71. listener.start();
  72. final result = await repo.openDocument();
  73. result.fold(
  74. (block) {
  75. document = _decodeJsonToDocument(block.deltaJson);
  76. _subscription = document.changes.listen((event) {
  77. final delta = event.item2;
  78. final documentDelta = document.toDelta();
  79. _composeDelta(delta, documentDelta);
  80. });
  81. emit(state.copyWith(loadingState: DocumentLoadingState.finish(left(unit))));
  82. },
  83. (err) {
  84. emit(state.copyWith(loadingState: DocumentLoadingState.finish(right(err))));
  85. },
  86. );
  87. }
  88. // Document _decodeListToDocument(Uint8List data) {
  89. // final json = jsonDecode(utf8.decode(data));
  90. // final document = Document.fromJson(json);
  91. // return document;
  92. // }
  93. void _composeDelta(Delta composedDelta, Delta documentDelta) async {
  94. final json = jsonEncode(composedDelta.toJson());
  95. Log.debug("doc_id: $repo.view.id - Send json: $json");
  96. final result = await repo.composeDelta(data: json);
  97. result.fold((rustDoc) {
  98. // final json = utf8.decode(doc.data);
  99. final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaJson));
  100. if (documentDelta != rustDelta) {
  101. Log.error("Receive : $rustDelta");
  102. Log.error("Expected : $documentDelta");
  103. }
  104. }, (r) => null);
  105. }
  106. Document _decodeJsonToDocument(String data) {
  107. final json = jsonDecode(data);
  108. final document = Document.fromJson(json);
  109. return document;
  110. }
  111. }
  112. @freezed
  113. class DocumentEvent with _$DocumentEvent {
  114. const factory DocumentEvent.initial() = Initial;
  115. const factory DocumentEvent.deleted() = Deleted;
  116. const factory DocumentEvent.restore() = Restore;
  117. const factory DocumentEvent.restorePage() = RestorePage;
  118. const factory DocumentEvent.deletePermanently() = DeletePermanently;
  119. }
  120. @freezed
  121. class DocumentState with _$DocumentState {
  122. const factory DocumentState({
  123. required DocumentLoadingState loadingState,
  124. required bool isDeleted,
  125. required bool forceClose,
  126. }) = _DocumentState;
  127. factory DocumentState.initial() => const DocumentState(
  128. loadingState: _Loading(),
  129. isDeleted: false,
  130. forceClose: false,
  131. );
  132. }
  133. @freezed
  134. class DocumentLoadingState with _$DocumentLoadingState {
  135. const factory DocumentLoadingState.loading() = _Loading;
  136. const factory DocumentLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
  137. }