view_service.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import 'dart:async';
  2. import 'package:appflowy_backend/protobuf/flowy-folder2/workspace.pb.dart';
  3. import 'package:dartz/dartz.dart';
  4. import 'package:appflowy_backend/dispatch/dispatch.dart';
  5. import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
  6. import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
  7. class ViewBackendService {
  8. static Future<Either<ViewPB, FlowyError>> createView({
  9. /// The [layoutType] is the type of the view.
  10. required ViewLayoutPB layoutType,
  11. /// The [parentViewId] is the parent view id.
  12. required String parentViewId,
  13. /// The [name] is the name of the view.
  14. required String name,
  15. String? desc,
  16. /// The default value of [openAfterCreate] is false, meaning the view will
  17. /// not be opened nor set as the current view. However, if set to true, the
  18. /// view will be opened and set as the current view. Upon relaunching the
  19. /// app, this view will be opened
  20. bool openAfterCreate = false,
  21. /// The initial data should be a JSON that represent the DocumentDataPB.
  22. /// Currently, only support create document with initial data.
  23. List<int>? initialDataBytes,
  24. /// The [ext] is used to pass through the custom configuration
  25. /// to the backend.
  26. /// Linking the view to the existing database, it needs to pass
  27. /// the database id. For example: "database_id": "xxx"
  28. ///
  29. Map<String, String> ext = const {},
  30. }) {
  31. final payload = CreateViewPayloadPB.create()
  32. ..parentViewId = parentViewId
  33. ..name = name
  34. ..desc = desc ?? ""
  35. ..layout = layoutType
  36. ..setAsCurrent = openAfterCreate
  37. ..initialData = initialDataBytes ?? [];
  38. if (ext.isNotEmpty) {
  39. payload.meta.addAll(ext);
  40. }
  41. return FolderEventCreateView(payload).send();
  42. }
  43. static Future<Either<ViewPB, FlowyError>> createDatabaseReferenceView({
  44. required String parentViewId,
  45. required String databaseId,
  46. required ViewLayoutPB layoutType,
  47. required String name,
  48. }) {
  49. return ViewBackendService.createView(
  50. layoutType: layoutType,
  51. parentViewId: parentViewId,
  52. name: name,
  53. openAfterCreate: false,
  54. ext: {
  55. 'database_id': databaseId,
  56. },
  57. );
  58. }
  59. /// Returns a list of views that are the children of the given [viewId].
  60. static Future<Either<List<ViewPB>, FlowyError>> getViews({
  61. required String viewId,
  62. }) {
  63. final payload = ViewIdPB.create()..value = viewId;
  64. return FolderEventReadView(payload).send().then((result) {
  65. return result.fold(
  66. (app) => left(app.childViews),
  67. (error) => right(error),
  68. );
  69. });
  70. }
  71. static Future<Either<Unit, FlowyError>> delete({required String viewId}) {
  72. final request = RepeatedViewIdPB.create()..items.add(viewId);
  73. return FolderEventDeleteView(request).send();
  74. }
  75. static Future<Either<Unit, FlowyError>> deleteView({required String viewId}) {
  76. final request = RepeatedViewIdPB.create()..items.add(viewId);
  77. return FolderEventDeleteView(request).send();
  78. }
  79. static Future<Either<Unit, FlowyError>> duplicate({required ViewPB view}) {
  80. return FolderEventDuplicateView(view).send();
  81. }
  82. static Future<Either<ViewPB, FlowyError>> updateView({
  83. required String viewId,
  84. String? name,
  85. }) {
  86. final payload = UpdateViewPayloadPB.create()..viewId = viewId;
  87. if (name != null) {
  88. payload.name = name;
  89. }
  90. return FolderEventUpdateView(payload).send();
  91. }
  92. static Future<Either<Unit, FlowyError>> moveView({
  93. required String viewId,
  94. required int fromIndex,
  95. required int toIndex,
  96. }) {
  97. final payload = MoveViewPayloadPB.create()
  98. ..viewId = viewId
  99. ..from = fromIndex
  100. ..to = toIndex;
  101. return FolderEventMoveView(payload).send();
  102. }
  103. Future<List<(ViewPB, List<ViewPB>)>> fetchViews(
  104. ViewLayoutPB layoutType,
  105. ) async {
  106. final result = <(ViewPB, List<ViewPB>)>[];
  107. return FolderEventGetCurrentWorkspace().send().then((value) async {
  108. final workspaces = value.getLeftOrNull<WorkspaceSettingPB>();
  109. if (workspaces != null) {
  110. final views = workspaces.workspace.views;
  111. for (final view in views) {
  112. final childViews = await getViews(viewId: view.id).then(
  113. (value) => value
  114. .getLeftOrNull<List<ViewPB>>()
  115. ?.where((e) => e.layout == layoutType)
  116. .toList(),
  117. );
  118. if (childViews != null && childViews.isNotEmpty) {
  119. result.add((view, childViews));
  120. }
  121. }
  122. }
  123. return result;
  124. });
  125. }
  126. Future<Either<ViewPB, FlowyError>> getView(
  127. String viewID,
  128. ) async {
  129. final payload = ViewIdPB.create()..value = viewID;
  130. return FolderEventReadView(payload).send();
  131. }
  132. Future<Either<ViewPB, FlowyError>> getChildView({
  133. required String parentViewId,
  134. required String childViewId,
  135. }) async {
  136. final payload = ViewIdPB.create()..value = parentViewId;
  137. return FolderEventReadView(payload).send().then((result) {
  138. return result.fold(
  139. (app) => left(
  140. app.childViews.firstWhere((e) => e.id == childViewId),
  141. ),
  142. (error) => right(error),
  143. );
  144. });
  145. }
  146. }
  147. extension AppFlowy on Either {
  148. T? getLeftOrNull<T>() {
  149. if (isLeft()) {
  150. final result = fold<T?>((l) => l, (r) => null);
  151. return result;
  152. }
  153. return null;
  154. }
  155. }