import 'dart:async'; import 'dart:convert'; import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart'; import 'package:dartz/dartz.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/app.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; class AppBackendService { Future> readApp({required String appId}) { final payload = AppIdPB.create()..value = appId; return FolderEventReadApp(payload).send(); } Future> createView({ required String appId, required String name, String? desc, required ViewLayoutTypePB layoutType, /// The initial data should be the JSON of the document. /// Currently, only support create document with initial data. /// /// The initial data must be follow this format as shown below. /// {"document":{"type":"editor","children":[]}} String? initialData, /// The [ext] is used to pass through the custom configuration /// to the backend. /// Linking the view to the existing database, it needs to pass /// the database id. For example: "database_id": "xxx" /// Map ext = const {}, }) { final payload = CreateViewPayloadPB.create() ..belongToId = appId ..name = name ..desc = desc ?? "" ..layout = layoutType ..initialData = utf8.encode( initialData ?? "", ); if (ext.isNotEmpty) { payload.ext.addAll(ext); } return FolderEventCreateView(payload).send(); } Future, FlowyError>> getViews({required String appId}) { final payload = AppIdPB.create()..value = appId; return FolderEventReadApp(payload).send().then((result) { return result.fold( (app) => left(app.belongings.items), (error) => right(error), ); }); } Future> delete({required String appId}) { final request = AppIdPB.create()..value = appId; return FolderEventDeleteApp(request).send(); } Future> deleteView({required String viewId}) { final request = RepeatedViewIdPB.create()..items.add(viewId); return FolderEventDeleteView(request).send(); } Future> updateApp( {required String appId, String? name}) { UpdateAppPayloadPB payload = UpdateAppPayloadPB.create()..appId = appId; if (name != null) { payload.name = name; } return FolderEventUpdateApp(payload).send(); } Future> moveView({ required String viewId, required int fromIndex, required int toIndex, }) { final payload = MoveFolderItemPayloadPB.create() ..itemId = viewId ..from = fromIndex ..to = toIndex ..ty = MoveFolderItemType.MoveView; return FolderEventMoveItem(payload).send(); } Future>>> fetchViews( ViewLayoutTypePB layoutType) async { final result = >>[]; return FolderEventReadCurrentWorkspace().send().then((value) async { final workspaces = value.getLeftOrNull(); if (workspaces != null) { final apps = workspaces.workspace.apps.items; for (var app in apps) { final views = await getViews(appId: app.id).then( (value) => value .getLeftOrNull>() ?.where((e) => e.layout == layoutType) .toList(), ); if (views != null && views.isNotEmpty) { result.add(Tuple2(app, views)); } } } return result; }); } Future> getView( String appID, String viewID, ) async { final payload = AppIdPB.create()..value = appID; return FolderEventReadApp(payload).send().then((result) { return result.fold( (app) => left( app.belongings.items.firstWhere((e) => e.id == viewID), ), (error) => right(error), ); }); } } extension AppFlowy on Either { T? getLeftOrNull() { if (isLeft()) { final result = fold((l) => l, (r) => null); return result; } return null; } }