Browse Source

test stream from rust to flutter

appflowy 3 years ago
parent
commit
ebc489738c
52 changed files with 1153 additions and 407 deletions
  1. 14 1
      app_flowy/lib/home/application/app/app_bloc.dart
  2. 173 70
      app_flowy/lib/home/application/app/app_bloc.freezed.dart
  3. 3 2
      app_flowy/lib/home/application/app/app_event.dart
  4. 2 0
      app_flowy/lib/home/application/app/app_state.dart
  5. 19 4
      app_flowy/lib/home/application/menu/menu_bloc.dart
  6. 358 56
      app_flowy/lib/home/application/menu/menu_bloc.freezed.dart
  7. 5 2
      app_flowy/lib/home/application/menu/menu_event.dart
  8. 2 0
      app_flowy/lib/home/application/menu/menu_state.dart
  9. 11 1
      app_flowy/lib/home/domain/i_app.dart
  10. 10 0
      app_flowy/lib/home/domain/i_workspace.dart
  11. 7 4
      app_flowy/lib/home/infrastructure/deps_resolver.dart
  12. 14 1
      app_flowy/lib/home/infrastructure/i_app_impl.dart
  13. 21 1
      app_flowy/lib/home/infrastructure/i_workspace_impl.dart
  14. 17 19
      app_flowy/lib/home/infrastructure/repos/app_repo.dart
  15. 31 15
      app_flowy/lib/home/infrastructure/repos/workspace_repo.dart
  16. 1 0
      app_flowy/lib/home/presentation/home_screen.dart
  17. 58 0
      app_flowy/lib/home/presentation/widgets/app/app_list_widget.dart
  18. 122 0
      app_flowy/lib/home/presentation/widgets/app/app_widget.dart
  19. 0 0
      app_flowy/lib/home/presentation/widgets/app/new_app.dart
  20. 0 0
      app_flowy/lib/home/presentation/widgets/app/view_list.dart
  21. 5 2
      app_flowy/lib/home/presentation/widgets/menu/home_menu.dart
  22. 1 1
      app_flowy/lib/main.dart
  23. 1 1
      app_flowy/lib/startup/startup.dart
  24. 13 0
      app_flowy/packages/flowy_infra_ui/lib/widget/error_page.dart
  25. 16 14
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbenum.dart
  26. 10 9
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbjson.dart
  27. 8 8
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pb.dart
  28. 6 6
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pbenum.dart
  29. 9 9
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pbjson.dart
  30. 5 5
      app_flowy/pubspec.lock
  31. 6 1
      rust-lib/dart-ffi/src/model/ffi_response.rs
  32. 2 2
      rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
  33. 0 1
      rust-lib/flowy-derive/src/proto_buf/deserialize.rs
  34. 10 1
      rust-lib/flowy-dispatch/src/dispatch.rs
  35. 1 1
      rust-lib/flowy-observable/src/dart/stream_sender.rs
  36. 2 2
      rust-lib/flowy-sdk/Cargo.toml
  37. 1 0
      rust-lib/flowy-workspace/Cargo.toml
  38. 4 4
      rust-lib/flowy-workspace/src/entities/view/parser/view_type.rs
  39. 7 7
      rust-lib/flowy-workspace/src/entities/view/view_create.rs
  40. 6 6
      rust-lib/flowy-workspace/src/event.rs
  41. 2 0
      rust-lib/flowy-workspace/src/handlers/app_handler.rs
  42. 3 0
      rust-lib/flowy-workspace/src/handlers/workspace_handler.rs
  43. 16 12
      rust-lib/flowy-workspace/src/observable/observable.rs
  44. 45 39
      rust-lib/flowy-workspace/src/protobuf/model/observable.rs
  45. 77 77
      rust-lib/flowy-workspace/src/protobuf/model/view_create.rs
  46. 6 5
      rust-lib/flowy-workspace/src/protobuf/proto/observable.proto
  47. 3 3
      rust-lib/flowy-workspace/src/protobuf/proto/view_create.proto
  48. 2 2
      rust-lib/flowy-workspace/src/services/app_controller.rs
  49. 2 0
      rust-lib/flowy-workspace/src/services/view_controller.rs
  50. 3 0
      rust-lib/flowy-workspace/src/services/workspace_controller.rs
  51. 11 11
      rust-lib/flowy-workspace/src/sql_tables/view/view_table.rs
  52. 2 2
      rust-lib/flowy-workspace/tests/event/app_test.rs

+ 14 - 1
app_flowy/lib/home/application/app/app_bloc.dart

@@ -1,6 +1,7 @@
 import 'package:app_flowy/home/domain/i_app.dart';
 import 'package:app_flowy/home/domain/i_app.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.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/errors.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:dartz/dartz.dart';
 import 'package:dartz/dartz.dart';
@@ -16,5 +17,17 @@ class AppBloc extends Bloc<AppEvent, AppState> {
   @override
   @override
   Stream<AppState> mapEventToState(
   Stream<AppState> mapEventToState(
     AppEvent event,
     AppEvent event,
-  ) async* {}
+  ) async* {
+    yield* event.map(
+      initial: (e) async* {
+        iAppImpl.startWatching(
+          updatedCallback: (name, desc) {},
+          addViewCallback: (views) {},
+        );
+      },
+      viewsReceived: (e) async* {
+        yield state;
+      },
+    );
+  }
 }
 }

+ 173 - 70
app_flowy/lib/home/application/app/app_bloc.freezed.dart

@@ -16,8 +16,12 @@ final _privateConstructorUsedError = UnsupportedError(
 class _$AppEventTearOff {
 class _$AppEventTearOff {
   const _$AppEventTearOff();
   const _$AppEventTearOff();
 
 
-  AppsReceived appsReceived(Either<List<App>, WorkspaceError> appsOrFail) {
-    return AppsReceived(
+  _Initial initial() {
+    return const _Initial();
+  }
+
+  ViewsReceived viewsReceived(Either<List<View>, WorkspaceError> appsOrFail) {
+    return ViewsReceived(
       appsOrFail,
       appsOrFail,
     );
     );
   }
   }
@@ -28,44 +32,40 @@ const $AppEvent = _$AppEventTearOff();
 
 
 /// @nodoc
 /// @nodoc
 mixin _$AppEvent {
 mixin _$AppEvent {
-  Either<List<App>, WorkspaceError> get appsOrFail =>
-      throw _privateConstructorUsedError;
-
   @optionalTypeArgs
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
   TResult when<TResult extends Object?>({
-    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
-        appsReceived,
+    required TResult Function() initial,
+    required TResult Function(Either<List<View>, WorkspaceError> appsOrFail)
+        viewsReceived,
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
   TResult maybeWhen<TResult extends Object?>({
-    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
-        appsReceived,
+    TResult Function()? initial,
+    TResult Function(Either<List<View>, WorkspaceError> appsOrFail)?
+        viewsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
   TResult map<TResult extends Object?>({
-    required TResult Function(AppsReceived value) appsReceived,
+    required TResult Function(_Initial value) initial,
+    required TResult Function(ViewsReceived value) viewsReceived,
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
   TResult maybeMap<TResult extends Object?>({
-    TResult Function(AppsReceived value)? appsReceived,
+    TResult Function(_Initial value)? initial,
+    TResult Function(ViewsReceived value)? viewsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
-
-  @JsonKey(ignore: true)
-  $AppEventCopyWith<AppEvent> get copyWith =>
-      throw _privateConstructorUsedError;
 }
 }
 
 
 /// @nodoc
 /// @nodoc
 abstract class $AppEventCopyWith<$Res> {
 abstract class $AppEventCopyWith<$Res> {
   factory $AppEventCopyWith(AppEvent value, $Res Function(AppEvent) then) =
   factory $AppEventCopyWith(AppEvent value, $Res Function(AppEvent) then) =
       _$AppEventCopyWithImpl<$Res>;
       _$AppEventCopyWithImpl<$Res>;
-  $Res call({Either<List<App>, WorkspaceError> appsOrFail});
 }
 }
 
 
 /// @nodoc
 /// @nodoc
@@ -75,69 +75,141 @@ class _$AppEventCopyWithImpl<$Res> implements $AppEventCopyWith<$Res> {
   final AppEvent _value;
   final AppEvent _value;
   // ignore: unused_field
   // ignore: unused_field
   final $Res Function(AppEvent) _then;
   final $Res Function(AppEvent) _then;
+}
+
+/// @nodoc
+abstract class _$InitialCopyWith<$Res> {
+  factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
+      __$InitialCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$InitialCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res>
+    implements _$InitialCopyWith<$Res> {
+  __$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
+      : super(_value, (v) => _then(v as _Initial));
 
 
   @override
   @override
-  $Res call({
-    Object? appsOrFail = freezed,
+  _Initial get _value => super._value as _Initial;
+}
+
+/// @nodoc
+
+class _$_Initial implements _Initial {
+  const _$_Initial();
+
+  @override
+  String toString() {
+    return 'AppEvent.initial()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is _Initial);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(Either<List<View>, WorkspaceError> appsOrFail)
+        viewsReceived,
   }) {
   }) {
-    return _then(_value.copyWith(
-      appsOrFail: appsOrFail == freezed
-          ? _value.appsOrFail
-          : appsOrFail // ignore: cast_nullable_to_non_nullable
-              as Either<List<App>, WorkspaceError>,
-    ));
+    return initial();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(Either<List<View>, WorkspaceError> appsOrFail)?
+        viewsReceived,
+    required TResult orElse(),
+  }) {
+    if (initial != null) {
+      return initial();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
+    required TResult Function(ViewsReceived value) viewsReceived,
+  }) {
+    return initial(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
+    TResult Function(ViewsReceived value)? viewsReceived,
+    required TResult orElse(),
+  }) {
+    if (initial != null) {
+      return initial(this);
+    }
+    return orElse();
   }
   }
 }
 }
 
 
+abstract class _Initial implements AppEvent {
+  const factory _Initial() = _$_Initial;
+}
+
 /// @nodoc
 /// @nodoc
-abstract class $AppsReceivedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
-  factory $AppsReceivedCopyWith(
-          AppsReceived value, $Res Function(AppsReceived) then) =
-      _$AppsReceivedCopyWithImpl<$Res>;
-  @override
-  $Res call({Either<List<App>, WorkspaceError> appsOrFail});
+abstract class $ViewsReceivedCopyWith<$Res> {
+  factory $ViewsReceivedCopyWith(
+          ViewsReceived value, $Res Function(ViewsReceived) then) =
+      _$ViewsReceivedCopyWithImpl<$Res>;
+  $Res call({Either<List<View>, WorkspaceError> appsOrFail});
 }
 }
 
 
 /// @nodoc
 /// @nodoc
-class _$AppsReceivedCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res>
-    implements $AppsReceivedCopyWith<$Res> {
-  _$AppsReceivedCopyWithImpl(
-      AppsReceived _value, $Res Function(AppsReceived) _then)
-      : super(_value, (v) => _then(v as AppsReceived));
+class _$ViewsReceivedCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res>
+    implements $ViewsReceivedCopyWith<$Res> {
+  _$ViewsReceivedCopyWithImpl(
+      ViewsReceived _value, $Res Function(ViewsReceived) _then)
+      : super(_value, (v) => _then(v as ViewsReceived));
 
 
   @override
   @override
-  AppsReceived get _value => super._value as AppsReceived;
+  ViewsReceived get _value => super._value as ViewsReceived;
 
 
   @override
   @override
   $Res call({
   $Res call({
     Object? appsOrFail = freezed,
     Object? appsOrFail = freezed,
   }) {
   }) {
-    return _then(AppsReceived(
+    return _then(ViewsReceived(
       appsOrFail == freezed
       appsOrFail == freezed
           ? _value.appsOrFail
           ? _value.appsOrFail
           : appsOrFail // ignore: cast_nullable_to_non_nullable
           : appsOrFail // ignore: cast_nullable_to_non_nullable
-              as Either<List<App>, WorkspaceError>,
+              as Either<List<View>, WorkspaceError>,
     ));
     ));
   }
   }
 }
 }
 
 
 /// @nodoc
 /// @nodoc
 
 
-class _$AppsReceived implements AppsReceived {
-  const _$AppsReceived(this.appsOrFail);
+class _$ViewsReceived implements ViewsReceived {
+  const _$ViewsReceived(this.appsOrFail);
 
 
   @override
   @override
-  final Either<List<App>, WorkspaceError> appsOrFail;
+  final Either<List<View>, WorkspaceError> appsOrFail;
 
 
   @override
   @override
   String toString() {
   String toString() {
-    return 'AppEvent.appsReceived(appsOrFail: $appsOrFail)';
+    return 'AppEvent.viewsReceived(appsOrFail: $appsOrFail)';
   }
   }
 
 
   @override
   @override
   bool operator ==(dynamic other) {
   bool operator ==(dynamic other) {
     return identical(this, other) ||
     return identical(this, other) ||
-        (other is AppsReceived &&
+        (other is ViewsReceived &&
             (identical(other.appsOrFail, appsOrFail) ||
             (identical(other.appsOrFail, appsOrFail) ||
                 const DeepCollectionEquality()
                 const DeepCollectionEquality()
                     .equals(other.appsOrFail, appsOrFail)));
                     .equals(other.appsOrFail, appsOrFail)));
@@ -149,27 +221,29 @@ class _$AppsReceived implements AppsReceived {
 
 
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
   @override
   @override
-  $AppsReceivedCopyWith<AppsReceived> get copyWith =>
-      _$AppsReceivedCopyWithImpl<AppsReceived>(this, _$identity);
+  $ViewsReceivedCopyWith<ViewsReceived> get copyWith =>
+      _$ViewsReceivedCopyWithImpl<ViewsReceived>(this, _$identity);
 
 
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
   TResult when<TResult extends Object?>({
-    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
-        appsReceived,
+    required TResult Function() initial,
+    required TResult Function(Either<List<View>, WorkspaceError> appsOrFail)
+        viewsReceived,
   }) {
   }) {
-    return appsReceived(appsOrFail);
+    return viewsReceived(appsOrFail);
   }
   }
 
 
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
   TResult maybeWhen<TResult extends Object?>({
-    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
-        appsReceived,
+    TResult Function()? initial,
+    TResult Function(Either<List<View>, WorkspaceError> appsOrFail)?
+        viewsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
-    if (appsReceived != null) {
-      return appsReceived(appsOrFail);
+    if (viewsReceived != null) {
+      return viewsReceived(appsOrFail);
     }
     }
     return orElse();
     return orElse();
   }
   }
@@ -177,34 +251,34 @@ class _$AppsReceived implements AppsReceived {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
   TResult map<TResult extends Object?>({
-    required TResult Function(AppsReceived value) appsReceived,
+    required TResult Function(_Initial value) initial,
+    required TResult Function(ViewsReceived value) viewsReceived,
   }) {
   }) {
-    return appsReceived(this);
+    return viewsReceived(this);
   }
   }
 
 
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
   TResult maybeMap<TResult extends Object?>({
-    TResult Function(AppsReceived value)? appsReceived,
+    TResult Function(_Initial value)? initial,
+    TResult Function(ViewsReceived value)? viewsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
-    if (appsReceived != null) {
-      return appsReceived(this);
+    if (viewsReceived != null) {
+      return viewsReceived(this);
     }
     }
     return orElse();
     return orElse();
   }
   }
 }
 }
 
 
-abstract class AppsReceived implements AppEvent {
-  const factory AppsReceived(Either<List<App>, WorkspaceError> appsOrFail) =
-      _$AppsReceived;
+abstract class ViewsReceived implements AppEvent {
+  const factory ViewsReceived(Either<List<View>, WorkspaceError> appsOrFail) =
+      _$ViewsReceived;
 
 
-  @override
-  Either<List<App>, WorkspaceError> get appsOrFail =>
+  Either<List<View>, WorkspaceError> get appsOrFail =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
-  @override
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
-  $AppsReceivedCopyWith<AppsReceived> get copyWith =>
+  $ViewsReceivedCopyWith<ViewsReceived> get copyWith =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
 }
 }
 
 
@@ -213,9 +287,11 @@ class _$AppStateTearOff {
   const _$AppStateTearOff();
   const _$AppStateTearOff();
 
 
   _AppState call(
   _AppState call(
-      {required Option<List<App>> apps,
+      {required bool isLoading,
+      required Option<List<App>> apps,
       required Either<Unit, WorkspaceError> successOrFailure}) {
       required Either<Unit, WorkspaceError> successOrFailure}) {
     return _AppState(
     return _AppState(
+      isLoading: isLoading,
       apps: apps,
       apps: apps,
       successOrFailure: successOrFailure,
       successOrFailure: successOrFailure,
     );
     );
@@ -227,6 +303,7 @@ const $AppState = _$AppStateTearOff();
 
 
 /// @nodoc
 /// @nodoc
 mixin _$AppState {
 mixin _$AppState {
+  bool get isLoading => throw _privateConstructorUsedError;
   Option<List<App>> get apps => throw _privateConstructorUsedError;
   Option<List<App>> get apps => throw _privateConstructorUsedError;
   Either<Unit, WorkspaceError> get successOrFailure =>
   Either<Unit, WorkspaceError> get successOrFailure =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
@@ -241,7 +318,9 @@ abstract class $AppStateCopyWith<$Res> {
   factory $AppStateCopyWith(AppState value, $Res Function(AppState) then) =
   factory $AppStateCopyWith(AppState value, $Res Function(AppState) then) =
       _$AppStateCopyWithImpl<$Res>;
       _$AppStateCopyWithImpl<$Res>;
   $Res call(
   $Res call(
-      {Option<List<App>> apps, Either<Unit, WorkspaceError> successOrFailure});
+      {bool isLoading,
+      Option<List<App>> apps,
+      Either<Unit, WorkspaceError> successOrFailure});
 }
 }
 
 
 /// @nodoc
 /// @nodoc
@@ -254,10 +333,15 @@ class _$AppStateCopyWithImpl<$Res> implements $AppStateCopyWith<$Res> {
 
 
   @override
   @override
   $Res call({
   $Res call({
+    Object? isLoading = freezed,
     Object? apps = freezed,
     Object? apps = freezed,
     Object? successOrFailure = freezed,
     Object? successOrFailure = freezed,
   }) {
   }) {
     return _then(_value.copyWith(
     return _then(_value.copyWith(
+      isLoading: isLoading == freezed
+          ? _value.isLoading
+          : isLoading // ignore: cast_nullable_to_non_nullable
+              as bool,
       apps: apps == freezed
       apps: apps == freezed
           ? _value.apps
           ? _value.apps
           : apps // ignore: cast_nullable_to_non_nullable
           : apps // ignore: cast_nullable_to_non_nullable
@@ -276,7 +360,9 @@ abstract class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res> {
       __$AppStateCopyWithImpl<$Res>;
       __$AppStateCopyWithImpl<$Res>;
   @override
   @override
   $Res call(
   $Res call(
-      {Option<List<App>> apps, Either<Unit, WorkspaceError> successOrFailure});
+      {bool isLoading,
+      Option<List<App>> apps,
+      Either<Unit, WorkspaceError> successOrFailure});
 }
 }
 
 
 /// @nodoc
 /// @nodoc
@@ -290,10 +376,15 @@ class __$AppStateCopyWithImpl<$Res> extends _$AppStateCopyWithImpl<$Res>
 
 
   @override
   @override
   $Res call({
   $Res call({
+    Object? isLoading = freezed,
     Object? apps = freezed,
     Object? apps = freezed,
     Object? successOrFailure = freezed,
     Object? successOrFailure = freezed,
   }) {
   }) {
     return _then(_AppState(
     return _then(_AppState(
+      isLoading: isLoading == freezed
+          ? _value.isLoading
+          : isLoading // ignore: cast_nullable_to_non_nullable
+              as bool,
       apps: apps == freezed
       apps: apps == freezed
           ? _value.apps
           ? _value.apps
           : apps // ignore: cast_nullable_to_non_nullable
           : apps // ignore: cast_nullable_to_non_nullable
@@ -309,8 +400,13 @@ class __$AppStateCopyWithImpl<$Res> extends _$AppStateCopyWithImpl<$Res>
 /// @nodoc
 /// @nodoc
 
 
 class _$_AppState implements _AppState {
 class _$_AppState implements _AppState {
-  const _$_AppState({required this.apps, required this.successOrFailure});
+  const _$_AppState(
+      {required this.isLoading,
+      required this.apps,
+      required this.successOrFailure});
 
 
+  @override
+  final bool isLoading;
   @override
   @override
   final Option<List<App>> apps;
   final Option<List<App>> apps;
   @override
   @override
@@ -318,13 +414,16 @@ class _$_AppState implements _AppState {
 
 
   @override
   @override
   String toString() {
   String toString() {
-    return 'AppState(apps: $apps, successOrFailure: $successOrFailure)';
+    return 'AppState(isLoading: $isLoading, apps: $apps, successOrFailure: $successOrFailure)';
   }
   }
 
 
   @override
   @override
   bool operator ==(dynamic other) {
   bool operator ==(dynamic other) {
     return identical(this, other) ||
     return identical(this, other) ||
         (other is _AppState &&
         (other is _AppState &&
+            (identical(other.isLoading, isLoading) ||
+                const DeepCollectionEquality()
+                    .equals(other.isLoading, isLoading)) &&
             (identical(other.apps, apps) ||
             (identical(other.apps, apps) ||
                 const DeepCollectionEquality().equals(other.apps, apps)) &&
                 const DeepCollectionEquality().equals(other.apps, apps)) &&
             (identical(other.successOrFailure, successOrFailure) ||
             (identical(other.successOrFailure, successOrFailure) ||
@@ -335,6 +434,7 @@ class _$_AppState implements _AppState {
   @override
   @override
   int get hashCode =>
   int get hashCode =>
       runtimeType.hashCode ^
       runtimeType.hashCode ^
+      const DeepCollectionEquality().hash(isLoading) ^
       const DeepCollectionEquality().hash(apps) ^
       const DeepCollectionEquality().hash(apps) ^
       const DeepCollectionEquality().hash(successOrFailure);
       const DeepCollectionEquality().hash(successOrFailure);
 
 
@@ -346,9 +446,12 @@ class _$_AppState implements _AppState {
 
 
 abstract class _AppState implements AppState {
 abstract class _AppState implements AppState {
   const factory _AppState(
   const factory _AppState(
-      {required Option<List<App>> apps,
+      {required bool isLoading,
+      required Option<List<App>> apps,
       required Either<Unit, WorkspaceError> successOrFailure}) = _$_AppState;
       required Either<Unit, WorkspaceError> successOrFailure}) = _$_AppState;
 
 
+  @override
+  bool get isLoading => throw _privateConstructorUsedError;
   @override
   @override
   Option<List<App>> get apps => throw _privateConstructorUsedError;
   Option<List<App>> get apps => throw _privateConstructorUsedError;
   @override
   @override

+ 3 - 2
app_flowy/lib/home/application/app/app_event.dart

@@ -2,6 +2,7 @@ part of 'app_bloc.dart';
 
 
 @freezed
 @freezed
 abstract class AppEvent with _$AppEvent {
 abstract class AppEvent with _$AppEvent {
-  const factory AppEvent.appsReceived(
-      Either<List<App>, WorkspaceError> appsOrFail) = AppsReceived;
+  const factory AppEvent.initial() = _Initial;
+  const factory AppEvent.viewsReceived(
+      Either<List<View>, WorkspaceError> appsOrFail) = ViewsReceived;
 }
 }

+ 2 - 0
app_flowy/lib/home/application/app/app_state.dart

@@ -3,11 +3,13 @@ part of 'app_bloc.dart';
 @freezed
 @freezed
 abstract class AppState implements _$AppState {
 abstract class AppState implements _$AppState {
   const factory AppState({
   const factory AppState({
+    required bool isLoading,
     required Option<List<App>> apps,
     required Option<List<App>> apps,
     required Either<Unit, WorkspaceError> successOrFailure,
     required Either<Unit, WorkspaceError> successOrFailure,
   }) = _AppState;
   }) = _AppState;
 
 
   factory AppState.initial() => AppState(
   factory AppState.initial() => AppState(
+        isLoading: false,
         apps: none(),
         apps: none(),
         successOrFailure: left(unit),
         successOrFailure: left(unit),
       );
       );

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

@@ -2,6 +2,7 @@ import 'dart:async';
 import 'package:app_flowy/home/domain/i_workspace.dart';
 import 'package:app_flowy/home/domain/i_workspace.dart';
 import 'package:app_flowy/home/domain/page_context.dart';
 import 'package:app_flowy/home/domain/page_context.dart';
 import 'package:dartz/dartz.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:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
@@ -19,24 +20,38 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
     MenuEvent event,
     MenuEvent event,
   ) async* {
   ) async* {
     yield* event.map(
     yield* event.map(
+      initial: (value) async* {
+        iWorkspaceImpl.startWatching(addAppCallback: (appsOrFail) {
+          appsOrFail.fold(
+            (apps) => add(MenuEvent.appsReceived(left(apps))),
+            (error) => add(MenuEvent.appsReceived(right(error))),
+          );
+        });
+      },
       collapse: (e) async* {
       collapse: (e) async* {
         final isCollapse = state.isCollapse;
         final isCollapse = state.isCollapse;
         yield state.copyWith(isCollapse: !isCollapse);
         yield state.copyWith(isCollapse: !isCollapse);
       },
       },
-      openPage: (e) async* {
+      openPage: (OpenPage e) async* {
         yield* _performActionOnOpenPage(e);
         yield* _performActionOnOpenPage(e);
       },
       },
-      createApp: (event) async* {
+      createApp: (CreateApp event) async* {
         yield* _performActionOnCreateApp(event);
         yield* _performActionOnCreateApp(event);
       },
       },
+      appsReceived: (AppsReceived value) async* {
+        yield value.appsOrFail.fold(
+          (apps) => state.copyWith(apps: some(apps)),
+          (error) => state.copyWith(successOrFailure: right(error)),
+        );
+      },
     );
     );
   }
   }
 
 
-  Stream<MenuState> _performActionOnOpenPage(_OpenPage e) async* {
+  Stream<MenuState> _performActionOnOpenPage(OpenPage e) async* {
     yield state.copyWith(pageContext: some(e.context));
     yield state.copyWith(pageContext: some(e.context));
   }
   }
 
 
-  Stream<MenuState> _performActionOnCreateApp(_CreateApp event) async* {
+  Stream<MenuState> _performActionOnCreateApp(CreateApp event) async* {
     await iWorkspaceImpl
     await iWorkspaceImpl
         .createApp(name: event.name, desc: event.desc)
         .createApp(name: event.name, desc: event.desc)
         .then((result) async* {
         .then((result) async* {

+ 358 - 56
app_flowy/lib/home/application/menu/menu_bloc.freezed.dart

@@ -16,22 +16,32 @@ final _privateConstructorUsedError = UnsupportedError(
 class _$MenuEventTearOff {
 class _$MenuEventTearOff {
   const _$MenuEventTearOff();
   const _$MenuEventTearOff();
 
 
+  _Initial initial() {
+    return const _Initial();
+  }
+
   Collapse collapse() {
   Collapse collapse() {
     return const Collapse();
     return const Collapse();
   }
   }
 
 
-  _OpenPage openPage(PageContext context) {
-    return _OpenPage(
+  OpenPage openPage(PageContext context) {
+    return OpenPage(
       context,
       context,
     );
     );
   }
   }
 
 
-  _CreateApp createApp(String name, {String? desc}) {
-    return _CreateApp(
+  CreateApp createApp(String name, {String? desc}) {
+    return CreateApp(
       name,
       name,
       desc: desc,
       desc: desc,
     );
     );
   }
   }
+
+  AppsReceived appsReceived(Either<List<App>, WorkspaceError> appsOrFail) {
+    return AppsReceived(
+      appsOrFail,
+    );
+  }
 }
 }
 
 
 /// @nodoc
 /// @nodoc
@@ -41,31 +51,41 @@ const $MenuEvent = _$MenuEventTearOff();
 mixin _$MenuEvent {
 mixin _$MenuEvent {
   @optionalTypeArgs
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
   TResult when<TResult extends Object?>({
+    required TResult Function() initial,
     required TResult Function() collapse,
     required TResult Function() collapse,
     required TResult Function(PageContext context) openPage,
     required TResult Function(PageContext context) openPage,
     required TResult Function(String name, String? desc) createApp,
     required TResult Function(String name, String? desc) createApp,
+    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
+        appsReceived,
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
   TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
     TResult Function()? collapse,
     TResult Function()? collapse,
     TResult Function(PageContext context)? openPage,
     TResult Function(PageContext context)? openPage,
     TResult Function(String name, String? desc)? createApp,
     TResult Function(String name, String? desc)? createApp,
+    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
+        appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
   TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
     required TResult Function(Collapse value) collapse,
     required TResult Function(Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
+    required TResult Function(OpenPage value) openPage,
+    required TResult Function(CreateApp value) createApp,
+    required TResult Function(AppsReceived value) appsReceived,
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
   TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
     TResult Function(Collapse value)? collapse,
     TResult Function(Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
+    TResult Function(OpenPage value)? openPage,
+    TResult Function(CreateApp value)? createApp,
+    TResult Function(AppsReceived value)? appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) =>
   }) =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
@@ -86,6 +106,103 @@ class _$MenuEventCopyWithImpl<$Res> implements $MenuEventCopyWith<$Res> {
   final $Res Function(MenuEvent) _then;
   final $Res Function(MenuEvent) _then;
 }
 }
 
 
+/// @nodoc
+abstract class _$InitialCopyWith<$Res> {
+  factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
+      __$InitialCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$InitialCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
+    implements _$InitialCopyWith<$Res> {
+  __$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
+      : super(_value, (v) => _then(v as _Initial));
+
+  @override
+  _Initial get _value => super._value as _Initial;
+}
+
+/// @nodoc
+
+class _$_Initial implements _Initial {
+  const _$_Initial();
+
+  @override
+  String toString() {
+    return 'MenuEvent.initial()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is _Initial);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function() collapse,
+    required TResult Function(PageContext context) openPage,
+    required TResult Function(String name, String? desc) createApp,
+    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
+        appsReceived,
+  }) {
+    return initial();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function()? collapse,
+    TResult Function(PageContext context)? openPage,
+    TResult Function(String name, String? desc)? createApp,
+    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
+        appsReceived,
+    required TResult orElse(),
+  }) {
+    if (initial != null) {
+      return initial();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
+    required TResult Function(Collapse value) collapse,
+    required TResult Function(OpenPage value) openPage,
+    required TResult Function(CreateApp value) createApp,
+    required TResult Function(AppsReceived value) appsReceived,
+  }) {
+    return initial(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
+    TResult Function(Collapse value)? collapse,
+    TResult Function(OpenPage value)? openPage,
+    TResult Function(CreateApp value)? createApp,
+    TResult Function(AppsReceived value)? appsReceived,
+    required TResult orElse(),
+  }) {
+    if (initial != null) {
+      return initial(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class _Initial implements MenuEvent {
+  const factory _Initial() = _$_Initial;
+}
+
 /// @nodoc
 /// @nodoc
 abstract class $CollapseCopyWith<$Res> {
 abstract class $CollapseCopyWith<$Res> {
   factory $CollapseCopyWith(Collapse value, $Res Function(Collapse) then) =
   factory $CollapseCopyWith(Collapse value, $Res Function(Collapse) then) =
@@ -123,9 +240,12 @@ class _$Collapse implements Collapse {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
   TResult when<TResult extends Object?>({
+    required TResult Function() initial,
     required TResult Function() collapse,
     required TResult Function() collapse,
     required TResult Function(PageContext context) openPage,
     required TResult Function(PageContext context) openPage,
     required TResult Function(String name, String? desc) createApp,
     required TResult Function(String name, String? desc) createApp,
+    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
+        appsReceived,
   }) {
   }) {
     return collapse();
     return collapse();
   }
   }
@@ -133,9 +253,12 @@ class _$Collapse implements Collapse {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
   TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
     TResult Function()? collapse,
     TResult Function()? collapse,
     TResult Function(PageContext context)? openPage,
     TResult Function(PageContext context)? openPage,
     TResult Function(String name, String? desc)? createApp,
     TResult Function(String name, String? desc)? createApp,
+    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
+        appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
     if (collapse != null) {
     if (collapse != null) {
@@ -147,9 +270,11 @@ class _$Collapse implements Collapse {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
   TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
     required TResult Function(Collapse value) collapse,
     required TResult Function(Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
+    required TResult Function(OpenPage value) openPage,
+    required TResult Function(CreateApp value) createApp,
+    required TResult Function(AppsReceived value) appsReceived,
   }) {
   }) {
     return collapse(this);
     return collapse(this);
   }
   }
@@ -157,9 +282,11 @@ class _$Collapse implements Collapse {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
   TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
     TResult Function(Collapse value)? collapse,
     TResult Function(Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
+    TResult Function(OpenPage value)? openPage,
+    TResult Function(CreateApp value)? createApp,
+    TResult Function(AppsReceived value)? appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
     if (collapse != null) {
     if (collapse != null) {
@@ -174,26 +301,26 @@ abstract class Collapse implements MenuEvent {
 }
 }
 
 
 /// @nodoc
 /// @nodoc
-abstract class _$OpenPageCopyWith<$Res> {
-  factory _$OpenPageCopyWith(_OpenPage value, $Res Function(_OpenPage) then) =
-      __$OpenPageCopyWithImpl<$Res>;
+abstract class $OpenPageCopyWith<$Res> {
+  factory $OpenPageCopyWith(OpenPage value, $Res Function(OpenPage) then) =
+      _$OpenPageCopyWithImpl<$Res>;
   $Res call({PageContext context});
   $Res call({PageContext context});
 }
 }
 
 
 /// @nodoc
 /// @nodoc
-class __$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$OpenPageCopyWith<$Res> {
-  __$OpenPageCopyWithImpl(_OpenPage _value, $Res Function(_OpenPage) _then)
-      : super(_value, (v) => _then(v as _OpenPage));
+class _$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
+    implements $OpenPageCopyWith<$Res> {
+  _$OpenPageCopyWithImpl(OpenPage _value, $Res Function(OpenPage) _then)
+      : super(_value, (v) => _then(v as OpenPage));
 
 
   @override
   @override
-  _OpenPage get _value => super._value as _OpenPage;
+  OpenPage get _value => super._value as OpenPage;
 
 
   @override
   @override
   $Res call({
   $Res call({
     Object? context = freezed,
     Object? context = freezed,
   }) {
   }) {
-    return _then(_OpenPage(
+    return _then(OpenPage(
       context == freezed
       context == freezed
           ? _value.context
           ? _value.context
           : context // ignore: cast_nullable_to_non_nullable
           : context // ignore: cast_nullable_to_non_nullable
@@ -204,8 +331,8 @@ class __$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
 
 
 /// @nodoc
 /// @nodoc
 
 
-class _$_OpenPage implements _OpenPage {
-  const _$_OpenPage(this.context);
+class _$OpenPage implements OpenPage {
+  const _$OpenPage(this.context);
 
 
   @override
   @override
   final PageContext context;
   final PageContext context;
@@ -218,7 +345,7 @@ class _$_OpenPage implements _OpenPage {
   @override
   @override
   bool operator ==(dynamic other) {
   bool operator ==(dynamic other) {
     return identical(this, other) ||
     return identical(this, other) ||
-        (other is _OpenPage &&
+        (other is OpenPage &&
             (identical(other.context, context) ||
             (identical(other.context, context) ||
                 const DeepCollectionEquality().equals(other.context, context)));
                 const DeepCollectionEquality().equals(other.context, context)));
   }
   }
@@ -229,15 +356,18 @@ class _$_OpenPage implements _OpenPage {
 
 
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
   @override
   @override
-  _$OpenPageCopyWith<_OpenPage> get copyWith =>
-      __$OpenPageCopyWithImpl<_OpenPage>(this, _$identity);
+  $OpenPageCopyWith<OpenPage> get copyWith =>
+      _$OpenPageCopyWithImpl<OpenPage>(this, _$identity);
 
 
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
   TResult when<TResult extends Object?>({
+    required TResult Function() initial,
     required TResult Function() collapse,
     required TResult Function() collapse,
     required TResult Function(PageContext context) openPage,
     required TResult Function(PageContext context) openPage,
     required TResult Function(String name, String? desc) createApp,
     required TResult Function(String name, String? desc) createApp,
+    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
+        appsReceived,
   }) {
   }) {
     return openPage(context);
     return openPage(context);
   }
   }
@@ -245,9 +375,12 @@ class _$_OpenPage implements _OpenPage {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
   TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
     TResult Function()? collapse,
     TResult Function()? collapse,
     TResult Function(PageContext context)? openPage,
     TResult Function(PageContext context)? openPage,
     TResult Function(String name, String? desc)? createApp,
     TResult Function(String name, String? desc)? createApp,
+    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
+        appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
     if (openPage != null) {
     if (openPage != null) {
@@ -259,9 +392,11 @@ class _$_OpenPage implements _OpenPage {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
   TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
     required TResult Function(Collapse value) collapse,
     required TResult Function(Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
+    required TResult Function(OpenPage value) openPage,
+    required TResult Function(CreateApp value) createApp,
+    required TResult Function(AppsReceived value) appsReceived,
   }) {
   }) {
     return openPage(this);
     return openPage(this);
   }
   }
@@ -269,9 +404,11 @@ class _$_OpenPage implements _OpenPage {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
   TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
     TResult Function(Collapse value)? collapse,
     TResult Function(Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
+    TResult Function(OpenPage value)? openPage,
+    TResult Function(CreateApp value)? createApp,
+    TResult Function(AppsReceived value)? appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
     if (openPage != null) {
     if (openPage != null) {
@@ -281,38 +418,37 @@ class _$_OpenPage implements _OpenPage {
   }
   }
 }
 }
 
 
-abstract class _OpenPage implements MenuEvent {
-  const factory _OpenPage(PageContext context) = _$_OpenPage;
+abstract class OpenPage implements MenuEvent {
+  const factory OpenPage(PageContext context) = _$OpenPage;
 
 
   PageContext get context => throw _privateConstructorUsedError;
   PageContext get context => throw _privateConstructorUsedError;
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
-  _$OpenPageCopyWith<_OpenPage> get copyWith =>
+  $OpenPageCopyWith<OpenPage> get copyWith =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
 }
 }
 
 
 /// @nodoc
 /// @nodoc
-abstract class _$CreateAppCopyWith<$Res> {
-  factory _$CreateAppCopyWith(
-          _CreateApp value, $Res Function(_CreateApp) then) =
-      __$CreateAppCopyWithImpl<$Res>;
+abstract class $CreateAppCopyWith<$Res> {
+  factory $CreateAppCopyWith(CreateApp value, $Res Function(CreateApp) then) =
+      _$CreateAppCopyWithImpl<$Res>;
   $Res call({String name, String? desc});
   $Res call({String name, String? desc});
 }
 }
 
 
 /// @nodoc
 /// @nodoc
-class __$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$CreateAppCopyWith<$Res> {
-  __$CreateAppCopyWithImpl(_CreateApp _value, $Res Function(_CreateApp) _then)
-      : super(_value, (v) => _then(v as _CreateApp));
+class _$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
+    implements $CreateAppCopyWith<$Res> {
+  _$CreateAppCopyWithImpl(CreateApp _value, $Res Function(CreateApp) _then)
+      : super(_value, (v) => _then(v as CreateApp));
 
 
   @override
   @override
-  _CreateApp get _value => super._value as _CreateApp;
+  CreateApp get _value => super._value as CreateApp;
 
 
   @override
   @override
   $Res call({
   $Res call({
     Object? name = freezed,
     Object? name = freezed,
     Object? desc = freezed,
     Object? desc = freezed,
   }) {
   }) {
-    return _then(_CreateApp(
+    return _then(CreateApp(
       name == freezed
       name == freezed
           ? _value.name
           ? _value.name
           : name // ignore: cast_nullable_to_non_nullable
           : name // ignore: cast_nullable_to_non_nullable
@@ -327,8 +463,8 @@ class __$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
 
 
 /// @nodoc
 /// @nodoc
 
 
-class _$_CreateApp implements _CreateApp {
-  const _$_CreateApp(this.name, {this.desc});
+class _$CreateApp implements CreateApp {
+  const _$CreateApp(this.name, {this.desc});
 
 
   @override
   @override
   final String name;
   final String name;
@@ -343,7 +479,7 @@ class _$_CreateApp implements _CreateApp {
   @override
   @override
   bool operator ==(dynamic other) {
   bool operator ==(dynamic other) {
     return identical(this, other) ||
     return identical(this, other) ||
-        (other is _CreateApp &&
+        (other is CreateApp &&
             (identical(other.name, name) ||
             (identical(other.name, name) ||
                 const DeepCollectionEquality().equals(other.name, name)) &&
                 const DeepCollectionEquality().equals(other.name, name)) &&
             (identical(other.desc, desc) ||
             (identical(other.desc, desc) ||
@@ -358,15 +494,18 @@ class _$_CreateApp implements _CreateApp {
 
 
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
   @override
   @override
-  _$CreateAppCopyWith<_CreateApp> get copyWith =>
-      __$CreateAppCopyWithImpl<_CreateApp>(this, _$identity);
+  $CreateAppCopyWith<CreateApp> get copyWith =>
+      _$CreateAppCopyWithImpl<CreateApp>(this, _$identity);
 
 
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
   TResult when<TResult extends Object?>({
+    required TResult Function() initial,
     required TResult Function() collapse,
     required TResult Function() collapse,
     required TResult Function(PageContext context) openPage,
     required TResult Function(PageContext context) openPage,
     required TResult Function(String name, String? desc) createApp,
     required TResult Function(String name, String? desc) createApp,
+    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
+        appsReceived,
   }) {
   }) {
     return createApp(name, desc);
     return createApp(name, desc);
   }
   }
@@ -374,9 +513,12 @@ class _$_CreateApp implements _CreateApp {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
   TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
     TResult Function()? collapse,
     TResult Function()? collapse,
     TResult Function(PageContext context)? openPage,
     TResult Function(PageContext context)? openPage,
     TResult Function(String name, String? desc)? createApp,
     TResult Function(String name, String? desc)? createApp,
+    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
+        appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
     if (createApp != null) {
     if (createApp != null) {
@@ -388,9 +530,11 @@ class _$_CreateApp implements _CreateApp {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
   TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
     required TResult Function(Collapse value) collapse,
     required TResult Function(Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
+    required TResult Function(OpenPage value) openPage,
+    required TResult Function(CreateApp value) createApp,
+    required TResult Function(AppsReceived value) appsReceived,
   }) {
   }) {
     return createApp(this);
     return createApp(this);
   }
   }
@@ -398,9 +542,11 @@ class _$_CreateApp implements _CreateApp {
   @override
   @override
   @optionalTypeArgs
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
   TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
     TResult Function(Collapse value)? collapse,
     TResult Function(Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
+    TResult Function(OpenPage value)? openPage,
+    TResult Function(CreateApp value)? createApp,
+    TResult Function(AppsReceived value)? appsReceived,
     required TResult orElse(),
     required TResult orElse(),
   }) {
   }) {
     if (createApp != null) {
     if (createApp != null) {
@@ -410,13 +556,145 @@ class _$_CreateApp implements _CreateApp {
   }
   }
 }
 }
 
 
-abstract class _CreateApp implements MenuEvent {
-  const factory _CreateApp(String name, {String? desc}) = _$_CreateApp;
+abstract class CreateApp implements MenuEvent {
+  const factory CreateApp(String name, {String? desc}) = _$CreateApp;
 
 
   String get name => throw _privateConstructorUsedError;
   String get name => throw _privateConstructorUsedError;
   String? get desc => throw _privateConstructorUsedError;
   String? get desc => throw _privateConstructorUsedError;
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
-  _$CreateAppCopyWith<_CreateApp> get copyWith =>
+  $CreateAppCopyWith<CreateApp> get copyWith =>
+      throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $AppsReceivedCopyWith<$Res> {
+  factory $AppsReceivedCopyWith(
+          AppsReceived value, $Res Function(AppsReceived) then) =
+      _$AppsReceivedCopyWithImpl<$Res>;
+  $Res call({Either<List<App>, WorkspaceError> appsOrFail});
+}
+
+/// @nodoc
+class _$AppsReceivedCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
+    implements $AppsReceivedCopyWith<$Res> {
+  _$AppsReceivedCopyWithImpl(
+      AppsReceived _value, $Res Function(AppsReceived) _then)
+      : super(_value, (v) => _then(v as AppsReceived));
+
+  @override
+  AppsReceived get _value => super._value as AppsReceived;
+
+  @override
+  $Res call({
+    Object? appsOrFail = freezed,
+  }) {
+    return _then(AppsReceived(
+      appsOrFail == freezed
+          ? _value.appsOrFail
+          : appsOrFail // ignore: cast_nullable_to_non_nullable
+              as Either<List<App>, WorkspaceError>,
+    ));
+  }
+}
+
+/// @nodoc
+
+class _$AppsReceived implements AppsReceived {
+  const _$AppsReceived(this.appsOrFail);
+
+  @override
+  final Either<List<App>, WorkspaceError> appsOrFail;
+
+  @override
+  String toString() {
+    return 'MenuEvent.appsReceived(appsOrFail: $appsOrFail)';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) ||
+        (other is AppsReceived &&
+            (identical(other.appsOrFail, appsOrFail) ||
+                const DeepCollectionEquality()
+                    .equals(other.appsOrFail, appsOrFail)));
+  }
+
+  @override
+  int get hashCode =>
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(appsOrFail);
+
+  @JsonKey(ignore: true)
+  @override
+  $AppsReceivedCopyWith<AppsReceived> get copyWith =>
+      _$AppsReceivedCopyWithImpl<AppsReceived>(this, _$identity);
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function() collapse,
+    required TResult Function(PageContext context) openPage,
+    required TResult Function(String name, String? desc) createApp,
+    required TResult Function(Either<List<App>, WorkspaceError> appsOrFail)
+        appsReceived,
+  }) {
+    return appsReceived(appsOrFail);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function()? collapse,
+    TResult Function(PageContext context)? openPage,
+    TResult Function(String name, String? desc)? createApp,
+    TResult Function(Either<List<App>, WorkspaceError> appsOrFail)?
+        appsReceived,
+    required TResult orElse(),
+  }) {
+    if (appsReceived != null) {
+      return appsReceived(appsOrFail);
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Initial value) initial,
+    required TResult Function(Collapse value) collapse,
+    required TResult Function(OpenPage value) openPage,
+    required TResult Function(CreateApp value) createApp,
+    required TResult Function(AppsReceived value) appsReceived,
+  }) {
+    return appsReceived(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Initial value)? initial,
+    TResult Function(Collapse value)? collapse,
+    TResult Function(OpenPage value)? openPage,
+    TResult Function(CreateApp value)? createApp,
+    TResult Function(AppsReceived value)? appsReceived,
+    required TResult orElse(),
+  }) {
+    if (appsReceived != null) {
+      return appsReceived(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class AppsReceived implements MenuEvent {
+  const factory AppsReceived(Either<List<App>, WorkspaceError> appsOrFail) =
+      _$AppsReceived;
+
+  Either<List<App>, WorkspaceError> get appsOrFail =>
+      throw _privateConstructorUsedError;
+  @JsonKey(ignore: true)
+  $AppsReceivedCopyWith<AppsReceived> get copyWith =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
 }
 }
 
 
@@ -427,10 +705,12 @@ class _$MenuStateTearOff {
   _MenuState call(
   _MenuState call(
       {required bool isCollapse,
       {required bool isCollapse,
       required Option<PageContext> pageContext,
       required Option<PageContext> pageContext,
+      required Option<List<App>> apps,
       required Either<Unit, WorkspaceError> successOrFailure}) {
       required Either<Unit, WorkspaceError> successOrFailure}) {
     return _MenuState(
     return _MenuState(
       isCollapse: isCollapse,
       isCollapse: isCollapse,
       pageContext: pageContext,
       pageContext: pageContext,
+      apps: apps,
       successOrFailure: successOrFailure,
       successOrFailure: successOrFailure,
     );
     );
   }
   }
@@ -443,6 +723,7 @@ const $MenuState = _$MenuStateTearOff();
 mixin _$MenuState {
 mixin _$MenuState {
   bool get isCollapse => throw _privateConstructorUsedError;
   bool get isCollapse => throw _privateConstructorUsedError;
   Option<PageContext> get pageContext => throw _privateConstructorUsedError;
   Option<PageContext> get pageContext => throw _privateConstructorUsedError;
+  Option<List<App>> get apps => throw _privateConstructorUsedError;
   Either<Unit, WorkspaceError> get successOrFailure =>
   Either<Unit, WorkspaceError> get successOrFailure =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
 
 
@@ -458,6 +739,7 @@ abstract class $MenuStateCopyWith<$Res> {
   $Res call(
   $Res call(
       {bool isCollapse,
       {bool isCollapse,
       Option<PageContext> pageContext,
       Option<PageContext> pageContext,
+      Option<List<App>> apps,
       Either<Unit, WorkspaceError> successOrFailure});
       Either<Unit, WorkspaceError> successOrFailure});
 }
 }
 
 
@@ -473,6 +755,7 @@ class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> {
   $Res call({
   $Res call({
     Object? isCollapse = freezed,
     Object? isCollapse = freezed,
     Object? pageContext = freezed,
     Object? pageContext = freezed,
+    Object? apps = freezed,
     Object? successOrFailure = freezed,
     Object? successOrFailure = freezed,
   }) {
   }) {
     return _then(_value.copyWith(
     return _then(_value.copyWith(
@@ -484,6 +767,10 @@ class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> {
           ? _value.pageContext
           ? _value.pageContext
           : pageContext // ignore: cast_nullable_to_non_nullable
           : pageContext // ignore: cast_nullable_to_non_nullable
               as Option<PageContext>,
               as Option<PageContext>,
+      apps: apps == freezed
+          ? _value.apps
+          : apps // ignore: cast_nullable_to_non_nullable
+              as Option<List<App>>,
       successOrFailure: successOrFailure == freezed
       successOrFailure: successOrFailure == freezed
           ? _value.successOrFailure
           ? _value.successOrFailure
           : successOrFailure // ignore: cast_nullable_to_non_nullable
           : successOrFailure // ignore: cast_nullable_to_non_nullable
@@ -501,6 +788,7 @@ abstract class _$MenuStateCopyWith<$Res> implements $MenuStateCopyWith<$Res> {
   $Res call(
   $Res call(
       {bool isCollapse,
       {bool isCollapse,
       Option<PageContext> pageContext,
       Option<PageContext> pageContext,
+      Option<List<App>> apps,
       Either<Unit, WorkspaceError> successOrFailure});
       Either<Unit, WorkspaceError> successOrFailure});
 }
 }
 
 
@@ -517,6 +805,7 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res>
   $Res call({
   $Res call({
     Object? isCollapse = freezed,
     Object? isCollapse = freezed,
     Object? pageContext = freezed,
     Object? pageContext = freezed,
+    Object? apps = freezed,
     Object? successOrFailure = freezed,
     Object? successOrFailure = freezed,
   }) {
   }) {
     return _then(_MenuState(
     return _then(_MenuState(
@@ -528,6 +817,10 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res>
           ? _value.pageContext
           ? _value.pageContext
           : pageContext // ignore: cast_nullable_to_non_nullable
           : pageContext // ignore: cast_nullable_to_non_nullable
               as Option<PageContext>,
               as Option<PageContext>,
+      apps: apps == freezed
+          ? _value.apps
+          : apps // ignore: cast_nullable_to_non_nullable
+              as Option<List<App>>,
       successOrFailure: successOrFailure == freezed
       successOrFailure: successOrFailure == freezed
           ? _value.successOrFailure
           ? _value.successOrFailure
           : successOrFailure // ignore: cast_nullable_to_non_nullable
           : successOrFailure // ignore: cast_nullable_to_non_nullable
@@ -542,6 +835,7 @@ class _$_MenuState implements _MenuState {
   const _$_MenuState(
   const _$_MenuState(
       {required this.isCollapse,
       {required this.isCollapse,
       required this.pageContext,
       required this.pageContext,
+      required this.apps,
       required this.successOrFailure});
       required this.successOrFailure});
 
 
   @override
   @override
@@ -549,11 +843,13 @@ class _$_MenuState implements _MenuState {
   @override
   @override
   final Option<PageContext> pageContext;
   final Option<PageContext> pageContext;
   @override
   @override
+  final Option<List<App>> apps;
+  @override
   final Either<Unit, WorkspaceError> successOrFailure;
   final Either<Unit, WorkspaceError> successOrFailure;
 
 
   @override
   @override
   String toString() {
   String toString() {
-    return 'MenuState(isCollapse: $isCollapse, pageContext: $pageContext, successOrFailure: $successOrFailure)';
+    return 'MenuState(isCollapse: $isCollapse, pageContext: $pageContext, apps: $apps, successOrFailure: $successOrFailure)';
   }
   }
 
 
   @override
   @override
@@ -566,6 +862,8 @@ class _$_MenuState implements _MenuState {
             (identical(other.pageContext, pageContext) ||
             (identical(other.pageContext, pageContext) ||
                 const DeepCollectionEquality()
                 const DeepCollectionEquality()
                     .equals(other.pageContext, pageContext)) &&
                     .equals(other.pageContext, pageContext)) &&
+            (identical(other.apps, apps) ||
+                const DeepCollectionEquality().equals(other.apps, apps)) &&
             (identical(other.successOrFailure, successOrFailure) ||
             (identical(other.successOrFailure, successOrFailure) ||
                 const DeepCollectionEquality()
                 const DeepCollectionEquality()
                     .equals(other.successOrFailure, successOrFailure)));
                     .equals(other.successOrFailure, successOrFailure)));
@@ -576,6 +874,7 @@ class _$_MenuState implements _MenuState {
       runtimeType.hashCode ^
       runtimeType.hashCode ^
       const DeepCollectionEquality().hash(isCollapse) ^
       const DeepCollectionEquality().hash(isCollapse) ^
       const DeepCollectionEquality().hash(pageContext) ^
       const DeepCollectionEquality().hash(pageContext) ^
+      const DeepCollectionEquality().hash(apps) ^
       const DeepCollectionEquality().hash(successOrFailure);
       const DeepCollectionEquality().hash(successOrFailure);
 
 
   @JsonKey(ignore: true)
   @JsonKey(ignore: true)
@@ -588,6 +887,7 @@ abstract class _MenuState implements MenuState {
   const factory _MenuState(
   const factory _MenuState(
       {required bool isCollapse,
       {required bool isCollapse,
       required Option<PageContext> pageContext,
       required Option<PageContext> pageContext,
+      required Option<List<App>> apps,
       required Either<Unit, WorkspaceError> successOrFailure}) = _$_MenuState;
       required Either<Unit, WorkspaceError> successOrFailure}) = _$_MenuState;
 
 
   @override
   @override
@@ -595,6 +895,8 @@ abstract class _MenuState implements MenuState {
   @override
   @override
   Option<PageContext> get pageContext => throw _privateConstructorUsedError;
   Option<PageContext> get pageContext => throw _privateConstructorUsedError;
   @override
   @override
+  Option<List<App>> get apps => throw _privateConstructorUsedError;
+  @override
   Either<Unit, WorkspaceError> get successOrFailure =>
   Either<Unit, WorkspaceError> get successOrFailure =>
       throw _privateConstructorUsedError;
       throw _privateConstructorUsedError;
   @override
   @override

+ 5 - 2
app_flowy/lib/home/application/menu/menu_event.dart

@@ -2,7 +2,10 @@ part of 'menu_bloc.dart';
 
 
 @freezed
 @freezed
 abstract class MenuEvent with _$MenuEvent {
 abstract class MenuEvent with _$MenuEvent {
+  const factory MenuEvent.initial() = _Initial;
   const factory MenuEvent.collapse() = Collapse;
   const factory MenuEvent.collapse() = Collapse;
-  const factory MenuEvent.openPage(PageContext context) = _OpenPage;
-  const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
+  const factory MenuEvent.openPage(PageContext context) = OpenPage;
+  const factory MenuEvent.createApp(String name, {String? desc}) = CreateApp;
+  const factory MenuEvent.appsReceived(
+      Either<List<App>, WorkspaceError> appsOrFail) = AppsReceived;
 }
 }

+ 2 - 0
app_flowy/lib/home/application/menu/menu_state.dart

@@ -5,12 +5,14 @@ abstract class MenuState implements _$MenuState {
   const factory MenuState({
   const factory MenuState({
     required bool isCollapse,
     required bool isCollapse,
     required Option<PageContext> pageContext,
     required Option<PageContext> pageContext,
+    required Option<List<App>> apps,
     required Either<Unit, WorkspaceError> successOrFailure,
     required Either<Unit, WorkspaceError> successOrFailure,
   }) = _MenuState;
   }) = _MenuState;
 
 
   factory MenuState.initial() => MenuState(
   factory MenuState.initial() => MenuState(
         isCollapse: false,
         isCollapse: false,
         pageContext: none(),
         pageContext: none(),
+        apps: none(),
         successOrFailure: left(unit),
         successOrFailure: left(unit),
       );
       );
 }
 }

+ 11 - 1
app_flowy/lib/home/domain/i_app.dart

@@ -1,6 +1,10 @@
 import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
 import 'package:dartz/dartz.dart';
 import 'package:dartz/dartz.dart';
 
 
+typedef AppUpdatedCallback = void Function(String name, String desc);
+typedef AppAddViewCallback = void Function(
+    Either<List<View>, WorkspaceError> viewsOrFailed);
+
 abstract class IApp {
 abstract class IApp {
   Future<Either<List<View>, WorkspaceError>> getViews({required String appId});
   Future<Either<List<View>, WorkspaceError>> getViews({required String appId});
 
 
@@ -8,5 +12,11 @@ abstract class IApp {
       {required String appId,
       {required String appId,
       required String name,
       required String name,
       String? desc,
       String? desc,
-      required ViewTypeIdentifier viewType});
+      required ViewType viewType});
+
+  void startWatching(
+      {AppAddViewCallback? addViewCallback,
+      AppUpdatedCallback? updatedCallback});
+
+  Future<void> stopWatching();
 }
 }

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

@@ -1,10 +1,20 @@
 import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
 import 'package:dartz/dartz.dart';
 import 'package:dartz/dartz.dart';
 
 
+typedef WorkspaceAddAppCallback = void Function(
+    Either<List<App>, WorkspaceError> appsOrFail);
+typedef WorkspaceUpdatedCallback = void Function(String name, String desc);
+
 abstract class IWorkspace {
 abstract class IWorkspace {
   Future<Either<App, WorkspaceError>> createApp(
   Future<Either<App, WorkspaceError>> createApp(
       {required String name, String? desc});
       {required String name, String? desc});
 
 
   Future<Either<List<App>, WorkspaceError>> getApps(
   Future<Either<List<App>, WorkspaceError>> getApps(
       {required String workspaceId});
       {required String workspaceId});
+
+  void startWatching(
+      {WorkspaceAddAppCallback? addAppCallback,
+      WorkspaceUpdatedCallback? updatedCallback});
+
+  Future<void> stopWatching();
 }
 }

+ 7 - 4
app_flowy/lib/home/infrastructure/deps_resolver.dart

@@ -14,11 +14,14 @@ class HomeDepsResolver {
         (appId, _) => AppRepository(appId: appId));
         (appId, _) => AppRepository(appId: appId));
 
 
     //Interface implementation
     //Interface implementation
-    getIt.registerFactory<IApp>(() => IAppImpl(repo: getIt<AppRepository>()));
-    getIt.registerFactory<IWorkspace>(
-        () => IWorkspaceImpl(repo: getIt<WorkspaceRepository>()));
+    getIt.registerFactoryParam<IApp, String, void>(
+        (appId, _) => IAppImpl(repo: getIt<AppRepository>(param1: appId)));
+
+    getIt.registerFactoryParam<IWorkspace, String, void>((workspacId, _) =>
+        IWorkspaceImpl(repo: getIt<WorkspaceRepository>(param1: workspacId)));
 
 
     //Bloc
     //Bloc
-    getIt.registerFactory<MenuBloc>(() => MenuBloc(getIt<IWorkspace>()));
+    getIt.registerFactoryParam<MenuBloc, String, void>(
+        (workspaceId, _) => MenuBloc(getIt<IWorkspace>(param1: workspaceId)));
   }
   }
 }
 }

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

@@ -22,7 +22,20 @@ class IAppImpl extends IApp {
       {required String appId,
       {required String appId,
       required String name,
       required String name,
       String? desc,
       String? desc,
-      required ViewTypeIdentifier viewType}) {
+      required ViewType viewType}) {
     return repo.createView(appId, name, desc ?? "", viewType);
     return repo.createView(appId, name, desc ?? "", viewType);
   }
   }
+
+  @override
+  void startWatching(
+      {AppAddViewCallback? addViewCallback,
+      AppUpdatedCallback? updatedCallback}) {
+    repo.startWatching(
+        addViewCallback: addViewCallback, updatedCallback: updatedCallback);
+  }
+
+  @override
+  Future<void> stopWatching() async {
+    await repo.close();
+  }
 }
 }

+ 21 - 1
app_flowy/lib/home/infrastructure/i_workspace_impl.dart

@@ -21,6 +21,26 @@ class IWorkspaceImpl extends IWorkspace {
   @override
   @override
   Future<Either<List<App>, WorkspaceError>> getApps(
   Future<Either<List<App>, WorkspaceError>> getApps(
       {required String workspaceId}) {
       {required String workspaceId}) {
-    return repo.getApps(workspaceId: workspaceId);
+    return repo
+        .getWorkspace(workspaceId: workspaceId, readApps: true)
+        .then((result) {
+      return result.fold(
+        (workspace) => left(workspace.apps.items),
+        (error) => right(error),
+      );
+    });
+  }
+
+  @override
+  void startWatching(
+      {WorkspaceAddAppCallback? addAppCallback,
+      WorkspaceUpdatedCallback? updatedCallback}) {
+    repo.startWatching(
+        addAppCallback: addAppCallback, updatedCallback: updatedCallback);
+  }
+
+  @override
+  Future<void> stopWatching() async {
+    await repo.close();
   }
   }
 }
 }

+ 17 - 19
app_flowy/lib/home/infrastructure/repos/app_repo.dart

@@ -1,4 +1,5 @@
 import 'dart:async';
 import 'dart:async';
+import 'package:app_flowy/home/domain/i_app.dart';
 import 'package:dartz/dartz.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_infra/flowy_logger.dart';
 import 'package:flowy_infra/flowy_logger.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
@@ -11,13 +12,10 @@ 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/view_create.pbenum.dart';
 import 'package:flowy_sdk/rust_stream.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 {
 class AppRepository {
   StreamSubscription<ObservableSubject>? _subscription;
   StreamSubscription<ObservableSubject>? _subscription;
-  ViewUpdatedCallback? _viewUpdatedCallback;
-  AppUpdatedCallback? _appUpdatedCallback;
+  AppAddViewCallback? _addViewCallback;
+  AppUpdatedCallback? _updatedCallback;
   String appId;
   String appId;
   AppRepository({
   AppRepository({
     required this.appId,
     required this.appId,
@@ -32,7 +30,7 @@ class AppRepository {
   }
   }
 
 
   Future<Either<View, WorkspaceError>> createView(
   Future<Either<View, WorkspaceError>> createView(
-      String appId, String name, String desc, ViewTypeIdentifier viewType) {
+      String appId, String name, String desc, ViewType viewType) {
     final request = CreateViewRequest.create()
     final request = CreateViewRequest.create()
       ..appId = appId
       ..appId = appId
       ..name = name
       ..name = name
@@ -56,42 +54,42 @@ class AppRepository {
   }
   }
 
 
   void startWatching(
   void startWatching(
-      {ViewUpdatedCallback? viewUpdatedCallback,
-      AppUpdatedCallback? appUpdatedCallback}) {
-    _viewUpdatedCallback = viewUpdatedCallback;
-    _appUpdatedCallback = appUpdatedCallback;
+      {AppAddViewCallback? addViewCallback,
+      AppUpdatedCallback? updatedCallback}) {
+    _addViewCallback = addViewCallback;
+    _updatedCallback = updatedCallback;
     _subscription = RustStreamReceiver.listen((observable) {
     _subscription = RustStreamReceiver.listen((observable) {
       if (observable.subjectId != appId) {
       if (observable.subjectId != appId) {
         return;
         return;
       }
       }
 
 
-      final ty = WorkspaceObservableType.valueOf(observable.ty);
+      final ty = WorkspaceObservable.valueOf(observable.ty);
       if (ty != null) {
       if (ty != null) {
         _handleObservableType(ty);
         _handleObservableType(ty);
       }
       }
     });
     });
   }
   }
 
 
-  void _handleObservableType(WorkspaceObservableType ty) {
+  void _handleObservableType(WorkspaceObservable ty) {
     switch (ty) {
     switch (ty) {
-      case WorkspaceObservableType.ViewUpdated:
-        if (_viewUpdatedCallback == null) {
+      case WorkspaceObservable.AppAddView:
+        if (_addViewCallback == null) {
           return;
           return;
         }
         }
         getViews(appId: appId).then((result) {
         getViews(appId: appId).then((result) {
           result.fold(
           result.fold(
-            (views) => _viewUpdatedCallback!(views),
-            (error) => Log.error(error),
+            (views) => _addViewCallback!(left(views)),
+            (error) => _addViewCallback!(right(error)),
           );
           );
         });
         });
         break;
         break;
-      case WorkspaceObservableType.AppDescUpdated:
-        if (_appUpdatedCallback == null) {
+      case WorkspaceObservable.AppUpdateDesc:
+        if (_updatedCallback == null) {
           return;
           return;
         }
         }
         getAppDesc().then((result) {
         getAppDesc().then((result) {
           result.fold(
           result.fold(
-            (app) => _appUpdatedCallback!(app.name, app.desc),
+            (app) => _updatedCallback!(app.name, app.desc),
             (error) => Log.error(error),
             (error) => Log.error(error),
           );
           );
         });
         });

+ 31 - 15
app_flowy/lib/home/infrastructure/repos/workspace_repo.dart

@@ -1,5 +1,6 @@
 import 'dart:async';
 import 'dart:async';
 
 
+import 'package:app_flowy/home/domain/i_workspace.dart';
 import 'package:dartz/dartz.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_infra/flowy_logger.dart';
 import 'package:flowy_infra/flowy_logger.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
@@ -7,14 +8,14 @@ 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_create.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/errors.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/observable.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_query.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_query.pb.dart';
 import 'package:flowy_sdk/rust_stream.dart';
 import 'package:flowy_sdk/rust_stream.dart';
 
 
-typedef AppUpdatedCallback = void Function(List<App> apps);
-
 class WorkspaceRepository {
 class WorkspaceRepository {
   StreamSubscription<ObservableSubject>? _subscription;
   StreamSubscription<ObservableSubject>? _subscription;
-  AppUpdatedCallback? _appUpdatedCallback;
+  WorkspaceAddAppCallback? _addAppCallback;
+  WorkspaceUpdatedCallback? _updatedCallback;
   String workspaceId;
   String workspaceId;
   WorkspaceRepository({
   WorkspaceRepository({
     required this.workspaceId,
     required this.workspaceId,
@@ -37,47 +38,62 @@ class WorkspaceRepository {
     });
     });
   }
   }
 
 
-  Future<Either<List<App>, WorkspaceError>> getApps(
-      {required String workspaceId}) {
+  Future<Either<Workspace, WorkspaceError>> getWorkspace(
+      {required String workspaceId, bool readApps = false}) {
     final request = QueryWorkspaceRequest.create()
     final request = QueryWorkspaceRequest.create()
       ..workspaceId = workspaceId
       ..workspaceId = workspaceId
-      ..readApps = true;
+      ..readApps = readApps;
 
 
     return WorkspaceEventGetWorkspace(request).send().then((result) {
     return WorkspaceEventGetWorkspace(request).send().then((result) {
       return result.fold(
       return result.fold(
-        (workspace) => left(workspace.apps.items),
+        (workspace) => left(workspace),
         (error) => right(error),
         (error) => right(error),
       );
       );
     });
     });
   }
   }
 
 
-  void startWatching({AppUpdatedCallback? appUpdatedCallback}) {
-    _appUpdatedCallback = appUpdatedCallback;
+  void startWatching(
+      {WorkspaceAddAppCallback? addAppCallback,
+      WorkspaceUpdatedCallback? updatedCallback}) {
+    _addAppCallback = addAppCallback;
+    _updatedCallback = updatedCallback;
+
     _subscription = RustStreamReceiver.listen((observable) {
     _subscription = RustStreamReceiver.listen((observable) {
       if (observable.subjectId != workspaceId) {
       if (observable.subjectId != workspaceId) {
         return;
         return;
       }
       }
 
 
-      final ty = WorkspaceObservableType.valueOf(observable.ty);
+      final ty = WorkspaceObservable.valueOf(observable.ty);
       if (ty != null) {
       if (ty != null) {
         _handleObservableType(ty);
         _handleObservableType(ty);
       }
       }
     });
     });
   }
   }
 
 
-  void _handleObservableType(WorkspaceObservableType ty) {
+  void _handleObservableType(WorkspaceObservable ty) {
     switch (ty) {
     switch (ty) {
-      case WorkspaceObservableType.WorkspaceUpdated:
-        if (_appUpdatedCallback == null) {
+      case WorkspaceObservable.WorkspaceUpdateDesc:
+        if (_updatedCallback == null) {
           return;
           return;
         }
         }
-        getApps(workspaceId: workspaceId).then((result) {
+        getWorkspace(workspaceId: workspaceId).then((result) {
           result.fold(
           result.fold(
-            (apps) => _appUpdatedCallback!(apps),
+            (workspace) => _updatedCallback!(workspace.name, workspace.desc),
             (error) => Log.error(error),
             (error) => Log.error(error),
           );
           );
         });
         });
         break;
         break;
+      case WorkspaceObservable.WorkspaceAddApp:
+        if (_addAppCallback == null) {
+          return;
+        }
+        getWorkspace(workspaceId: workspaceId, readApps: true).then((result) {
+          result.fold(
+            (workspace) => _addAppCallback!(left(workspace.apps.items)),
+            (error) => _addAppCallback!(right(error)),
+          );
+        });
+        break;
       default:
       default:
         break;
         break;
     }
     }

+ 1 - 0
app_flowy/lib/home/presentation/home_screen.dart

@@ -80,6 +80,7 @@ class HomeScreen extends StatelessWidget {
       isCollapseChanged: (isCollapse) {
       isCollapseChanged: (isCollapse) {
         homeBloc.add(HomeEvent.forceCollapse(isCollapse));
         homeBloc.add(HomeEvent.forceCollapse(isCollapse));
       },
       },
+      workspaceId: userDetail.workspace,
     );
     );
     homeMenu = RepaintBoundary(child: homeMenu);
     homeMenu = RepaintBoundary(child: homeMenu);
     homeMenu = FocusTraversalGroup(child: homeMenu);
     homeMenu = FocusTraversalGroup(child: homeMenu);

+ 58 - 0
app_flowy/lib/home/presentation/widgets/app/app_list_widget.dart

@@ -0,0 +1,58 @@
+import 'package:app_flowy/home/application/app/app_bloc.dart';
+import 'package:app_flowy/startup/startup.dart';
+// ignore: import_of_legacy_library_into_null_safe
+import 'package:expandable/expandable.dart';
+import 'package:flowy_infra/flowy_logger.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flowy_infra_ui/widget/error_page.dart';
+
+import 'app_widget.dart';
+
+class AppList extends StatelessWidget {
+  const AppList({Key? key}) : super(key: key);
+  @override
+  Widget build(BuildContext context) {
+    return MultiBlocProvider(
+      providers: [
+        BlocProvider(
+          create: (context) => getIt<AppBloc>()..add(const AppEvent.initial()),
+        ),
+      ],
+      child: BlocBuilder<AppBloc, AppState>(
+        buildWhen: (p, c) => p.apps != c.apps,
+        builder: (context, state) {
+          Log.info('AppList build');
+          if (state.isLoading) {
+            return const Center(
+              child: CircularProgressIndicator.adaptive(),
+            );
+          }
+
+          return state.apps.fold(
+            () => state.successOrFailure.fold(
+              (_) => const Text('You have no apps, create one?'),
+              (error) => FlowyErrorPage(error.toString()),
+            ),
+            (apps) => _buildBody(apps),
+          );
+        },
+      ),
+    );
+  }
+
+  Widget _buildBody(List<App> apps) {
+    return ExpandableTheme(
+        data: const ExpandableThemeData(
+          iconColor: Colors.blue,
+          useInkWell: true,
+        ),
+        child: Expanded(
+          child: ListView(
+            physics: const BouncingScrollPhysics(),
+            children: apps.map((app) => AppWidget(app)).toList(),
+          ),
+        ));
+  }
+}

+ 122 - 0
app_flowy/lib/home/presentation/widgets/app/app_widget.dart

@@ -0,0 +1,122 @@
+// ignore: import_of_legacy_library_into_null_safe
+import 'package:app_flowy/home/presentation/widgets/menu/hom_menu_size.dart';
+import 'package:expandable/expandable.dart';
+import 'package:flowy_infra/size.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class AppWidget extends StatelessWidget {
+  final App app;
+  const AppWidget(this.app, {Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+
+  ExpandableNotifier expandableWrapper(BuildContext context, Widget child) {
+    return ExpandableNotifier(
+      child: ScrollOnExpand(
+        scrollOnExpand: true,
+        scrollOnCollapse: false,
+        child: Card(
+          clipBehavior: Clip.antiAlias,
+          child: Column(
+            children: <Widget>[
+              ExpandablePanel(
+                theme: const ExpandableThemeData(
+                  headerAlignment: ExpandablePanelHeaderAlignment.center,
+                  tapBodyToExpand: false,
+                  tapBodyToCollapse: false,
+                  iconPadding: EdgeInsets.zero,
+                  hasIcon: false,
+                ),
+                header: AppHeader(app),
+                expanded: Padding(
+                  padding: EdgeInsets.only(left: Sizes.iconMed),
+                  child: child,
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class AppHeader extends StatelessWidget {
+  final App app;
+  const AppHeader(
+    this.app, {
+    Key? key,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      color: Colors.white,
+      child: Padding(
+        padding: EdgeInsets.symmetric(vertical: Insets.m),
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            ExpandableIcon(
+              theme: ExpandableThemeData(
+                expandIcon: Icons.arrow_right,
+                collapseIcon: Icons.arrow_drop_down,
+                iconColor: Colors.black,
+                iconSize: HomeMenuSize.collapseIconSize,
+                iconPadding: EdgeInsets.zero,
+                hasIcon: false,
+              ),
+            ),
+            Expanded(
+              child: Text(app.name),
+            ),
+            SizedBox(
+              height: HomeMenuSize.createViewButtonSize,
+              child: createViewPopupMenu(context),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget createViewPopupMenu(BuildContext context) {
+    return PopupMenuButton(
+        iconSize: 24,
+        tooltip: 'create new view',
+        icon: const Icon(Icons.add),
+        padding: EdgeInsets.zero,
+        onSelected: (viewType) =>
+            handleCreateView(viewType as ViewType, context),
+        itemBuilder: (context) => menuItemBuilder());
+  }
+
+  List<PopupMenuEntry> menuItemBuilder() {
+    return ViewType.values
+        // .where((element) => element != ViewType.ViewTypeUnknown)
+        .map((ty) {
+      return PopupMenuItem<ViewType>(
+          value: ty,
+          child: Row(
+            children: <Widget>[Text(ty.name)],
+          ));
+    }).toList();
+  }
+
+  void handleCreateView(ViewType viewType, BuildContext context) {
+    switch (viewType) {
+      case ViewType.Docs:
+        // context
+        //     .read<AppEditBloc>()
+        //     .add(AppEditEvent.createView(app.id, 'Grid View'));
+        break;
+    }
+  }
+}

+ 0 - 0
app_flowy/lib/home/presentation/widgets/app/new_app.dart


+ 0 - 0
app_flowy/lib/home/presentation/widgets/app/view_list.dart


+ 5 - 2
app_flowy/lib/home/presentation/widgets/menu/home_menu.dart

@@ -19,17 +19,20 @@ import 'package:textstyle_extensions/textstyle_extensions.dart';
 class HomeMenu extends StatelessWidget {
 class HomeMenu extends StatelessWidget {
   final Function(Option<PageContext>) pageContextChanged;
   final Function(Option<PageContext>) pageContextChanged;
   final Function(bool) isCollapseChanged;
   final Function(bool) isCollapseChanged;
+  final String workspaceId;
 
 
   const HomeMenu(
   const HomeMenu(
       {Key? key,
       {Key? key,
       required this.pageContextChanged,
       required this.pageContextChanged,
-      required this.isCollapseChanged})
+      required this.isCollapseChanged,
+      required this.workspaceId})
       : super(key: key);
       : super(key: key);
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return BlocProvider(
     return BlocProvider(
-      create: (context) => getIt<MenuBloc>(),
+      create: (context) =>
+          getIt<MenuBloc>(param1: workspaceId)..add(const MenuEvent.initial()),
       child: MultiBlocListener(
       child: MultiBlocListener(
         listeners: [
         listeners: [
           BlocListener<MenuBloc, MenuState>(
           BlocListener<MenuBloc, MenuState>(

+ 1 - 1
app_flowy/lib/main.dart

@@ -10,5 +10,5 @@ class FlowyAppFactory implements AppFactory {
 }
 }
 
 
 void main() {
 void main() {
-  App.run(FlowyAppFactory());
+  Application.run(FlowyAppFactory());
 }
 }

+ 1 - 1
app_flowy/lib/startup/startup.dart

@@ -14,7 +14,7 @@ abstract class AppFactory {
   Widget create();
   Widget create();
 }
 }
 
 
-class App {
+class Application {
   static void run(AppFactory f) {
   static void run(AppFactory f) {
     // Specify the evn
     // Specify the evn
     const env = IntegrationEnv.dev;
     const env = IntegrationEnv.dev;

+ 13 - 0
app_flowy/packages/flowy_infra_ui/lib/widget/error_page.dart

@@ -0,0 +1,13 @@
+import 'package:flutter/material.dart';
+
+class FlowyErrorPage extends StatelessWidget {
+  final String error;
+  const FlowyErrorPage(this.error, {Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      child: Text(error),
+    );
+  }
+}

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

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

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

@@ -8,17 +8,18 @@
 import 'dart:core' as $core;
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use workspaceObservableTypeDescriptor instead')
-const WorkspaceObservableType$json = const {
-  '1': 'WorkspaceObservableType',
+@$core.Deprecated('Use workspaceObservableDescriptor instead')
+const WorkspaceObservable$json = const {
+  '1': 'WorkspaceObservable',
   '2': const [
   '2': const [
     const {'1': 'Unknown', '2': 0},
     const {'1': 'Unknown', '2': 0},
-    const {'1': 'WorkspaceUpdated', '2': 10},
-    const {'1': 'AppDescUpdated', '2': 20},
-    const {'1': 'AppViewsUpdated', '2': 21},
-    const {'1': 'ViewUpdated', '2': 30},
+    const {'1': 'WorkspaceUpdateDesc', '2': 10},
+    const {'1': 'WorkspaceAddApp', '2': 11},
+    const {'1': 'AppUpdateDesc', '2': 20},
+    const {'1': 'AppAddView', '2': 21},
+    const {'1': 'ViewUpdateDesc', '2': 30},
   ],
   ],
 };
 };
 
 
-/// Descriptor for `WorkspaceObservableType`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List workspaceObservableTypeDescriptor = $convert.base64Decode('ChdXb3Jrc3BhY2VPYnNlcnZhYmxlVHlwZRILCgdVbmtub3duEAASFAoQV29ya3NwYWNlVXBkYXRlZBAKEhIKDkFwcERlc2NVcGRhdGVkEBQSEwoPQXBwVmlld3NVcGRhdGVkEBUSDwoLVmlld1VwZGF0ZWQQHg==');
+/// Descriptor for `WorkspaceObservable`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List workspaceObservableDescriptor = $convert.base64Decode('ChNXb3Jrc3BhY2VPYnNlcnZhYmxlEgsKB1Vua25vd24QABIXChNXb3Jrc3BhY2VVcGRhdGVEZXNjEAoSEwoPV29ya3NwYWNlQWRkQXBwEAsSEQoNQXBwVXBkYXRlRGVzYxAUEg4KCkFwcEFkZFZpZXcQFRISCg5WaWV3VXBkYXRlRGVzYxAe');

+ 8 - 8
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pb.dart

@@ -29,7 +29,7 @@ class CreateViewRequest extends $pb.GeneratedMessage {
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
-    ..e<ViewTypeIdentifier>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewTypeIdentifier.Docs, valueOf: ViewTypeIdentifier.valueOf, enumValues: ViewTypeIdentifier.values)
+    ..e<ViewType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewType.Docs, valueOf: ViewType.valueOf, enumValues: ViewType.values)
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
@@ -39,7 +39,7 @@ class CreateViewRequest extends $pb.GeneratedMessage {
     $core.String? name,
     $core.String? name,
     $core.String? desc,
     $core.String? desc,
     $core.String? thumbnail,
     $core.String? thumbnail,
-    ViewTypeIdentifier? viewType,
+    ViewType? viewType,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (appId != null) {
     if (appId != null) {
@@ -120,9 +120,9 @@ class CreateViewRequest extends $pb.GeneratedMessage {
   void clearThumbnail() => clearField(4);
   void clearThumbnail() => clearField(4);
 
 
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
-  ViewTypeIdentifier get viewType => $_getN(4);
+  ViewType get viewType => $_getN(4);
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
-  set viewType(ViewTypeIdentifier v) { setField(5, v); }
+  set viewType(ViewType v) { setField(5, v); }
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
   $core.bool hasViewType() => $_has(4);
   $core.bool hasViewType() => $_has(4);
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
@@ -135,7 +135,7 @@ class View extends $pb.GeneratedMessage {
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
-    ..e<ViewTypeIdentifier>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewTypeIdentifier.Docs, valueOf: ViewTypeIdentifier.valueOf, enumValues: ViewTypeIdentifier.values)
+    ..e<ViewType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewType.Docs, valueOf: ViewType.valueOf, enumValues: ViewType.values)
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
@@ -145,7 +145,7 @@ class View extends $pb.GeneratedMessage {
     $core.String? appId,
     $core.String? appId,
     $core.String? name,
     $core.String? name,
     $core.String? desc,
     $core.String? desc,
-    ViewTypeIdentifier? viewType,
+    ViewType? viewType,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (id != null) {
     if (id != null) {
@@ -223,9 +223,9 @@ class View extends $pb.GeneratedMessage {
   void clearDesc() => clearField(4);
   void clearDesc() => clearField(4);
 
 
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
-  ViewTypeIdentifier get viewType => $_getN(4);
+  ViewType get viewType => $_getN(4);
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
-  set viewType(ViewTypeIdentifier v) { setField(5, v); }
+  set viewType(ViewType v) { setField(5, v); }
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)
   $core.bool hasViewType() => $_has(4);
   $core.bool hasViewType() => $_has(4);
   @$pb.TagNumber(5)
   @$pb.TagNumber(5)

+ 6 - 6
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pbenum.dart

@@ -9,16 +9,16 @@
 import 'dart:core' as $core;
 import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 import 'package:protobuf/protobuf.dart' as $pb;
 
 
-class ViewTypeIdentifier extends $pb.ProtobufEnum {
-  static const ViewTypeIdentifier Docs = ViewTypeIdentifier._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Docs');
+class ViewType extends $pb.ProtobufEnum {
+  static const ViewType Docs = ViewType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Docs');
 
 
-  static const $core.List<ViewTypeIdentifier> values = <ViewTypeIdentifier> [
+  static const $core.List<ViewType> values = <ViewType> [
     Docs,
     Docs,
   ];
   ];
 
 
-  static final $core.Map<$core.int, ViewTypeIdentifier> _byValue = $pb.ProtobufEnum.initByValue(values);
-  static ViewTypeIdentifier? valueOf($core.int value) => _byValue[value];
+  static final $core.Map<$core.int, ViewType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static ViewType? valueOf($core.int value) => _byValue[value];
 
 
-  const ViewTypeIdentifier._($core.int v, $core.String n) : super(v, n);
+  const ViewType._($core.int v, $core.String n) : super(v, n);
 }
 }
 
 

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

@@ -8,16 +8,16 @@
 import 'dart:core' as $core;
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use viewTypeIdentifierDescriptor instead')
-const ViewTypeIdentifier$json = const {
-  '1': 'ViewTypeIdentifier',
+@$core.Deprecated('Use viewTypeDescriptor instead')
+const ViewType$json = const {
+  '1': 'ViewType',
   '2': const [
   '2': const [
     const {'1': 'Docs', '2': 0},
     const {'1': 'Docs', '2': 0},
   ],
   ],
 };
 };
 
 
-/// Descriptor for `ViewTypeIdentifier`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List viewTypeIdentifierDescriptor = $convert.base64Decode('ChJWaWV3VHlwZUlkZW50aWZpZXISCAoERG9jcxAA');
+/// Descriptor for `ViewType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List viewTypeDescriptor = $convert.base64Decode('CghWaWV3VHlwZRIICgREb2NzEAA=');
 @$core.Deprecated('Use createViewRequestDescriptor instead')
 @$core.Deprecated('Use createViewRequestDescriptor instead')
 const CreateViewRequest$json = const {
 const CreateViewRequest$json = const {
   '1': 'CreateViewRequest',
   '1': 'CreateViewRequest',
@@ -26,7 +26,7 @@ const CreateViewRequest$json = const {
     const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'},
     const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'},
     const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'thumbnail'},
     const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'thumbnail'},
-    const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewTypeIdentifier', '10': 'viewType'},
+    const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewType', '10': 'viewType'},
   ],
   ],
   '8': const [
   '8': const [
     const {'1': 'one_of_thumbnail'},
     const {'1': 'one_of_thumbnail'},
@@ -34,7 +34,7 @@ const CreateViewRequest$json = const {
 };
 };
 
 
 /// Descriptor for `CreateViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
 /// Descriptor for `CreateViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List createViewRequestDescriptor = $convert.base64Decode('ChFDcmVhdGVWaWV3UmVxdWVzdBIVCgZhcHBfaWQYASABKAlSBWFwcElkEhIKBG5hbWUYAiABKAlSBG5hbWUSEgoEZGVzYxgDIAEoCVIEZGVzYxIeCgl0aHVtYm5haWwYBCABKAlIAFIJdGh1bWJuYWlsEjAKCXZpZXdfdHlwZRgFIAEoDjITLlZpZXdUeXBlSWRlbnRpZmllclIIdmlld1R5cGVCEgoQb25lX29mX3RodW1ibmFpbA==');
+final $typed_data.Uint8List createViewRequestDescriptor = $convert.base64Decode('ChFDcmVhdGVWaWV3UmVxdWVzdBIVCgZhcHBfaWQYASABKAlSBWFwcElkEhIKBG5hbWUYAiABKAlSBG5hbWUSEgoEZGVzYxgDIAEoCVIEZGVzYxIeCgl0aHVtYm5haWwYBCABKAlIAFIJdGh1bWJuYWlsEiYKCXZpZXdfdHlwZRgFIAEoDjIJLlZpZXdUeXBlUgh2aWV3VHlwZUISChBvbmVfb2ZfdGh1bWJuYWls');
 @$core.Deprecated('Use viewDescriptor instead')
 @$core.Deprecated('Use viewDescriptor instead')
 const View$json = const {
 const View$json = const {
   '1': 'View',
   '1': 'View',
@@ -43,12 +43,12 @@ const View$json = const {
     const {'1': 'app_id', '3': 2, '4': 1, '5': 9, '10': 'appId'},
     const {'1': 'app_id', '3': 2, '4': 1, '5': 9, '10': 'appId'},
     const {'1': 'name', '3': 3, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'name', '3': 3, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'desc', '3': 4, '4': 1, '5': 9, '10': 'desc'},
     const {'1': 'desc', '3': 4, '4': 1, '5': 9, '10': 'desc'},
-    const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewTypeIdentifier', '10': 'viewType'},
+    const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewType', '10': 'viewType'},
   ],
   ],
 };
 };
 
 
 /// Descriptor for `View`. Decode as a `google.protobuf.DescriptorProto`.
 /// Descriptor for `View`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List viewDescriptor = $convert.base64Decode('CgRWaWV3Eg4KAmlkGAEgASgJUgJpZBIVCgZhcHBfaWQYAiABKAlSBWFwcElkEhIKBG5hbWUYAyABKAlSBG5hbWUSEgoEZGVzYxgEIAEoCVIEZGVzYxIwCgl2aWV3X3R5cGUYBSABKA4yEy5WaWV3VHlwZUlkZW50aWZpZXJSCHZpZXdUeXBl');
+final $typed_data.Uint8List viewDescriptor = $convert.base64Decode('CgRWaWV3Eg4KAmlkGAEgASgJUgJpZBIVCgZhcHBfaWQYAiABKAlSBWFwcElkEhIKBG5hbWUYAyABKAlSBG5hbWUSEgoEZGVzYxgEIAEoCVIEZGVzYxImCgl2aWV3X3R5cGUYBSABKA4yCS5WaWV3VHlwZVIIdmlld1R5cGU=');
 @$core.Deprecated('Use repeatedViewDescriptor instead')
 @$core.Deprecated('Use repeatedViewDescriptor instead')
 const RepeatedView$json = const {
 const RepeatedView$json = const {
   '1': 'RepeatedView',
   '1': 'RepeatedView',

+ 5 - 5
app_flowy/pubspec.lock

@@ -14,7 +14,7 @@ packages:
       name: analyzer
       name: analyzer
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
-    version: "1.7.1"
+    version: "1.7.2"
   animations:
   animations:
     dependency: transitive
     dependency: transitive
     description:
     description:
@@ -35,7 +35,7 @@ packages:
       name: async
       name: async
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
-    version: "2.6.1"
+    version: "2.7.0"
   bloc:
   bloc:
     dependency: transitive
     dependency: transitive
     description:
     description:
@@ -119,7 +119,7 @@ packages:
       name: charcode
       name: charcode
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
-    version: "1.2.0"
+    version: "1.3.1"
   checked_yaml:
   checked_yaml:
     dependency: transitive
     dependency: transitive
     description:
     description:
@@ -456,7 +456,7 @@ packages:
       name: meta
       name: meta
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
-    version: "1.3.0"
+    version: "1.7.0"
   mime:
   mime:
     dependency: transitive
     dependency: transitive
     description:
     description:
@@ -701,7 +701,7 @@ packages:
       name: test_api
       name: test_api
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
-    version: "0.3.0"
+    version: "0.4.1"
   textstyle_extensions:
   textstyle_extensions:
     dependency: transitive
     dependency: transitive
     description:
     description:

+ 6 - 1
rust-lib/dart-ffi/src/model/ffi_response.rs

@@ -1,5 +1,5 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-use flowy_dispatch::prelude::{EventResponse, Payload, StatusCode};
+use flowy_dispatch::prelude::{DispatchError, EventResponse, Payload, StatusCode};
 
 
 #[derive(ProtoBuf_Enum, Clone, Copy)]
 #[derive(ProtoBuf_Enum, Clone, Copy)]
 pub enum FFIStatusCode {
 pub enum FFIStatusCode {
@@ -33,6 +33,11 @@ impl std::convert::From<EventResponse> for FFIResponse {
             StatusCode::Err => FFIStatusCode::Err,
             StatusCode::Err => FFIStatusCode::Err,
         };
         };
 
 
+        // let msg = match resp.error {
+        //     None => "".to_owned(),
+        //     Some(e) => format!("{:?}", e),
+        // };
+
         FFIResponse { payload, code }
         FFIResponse { payload, code }
     }
     }
 }
 }

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

@@ -43,10 +43,10 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "SignInParams"
         | "SignInParams"
         | "UserError"
         | "UserError"
         => TypeCategory::Protobuf,
         => TypeCategory::Protobuf,
-        "ViewTypeIdentifier"
+        "ViewType"
         | "WorkspaceEvent"
         | "WorkspaceEvent"
         | "WorkspaceErrorCode"
         | "WorkspaceErrorCode"
-        | "WorkspaceObservableType"
+        | "WorkspaceObservable"
         | "FFIStatusCode"
         | "FFIStatusCode"
         | "UserStatus"
         | "UserStatus"
         | "UserEvent"
         | "UserEvent"

+ 0 - 1
rust-lib/flowy-derive/src/proto_buf/deserialize.rs

@@ -88,7 +88,6 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option<TokenStream>
         },
         },
         TypeCategory::Array => {
         TypeCategory::Array => {
             let take_func = format_ident!("take_{}", ident.to_string());
             let take_func = format_ident!("take_{}", ident.to_string());
-            let ty = bracketed_ty_info.unwrap().ty;
             Some(quote! {
             Some(quote! {
                 if pb.#has_func() {
                 if pb.#has_func() {
                     o.#member=Some(pb.#take_func());
                     o.#member=Some(pb.#take_func());

+ 10 - 1
rust-lib/flowy-dispatch/src/dispatch.rs

@@ -155,6 +155,7 @@ impl Service<DispatchContext> for DispatchService {
 
 
         Box::pin(async move {
         Box::pin(async move {
             let result = {
             let result = {
+                // print_module_map_info(&module_map);
                 match module_map.get(&request.event) {
                 match module_map.get(&request.event) {
                     Some(module) => {
                     Some(module) => {
                         let fut = module.new_service(());
                         let fut = module.new_service(());
@@ -163,7 +164,7 @@ impl Service<DispatchContext> for DispatchService {
                     },
                     },
                     None => {
                     None => {
                         let msg = format!("Can not find the event handler. {:?}", request);
                         let msg = format!("Can not find the event handler. {:?}", request);
-                        log::trace!("{}", msg);
+                        log::error!("{}", msg);
                         Err(InternalError::new(msg).into())
                         Err(InternalError::new(msg).into())
                     },
                     },
                 }
                 }
@@ -180,6 +181,7 @@ impl Service<DispatchContext> for DispatchService {
     }
     }
 }
 }
 
 
+#[allow(dead_code)]
 fn module_info(modules: &Vec<Module>) -> String {
 fn module_info(modules: &Vec<Module>) -> String {
     let mut info = format!("{} modules loaded\n", modules.len());
     let mut info = format!("{} modules loaded\n", modules.len());
     for module in modules {
     for module in modules {
@@ -187,3 +189,10 @@ fn module_info(modules: &Vec<Module>) -> String {
     }
     }
     info
     info
 }
 }
+
+#[allow(dead_code)]
+fn print_module_map_info(module_map: &ModuleMap) {
+    module_map.iter().for_each(|(k, v)| {
+        log::info!("Event: {:?} module: {:?}", k, v.name);
+    })
+}

+ 1 - 1
rust-lib/flowy-observable/src/dart/stream_sender.rs

@@ -14,7 +14,7 @@ impl RustStreamSender {
     fn new() -> Self { Self { isolate: None } }
     fn new() -> Self { Self { isolate: None } }
 
 
     fn inner_set_port(&mut self, port: i64) {
     fn inner_set_port(&mut self, port: i64) {
-        log::debug!("Setup rust to flutter stream with port {}", port);
+        log::info!("Setup rust to flutter stream with port {}", port);
         self.isolate = Some(allo_isolate::Isolate::new(port));
         self.isolate = Some(allo_isolate::Isolate::new(port));
     }
     }
 
 

+ 2 - 2
rust-lib/flowy-sdk/Cargo.toml

@@ -7,8 +7,8 @@ edition = "2018"
 
 
 [dependencies]
 [dependencies]
 flowy-dispatch = { path = "../flowy-dispatch", features = ["use_tracing"]}
 flowy-dispatch = { path = "../flowy-dispatch", features = ["use_tracing"]}
-flowy-log = { path = "../flowy-log" }
-#flowy-log = { path = "../flowy-log", features = ["use_bunyan"] }
+#flowy-log = { path = "../flowy-log" }
+flowy-log = { path = "../flowy-log", features = ["use_bunyan"] }
 flowy-user = { path = "../flowy-user" }
 flowy-user = { path = "../flowy-user" }
 flowy-infra = { path = "../flowy-infra" }
 flowy-infra = { path = "../flowy-infra" }
 flowy-workspace = { path = "../flowy-workspace" }
 flowy-workspace = { path = "../flowy-workspace" }

+ 1 - 0
rust-lib/flowy-workspace/Cargo.toml

@@ -25,6 +25,7 @@ serde = { version = "1.0", features = ["derive"] }
 derive_more = {version = "0.99", features = ["display"]}
 derive_more = {version = "0.99", features = ["display"]}
 bincode = { version = "1.3"}
 bincode = { version = "1.3"}
 unicode-segmentation = "1.7.1"
 unicode-segmentation = "1.7.1"
+tracing = { version = "0.1", features = ["log"] }
 
 
 [dev-dependencies]
 [dev-dependencies]
 flowy-test = { path = "../flowy-test" }
 flowy-test = { path = "../flowy-test" }

+ 4 - 4
rust-lib/flowy-workspace/src/entities/view/parser/view_type.rs

@@ -1,12 +1,12 @@
-use crate::{entities::view::ViewTypeIdentifier, sql_tables::view::ViewType};
+use crate::{entities::view::ViewType, sql_tables::view::ViewTableType};
 
 
 #[derive(Debug)]
 #[derive(Debug)]
-pub struct ViewTypeCheck(pub ViewType);
+pub struct ViewTypeCheck(pub ViewTableType);
 
 
 impl ViewTypeCheck {
 impl ViewTypeCheck {
-    pub fn parse(s: ViewTypeIdentifier) -> Result<ViewTypeCheck, String> {
+    pub fn parse(s: ViewType) -> Result<ViewTypeCheck, String> {
         match s {
         match s {
-            ViewTypeIdentifier::Docs => Ok(Self(ViewType::Docs)),
+            ViewType::Docs => Ok(Self(ViewTableType::Docs)),
         }
         }
     }
     }
 }
 }

+ 7 - 7
rust-lib/flowy-workspace/src/entities/view/view_create.rs

@@ -2,18 +2,18 @@ use crate::{
     entities::{app::parser::AppId, view::parser::*},
     entities::{app::parser::AppId, view::parser::*},
     errors::{ErrorBuilder, WorkspaceError, WorkspaceErrorCode},
     errors::{ErrorBuilder, WorkspaceError, WorkspaceErrorCode},
     impl_def_and_def_mut,
     impl_def_and_def_mut,
-    sql_tables::view::ViewType,
+    sql_tables::view::ViewTableType,
 };
 };
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use std::convert::TryInto;
 use std::convert::TryInto;
 
 
 #[derive(PartialEq, Debug, ProtoBuf_Enum)]
 #[derive(PartialEq, Debug, ProtoBuf_Enum)]
-pub enum ViewTypeIdentifier {
+pub enum ViewType {
     Docs = 0,
     Docs = 0,
 }
 }
 
 
-impl std::default::Default for ViewTypeIdentifier {
-    fn default() -> Self { ViewTypeIdentifier::Docs }
+impl std::default::Default for ViewType {
+    fn default() -> Self { ViewType::Docs }
 }
 }
 
 
 #[derive(Default, ProtoBuf)]
 #[derive(Default, ProtoBuf)]
@@ -31,7 +31,7 @@ pub struct CreateViewRequest {
     pub thumbnail: Option<String>,
     pub thumbnail: Option<String>,
 
 
     #[pb(index = 5)]
     #[pb(index = 5)]
-    pub view_type: ViewTypeIdentifier,
+    pub view_type: ViewType,
 }
 }
 
 
 pub struct CreateViewParams {
 pub struct CreateViewParams {
@@ -39,7 +39,7 @@ pub struct CreateViewParams {
     pub name: String,
     pub name: String,
     pub desc: String,
     pub desc: String,
     pub thumbnail: String,
     pub thumbnail: String,
-    pub view_type: ViewType,
+    pub view_type: ViewTableType,
 }
 }
 
 
 impl TryInto<CreateViewParams> for CreateViewRequest {
 impl TryInto<CreateViewParams> for CreateViewRequest {
@@ -101,7 +101,7 @@ pub struct View {
     pub desc: String,
     pub desc: String,
 
 
     #[pb(index = 5)]
     #[pb(index = 5)]
-    pub view_type: ViewTypeIdentifier,
+    pub view_type: ViewType,
 }
 }
 
 
 #[derive(PartialEq, Debug, Default, ProtoBuf)]
 #[derive(PartialEq, Debug, Default, ProtoBuf)]

+ 6 - 6
rust-lib/flowy-workspace/src/event.rs

@@ -4,27 +4,27 @@ use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
 #[event_err = "WorkspaceError"]
 #[event_err = "WorkspaceError"]
 pub enum WorkspaceEvent {
 pub enum WorkspaceEvent {
-    #[display(fmt = "Create workspace")]
+    #[display(fmt = "CreateWorkspace")]
     #[event(input = "CreateWorkspaceRequest", output = "Workspace")]
     #[event(input = "CreateWorkspaceRequest", output = "Workspace")]
     CreateWorkspace = 0,
     CreateWorkspace = 0,
 
 
-    #[display(fmt = "Get user's current workspace")]
+    #[display(fmt = "GetCurWorkspace")]
     #[event(output = "Workspace")]
     #[event(output = "Workspace")]
     GetCurWorkspace = 1,
     GetCurWorkspace = 1,
 
 
-    #[display(fmt = "Get user's workspace")]
+    #[display(fmt = "GetWorkspace")]
     #[event(input = "QueryWorkspaceRequest", output = "Workspace")]
     #[event(input = "QueryWorkspaceRequest", output = "Workspace")]
     GetWorkspace    = 2,
     GetWorkspace    = 2,
 
 
-    #[display(fmt = "Create app information")]
+    #[display(fmt = "CreateApp")]
     #[event(input = "CreateAppRequest", output = "App")]
     #[event(input = "CreateAppRequest", output = "App")]
     CreateApp       = 101,
     CreateApp       = 101,
 
 
-    #[display(fmt = "Get app information")]
+    #[display(fmt = "GetApp")]
     #[event(input = "QueryAppRequest", output = "App")]
     #[event(input = "QueryAppRequest", output = "App")]
     GetApp          = 102,
     GetApp          = 102,
 
 
-    #[display(fmt = "Create view")]
+    #[display(fmt = "CreateView")]
     #[event(input = "CreateViewRequest", output = "View")]
     #[event(input = "CreateViewRequest", output = "View")]
     CreateView      = 201,
     CreateView      = 201,
 }
 }

+ 2 - 0
rust-lib/flowy-workspace/src/handlers/app_handler.rs

@@ -9,6 +9,7 @@ use crate::{
 use flowy_dispatch::prelude::{response_ok, Data, ModuleData, ResponseResult};
 use flowy_dispatch::prelude::{response_ok, Data, ModuleData, ResponseResult};
 use std::{convert::TryInto, sync::Arc};
 use std::{convert::TryInto, sync::Arc};
 
 
+#[tracing::instrument(name = "create_app", skip(data, controller))]
 pub async fn create_app(
 pub async fn create_app(
     data: Data<CreateAppRequest>,
     data: Data<CreateAppRequest>,
     controller: ModuleData<Arc<AppController>>,
     controller: ModuleData<Arc<AppController>>,
@@ -18,6 +19,7 @@ pub async fn create_app(
     response_ok(detail)
     response_ok(detail)
 }
 }
 
 
+#[tracing::instrument(name = "get_app", skip(data, controller))]
 pub async fn get_app(
 pub async fn get_app(
     data: Data<QueryAppRequest>,
     data: Data<QueryAppRequest>,
     controller: ModuleData<Arc<AppController>>,
     controller: ModuleData<Arc<AppController>>,

+ 3 - 0
rust-lib/flowy-workspace/src/handlers/workspace_handler.rs

@@ -6,6 +6,7 @@ use crate::{
 use flowy_dispatch::prelude::{response_ok, Data, ModuleData, ResponseResult};
 use flowy_dispatch::prelude::{response_ok, Data, ModuleData, ResponseResult};
 use std::{convert::TryInto, sync::Arc};
 use std::{convert::TryInto, sync::Arc};
 
 
+#[tracing::instrument(name = "create_workspace", skip(data, controller))]
 pub async fn create_workspace(
 pub async fn create_workspace(
     data: Data<CreateWorkspaceRequest>,
     data: Data<CreateWorkspaceRequest>,
     controller: ModuleData<Arc<WorkspaceController>>,
     controller: ModuleData<Arc<WorkspaceController>>,
@@ -16,6 +17,7 @@ pub async fn create_workspace(
     response_ok(detail)
     response_ok(detail)
 }
 }
 
 
+#[tracing::instrument(name = "get_cur_workspace", skip(controller))]
 pub async fn get_cur_workspace(
 pub async fn get_cur_workspace(
     controller: ModuleData<Arc<WorkspaceController>>,
     controller: ModuleData<Arc<WorkspaceController>>,
 ) -> ResponseResult<Workspace, WorkspaceError> {
 ) -> ResponseResult<Workspace, WorkspaceError> {
@@ -23,6 +25,7 @@ pub async fn get_cur_workspace(
     response_ok(workspace)
     response_ok(workspace)
 }
 }
 
 
+#[tracing::instrument(name = "get_workspace", skip(data, controller))]
 pub async fn get_workspace(
 pub async fn get_workspace(
     data: Data<QueryWorkspaceRequest>,
     data: Data<QueryWorkspaceRequest>,
     controller: ModuleData<Arc<WorkspaceController>>,
     controller: ModuleData<Arc<WorkspaceController>>,

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

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

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

@@ -24,37 +24,40 @@
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum WorkspaceObservableType {
+pub enum WorkspaceObservable {
     Unknown = 0,
     Unknown = 0,
-    WorkspaceUpdated = 10,
-    AppDescUpdated = 20,
-    AppViewsUpdated = 21,
-    ViewUpdated = 30,
+    WorkspaceUpdateDesc = 10,
+    WorkspaceAddApp = 11,
+    AppUpdateDesc = 20,
+    AppAddView = 21,
+    ViewUpdateDesc = 30,
 }
 }
 
 
-impl ::protobuf::ProtobufEnum for WorkspaceObservableType {
+impl ::protobuf::ProtobufEnum for WorkspaceObservable {
     fn value(&self) -> i32 {
     fn value(&self) -> i32 {
         *self as i32
         *self as i32
     }
     }
 
 
-    fn from_i32(value: i32) -> ::std::option::Option<WorkspaceObservableType> {
+    fn from_i32(value: i32) -> ::std::option::Option<WorkspaceObservable> {
         match value {
         match value {
-            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),
+            0 => ::std::option::Option::Some(WorkspaceObservable::Unknown),
+            10 => ::std::option::Option::Some(WorkspaceObservable::WorkspaceUpdateDesc),
+            11 => ::std::option::Option::Some(WorkspaceObservable::WorkspaceAddApp),
+            20 => ::std::option::Option::Some(WorkspaceObservable::AppUpdateDesc),
+            21 => ::std::option::Option::Some(WorkspaceObservable::AppAddView),
+            30 => ::std::option::Option::Some(WorkspaceObservable::ViewUpdateDesc),
             _ => ::std::option::Option::None
             _ => ::std::option::Option::None
         }
         }
     }
     }
 
 
     fn values() -> &'static [Self] {
     fn values() -> &'static [Self] {
-        static values: &'static [WorkspaceObservableType] = &[
-            WorkspaceObservableType::Unknown,
-            WorkspaceObservableType::WorkspaceUpdated,
-            WorkspaceObservableType::AppDescUpdated,
-            WorkspaceObservableType::AppViewsUpdated,
-            WorkspaceObservableType::ViewUpdated,
+        static values: &'static [WorkspaceObservable] = &[
+            WorkspaceObservable::Unknown,
+            WorkspaceObservable::WorkspaceUpdateDesc,
+            WorkspaceObservable::WorkspaceAddApp,
+            WorkspaceObservable::AppUpdateDesc,
+            WorkspaceObservable::AppAddView,
+            WorkspaceObservable::ViewUpdateDesc,
         ];
         ];
         values
         values
     }
     }
@@ -62,43 +65,46 @@ impl ::protobuf::ProtobufEnum for WorkspaceObservableType {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
         descriptor.get(|| {
-            ::protobuf::reflect::EnumDescriptor::new_pb_name::<WorkspaceObservableType>("WorkspaceObservableType", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<WorkspaceObservable>("WorkspaceObservable", file_descriptor_proto())
         })
         })
     }
     }
 }
 }
 
 
-impl ::std::marker::Copy for WorkspaceObservableType {
+impl ::std::marker::Copy for WorkspaceObservable {
 }
 }
 
 
-impl ::std::default::Default for WorkspaceObservableType {
+impl ::std::default::Default for WorkspaceObservable {
     fn default() -> Self {
     fn default() -> Self {
-        WorkspaceObservableType::Unknown
+        WorkspaceObservable::Unknown
     }
     }
 }
 }
 
 
-impl ::protobuf::reflect::ProtobufValue for WorkspaceObservableType {
+impl ::protobuf::reflect::ProtobufValue for WorkspaceObservable {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
     }
 }
 }
 
 
 static file_descriptor_proto_data: &'static [u8] = b"\
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \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\
+    \n\x10observable.proto*\x87\x01\n\x13WorkspaceObservable\x12\x0b\n\x07Un\
+    known\x10\0\x12\x17\n\x13WorkspaceUpdateDesc\x10\n\x12\x13\n\x0fWorkspac\
+    eAddApp\x10\x0b\x12\x11\n\rAppUpdateDesc\x10\x14\x12\x0e\n\nAppAddView\
+    \x10\x15\x12\x12\n\x0eViewUpdateDesc\x10\x1eJ\xa0\x02\n\x06\x12\x04\0\0\
+    \t\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\t\
+    \x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x18\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\x1d\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x17\n\x0c\
+    \n\x05\x05\0\x02\x01\x02\x12\x03\x04\x1a\x1c\n\x0b\n\x04\x05\0\x02\x02\
+    \x12\x03\x05\x04\x19\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x13\n\
+    \x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\x16\x18\n\x0b\n\x04\x05\0\x02\
+    \x03\x12\x03\x06\x04\x17\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\
+    \x11\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x14\x16\n\x0b\n\x04\x05\0\
+    \x02\x04\x12\x03\x07\x04\x14\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\
+    \x04\x0e\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\x11\x13\n\x0b\n\x04\
+    \x05\0\x02\x05\x12\x03\x08\x04\x18\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\
+    \x08\x04\x12\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x08\x15\x17b\x06proto\
+    3\
 ";
 ";
 
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 77 - 77
rust-lib/flowy-workspace/src/protobuf/model/view_create.rs

@@ -29,7 +29,7 @@ pub struct CreateViewRequest {
     pub app_id: ::std::string::String,
     pub app_id: ::std::string::String,
     pub name: ::std::string::String,
     pub name: ::std::string::String,
     pub desc: ::std::string::String,
     pub desc: ::std::string::String,
-    pub view_type: ViewTypeIdentifier,
+    pub view_type: ViewType,
     // message oneof groups
     // message oneof groups
     pub one_of_thumbnail: ::std::option::Option<CreateViewRequest_oneof_one_of_thumbnail>,
     pub one_of_thumbnail: ::std::option::Option<CreateViewRequest_oneof_one_of_thumbnail>,
     // special fields
     // special fields
@@ -180,18 +180,18 @@ impl CreateViewRequest {
         }
         }
     }
     }
 
 
-    // .ViewTypeIdentifier view_type = 5;
+    // .ViewType view_type = 5;
 
 
 
 
-    pub fn get_view_type(&self) -> ViewTypeIdentifier {
+    pub fn get_view_type(&self) -> ViewType {
         self.view_type
         self.view_type
     }
     }
     pub fn clear_view_type(&mut self) {
     pub fn clear_view_type(&mut self) {
-        self.view_type = ViewTypeIdentifier::Docs;
+        self.view_type = ViewType::Docs;
     }
     }
 
 
     // Param is passed by value, moved
     // Param is passed by value, moved
-    pub fn set_view_type(&mut self, v: ViewTypeIdentifier) {
+    pub fn set_view_type(&mut self, v: ViewType) {
         self.view_type = v;
         self.view_type = v;
     }
     }
 }
 }
@@ -244,7 +244,7 @@ impl ::protobuf::Message for CreateViewRequest {
         if !self.desc.is_empty() {
         if !self.desc.is_empty() {
             my_size += ::protobuf::rt::string_size(3, &self.desc);
             my_size += ::protobuf::rt::string_size(3, &self.desc);
         }
         }
-        if self.view_type != ViewTypeIdentifier::Docs {
+        if self.view_type != ViewType::Docs {
             my_size += ::protobuf::rt::enum_size(5, self.view_type);
             my_size += ::protobuf::rt::enum_size(5, self.view_type);
         }
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail {
         if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail {
@@ -269,7 +269,7 @@ impl ::protobuf::Message for CreateViewRequest {
         if !self.desc.is_empty() {
         if !self.desc.is_empty() {
             os.write_string(3, &self.desc)?;
             os.write_string(3, &self.desc)?;
         }
         }
-        if self.view_type != ViewTypeIdentifier::Docs {
+        if self.view_type != ViewType::Docs {
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
         }
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail {
         if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail {
@@ -337,7 +337,7 @@ impl ::protobuf::Message for CreateViewRequest {
                 CreateViewRequest::has_thumbnail,
                 CreateViewRequest::has_thumbnail,
                 CreateViewRequest::get_thumbnail,
                 CreateViewRequest::get_thumbnail,
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ViewTypeIdentifier>>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ViewType>>(
                 "view_type",
                 "view_type",
                 |m: &CreateViewRequest| { &m.view_type },
                 |m: &CreateViewRequest| { &m.view_type },
                 |m: &mut CreateViewRequest| { &mut m.view_type },
                 |m: &mut CreateViewRequest| { &mut m.view_type },
@@ -362,7 +362,7 @@ impl ::protobuf::Clear for CreateViewRequest {
         self.name.clear();
         self.name.clear();
         self.desc.clear();
         self.desc.clear();
         self.one_of_thumbnail = ::std::option::Option::None;
         self.one_of_thumbnail = ::std::option::Option::None;
-        self.view_type = ViewTypeIdentifier::Docs;
+        self.view_type = ViewType::Docs;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
 }
 }
@@ -386,7 +386,7 @@ pub struct View {
     pub app_id: ::std::string::String,
     pub app_id: ::std::string::String,
     pub name: ::std::string::String,
     pub name: ::std::string::String,
     pub desc: ::std::string::String,
     pub desc: ::std::string::String,
-    pub view_type: ViewTypeIdentifier,
+    pub view_type: ViewType,
     // special fields
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
     pub cached_size: ::protobuf::CachedSize,
@@ -507,18 +507,18 @@ impl View {
         ::std::mem::replace(&mut self.desc, ::std::string::String::new())
         ::std::mem::replace(&mut self.desc, ::std::string::String::new())
     }
     }
 
 
-    // .ViewTypeIdentifier view_type = 5;
+    // .ViewType view_type = 5;
 
 
 
 
-    pub fn get_view_type(&self) -> ViewTypeIdentifier {
+    pub fn get_view_type(&self) -> ViewType {
         self.view_type
         self.view_type
     }
     }
     pub fn clear_view_type(&mut self) {
     pub fn clear_view_type(&mut self) {
-        self.view_type = ViewTypeIdentifier::Docs;
+        self.view_type = ViewType::Docs;
     }
     }
 
 
     // Param is passed by value, moved
     // Param is passed by value, moved
-    pub fn set_view_type(&mut self, v: ViewTypeIdentifier) {
+    pub fn set_view_type(&mut self, v: ViewType) {
         self.view_type = v;
         self.view_type = v;
     }
     }
 }
 }
@@ -571,7 +571,7 @@ impl ::protobuf::Message for View {
         if !self.desc.is_empty() {
         if !self.desc.is_empty() {
             my_size += ::protobuf::rt::string_size(4, &self.desc);
             my_size += ::protobuf::rt::string_size(4, &self.desc);
         }
         }
-        if self.view_type != ViewTypeIdentifier::Docs {
+        if self.view_type != ViewType::Docs {
             my_size += ::protobuf::rt::enum_size(5, self.view_type);
             my_size += ::protobuf::rt::enum_size(5, self.view_type);
         }
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
@@ -592,7 +592,7 @@ impl ::protobuf::Message for View {
         if !self.desc.is_empty() {
         if !self.desc.is_empty() {
             os.write_string(4, &self.desc)?;
             os.write_string(4, &self.desc)?;
         }
         }
-        if self.view_type != ViewTypeIdentifier::Docs {
+        if self.view_type != ViewType::Docs {
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
         }
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         os.write_unknown_fields(self.get_unknown_fields())?;
@@ -653,7 +653,7 @@ impl ::protobuf::Message for View {
                 |m: &View| { &m.desc },
                 |m: &View| { &m.desc },
                 |m: &mut View| { &mut m.desc },
                 |m: &mut View| { &mut m.desc },
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ViewTypeIdentifier>>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ViewType>>(
                 "view_type",
                 "view_type",
                 |m: &View| { &m.view_type },
                 |m: &View| { &m.view_type },
                 |m: &mut View| { &mut m.view_type },
                 |m: &mut View| { &mut m.view_type },
@@ -678,7 +678,7 @@ impl ::protobuf::Clear for View {
         self.app_id.clear();
         self.app_id.clear();
         self.name.clear();
         self.name.clear();
         self.desc.clear();
         self.desc.clear();
-        self.view_type = ViewTypeIdentifier::Docs;
+        self.view_type = ViewType::Docs;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
 }
 }
@@ -862,25 +862,25 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedView {
 }
 }
 
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum ViewTypeIdentifier {
+pub enum ViewType {
     Docs = 0,
     Docs = 0,
 }
 }
 
 
-impl ::protobuf::ProtobufEnum for ViewTypeIdentifier {
+impl ::protobuf::ProtobufEnum for ViewType {
     fn value(&self) -> i32 {
     fn value(&self) -> i32 {
         *self as i32
         *self as i32
     }
     }
 
 
-    fn from_i32(value: i32) -> ::std::option::Option<ViewTypeIdentifier> {
+    fn from_i32(value: i32) -> ::std::option::Option<ViewType> {
         match value {
         match value {
-            0 => ::std::option::Option::Some(ViewTypeIdentifier::Docs),
+            0 => ::std::option::Option::Some(ViewType::Docs),
             _ => ::std::option::Option::None
             _ => ::std::option::Option::None
         }
         }
     }
     }
 
 
     fn values() -> &'static [Self] {
     fn values() -> &'static [Self] {
-        static values: &'static [ViewTypeIdentifier] = &[
-            ViewTypeIdentifier::Docs,
+        static values: &'static [ViewType] = &[
+            ViewType::Docs,
         ];
         ];
         values
         values
     }
     }
@@ -888,77 +888,77 @@ impl ::protobuf::ProtobufEnum for ViewTypeIdentifier {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
         descriptor.get(|| {
-            ::protobuf::reflect::EnumDescriptor::new_pb_name::<ViewTypeIdentifier>("ViewTypeIdentifier", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<ViewType>("ViewType", file_descriptor_proto())
         })
         })
     }
     }
 }
 }
 
 
-impl ::std::marker::Copy for ViewTypeIdentifier {
+impl ::std::marker::Copy for ViewType {
 }
 }
 
 
-impl ::std::default::Default for ViewTypeIdentifier {
+impl ::std::default::Default for ViewType {
     fn default() -> Self {
     fn default() -> Self {
-        ViewTypeIdentifier::Docs
+        ViewType::Docs
     }
     }
 }
 }
 
 
-impl ::protobuf::reflect::ProtobufValue for ViewTypeIdentifier {
+impl ::protobuf::reflect::ProtobufValue for ViewType {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
     }
 }
 }
 
 
 static file_descriptor_proto_data: &'static [u8] = b"\
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x11view_create.proto\"\xb8\x01\n\x11CreateViewRequest\x12\x15\n\x06ap\
+    \n\x11view_create.proto\"\xae\x01\n\x11CreateViewRequest\x12\x15\n\x06ap\
     p_id\x18\x01\x20\x01(\tR\x05appId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\
     p_id\x18\x01\x20\x01(\tR\x05appId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\
     \x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x1e\n\tthumbn\
     \x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x1e\n\tthumbn\
-    ail\x18\x04\x20\x01(\tH\0R\tthumbnail\x120\n\tview_type\x18\x05\x20\x01(\
-    \x0e2\x13.ViewTypeIdentifierR\x08viewTypeB\x12\n\x10one_of_thumbnail\"\
-    \x87\x01\n\x04View\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x15\n\
-    \x06app_id\x18\x02\x20\x01(\tR\x05appId\x12\x12\n\x04name\x18\x03\x20\
-    \x01(\tR\x04name\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04desc\x120\n\tv\
-    iew_type\x18\x05\x20\x01(\x0e2\x13.ViewTypeIdentifierR\x08viewType\"+\n\
-    \x0cRepeatedView\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.ViewR\x05i\
-    tems*\x1e\n\x12ViewTypeIdentifier\x12\x08\n\x04Docs\x10\0J\xa1\x06\n\x06\
-    \x12\x04\0\0\x15\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\
-    \x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\
-    \x04\0\x02\0\x12\x03\x03\x04\x16\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\
-    \x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x11\n\x0c\n\x05\x04\0\
-    \x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\
-    \x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\
-    \x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\
-    \x04\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x14\n\x0c\n\x05\
-    \x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\x12\
-    \x03\x05\x0b\x0f\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x12\x13\n\x0b\
-    \n\x04\x04\0\x08\0\x12\x03\x06\x044\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\
-    \x06\n\x1a\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\
-    \x02\x03\x05\x12\x03\x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$\
-    -\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x02\x04\
-    \x12\x03\x07\x04%\n\x0c\n\x05\x04\0\x02\x04\x06\x12\x03\x07\x04\x16\n\
-    \x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x17\x20\n\x0c\n\x05\x04\0\x02\
-    \x04\x03\x12\x03\x07#$\n\n\n\x02\x04\x01\x12\x04\t\0\x0f\x01\n\n\n\x03\
-    \x04\x01\x01\x12\x03\t\x08\x0c\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\
-    \x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\
-    \x02\0\x01\x12\x03\n\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x10\
-    \x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x04\x16\n\x0c\n\x05\x04\x01\
-    \x02\x01\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\
-    \x0b\x0b\x11\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\x14\x15\n\x0b\n\
-    \x04\x04\x01\x02\x02\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\
-    \x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0c\x0b\x0f\n\
-    \x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x01\
-    \x02\x03\x12\x03\r\x04\x14\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\r\x04\
-    \n\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\r\x0b\x0f\n\x0c\n\x05\x04\x01\
-    \x02\x03\x03\x12\x03\r\x12\x13\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\
-    \x04%\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0e\x04\x16\n\x0c\n\x05\
-    \x04\x01\x02\x04\x01\x12\x03\x0e\x17\x20\n\x0c\n\x05\x04\x01\x02\x04\x03\
-    \x12\x03\x0e#$\n\n\n\x02\x04\x02\x12\x04\x10\0\x12\x01\n\n\n\x03\x04\x02\
-    \x01\x12\x03\x10\x08\x14\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x11\x04\x1c\n\
-    \x0c\n\x05\x04\x02\x02\0\x04\x12\x03\x11\x04\x0c\n\x0c\n\x05\x04\x02\x02\
-    \0\x06\x12\x03\x11\r\x11\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x11\x12\
-    \x17\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x11\x1a\x1b\n\n\n\x02\x05\0\
-    \x12\x04\x13\0\x15\x01\n\n\n\x03\x05\0\x01\x12\x03\x13\x05\x17\n\x0b\n\
-    \x04\x05\0\x02\0\x12\x03\x14\x04\r\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\
-    \x14\x04\x08\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x14\x0b\x0cb\x06proto3\
+    ail\x18\x04\x20\x01(\tH\0R\tthumbnail\x12&\n\tview_type\x18\x05\x20\x01(\
+    \x0e2\t.ViewTypeR\x08viewTypeB\x12\n\x10one_of_thumbnail\"}\n\x04View\
+    \x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x15\n\x06app_id\x18\x02\
+    \x20\x01(\tR\x05appId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\
+    \x12\n\x04desc\x18\x04\x20\x01(\tR\x04desc\x12&\n\tview_type\x18\x05\x20\
+    \x01(\x0e2\t.ViewTypeR\x08viewType\"+\n\x0cRepeatedView\x12\x1b\n\x05ite\
+    ms\x18\x01\x20\x03(\x0b2\x05.ViewR\x05items*\x14\n\x08ViewType\x12\x08\n\
+    \x04Docs\x10\0J\xa1\x06\n\x06\x12\x04\0\0\x15\x01\n\x08\n\x01\x0c\x12\
+    \x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\
+    \x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\x0c\n\
+    \x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\
+    \x03\x03\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\
+    \x04\x04\0\x02\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\
+    \x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\
+    \x05\x04\0\x02\x01\x03\x12\x03\x04\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\
+    \x03\x05\x04\x14\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\
+    \x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x0f\n\x0c\n\x05\x04\0\x02\x02\x03\
+    \x12\x03\x05\x12\x13\n\x0b\n\x04\x04\0\x08\0\x12\x03\x06\x044\n\x0c\n\
+    \x05\x04\0\x08\0\x01\x12\x03\x06\n\x1a\n\x0b\n\x04\x04\0\x02\x03\x12\x03\
+    \x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x1d#\n\x0c\n\x05\x04\
+    \0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x0601\
+    \n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x04\x1b\n\x0c\n\x05\x04\0\x02\x04\
+    \x06\x12\x03\x07\x04\x0c\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\r\x16\
+    \n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07\x19\x1a\n\n\n\x02\x04\x01\x12\
+    \x04\t\0\x0f\x01\n\n\n\x03\x04\x01\x01\x12\x03\t\x08\x0c\n\x0b\n\x04\x04\
+    \x01\x02\0\x12\x03\n\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\
+    \n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\n\x0b\r\n\x0c\n\x05\x04\x01\x02\
+    \0\x03\x12\x03\n\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x04\x16\
+    \n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x01\
+    \x02\x01\x01\x12\x03\x0b\x0b\x11\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\
+    \x0b\x14\x15\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0c\x04\x14\n\x0c\n\x05\
+    \x04\x01\x02\x02\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x01\x02\x02\x01\
+    \x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0c\x12\x13\
+    \n\x0b\n\x04\x04\x01\x02\x03\x12\x03\r\x04\x14\n\x0c\n\x05\x04\x01\x02\
+    \x03\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\r\x0b\
+    \x0f\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\r\x12\x13\n\x0b\n\x04\x04\
+    \x01\x02\x04\x12\x03\x0e\x04\x1b\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\
+    \x0e\x04\x0c\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\x0e\r\x16\n\x0c\n\
+    \x05\x04\x01\x02\x04\x03\x12\x03\x0e\x19\x1a\n\n\n\x02\x04\x02\x12\x04\
+    \x10\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\x10\x08\x14\n\x0b\n\x04\x04\
+    \x02\x02\0\x12\x03\x11\x04\x1c\n\x0c\n\x05\x04\x02\x02\0\x04\x12\x03\x11\
+    \x04\x0c\n\x0c\n\x05\x04\x02\x02\0\x06\x12\x03\x11\r\x11\n\x0c\n\x05\x04\
+    \x02\x02\0\x01\x12\x03\x11\x12\x17\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\
+    \x11\x1a\x1b\n\n\n\x02\x05\0\x12\x04\x13\0\x15\x01\n\n\n\x03\x05\0\x01\
+    \x12\x03\x13\x05\r\n\x0b\n\x04\x05\0\x02\0\x12\x03\x14\x04\r\n\x0c\n\x05\
+    \x05\0\x02\0\x01\x12\x03\x14\x04\x08\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\
+    \x14\x0b\x0cb\x06proto3\
 ";
 ";
 
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

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

@@ -1,9 +1,10 @@
 syntax = "proto3";
 syntax = "proto3";
 
 
-enum WorkspaceObservableType {
+enum WorkspaceObservable {
     Unknown = 0;
     Unknown = 0;
-    WorkspaceUpdated = 10;
-    AppDescUpdated = 20;
-    AppViewsUpdated = 21;
-    ViewUpdated = 30;
+    WorkspaceUpdateDesc = 10;
+    WorkspaceAddApp = 11;
+    AppUpdateDesc = 20;
+    AppAddView = 21;
+    ViewUpdateDesc = 30;
 }
 }

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

@@ -5,18 +5,18 @@ message CreateViewRequest {
     string name = 2;
     string name = 2;
     string desc = 3;
     string desc = 3;
     oneof one_of_thumbnail { string thumbnail = 4; };
     oneof one_of_thumbnail { string thumbnail = 4; };
-    ViewTypeIdentifier view_type = 5;
+    ViewType view_type = 5;
 }
 }
 message View {
 message View {
     string id = 1;
     string id = 1;
     string app_id = 2;
     string app_id = 2;
     string name = 3;
     string name = 3;
     string desc = 4;
     string desc = 4;
-    ViewTypeIdentifier view_type = 5;
+    ViewType view_type = 5;
 }
 }
 message RepeatedView {
 message RepeatedView {
     repeated View items = 1;
     repeated View items = 1;
 }
 }
-enum ViewTypeIdentifier {
+enum ViewType {
     Docs = 0;
     Docs = 0;
 }
 }

+ 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_table = AppTable::new(params);
         let app: App = app_table.clone().into();
         let app: App = app_table.clone().into();
         let _ = self.sql.write_app_table(app_table)?;
         let _ = self.sql.write_app_table(app_table)?;
-        send_observable(&app.workspace_id, WorkspaceObservableType::WorkspaceUpdated);
+        send_observable(&app.workspace_id, WorkspaceObservable::WorkspaceAddApp);
         Ok(app)
         Ok(app)
     }
     }
 
 
@@ -49,7 +49,7 @@ impl AppController {
         let changeset = AppTableChangeset::new(params);
         let changeset = AppTableChangeset::new(params);
         let app_id = changeset.id.clone();
         let app_id = changeset.id.clone();
         let _ = self.sql.update_app_table(changeset)?;
         let _ = self.sql.update_app_table(changeset)?;
-        send_observable(&app_id, WorkspaceObservableType::AppDescUpdated);
+        send_observable(&app_id, WorkspaceObservable::AppUpdateDesc);
         Ok(())
         Ok(())
     }
     }
 
 

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

@@ -2,6 +2,7 @@ use crate::{
     entities::view::{CreateViewParams, View},
     entities::view::{CreateViewParams, View},
     errors::WorkspaceError,
     errors::WorkspaceError,
     module::WorkspaceDatabase,
     module::WorkspaceDatabase,
+    observable::{send_observable, WorkspaceObservable},
     sql_tables::view::{ViewTable, ViewTableSql},
     sql_tables::view::{ViewTable, ViewTableSql},
 };
 };
 use std::sync::Arc;
 use std::sync::Arc;
@@ -21,6 +22,7 @@ impl ViewController {
         let view: View = view_table.clone().into();
         let view: View = view_table.clone().into();
         let _ = self.sql.write_view_table(view_table)?;
         let _ = self.sql.write_view_table(view_table)?;
 
 
+        send_observable(&view.id, WorkspaceObservable::AppAddView);
         Ok(view)
         Ok(view)
     }
     }
 }
 }

+ 3 - 0
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -2,6 +2,7 @@ use crate::{
     entities::{app::App, workspace::*},
     entities::{app::App, workspace::*},
     errors::*,
     errors::*,
     module::{WorkspaceDatabase, WorkspaceUser},
     module::{WorkspaceDatabase, WorkspaceUser},
+    observable::{send_observable, WorkspaceObservable},
     services::AppController,
     services::AppController,
     sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset},
     sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset},
 };
 };
@@ -42,8 +43,10 @@ impl WorkspaceController {
 
 
     pub fn update_workspace(&self, params: UpdateWorkspaceParams) -> Result<(), WorkspaceError> {
     pub fn update_workspace(&self, params: UpdateWorkspaceParams) -> Result<(), WorkspaceError> {
         let changeset = WorkspaceTableChangeset::new(params);
         let changeset = WorkspaceTableChangeset::new(params);
+        let workspace_id = changeset.id.clone();
         let _ = self.sql.update_workspace(changeset)?;
         let _ = self.sql.update_workspace(changeset)?;
 
 
+        send_observable(&workspace_id, WorkspaceObservable::WorkspaceUpdateDesc);
         Ok(())
         Ok(())
     }
     }
 
 

+ 11 - 11
rust-lib/flowy-workspace/src/sql_tables/view/view_table.rs

@@ -1,5 +1,5 @@
 use crate::{
 use crate::{
-    entities::view::{CreateViewParams, View, ViewTypeIdentifier},
+    entities::view::{CreateViewParams, View, ViewType},
     impl_sql_integer_expression,
     impl_sql_integer_expression,
     sql_tables::app::AppTable,
     sql_tables::app::AppTable,
 };
 };
@@ -18,7 +18,7 @@ pub(crate) struct ViewTable {
     pub modified_time: i64,
     pub modified_time: i64,
     pub create_time: i64,
     pub create_time: i64,
     pub thumbnail: String,
     pub thumbnail: String,
-    pub view_type: ViewType,
+    pub view_type: ViewTableType,
     pub version: i64,
     pub version: i64,
 }
 }
 
 
@@ -43,7 +43,7 @@ impl ViewTable {
 impl std::convert::Into<View> for ViewTable {
 impl std::convert::Into<View> for ViewTable {
     fn into(self) -> View {
     fn into(self) -> View {
         let view_type = match self.view_type {
         let view_type = match self.view_type {
-            ViewType::Docs => ViewTypeIdentifier::Docs,
+            ViewTableType::Docs => ViewType::Docs,
         };
         };
 
 
         View {
         View {
@@ -79,28 +79,28 @@ impl ViewTableChangeset {
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
 #[repr(i32)]
 #[repr(i32)]
 #[sql_type = "Integer"]
 #[sql_type = "Integer"]
-pub enum ViewType {
+pub enum ViewTableType {
     Docs = 0,
     Docs = 0,
 }
 }
 
 
-impl std::default::Default for ViewType {
-    fn default() -> Self { ViewType::Docs }
+impl std::default::Default for ViewTableType {
+    fn default() -> Self { ViewTableType::Docs }
 }
 }
 
 
-impl std::convert::From<i32> for ViewType {
+impl std::convert::From<i32> for ViewTableType {
     fn from(value: i32) -> Self {
     fn from(value: i32) -> Self {
         match value {
         match value {
-            0 => ViewType::Docs,
+            0 => ViewTableType::Docs,
             o => {
             o => {
                 log::error!("Unsupported view type {}, fallback to ViewType::Docs", o);
                 log::error!("Unsupported view type {}, fallback to ViewType::Docs", o);
-                ViewType::Docs
+                ViewTableType::Docs
             },
             },
         }
         }
     }
     }
 }
 }
 
 
-impl ViewType {
+impl ViewTableType {
     pub fn value(&self) -> i32 { *self as i32 }
     pub fn value(&self) -> i32 { *self as i32 }
 }
 }
 
 
-impl_sql_integer_expression!(ViewType);
+impl_sql_integer_expression!(ViewTableType);

+ 2 - 2
rust-lib/flowy-workspace/tests/event/app_test.rs

@@ -37,7 +37,7 @@ fn app_create_with_view_and_then_get_success() {
         name: "View A".to_string(),
         name: "View A".to_string(),
         desc: "".to_string(),
         desc: "".to_string(),
         thumbnail: None,
         thumbnail: None,
-        view_type: ViewTypeIdentifier::Docs,
+        view_type: ViewType::Docs,
     };
     };
 
 
     let request_b = CreateViewRequest {
     let request_b = CreateViewRequest {
@@ -45,7 +45,7 @@ fn app_create_with_view_and_then_get_success() {
         name: "View B".to_string(),
         name: "View B".to_string(),
         desc: "".to_string(),
         desc: "".to_string(),
         thumbnail: None,
         thumbnail: None,
-        view_type: ViewTypeIdentifier::Docs,
+        view_type: ViewType::Docs,
     };
     };
 
 
     let view_a = create_view(request_a);
     let view_a = create_view(request_a);