Browse Source

config workspace and app repo callback

appflowy 3 years ago
parent
commit
a529a3bf43

+ 4 - 4
app_flowy/lib/home/application/menu/menu_bloc.dart

@@ -1,5 +1,5 @@
 import 'dart:async';
-import 'package:app_flowy/home/domain/i_app.dart';
+import 'package:app_flowy/home/domain/i_workspace.dart';
 import 'package:app_flowy/home/domain/page_context.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
@@ -11,8 +11,8 @@ part 'menu_state.dart';
 part 'menu_bloc.freezed.dart';
 
 class MenuBloc extends Bloc<MenuEvent, MenuState> {
-  final IApp iAppImpl;
-  MenuBloc(this.iAppImpl) : super(MenuState.initial());
+  final IWorkspace iWorkspaceImpl;
+  MenuBloc(this.iWorkspaceImpl) : super(MenuState.initial());
 
   @override
   Stream<MenuState> mapEventToState(
@@ -37,7 +37,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
   }
 
   Stream<MenuState> _performActionOnCreateApp(_CreateApp event) async* {
-    await iAppImpl
+    await iWorkspaceImpl
         .createApp(name: event.name, desc: event.desc)
         .then((result) async* {
       result.fold(

+ 0 - 6
app_flowy/lib/home/domain/i_app.dart

@@ -2,12 +2,6 @@ import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
 import 'package:dartz/dartz.dart';
 
 abstract class IApp {
-  Future<Either<App, WorkspaceError>> createApp(
-      {required String name, String? desc});
-
-  Future<Either<List<App>, WorkspaceError>> getApps(
-      {required String workspaceId});
-
   Future<Either<List<View>, WorkspaceError>> getViews({required String appId});
 
   Future<Either<View, WorkspaceError>> createView(

+ 10 - 0
app_flowy/lib/home/domain/i_workspace.dart

@@ -0,0 +1,10 @@
+import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
+import 'package:dartz/dartz.dart';
+
+abstract class IWorkspace {
+  Future<Either<App, WorkspaceError>> createApp(
+      {required String name, String? desc});
+
+  Future<Either<List<App>, WorkspaceError>> getApps(
+      {required String workspaceId});
+}

+ 0 - 65
app_flowy/lib/home/infrastructure/app_repo.dart

@@ -1,65 +0,0 @@
-import 'package:dartz/dartz.dart';
-import 'package:flowy_sdk/dispatch/dispatch.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/app_query.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_query.pb.dart';
-
-class AppRepository {
-  Future<Either<App, WorkspaceError>> createApp(String appName, String desc) {
-    return WorkspaceEventGetCurWorkspace().send().then((result) {
-      return result.fold(
-        (workspace) {
-          final request = CreateAppRequest.create()
-            ..name = appName
-            ..workspaceId = workspace.id
-            ..desc = desc;
-          return WorkspaceEventCreateApp(request).send();
-        },
-        (error) {
-          return right(error);
-        },
-      );
-    });
-  }
-
-  Future<Either<List<App>, WorkspaceError>> getApps(
-      {required String workspaceId}) {
-    final request = QueryWorkspaceRequest.create()
-      ..workspaceId = workspaceId
-      ..readApps = true;
-
-    return WorkspaceEventGetWorkspace(request).send().then((result) {
-      return result.fold(
-        (workspace) => left(workspace.apps.items),
-        (error) => right(error),
-      );
-    });
-  }
-
-  Future<Either<List<View>, WorkspaceError>> getViews({required String appId}) {
-    final request = QueryAppRequest.create()
-      ..appId = appId
-      ..readViews = true;
-
-    return WorkspaceEventGetApp(request).send().then((result) {
-      return result.fold(
-        (app) => left(app.views.items),
-        (error) => right(error),
-      );
-    });
-  }
-
-  Future<Either<View, WorkspaceError>> createView(
-      String appId, String name, String desc, ViewTypeIdentifier viewType) {
-    final request = CreateViewRequest.create()
-      ..appId = appId
-      ..name = name
-      ..desc = desc
-      ..viewType = viewType;
-
-    return WorkspaceEventCreateView(request).send();
-  }
-}

+ 11 - 3
app_flowy/lib/home/infrastructure/deps_resolver.dart

@@ -1,16 +1,24 @@
 import 'package:app_flowy/home/application/menu/menu_bloc.dart';
-import 'package:app_flowy/home/infrastructure/app_repo.dart';
 import 'package:app_flowy/home/infrastructure/i_app_impl.dart';
+import 'package:app_flowy/home/infrastructure/i_workspace_impl.dart';
+import 'package:app_flowy/home/infrastructure/repos/app_repo.dart';
+import 'package:app_flowy/home/infrastructure/repos/workspace_repo.dart';
 import 'package:get_it/get_it.dart';
 
 class HomeDepsResolver {
   static Future<void> resolve(GetIt getIt) async {
-    getIt.registerLazySingleton<AppRepository>(() => AppRepository());
+    getIt.registerLazySingleton<WorkspaceRepository>(
+        () => WorkspaceRepository());
+
+    getIt.registerFactoryParam<AppRepository, String, void>(
+        (appId, _) => AppRepository(appId: appId));
 
     //Interface implementation
     getIt.registerFactory<IApp>(() => IAppImpl(repo: getIt<AppRepository>()));
+    getIt.registerFactory<IWorkspace>(
+        () => IWorkspaceImpl(repo: getIt<WorkspaceRepository>()));
 
     //Bloc
-    getIt.registerFactory<MenuBloc>(() => MenuBloc(getIt<IApp>()));
+    getIt.registerFactory<MenuBloc>(() => MenuBloc(getIt<IWorkspace>()));
   }
 }

+ 1 - 14
app_flowy/lib/home/infrastructure/i_app_impl.dart

@@ -1,8 +1,7 @@
+import 'package:app_flowy/home/infrastructure/repos/app_repo.dart';
 import 'package:dartz/dartz.dart';
-import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
 import 'package:app_flowy/home/domain/i_app.dart';
-import 'package:app_flowy/home/infrastructure/app_repo.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
 
 export 'package:app_flowy/home/domain/i_app.dart';
@@ -13,18 +12,6 @@ class IAppImpl extends IApp {
     required this.repo,
   });
 
-  @override
-  Future<Either<App, WorkspaceError>> createApp(
-      {required String name, String? desc}) {
-    return repo.createApp(name, desc ?? "");
-  }
-
-  @override
-  Future<Either<List<App>, WorkspaceError>> getApps(
-      {required String workspaceId}) {
-    return repo.getApps(workspaceId: workspaceId);
-  }
-
   @override
   Future<Either<List<View>, WorkspaceError>> getViews({required String appId}) {
     return repo.getViews(appId: appId);

+ 26 - 0
app_flowy/lib/home/infrastructure/i_workspace_impl.dart

@@ -0,0 +1,26 @@
+import 'package:app_flowy/home/domain/i_workspace.dart';
+import 'package:app_flowy/home/infrastructure/repos/workspace_repo.dart';
+import 'package:dartz/dartz.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
+
+export 'package:app_flowy/home/domain/i_workspace.dart';
+
+class IWorkspaceImpl extends IWorkspace {
+  WorkspaceRepository repo;
+  IWorkspaceImpl({
+    required this.repo,
+  });
+
+  @override
+  Future<Either<App, WorkspaceError>> createApp(
+      {required String name, String? desc}) {
+    return repo.createApp(name, desc ?? "");
+  }
+
+  @override
+  Future<Either<List<App>, WorkspaceError>> getApps(
+      {required String workspaceId}) {
+    return repo.getApps(workspaceId: workspaceId);
+  }
+}

+ 107 - 0
app_flowy/lib/home/infrastructure/repos/app_repo.dart

@@ -0,0 +1,107 @@
+import 'dart:async';
+import 'package:dartz/dartz.dart';
+import 'package:flowy_infra/flowy_logger.dart';
+import 'package:flowy_sdk/dispatch/dispatch.dart';
+import 'package:flowy_sdk/protobuf/flowy-observable/subject.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/app_query.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
+import 'package:flowy_sdk/rust_stream.dart';
+
+typedef AppUpdatedCallback = void Function(String name, String desc);
+typedef ViewUpdatedCallback = void Function(List<View> views);
+
+class AppRepository {
+  StreamSubscription<ObservableSubject>? _subscription;
+  ViewUpdatedCallback? _viewUpdatedCallback;
+  AppUpdatedCallback? _appUpdatedCallback;
+  String appId;
+  AppRepository({
+    required this.appId,
+  });
+
+  Future<Either<App, WorkspaceError>> getAppDesc() {
+    final request = QueryAppRequest.create()
+      ..appId = appId
+      ..readViews = false;
+
+    return WorkspaceEventGetApp(request).send();
+  }
+
+  Future<Either<View, WorkspaceError>> createView(
+      String appId, String name, String desc, ViewTypeIdentifier viewType) {
+    final request = CreateViewRequest.create()
+      ..appId = appId
+      ..name = name
+      ..desc = desc
+      ..viewType = viewType;
+
+    return WorkspaceEventCreateView(request).send();
+  }
+
+  Future<Either<List<View>, WorkspaceError>> getViews({required String appId}) {
+    final request = QueryAppRequest.create()
+      ..appId = appId
+      ..readViews = true;
+
+    return WorkspaceEventGetApp(request).send().then((result) {
+      return result.fold(
+        (app) => left(app.views.items),
+        (error) => right(error),
+      );
+    });
+  }
+
+  void startWatching(
+      {ViewUpdatedCallback? viewUpdatedCallback,
+      AppUpdatedCallback? appUpdatedCallback}) {
+    _viewUpdatedCallback = viewUpdatedCallback;
+    _appUpdatedCallback = appUpdatedCallback;
+    _subscription = RustStreamReceiver.listen((observable) {
+      if (observable.subjectId != appId) {
+        return;
+      }
+
+      final ty = WorkspaceObservableType.valueOf(observable.ty);
+      if (ty != null) {
+        _handleObservableType(ty);
+      }
+    });
+  }
+
+  void _handleObservableType(WorkspaceObservableType ty) {
+    switch (ty) {
+      case WorkspaceObservableType.ViewUpdated:
+        if (_viewUpdatedCallback == null) {
+          return;
+        }
+        getViews(appId: appId).then((result) {
+          result.fold(
+            (views) => _viewUpdatedCallback!(views),
+            (error) => Log.error(error),
+          );
+        });
+        break;
+      case WorkspaceObservableType.AppDescUpdated:
+        if (_appUpdatedCallback == null) {
+          return;
+        }
+        getAppDesc().then((result) {
+          result.fold(
+            (app) => _appUpdatedCallback!(app.name, app.desc),
+            (error) => Log.error(error),
+          );
+        });
+        break;
+      default:
+        break;
+    }
+  }
+
+  Future<void> close() async {
+    await _subscription?.cancel();
+  }
+}

+ 89 - 0
app_flowy/lib/home/infrastructure/repos/workspace_repo.dart

@@ -0,0 +1,89 @@
+import 'dart:async';
+
+import 'package:dartz/dartz.dart';
+import 'package:flowy_infra/flowy_logger.dart';
+import 'package:flowy_sdk/dispatch/dispatch.dart';
+import 'package:flowy_sdk/protobuf/flowy-observable/subject.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_query.pb.dart';
+import 'package:flowy_sdk/rust_stream.dart';
+
+typedef AppUpdatedCallback = void Function(List<App> apps);
+
+class WorkspaceRepository {
+  StreamSubscription<ObservableSubject>? _subscription;
+  AppUpdatedCallback? _appUpdatedCallback;
+  String workspaceId;
+  WorkspaceRepository({
+    required this.workspaceId,
+  });
+
+  Future<Either<App, WorkspaceError>> createApp(String appName, String desc) {
+    return WorkspaceEventGetCurWorkspace().send().then((result) {
+      return result.fold(
+        (workspace) {
+          final request = CreateAppRequest.create()
+            ..name = appName
+            ..workspaceId = workspace.id
+            ..desc = desc;
+          return WorkspaceEventCreateApp(request).send();
+        },
+        (error) {
+          return right(error);
+        },
+      );
+    });
+  }
+
+  Future<Either<List<App>, WorkspaceError>> getApps(
+      {required String workspaceId}) {
+    final request = QueryWorkspaceRequest.create()
+      ..workspaceId = workspaceId
+      ..readApps = true;
+
+    return WorkspaceEventGetWorkspace(request).send().then((result) {
+      return result.fold(
+        (workspace) => left(workspace.apps.items),
+        (error) => right(error),
+      );
+    });
+  }
+
+  void startWatching({AppUpdatedCallback? appUpdatedCallback}) {
+    _appUpdatedCallback = appUpdatedCallback;
+    _subscription = RustStreamReceiver.listen((observable) {
+      if (observable.subjectId != workspaceId) {
+        return;
+      }
+
+      final ty = WorkspaceObservableType.valueOf(observable.ty);
+      if (ty != null) {
+        _handleObservableType(ty);
+      }
+    });
+  }
+
+  void _handleObservableType(WorkspaceObservableType ty) {
+    switch (ty) {
+      case WorkspaceObservableType.WorkspaceUpdated:
+        if (_appUpdatedCallback == null) {
+          return;
+        }
+        getApps(workspaceId: workspaceId).then((result) {
+          result.fold(
+            (apps) => _appUpdatedCallback!(apps),
+            (error) => Log.error(error),
+          );
+        });
+        break;
+      default:
+        break;
+    }
+  }
+
+  Future<void> close() async {
+    await _subscription?.cancel();
+  }
+}

+ 14 - 10
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbenum.dart

@@ -9,20 +9,24 @@
 import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-class ObservableType extends $pb.ProtobufEnum {
-  static const ObservableType Unknown = ObservableType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
-  static const ObservableType WorkspaceDidUpdate = ObservableType._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDidUpdate');
-  static const ObservableType AppDidUpdate = ObservableType._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppDidUpdate');
+class WorkspaceObservableType extends $pb.ProtobufEnum {
+  static const WorkspaceObservableType Unknown = WorkspaceObservableType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
+  static const WorkspaceObservableType WorkspaceUpdated = WorkspaceObservableType._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceUpdated');
+  static const WorkspaceObservableType AppDescUpdated = WorkspaceObservableType._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppDescUpdated');
+  static const WorkspaceObservableType AppViewsUpdated = WorkspaceObservableType._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppViewsUpdated');
+  static const WorkspaceObservableType ViewUpdated = WorkspaceObservableType._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewUpdated');
 
-  static const $core.List<ObservableType> values = <ObservableType> [
+  static const $core.List<WorkspaceObservableType> values = <WorkspaceObservableType> [
     Unknown,
-    WorkspaceDidUpdate,
-    AppDidUpdate,
+    WorkspaceUpdated,
+    AppDescUpdated,
+    AppViewsUpdated,
+    ViewUpdated,
   ];
 
-  static final $core.Map<$core.int, ObservableType> _byValue = $pb.ProtobufEnum.initByValue(values);
-  static ObservableType? valueOf($core.int value) => _byValue[value];
+  static final $core.Map<$core.int, WorkspaceObservableType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static WorkspaceObservableType? valueOf($core.int value) => _byValue[value];
 
-  const ObservableType._($core.int v, $core.String n) : super(v, n);
+  const WorkspaceObservableType._($core.int v, $core.String n) : super(v, n);
 }
 

+ 9 - 7
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbjson.dart

@@ -8,15 +8,17 @@
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use observableTypeDescriptor instead')
-const ObservableType$json = const {
-  '1': 'ObservableType',
+@$core.Deprecated('Use workspaceObservableTypeDescriptor instead')
+const WorkspaceObservableType$json = const {
+  '1': 'WorkspaceObservableType',
   '2': const [
     const {'1': 'Unknown', '2': 0},
-    const {'1': 'WorkspaceDidUpdate', '2': 10},
-    const {'1': 'AppDidUpdate', '2': 11},
+    const {'1': 'WorkspaceUpdated', '2': 10},
+    const {'1': 'AppDescUpdated', '2': 20},
+    const {'1': 'AppViewsUpdated', '2': 21},
+    const {'1': 'ViewUpdated', '2': 30},
   ],
 };
 
-/// Descriptor for `ObservableType`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List observableTypeDescriptor = $convert.base64Decode('Cg5PYnNlcnZhYmxlVHlwZRILCgdVbmtub3duEAASFgoSV29ya3NwYWNlRGlkVXBkYXRlEAoSEAoMQXBwRGlkVXBkYXRlEAs=');
+/// Descriptor for `WorkspaceObservableType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List workspaceObservableTypeDescriptor = $convert.base64Decode('ChdXb3Jrc3BhY2VPYnNlcnZhYmxlVHlwZRILCgdVbmtub3duEAASFAoQV29ya3NwYWNlVXBkYXRlZBAKEhIKDkFwcERlc2NVcGRhdGVkEBQSEwoPQXBwVmlld3NVcGRhdGVkEBUSDwoLVmlld1VwZGF0ZWQQHg==');

+ 1 - 1
rust-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -46,7 +46,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         "ViewTypeIdentifier"
         | "WorkspaceEvent"
         | "WorkspaceErrorCode"
-        | "ObservableType"
+        | "WorkspaceObservableType"
         | "FFIStatusCode"
         | "UserStatus"
         | "UserEvent"

+ 1 - 1
rust-lib/flowy-observable/Flowy.toml

@@ -1,3 +1,3 @@
 
 proto_crates = ["src/entities"]
-event_files = [""]
+event_files = []

+ 12 - 11
rust-lib/flowy-workspace/src/observable/observable.rs

@@ -4,25 +4,26 @@ use flowy_observable::{dart::RustStreamSender, entities::ObservableSubject};
 const OBSERVABLE_CATEGORY: &'static str = "Workspace";
 
 #[derive(ProtoBuf_Enum, Debug)]
-pub(crate) enum ObservableType {
-    Unknown            = 0,
-
-    WorkspaceDidUpdate = 10,
-    AppDidUpdate       = 11,
+pub(crate) enum WorkspaceObservableType {
+    Unknown          = 0,
+    WorkspaceUpdated = 10,
+    AppDescUpdated   = 20,
+    AppViewsUpdated  = 21,
+    ViewUpdated      = 30,
 }
 
-impl std::default::Default for ObservableType {
-    fn default() -> Self { ObservableType::Unknown }
+impl std::default::Default for WorkspaceObservableType {
+    fn default() -> Self { WorkspaceObservableType::Unknown }
 }
 
 pub(crate) struct ObservableSender {
-    ty: ObservableType,
+    ty: WorkspaceObservableType,
     subject_id: String,
     payload: Option<Vec<u8>>,
 }
 
 impl ObservableSender {
-    pub(crate) fn new(subject_id: &str, ty: ObservableType) -> Self {
+    pub(crate) fn new(subject_id: &str, ty: WorkspaceObservableType) -> Self {
         Self {
             subject_id: subject_id.to_owned(),
             ty,
@@ -59,11 +60,11 @@ impl ObservableSender {
     }
 }
 
-pub(crate) fn send_observable(id: &str, ty: ObservableType) {
+pub(crate) fn send_observable(id: &str, ty: WorkspaceObservableType) {
     ObservableSender::new(id, ty).send();
 }
 
-pub(crate) fn send_observable_with_payload<T>(id: &str, ty: ObservableType, payload: T)
+pub(crate) fn send_observable_with_payload<T>(id: &str, ty: WorkspaceObservableType, payload: T)
 where
     T: ToBytes,
 {

+ 39 - 28
rust-lib/flowy-workspace/src/protobuf/model/observable.rs

@@ -24,31 +24,37 @@
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum ObservableType {
+pub enum WorkspaceObservableType {
     Unknown = 0,
-    WorkspaceDidUpdate = 10,
-    AppDidUpdate = 11,
+    WorkspaceUpdated = 10,
+    AppDescUpdated = 20,
+    AppViewsUpdated = 21,
+    ViewUpdated = 30,
 }
 
-impl ::protobuf::ProtobufEnum for ObservableType {
+impl ::protobuf::ProtobufEnum for WorkspaceObservableType {
     fn value(&self) -> i32 {
         *self as i32
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<ObservableType> {
+    fn from_i32(value: i32) -> ::std::option::Option<WorkspaceObservableType> {
         match value {
-            0 => ::std::option::Option::Some(ObservableType::Unknown),
-            10 => ::std::option::Option::Some(ObservableType::WorkspaceDidUpdate),
-            11 => ::std::option::Option::Some(ObservableType::AppDidUpdate),
+            0 => ::std::option::Option::Some(WorkspaceObservableType::Unknown),
+            10 => ::std::option::Option::Some(WorkspaceObservableType::WorkspaceUpdated),
+            20 => ::std::option::Option::Some(WorkspaceObservableType::AppDescUpdated),
+            21 => ::std::option::Option::Some(WorkspaceObservableType::AppViewsUpdated),
+            30 => ::std::option::Option::Some(WorkspaceObservableType::ViewUpdated),
             _ => ::std::option::Option::None
         }
     }
 
     fn values() -> &'static [Self] {
-        static values: &'static [ObservableType] = &[
-            ObservableType::Unknown,
-            ObservableType::WorkspaceDidUpdate,
-            ObservableType::AppDidUpdate,
+        static values: &'static [WorkspaceObservableType] = &[
+            WorkspaceObservableType::Unknown,
+            WorkspaceObservableType::WorkspaceUpdated,
+            WorkspaceObservableType::AppDescUpdated,
+            WorkspaceObservableType::AppViewsUpdated,
+            WorkspaceObservableType::ViewUpdated,
         ];
         values
     }
@@ -56,38 +62,43 @@ impl ::protobuf::ProtobufEnum for ObservableType {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
-            ::protobuf::reflect::EnumDescriptor::new_pb_name::<ObservableType>("ObservableType", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<WorkspaceObservableType>("WorkspaceObservableType", file_descriptor_proto())
         })
     }
 }
 
-impl ::std::marker::Copy for ObservableType {
+impl ::std::marker::Copy for WorkspaceObservableType {
 }
 
-impl ::std::default::Default for ObservableType {
+impl ::std::default::Default for WorkspaceObservableType {
     fn default() -> Self {
-        ObservableType::Unknown
+        WorkspaceObservableType::Unknown
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for ObservableType {
+impl ::protobuf::reflect::ProtobufValue for WorkspaceObservableType {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x10observable.proto*G\n\x0eObservableType\x12\x0b\n\x07Unknown\x10\0\
-    \x12\x16\n\x12WorkspaceDidUpdate\x10\n\x12\x10\n\x0cAppDidUpdate\x10\x0b\
-    J\xa5\x01\n\x06\x12\x04\0\0\x06\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\
-    \n\x02\x05\0\x12\x04\x02\0\x06\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\
-    \x13\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x10\n\x0c\n\x05\x05\0\x02\0\
-    \x01\x12\x03\x03\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x0e\x0f\
-    \n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x1c\n\x0c\n\x05\x05\0\x02\x01\
-    \x01\x12\x03\x04\x04\x16\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x19\
-    \x1b\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x16\n\x0c\n\x05\x05\0\x02\
-    \x02\x01\x12\x03\x05\x04\x10\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\
-    \x13\x15b\x06proto3\
+    \n\x10observable.proto*v\n\x17WorkspaceObservableType\x12\x0b\n\x07Unkno\
+    wn\x10\0\x12\x14\n\x10WorkspaceUpdated\x10\n\x12\x12\n\x0eAppDescUpdated\
+    \x10\x14\x12\x13\n\x0fAppViewsUpdated\x10\x15\x12\x0f\n\x0bViewUpdated\
+    \x10\x1eJ\xf7\x01\n\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\
+    \x12\n\n\n\x02\x05\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x05\0\x01\x12\x03\
+    \x02\x05\x1c\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x10\n\x0c\n\x05\x05\
+    \0\x02\0\x01\x12\x03\x03\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\
+    \x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x1a\n\x0c\n\x05\x05\0\
+    \x02\x01\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\
+    \x04\x17\x19\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x18\n\x0c\n\x05\
+    \x05\0\x02\x02\x01\x12\x03\x05\x04\x12\n\x0c\n\x05\x05\0\x02\x02\x02\x12\
+    \x03\x05\x15\x17\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x19\n\x0c\n\
+    \x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\n\x05\x05\0\x02\x03\x02\
+    \x12\x03\x06\x16\x18\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x15\n\x0c\
+    \n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x0f\n\x0c\n\x05\x05\0\x02\x04\
+    \x02\x12\x03\x07\x12\x14b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 5 - 3
rust-lib/flowy-workspace/src/protobuf/proto/observable.proto

@@ -1,7 +1,9 @@
 syntax = "proto3";
 
-enum ObservableType {
+enum WorkspaceObservableType {
     Unknown = 0;
-    WorkspaceDidUpdate = 10;
-    AppDidUpdate = 11;
+    WorkspaceUpdated = 10;
+    AppDescUpdated = 20;
+    AppViewsUpdated = 21;
+    ViewUpdated = 30;
 }

+ 2 - 2
rust-lib/flowy-workspace/src/services/app_controller.rs

@@ -36,7 +36,7 @@ impl AppController {
         let app_table = AppTable::new(params);
         let app: App = app_table.clone().into();
         let _ = self.sql.write_app_table(app_table)?;
-        send_observable(&app.workspace_id, ObservableType::WorkspaceDidUpdate);
+        send_observable(&app.workspace_id, WorkspaceObservableType::WorkspaceUpdated);
         Ok(app)
     }
 
@@ -49,7 +49,7 @@ impl AppController {
         let changeset = AppTableChangeset::new(params);
         let app_id = changeset.id.clone();
         let _ = self.sql.update_app_table(changeset)?;
-        send_observable(&app_id, ObservableType::AppDidUpdate);
+        send_observable(&app_id, WorkspaceObservableType::AppDescUpdated);
         Ok(())
     }