浏览代码

[flutter]: delete view

appflowy 3 年之前
父节点
当前提交
50172e3fd4

+ 1 - 0
app_flowy/lib/workspace/application/app/app_listen_bloc.dart

@@ -18,6 +18,7 @@ class AppListenBloc extends Bloc<AppListenEvent, AppListenState> {
     yield* event.map(started: (_) async* {
       listener.start(
         addViewCallback: (viewsOrFail) => _handleViewsOrFail(viewsOrFail),
+        deleteViewCallback: (viewsOrFail) => _handleViewsOrFail(viewsOrFail),
       );
     }, didReceiveViews: (ViewsReceived value) async* {
       yield value.viewsOrFail.fold(

+ 40 - 19
app_flowy/lib/workspace/application/view/view_bloc.dart

@@ -1,4 +1,3 @@
-import 'package:app_flowy/workspace/domain/view_edit.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@@ -10,49 +9,71 @@ part 'view_bloc.freezed.dart';
 
 class ViewBloc extends Bloc<ViewEvent, ViewState> {
   final IView iViewImpl;
+  final IViewListener listener;
 
   ViewBloc({
     required this.iViewImpl,
-  }) : super(ViewState.initial(iViewImpl.view));
+    required this.listener,
+  }) : super(ViewState.init(iViewImpl.view));
 
   @override
   Stream<ViewState> mapEventToState(ViewEvent event) async* {
-    yield* event.map(
-      setIsSelected: (e) async* {
-        yield state.copyWith(isSelected: e.isSelected);
-      },
-      setIsEditing: (e) async* {
-        yield state.copyWith(isEditing: e.isEditing);
-      },
-      setAction: (e) async* {
-        yield state.copyWith(action: e.action);
-      },
+    yield* event.map(initial: (e) async* {
+      listener.start(updatedCallback: (result) => add(ViewEvent.viewDidUpdate(result)));
+      yield state;
+    }, setIsEditing: (e) async* {
+      yield state.copyWith(isEditing: e.isEditing);
+    }, viewDidUpdate: (e) async* {
+      yield* _handleViewDidUpdate(e.result);
+    }, rename: (e) async* {
+      final result = await iViewImpl.rename(e.newName);
+      yield result.fold(
+        (l) => state.copyWith(successOrFailure: left(unit)),
+        (error) => state.copyWith(successOrFailure: right(error)),
+      );
+    }, delete: (e) async* {
+      final result = await iViewImpl.pushIntoTrash();
+      yield result.fold(
+        (l) => state.copyWith(successOrFailure: left(unit)),
+        (error) => state.copyWith(successOrFailure: right(error)),
+      );
+    });
+  }
+
+  Stream<ViewState> _handleViewDidUpdate(Either<View, WorkspaceError> result) async* {
+    yield result.fold(
+      (view) => state.copyWith(view: view, successOrFailure: left(unit)),
+      (error) => state.copyWith(successOrFailure: right(error)),
     );
   }
+
+  @override
+  Future<void> close() async {
+    await listener.stop();
+    return super.close();
+  }
 }
 
 @freezed
 class ViewEvent with _$ViewEvent {
-  const factory ViewEvent.setIsSelected(bool isSelected) = SetSelected;
+  const factory ViewEvent.initial() = Initial;
   const factory ViewEvent.setIsEditing(bool isEditing) = SetEditing;
-  const factory ViewEvent.setAction(Option<ViewAction> action) = SetAction;
+  const factory ViewEvent.rename(String newName) = Rename;
+  const factory ViewEvent.delete() = Delete;
+  const factory ViewEvent.viewDidUpdate(Either<View, WorkspaceError> result) = ViewDidUpdate;
 }
 
 @freezed
 class ViewState with _$ViewState {
   const factory ViewState({
     required View view,
-    required bool isSelected,
     required bool isEditing,
-    required Option<ViewAction> action,
     required Either<Unit, WorkspaceError> successOrFailure,
   }) = _ViewState;
 
-  factory ViewState.initial(View view) => ViewState(
+  factory ViewState.init(View view) => ViewState(
         view: view,
-        isSelected: false,
         isEditing: false,
-        action: none(),
         successOrFailure: left(unit),
       );
 }

+ 364 - 178
app_flowy/lib/workspace/application/view/view_bloc.freezed.dart

@@ -16,10 +16,8 @@ final _privateConstructorUsedError = UnsupportedError(
 class _$ViewEventTearOff {
   const _$ViewEventTearOff();
 
-  SetSelected setIsSelected(bool isSelected) {
-    return SetSelected(
-      isSelected,
-    );
+  Initial initial() {
+    return const Initial();
   }
 
   SetEditing setIsEditing(bool isEditing) {
@@ -28,9 +26,19 @@ class _$ViewEventTearOff {
     );
   }
 
-  SetAction setAction(Option<ViewAction> action) {
-    return SetAction(
-      action,
+  Rename rename(String newName) {
+    return Rename(
+      newName,
+    );
+  }
+
+  Delete delete() {
+    return const Delete();
+  }
+
+  ViewDidUpdate viewDidUpdate(Either<View, WorkspaceError> result) {
+    return ViewDidUpdate(
+      result,
     );
   }
 }
@@ -42,31 +50,40 @@ const $ViewEvent = _$ViewEventTearOff();
 mixin _$ViewEvent {
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
-    required TResult Function(bool isSelected) setIsSelected,
+    required TResult Function() initial,
     required TResult Function(bool isEditing) setIsEditing,
-    required TResult Function(Option<ViewAction> action) setAction,
+    required TResult Function(String newName) rename,
+    required TResult Function() delete,
+    required TResult Function(Either<View, WorkspaceError> result)
+        viewDidUpdate,
   }) =>
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
-    TResult Function(bool isSelected)? setIsSelected,
+    TResult Function()? initial,
     TResult Function(bool isEditing)? setIsEditing,
-    TResult Function(Option<ViewAction> action)? setAction,
+    TResult Function(String newName)? rename,
+    TResult Function()? delete,
+    TResult Function(Either<View, WorkspaceError> result)? viewDidUpdate,
     required TResult orElse(),
   }) =>
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
-    required TResult Function(SetSelected value) setIsSelected,
+    required TResult Function(Initial value) initial,
     required TResult Function(SetEditing value) setIsEditing,
-    required TResult Function(SetAction value) setAction,
+    required TResult Function(Rename value) rename,
+    required TResult Function(Delete value) delete,
+    required TResult Function(ViewDidUpdate value) viewDidUpdate,
   }) =>
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
-    TResult Function(SetSelected value)? setIsSelected,
+    TResult Function(Initial value)? initial,
     TResult Function(SetEditing value)? setIsEditing,
-    TResult Function(SetAction value)? setAction,
+    TResult Function(Rename value)? rename,
+    TResult Function(Delete value)? delete,
+    TResult Function(ViewDidUpdate value)? viewDidUpdate,
     required TResult orElse(),
   }) =>
       throw _privateConstructorUsedError;
@@ -88,87 +105,64 @@ class _$ViewEventCopyWithImpl<$Res> implements $ViewEventCopyWith<$Res> {
 }
 
 /// @nodoc
-abstract class $SetSelectedCopyWith<$Res> {
-  factory $SetSelectedCopyWith(
-          SetSelected value, $Res Function(SetSelected) then) =
-      _$SetSelectedCopyWithImpl<$Res>;
-  $Res call({bool isSelected});
+abstract class $InitialCopyWith<$Res> {
+  factory $InitialCopyWith(Initial value, $Res Function(Initial) then) =
+      _$InitialCopyWithImpl<$Res>;
 }
 
 /// @nodoc
-class _$SetSelectedCopyWithImpl<$Res> extends _$ViewEventCopyWithImpl<$Res>
-    implements $SetSelectedCopyWith<$Res> {
-  _$SetSelectedCopyWithImpl(
-      SetSelected _value, $Res Function(SetSelected) _then)
-      : super(_value, (v) => _then(v as SetSelected));
+class _$InitialCopyWithImpl<$Res> extends _$ViewEventCopyWithImpl<$Res>
+    implements $InitialCopyWith<$Res> {
+  _$InitialCopyWithImpl(Initial _value, $Res Function(Initial) _then)
+      : super(_value, (v) => _then(v as Initial));
 
   @override
-  SetSelected get _value => super._value as SetSelected;
-
-  @override
-  $Res call({
-    Object? isSelected = freezed,
-  }) {
-    return _then(SetSelected(
-      isSelected == freezed
-          ? _value.isSelected
-          : isSelected // ignore: cast_nullable_to_non_nullable
-              as bool,
-    ));
-  }
+  Initial get _value => super._value as Initial;
 }
 
 /// @nodoc
 
-class _$SetSelected implements SetSelected {
-  const _$SetSelected(this.isSelected);
-
-  @override
-  final bool isSelected;
+class _$Initial implements Initial {
+  const _$Initial();
 
   @override
   String toString() {
-    return 'ViewEvent.setIsSelected(isSelected: $isSelected)';
+    return 'ViewEvent.initial()';
   }
 
   @override
   bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is SetSelected &&
-            (identical(other.isSelected, isSelected) ||
-                const DeepCollectionEquality()
-                    .equals(other.isSelected, isSelected)));
+    return identical(this, other) || (other is Initial);
   }
 
   @override
-  int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(isSelected);
-
-  @JsonKey(ignore: true)
-  @override
-  $SetSelectedCopyWith<SetSelected> get copyWith =>
-      _$SetSelectedCopyWithImpl<SetSelected>(this, _$identity);
+  int get hashCode => runtimeType.hashCode;
 
   @override
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
-    required TResult Function(bool isSelected) setIsSelected,
+    required TResult Function() initial,
     required TResult Function(bool isEditing) setIsEditing,
-    required TResult Function(Option<ViewAction> action) setAction,
+    required TResult Function(String newName) rename,
+    required TResult Function() delete,
+    required TResult Function(Either<View, WorkspaceError> result)
+        viewDidUpdate,
   }) {
-    return setIsSelected(isSelected);
+    return initial();
   }
 
   @override
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
-    TResult Function(bool isSelected)? setIsSelected,
+    TResult Function()? initial,
     TResult Function(bool isEditing)? setIsEditing,
-    TResult Function(Option<ViewAction> action)? setAction,
+    TResult Function(String newName)? rename,
+    TResult Function()? delete,
+    TResult Function(Either<View, WorkspaceError> result)? viewDidUpdate,
     required TResult orElse(),
   }) {
-    if (setIsSelected != null) {
-      return setIsSelected(isSelected);
+    if (initial != null) {
+      return initial();
     }
     return orElse();
   }
@@ -176,35 +170,34 @@ class _$SetSelected implements SetSelected {
   @override
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
-    required TResult Function(SetSelected value) setIsSelected,
+    required TResult Function(Initial value) initial,
     required TResult Function(SetEditing value) setIsEditing,
-    required TResult Function(SetAction value) setAction,
+    required TResult Function(Rename value) rename,
+    required TResult Function(Delete value) delete,
+    required TResult Function(ViewDidUpdate value) viewDidUpdate,
   }) {
-    return setIsSelected(this);
+    return initial(this);
   }
 
   @override
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
-    TResult Function(SetSelected value)? setIsSelected,
+    TResult Function(Initial value)? initial,
     TResult Function(SetEditing value)? setIsEditing,
-    TResult Function(SetAction value)? setAction,
+    TResult Function(Rename value)? rename,
+    TResult Function(Delete value)? delete,
+    TResult Function(ViewDidUpdate value)? viewDidUpdate,
     required TResult orElse(),
   }) {
-    if (setIsSelected != null) {
-      return setIsSelected(this);
+    if (initial != null) {
+      return initial(this);
     }
     return orElse();
   }
 }
 
-abstract class SetSelected implements ViewEvent {
-  const factory SetSelected(bool isSelected) = _$SetSelected;
-
-  bool get isSelected => throw _privateConstructorUsedError;
-  @JsonKey(ignore: true)
-  $SetSelectedCopyWith<SetSelected> get copyWith =>
-      throw _privateConstructorUsedError;
+abstract class Initial implements ViewEvent {
+  const factory Initial() = _$Initial;
 }
 
 /// @nodoc
@@ -271,9 +264,12 @@ class _$SetEditing implements SetEditing {
   @override
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
-    required TResult Function(bool isSelected) setIsSelected,
+    required TResult Function() initial,
     required TResult Function(bool isEditing) setIsEditing,
-    required TResult Function(Option<ViewAction> action) setAction,
+    required TResult Function(String newName) rename,
+    required TResult Function() delete,
+    required TResult Function(Either<View, WorkspaceError> result)
+        viewDidUpdate,
   }) {
     return setIsEditing(isEditing);
   }
@@ -281,9 +277,11 @@ class _$SetEditing implements SetEditing {
   @override
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
-    TResult Function(bool isSelected)? setIsSelected,
+    TResult Function()? initial,
     TResult Function(bool isEditing)? setIsEditing,
-    TResult Function(Option<ViewAction> action)? setAction,
+    TResult Function(String newName)? rename,
+    TResult Function()? delete,
+    TResult Function(Either<View, WorkspaceError> result)? viewDidUpdate,
     required TResult orElse(),
   }) {
     if (setIsEditing != null) {
@@ -295,9 +293,11 @@ class _$SetEditing implements SetEditing {
   @override
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
-    required TResult Function(SetSelected value) setIsSelected,
+    required TResult Function(Initial value) initial,
     required TResult Function(SetEditing value) setIsEditing,
-    required TResult Function(SetAction value) setAction,
+    required TResult Function(Rename value) rename,
+    required TResult Function(Delete value) delete,
+    required TResult Function(ViewDidUpdate value) viewDidUpdate,
   }) {
     return setIsEditing(this);
   }
@@ -305,9 +305,11 @@ class _$SetEditing implements SetEditing {
   @override
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
-    TResult Function(SetSelected value)? setIsSelected,
+    TResult Function(Initial value)? initial,
     TResult Function(SetEditing value)? setIsEditing,
-    TResult Function(SetAction value)? setAction,
+    TResult Function(Rename value)? rename,
+    TResult Function(Delete value)? delete,
+    TResult Function(ViewDidUpdate value)? viewDidUpdate,
     required TResult orElse(),
   }) {
     if (setIsEditing != null) {
@@ -327,84 +329,312 @@ abstract class SetEditing implements ViewEvent {
 }
 
 /// @nodoc
-abstract class $SetActionCopyWith<$Res> {
-  factory $SetActionCopyWith(SetAction value, $Res Function(SetAction) then) =
-      _$SetActionCopyWithImpl<$Res>;
-  $Res call({Option<ViewAction> action});
+abstract class $RenameCopyWith<$Res> {
+  factory $RenameCopyWith(Rename value, $Res Function(Rename) then) =
+      _$RenameCopyWithImpl<$Res>;
+  $Res call({String newName});
+}
+
+/// @nodoc
+class _$RenameCopyWithImpl<$Res> extends _$ViewEventCopyWithImpl<$Res>
+    implements $RenameCopyWith<$Res> {
+  _$RenameCopyWithImpl(Rename _value, $Res Function(Rename) _then)
+      : super(_value, (v) => _then(v as Rename));
+
+  @override
+  Rename get _value => super._value as Rename;
+
+  @override
+  $Res call({
+    Object? newName = freezed,
+  }) {
+    return _then(Rename(
+      newName == freezed
+          ? _value.newName
+          : newName // ignore: cast_nullable_to_non_nullable
+              as String,
+    ));
+  }
+}
+
+/// @nodoc
+
+class _$Rename implements Rename {
+  const _$Rename(this.newName);
+
+  @override
+  final String newName;
+
+  @override
+  String toString() {
+    return 'ViewEvent.rename(newName: $newName)';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) ||
+        (other is Rename &&
+            (identical(other.newName, newName) ||
+                const DeepCollectionEquality().equals(other.newName, newName)));
+  }
+
+  @override
+  int get hashCode =>
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(newName);
+
+  @JsonKey(ignore: true)
+  @override
+  $RenameCopyWith<Rename> get copyWith =>
+      _$RenameCopyWithImpl<Rename>(this, _$identity);
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(bool isEditing) setIsEditing,
+    required TResult Function(String newName) rename,
+    required TResult Function() delete,
+    required TResult Function(Either<View, WorkspaceError> result)
+        viewDidUpdate,
+  }) {
+    return rename(newName);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(bool isEditing)? setIsEditing,
+    TResult Function(String newName)? rename,
+    TResult Function()? delete,
+    TResult Function(Either<View, WorkspaceError> result)? viewDidUpdate,
+    required TResult orElse(),
+  }) {
+    if (rename != null) {
+      return rename(newName);
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Initial value) initial,
+    required TResult Function(SetEditing value) setIsEditing,
+    required TResult Function(Rename value) rename,
+    required TResult Function(Delete value) delete,
+    required TResult Function(ViewDidUpdate value) viewDidUpdate,
+  }) {
+    return rename(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Initial value)? initial,
+    TResult Function(SetEditing value)? setIsEditing,
+    TResult Function(Rename value)? rename,
+    TResult Function(Delete value)? delete,
+    TResult Function(ViewDidUpdate value)? viewDidUpdate,
+    required TResult orElse(),
+  }) {
+    if (rename != null) {
+      return rename(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class Rename implements ViewEvent {
+  const factory Rename(String newName) = _$Rename;
+
+  String get newName => throw _privateConstructorUsedError;
+  @JsonKey(ignore: true)
+  $RenameCopyWith<Rename> get copyWith => throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $DeleteCopyWith<$Res> {
+  factory $DeleteCopyWith(Delete value, $Res Function(Delete) then) =
+      _$DeleteCopyWithImpl<$Res>;
 }
 
 /// @nodoc
-class _$SetActionCopyWithImpl<$Res> extends _$ViewEventCopyWithImpl<$Res>
-    implements $SetActionCopyWith<$Res> {
-  _$SetActionCopyWithImpl(SetAction _value, $Res Function(SetAction) _then)
-      : super(_value, (v) => _then(v as SetAction));
+class _$DeleteCopyWithImpl<$Res> extends _$ViewEventCopyWithImpl<$Res>
+    implements $DeleteCopyWith<$Res> {
+  _$DeleteCopyWithImpl(Delete _value, $Res Function(Delete) _then)
+      : super(_value, (v) => _then(v as Delete));
 
   @override
-  SetAction get _value => super._value as SetAction;
+  Delete get _value => super._value as Delete;
+}
+
+/// @nodoc
+
+class _$Delete implements Delete {
+  const _$Delete();
+
+  @override
+  String toString() {
+    return 'ViewEvent.delete()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is Delete);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(bool isEditing) setIsEditing,
+    required TResult Function(String newName) rename,
+    required TResult Function() delete,
+    required TResult Function(Either<View, WorkspaceError> result)
+        viewDidUpdate,
+  }) {
+    return delete();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(bool isEditing)? setIsEditing,
+    TResult Function(String newName)? rename,
+    TResult Function()? delete,
+    TResult Function(Either<View, WorkspaceError> result)? viewDidUpdate,
+    required TResult orElse(),
+  }) {
+    if (delete != null) {
+      return delete();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Initial value) initial,
+    required TResult Function(SetEditing value) setIsEditing,
+    required TResult Function(Rename value) rename,
+    required TResult Function(Delete value) delete,
+    required TResult Function(ViewDidUpdate value) viewDidUpdate,
+  }) {
+    return delete(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Initial value)? initial,
+    TResult Function(SetEditing value)? setIsEditing,
+    TResult Function(Rename value)? rename,
+    TResult Function(Delete value)? delete,
+    TResult Function(ViewDidUpdate value)? viewDidUpdate,
+    required TResult orElse(),
+  }) {
+    if (delete != null) {
+      return delete(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class Delete implements ViewEvent {
+  const factory Delete() = _$Delete;
+}
+
+/// @nodoc
+abstract class $ViewDidUpdateCopyWith<$Res> {
+  factory $ViewDidUpdateCopyWith(
+          ViewDidUpdate value, $Res Function(ViewDidUpdate) then) =
+      _$ViewDidUpdateCopyWithImpl<$Res>;
+  $Res call({Either<View, WorkspaceError> result});
+}
+
+/// @nodoc
+class _$ViewDidUpdateCopyWithImpl<$Res> extends _$ViewEventCopyWithImpl<$Res>
+    implements $ViewDidUpdateCopyWith<$Res> {
+  _$ViewDidUpdateCopyWithImpl(
+      ViewDidUpdate _value, $Res Function(ViewDidUpdate) _then)
+      : super(_value, (v) => _then(v as ViewDidUpdate));
+
+  @override
+  ViewDidUpdate get _value => super._value as ViewDidUpdate;
 
   @override
   $Res call({
-    Object? action = freezed,
+    Object? result = freezed,
   }) {
-    return _then(SetAction(
-      action == freezed
-          ? _value.action
-          : action // ignore: cast_nullable_to_non_nullable
-              as Option<ViewAction>,
+    return _then(ViewDidUpdate(
+      result == freezed
+          ? _value.result
+          : result // ignore: cast_nullable_to_non_nullable
+              as Either<View, WorkspaceError>,
     ));
   }
 }
 
 /// @nodoc
 
-class _$SetAction implements SetAction {
-  const _$SetAction(this.action);
+class _$ViewDidUpdate implements ViewDidUpdate {
+  const _$ViewDidUpdate(this.result);
 
   @override
-  final Option<ViewAction> action;
+  final Either<View, WorkspaceError> result;
 
   @override
   String toString() {
-    return 'ViewEvent.setAction(action: $action)';
+    return 'ViewEvent.viewDidUpdate(result: $result)';
   }
 
   @override
   bool operator ==(dynamic other) {
     return identical(this, other) ||
-        (other is SetAction &&
-            (identical(other.action, action) ||
-                const DeepCollectionEquality().equals(other.action, action)));
+        (other is ViewDidUpdate &&
+            (identical(other.result, result) ||
+                const DeepCollectionEquality().equals(other.result, result)));
   }
 
   @override
   int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(action);
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(result);
 
   @JsonKey(ignore: true)
   @override
-  $SetActionCopyWith<SetAction> get copyWith =>
-      _$SetActionCopyWithImpl<SetAction>(this, _$identity);
+  $ViewDidUpdateCopyWith<ViewDidUpdate> get copyWith =>
+      _$ViewDidUpdateCopyWithImpl<ViewDidUpdate>(this, _$identity);
 
   @override
   @optionalTypeArgs
   TResult when<TResult extends Object?>({
-    required TResult Function(bool isSelected) setIsSelected,
+    required TResult Function() initial,
     required TResult Function(bool isEditing) setIsEditing,
-    required TResult Function(Option<ViewAction> action) setAction,
+    required TResult Function(String newName) rename,
+    required TResult Function() delete,
+    required TResult Function(Either<View, WorkspaceError> result)
+        viewDidUpdate,
   }) {
-    return setAction(action);
+    return viewDidUpdate(result);
   }
 
   @override
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
-    TResult Function(bool isSelected)? setIsSelected,
+    TResult Function()? initial,
     TResult Function(bool isEditing)? setIsEditing,
-    TResult Function(Option<ViewAction> action)? setAction,
+    TResult Function(String newName)? rename,
+    TResult Function()? delete,
+    TResult Function(Either<View, WorkspaceError> result)? viewDidUpdate,
     required TResult orElse(),
   }) {
-    if (setAction != null) {
-      return setAction(action);
+    if (viewDidUpdate != null) {
+      return viewDidUpdate(result);
     }
     return orElse();
   }
@@ -412,34 +642,39 @@ class _$SetAction implements SetAction {
   @override
   @optionalTypeArgs
   TResult map<TResult extends Object?>({
-    required TResult Function(SetSelected value) setIsSelected,
+    required TResult Function(Initial value) initial,
     required TResult Function(SetEditing value) setIsEditing,
-    required TResult Function(SetAction value) setAction,
+    required TResult Function(Rename value) rename,
+    required TResult Function(Delete value) delete,
+    required TResult Function(ViewDidUpdate value) viewDidUpdate,
   }) {
-    return setAction(this);
+    return viewDidUpdate(this);
   }
 
   @override
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
-    TResult Function(SetSelected value)? setIsSelected,
+    TResult Function(Initial value)? initial,
     TResult Function(SetEditing value)? setIsEditing,
-    TResult Function(SetAction value)? setAction,
+    TResult Function(Rename value)? rename,
+    TResult Function(Delete value)? delete,
+    TResult Function(ViewDidUpdate value)? viewDidUpdate,
     required TResult orElse(),
   }) {
-    if (setAction != null) {
-      return setAction(this);
+    if (viewDidUpdate != null) {
+      return viewDidUpdate(this);
     }
     return orElse();
   }
 }
 
-abstract class SetAction implements ViewEvent {
-  const factory SetAction(Option<ViewAction> action) = _$SetAction;
+abstract class ViewDidUpdate implements ViewEvent {
+  const factory ViewDidUpdate(Either<View, WorkspaceError> result) =
+      _$ViewDidUpdate;
 
-  Option<ViewAction> get action => throw _privateConstructorUsedError;
+  Either<View, WorkspaceError> get result => throw _privateConstructorUsedError;
   @JsonKey(ignore: true)
-  $SetActionCopyWith<SetAction> get copyWith =>
+  $ViewDidUpdateCopyWith<ViewDidUpdate> get copyWith =>
       throw _privateConstructorUsedError;
 }
 
@@ -449,15 +684,11 @@ class _$ViewStateTearOff {
 
   _ViewState call(
       {required View view,
-      required bool isSelected,
       required bool isEditing,
-      required Option<ViewAction> action,
       required Either<Unit, WorkspaceError> successOrFailure}) {
     return _ViewState(
       view: view,
-      isSelected: isSelected,
       isEditing: isEditing,
-      action: action,
       successOrFailure: successOrFailure,
     );
   }
@@ -469,9 +700,7 @@ const $ViewState = _$ViewStateTearOff();
 /// @nodoc
 mixin _$ViewState {
   View get view => throw _privateConstructorUsedError;
-  bool get isSelected => throw _privateConstructorUsedError;
   bool get isEditing => throw _privateConstructorUsedError;
-  Option<ViewAction> get action => throw _privateConstructorUsedError;
   Either<Unit, WorkspaceError> get successOrFailure =>
       throw _privateConstructorUsedError;
 
@@ -486,9 +715,7 @@ abstract class $ViewStateCopyWith<$Res> {
       _$ViewStateCopyWithImpl<$Res>;
   $Res call(
       {View view,
-      bool isSelected,
       bool isEditing,
-      Option<ViewAction> action,
       Either<Unit, WorkspaceError> successOrFailure});
 }
 
@@ -503,9 +730,7 @@ class _$ViewStateCopyWithImpl<$Res> implements $ViewStateCopyWith<$Res> {
   @override
   $Res call({
     Object? view = freezed,
-    Object? isSelected = freezed,
     Object? isEditing = freezed,
-    Object? action = freezed,
     Object? successOrFailure = freezed,
   }) {
     return _then(_value.copyWith(
@@ -513,18 +738,10 @@ class _$ViewStateCopyWithImpl<$Res> implements $ViewStateCopyWith<$Res> {
           ? _value.view
           : view // ignore: cast_nullable_to_non_nullable
               as View,
-      isSelected: isSelected == freezed
-          ? _value.isSelected
-          : isSelected // ignore: cast_nullable_to_non_nullable
-              as bool,
       isEditing: isEditing == freezed
           ? _value.isEditing
           : isEditing // ignore: cast_nullable_to_non_nullable
               as bool,
-      action: action == freezed
-          ? _value.action
-          : action // ignore: cast_nullable_to_non_nullable
-              as Option<ViewAction>,
       successOrFailure: successOrFailure == freezed
           ? _value.successOrFailure
           : successOrFailure // ignore: cast_nullable_to_non_nullable
@@ -541,9 +758,7 @@ abstract class _$ViewStateCopyWith<$Res> implements $ViewStateCopyWith<$Res> {
   @override
   $Res call(
       {View view,
-      bool isSelected,
       bool isEditing,
-      Option<ViewAction> action,
       Either<Unit, WorkspaceError> successOrFailure});
 }
 
@@ -559,9 +774,7 @@ class __$ViewStateCopyWithImpl<$Res> extends _$ViewStateCopyWithImpl<$Res>
   @override
   $Res call({
     Object? view = freezed,
-    Object? isSelected = freezed,
     Object? isEditing = freezed,
-    Object? action = freezed,
     Object? successOrFailure = freezed,
   }) {
     return _then(_ViewState(
@@ -569,18 +782,10 @@ class __$ViewStateCopyWithImpl<$Res> extends _$ViewStateCopyWithImpl<$Res>
           ? _value.view
           : view // ignore: cast_nullable_to_non_nullable
               as View,
-      isSelected: isSelected == freezed
-          ? _value.isSelected
-          : isSelected // ignore: cast_nullable_to_non_nullable
-              as bool,
       isEditing: isEditing == freezed
           ? _value.isEditing
           : isEditing // ignore: cast_nullable_to_non_nullable
               as bool,
-      action: action == freezed
-          ? _value.action
-          : action // ignore: cast_nullable_to_non_nullable
-              as Option<ViewAction>,
       successOrFailure: successOrFailure == freezed
           ? _value.successOrFailure
           : successOrFailure // ignore: cast_nullable_to_non_nullable
@@ -594,25 +799,19 @@ class __$ViewStateCopyWithImpl<$Res> extends _$ViewStateCopyWithImpl<$Res>
 class _$_ViewState implements _ViewState {
   const _$_ViewState(
       {required this.view,
-      required this.isSelected,
       required this.isEditing,
-      required this.action,
       required this.successOrFailure});
 
   @override
   final View view;
   @override
-  final bool isSelected;
-  @override
   final bool isEditing;
   @override
-  final Option<ViewAction> action;
-  @override
   final Either<Unit, WorkspaceError> successOrFailure;
 
   @override
   String toString() {
-    return 'ViewState(view: $view, isSelected: $isSelected, isEditing: $isEditing, action: $action, successOrFailure: $successOrFailure)';
+    return 'ViewState(view: $view, isEditing: $isEditing, successOrFailure: $successOrFailure)';
   }
 
   @override
@@ -621,14 +820,9 @@ class _$_ViewState implements _ViewState {
         (other is _ViewState &&
             (identical(other.view, view) ||
                 const DeepCollectionEquality().equals(other.view, view)) &&
-            (identical(other.isSelected, isSelected) ||
-                const DeepCollectionEquality()
-                    .equals(other.isSelected, isSelected)) &&
             (identical(other.isEditing, isEditing) ||
                 const DeepCollectionEquality()
                     .equals(other.isEditing, isEditing)) &&
-            (identical(other.action, action) ||
-                const DeepCollectionEquality().equals(other.action, action)) &&
             (identical(other.successOrFailure, successOrFailure) ||
                 const DeepCollectionEquality()
                     .equals(other.successOrFailure, successOrFailure)));
@@ -638,9 +832,7 @@ class _$_ViewState implements _ViewState {
   int get hashCode =>
       runtimeType.hashCode ^
       const DeepCollectionEquality().hash(view) ^
-      const DeepCollectionEquality().hash(isSelected) ^
       const DeepCollectionEquality().hash(isEditing) ^
-      const DeepCollectionEquality().hash(action) ^
       const DeepCollectionEquality().hash(successOrFailure);
 
   @JsonKey(ignore: true)
@@ -652,20 +844,14 @@ class _$_ViewState implements _ViewState {
 abstract class _ViewState implements ViewState {
   const factory _ViewState(
       {required View view,
-      required bool isSelected,
       required bool isEditing,
-      required Option<ViewAction> action,
       required Either<Unit, WorkspaceError> successOrFailure}) = _$_ViewState;
 
   @override
   View get view => throw _privateConstructorUsedError;
   @override
-  bool get isSelected => throw _privateConstructorUsedError;
-  @override
   bool get isEditing => throw _privateConstructorUsedError;
   @override
-  Option<ViewAction> get action => throw _privateConstructorUsedError;
-  @override
   Either<Unit, WorkspaceError> get successOrFailure =>
       throw _privateConstructorUsedError;
   @override

+ 4 - 1
app_flowy/lib/workspace/domain/i_app.dart

@@ -13,7 +13,10 @@ abstract class IApp {
 }
 
 abstract class IAppListenr {
-  void start({AppCreateViewCallback? addViewCallback, AppUpdatedCallback? updatedCallback});
+  void start(
+      {AppCreateViewCallback? addViewCallback,
+      AppDeleteViewCallback? deleteViewCallback,
+      AppUpdatedCallback? updatedCallback});
 
   Future<void> stop();
 }

+ 1 - 1
app_flowy/lib/workspace/domain/i_view.dart

@@ -9,7 +9,7 @@ abstract class IView {
 
   Future<Either<Unit, WorkspaceError>> pushIntoTrash();
 
-  Future<Either<Unit, WorkspaceError>> rename(String newName);
+  Future<Either<View, WorkspaceError>> rename(String newName);
 }
 
 abstract class IViewListener {

+ 6 - 1
app_flowy/lib/workspace/infrastructure/deps_resolver.dart

@@ -67,7 +67,12 @@ class HomeDepsResolver {
     getIt.registerFactoryParam<AppListenBloc, String, void>(
         (appId, _) => AppListenBloc(getIt<IAppListenr>(param1: appId)));
 
-    getIt.registerFactoryParam<ViewBloc, View, void>((view, _) => ViewBloc(iViewImpl: getIt<IView>(param1: view)));
+    getIt.registerFactoryParam<ViewBloc, View, void>(
+      (view, _) => ViewBloc(
+        iViewImpl: getIt<IView>(param1: view),
+        listener: getIt<IViewListener>(param1: view),
+      ),
+    );
 
     getIt.registerFactoryParam<DocBloc, String, void>((docId, _) => DocBloc(iDocImpl: getIt<IDoc>(param1: docId)));
 

+ 7 - 4
app_flowy/lib/workspace/infrastructure/i_app_impl.dart

@@ -35,12 +35,15 @@ class IAppListenerhImpl extends IAppListenr {
   });
 
   @override
-  void start({AppCreateViewCallback? addViewCallback, AppUpdatedCallback? updatedCallback}) {
-    repo.startListen(createView: addViewCallback, update: updatedCallback);
+  Future<void> stop() async {
+    await repo.close();
   }
 
   @override
-  Future<void> stop() async {
-    await repo.close();
+  void start(
+      {AppCreateViewCallback? addViewCallback,
+      AppDeleteViewCallback? deleteViewCallback,
+      AppUpdatedCallback? updatedCallback}) {
+    repo.startListen(createView: addViewCallback, deleteView: deleteViewCallback, update: updatedCallback);
   }
 }

+ 7 - 2
app_flowy/lib/workspace/infrastructure/i_view_impl.dart

@@ -14,11 +14,16 @@ class IViewImpl extends IView {
 
   @override
   Future<Either<Unit, WorkspaceError>> pushIntoTrash() {
-    return repo.updateView(isTrash: true);
+    return repo.updateView(isTrash: true).then((result) {
+      return result.fold(
+        (_) => left(unit),
+        (error) => right(error),
+      );
+    });
   }
 
   @override
-  Future<Either<Unit, WorkspaceError>> rename(String newName) {
+  Future<Either<View, WorkspaceError>> rename(String newName) {
     return repo.updateView(name: newName);
   }
 }

+ 6 - 15
app_flowy/lib/workspace/infrastructure/repos/helper.dart

@@ -34,12 +34,10 @@ import 'package:dartz/dartz.dart';
 //   }
 // }
 
-typedef UserObservableCallback = void Function(
-    UserObservable, Either<Uint8List, UserError>);
+typedef UserObservableCallback = void Function(UserObservable, Either<Uint8List, UserError>);
 
 class UserObservableParser extends ObservableParser<UserObservable, UserError> {
-  UserObservableParser(
-      {required String id, required UserObservableCallback callback})
+  UserObservableParser({required String id, required UserObservableCallback callback})
       : super(
           id: id,
           callback: callback,
@@ -48,13 +46,10 @@ class UserObservableParser extends ObservableParser<UserObservable, UserError> {
         );
 }
 
-typedef WorkspaceObservableCallback = void Function(
-    WorkspaceObservable, Either<Uint8List, WorkspaceError>);
+typedef WorkspaceObservableCallback = void Function(WorkspaceObservable, Either<Uint8List, WorkspaceError>);
 
-class WorkspaceObservableParser
-    extends ObservableParser<WorkspaceObservable, WorkspaceError> {
-  WorkspaceObservableParser(
-      {required String id, required WorkspaceObservableCallback callback})
+class WorkspaceObservableParser extends ObservableParser<WorkspaceObservable, WorkspaceError> {
+  WorkspaceObservableParser({required String id, required WorkspaceObservableCallback callback})
       : super(
           id: id,
           callback: callback,
@@ -70,11 +65,7 @@ class ObservableParser<T, E> {
   T? Function(int) tyParser;
   E Function(Uint8List) errorParser;
 
-  ObservableParser(
-      {required this.id,
-      required this.callback,
-      required this.errorParser,
-      required this.tyParser});
+  ObservableParser({required this.id, required this.callback, required this.errorParser, required this.tyParser});
   void parse(ObservableSubject subject) {
     if (subject.id != id) {
       return;

+ 1 - 1
app_flowy/lib/workspace/infrastructure/repos/view_repo.dart

@@ -26,7 +26,7 @@ class ViewRepository {
     return WorkspaceEventReadView(request).send();
   }
 
-  Future<Either<Unit, WorkspaceError>> updateView({String? name, String? desc, bool? isTrash}) {
+  Future<Either<View, WorkspaceError>> updateView({String? name, String? desc, bool? isTrash}) {
     final request = UpdateViewRequest.create()..viewId = view.id;
 
     if (name != null) {

+ 39 - 36
app_flowy/lib/workspace/presentation/widgets/menu/widget/app/section/item.dart

@@ -9,7 +9,6 @@ import 'package:flowy_infra_ui/style_widget/hover.dart';
 import 'package:flowy_infra_ui/style_widget/icon_button.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
-import 'package:flowy_log/flowy_log.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -22,50 +21,43 @@ import 'package:app_flowy/workspace/presentation/widgets/menu/widget/app/menu_ap
 
 // ignore: must_be_immutable
 class ViewSectionItem extends StatelessWidget {
-  final ViewBloc bloc;
+  final bool isSelected;
+  final View view;
   final void Function(View) onSelected;
 
   ViewSectionItem({
     Key? key,
-    required View view,
-    required bool isSelected,
+    required this.view,
+    required this.isSelected,
     required this.onSelected,
-  })  : bloc = getIt<ViewBloc>(param1: view),
-        super(key: ValueKey(view.id)) {
-    bloc.add(ViewEvent.setIsSelected(isSelected));
-  }
+  }) : super(key: ValueKey('$view.id/$isSelected'));
 
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-
-    return BlocProvider.value(
-      value: bloc,
-      child: BlocListener<ViewBloc, ViewState>(
-        listenWhen: (p, c) => p.action != c.action,
-        listener: (context, state) {
-          state.action.fold(() => null, (action) {
-            Log.info('$action');
-          });
+    return MultiBlocProvider(
+      providers: [
+        BlocProvider(create: (ctx) => getIt<ViewBloc>(param1: view)..add(const ViewEvent.initial())),
+      ],
+      child: BlocBuilder<ViewBloc, ViewState>(
+        builder: (context, state) {
+          return InkWell(
+            onTap: () {
+              onSelected(context.read<ViewBloc>().state.view);
+              getIt<HomeStackManager>().setStack(state.view.intoStackContext());
+            },
+            child: FlowyHover(
+              config: HoverDisplayConfig(hoverColor: theme.bg3),
+              builder: (context, onHover) => _render(context, onHover, state),
+              isOnSelected: () => state.isEditing || isSelected,
+            ),
+          );
         },
-        child: BlocBuilder<ViewBloc, ViewState>(
-          builder: (context, state) {
-            return InkWell(
-              onTap: () => onSelected(context.read<ViewBloc>().state.view),
-              child: FlowyHover(
-                config: HoverDisplayConfig(hoverColor: theme.bg3),
-                builder: (context, onHover) => _render(context, onHover),
-                isOnSelected: () => state.isEditing || state.isSelected,
-              ),
-            );
-          },
-        ),
       ),
     );
   }
 
-  Widget _render(BuildContext context, bool onHover) {
-    final state = context.read<ViewBloc>().state;
+  Widget _render(BuildContext context, bool onHover, ViewState state) {
     List<Widget> children = [
       SizedBox(width: 16, height: 16, child: state.view.thumbnail()),
       const HSpace(6),
@@ -75,13 +67,10 @@ class ViewSectionItem extends StatelessWidget {
     if (onHover || state.isEditing) {
       children.add(const Spacer());
       children.add(ViewDisclosureButton(
-        onTap: () {
-          context.read<ViewBloc>().add(const ViewEvent.setIsEditing(true));
-          getIt<HomeStackManager>().setStack(state.view.intoStackContext());
-        },
+        onTap: () => context.read<ViewBloc>().add(const ViewEvent.setIsEditing(true)),
         onSelected: (action) {
           context.read<ViewBloc>().add(const ViewEvent.setIsEditing(false));
-          context.read<ViewBloc>().add(ViewEvent.setAction(action));
+          _handleAction(context, action);
         },
       ));
     }
@@ -94,6 +83,20 @@ class ViewSectionItem extends StatelessWidget {
       ),
     );
   }
+
+  void _handleAction(BuildContext context, dartz.Option<ViewAction> action) {
+    action.foldRight({}, (action, previous) {
+      switch (action) {
+        case ViewAction.rename:
+
+          // TODO: Handle this case.
+          break;
+        case ViewAction.delete:
+          context.read<ViewBloc>().add(const ViewEvent.delete());
+          break;
+      }
+    });
+  }
 }
 
 // [[Widget: LifeCycle]]

+ 2 - 2
app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -207,14 +207,14 @@ class WorkspaceEventUpdateView {
      UpdateViewRequest request;
      WorkspaceEventUpdateView(this.request);
 
-    Future<Either<Unit, WorkspaceError>> send() {
+    Future<Either<View, WorkspaceError>> send() {
     final request = FFIRequest.create()
           ..event = WorkspaceEvent.UpdateView.toString()
           ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
+           (okBytes) => left(View.fromBuffer(okBytes)),
            (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
         ));
     }

+ 0 - 1
rust-lib/flowy-dart-notify/src/lib.rs

@@ -72,7 +72,6 @@ impl DartNotifyBuilder {
             error,
         };
 
-        log::debug!("Notify {}", subject);
         match DartStreamSender::post(subject) {
             Ok(_) => {},
             Err(error) => log::error!("Send observable subject failed: {}", error),

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

@@ -40,7 +40,7 @@ pub enum WorkspaceEvent {
     #[event(input = "QueryViewRequest", output = "View")]
     ReadView          = 202,
 
-    #[event(input = "UpdateViewRequest")]
+    #[event(input = "UpdateViewRequest", output = "View")]
     UpdateView        = 203,
 
     #[event(input = "DeleteViewRequest")]

+ 32 - 26
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -58,7 +58,7 @@ impl ViewController {
             let _ = self.save_view(view.clone(), conn)?;
             self.document.create(CreateDocParams::new(&view.id, params.data))?;
 
-            let repeated_view = self.read_local_views_belong_to(&view.belong_to_id, conn)?;
+            let repeated_view = self.sql.read_views_belong_to(&view.belong_to_id, Some(false), conn)?;
             dart_notify(&view.belong_to_id, WorkspaceObservable::AppCreateView)
                 .payload(repeated_view)
                 .send();
@@ -96,7 +96,10 @@ impl ViewController {
             let view_table = self.sql.delete_view(&params.view_id, conn)?;
             let _ = self.document.delete(params.into())?;
 
-            let repeated_view = self.read_local_views_belong_to(&view_table.belong_to_id, conn)?;
+            let repeated_view = self
+                .sql
+                .read_views_belong_to(&view_table.belong_to_id, Some(false), conn)?;
+
             dart_notify(&view_table.belong_to_id, WorkspaceObservable::AppDeleteView)
                 .payload(repeated_view)
                 .send();
@@ -111,26 +114,45 @@ impl ViewController {
     pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
         // TODO: read from server
         let conn = self.database.db_connection()?;
-        let repeated_view = self.read_local_views_belong_to(belong_to_id, &*conn)?;
+        let repeated_view = self.sql.read_views_belong_to(belong_to_id, Some(false), &*conn)?;
         Ok(repeated_view)
     }
 
-    pub(crate) async fn update_view(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> {
+    #[tracing::instrument(level = "debug", skip(self, params), fields(dart_notify)  err)]
+    pub(crate) async fn update_view(&self, params: UpdateViewParams) -> Result<View, WorkspaceError> {
         let conn = &*self.database.db_connection()?;
         let changeset = ViewTableChangeset::new(params.clone());
         let view_id = changeset.id.clone();
 
-        conn.immediate_transaction::<_, WorkspaceError, _>(|| {
+        let updated_view = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.sql.update_view(changeset, conn)?;
             let view: View = self.sql.read_view(&view_id, None, conn)?.into();
-            dart_notify(&view_id, WorkspaceObservable::ViewUpdated)
-                .payload(view)
-                .send();
-            Ok(())
+
+            if params.is_trash.is_some() {
+                let repeated_view = self.sql.read_views_belong_to(&view.belong_to_id, Some(false), conn)?;
+                tracing::Span::current().record(
+                    "dart_notify",
+                    &format!("{:?}: {}", WorkspaceObservable::AppDeleteView, &view.belong_to_id).as_str(),
+                );
+                dart_notify(&view.belong_to_id, WorkspaceObservable::AppDeleteView)
+                    .payload(repeated_view)
+                    .send();
+            } else {
+                tracing::Span::current().record(
+                    "dart_notify",
+                    &format!("{:?}: {}", WorkspaceObservable::ViewUpdated, &view_id).as_str(),
+                );
+
+                dart_notify(&view_id, WorkspaceObservable::ViewUpdated)
+                    .payload(view.clone())
+                    .send();
+            }
+
+            Ok(view)
         })?;
 
         let _ = self.update_view_on_server(params);
-        Ok(())
+        Ok(updated_view)
     }
 
     pub(crate) async fn apply_doc_delta(&self, params: DocDelta) -> Result<DocDelta, WorkspaceError> {
@@ -197,20 +219,4 @@ impl ViewController {
         });
         Ok(())
     }
-
-    // belong_to_id will be the app_id or view_id.
-    fn read_local_views_belong_to(
-        &self,
-        belong_to_id: &str,
-        conn: &SqliteConnection,
-    ) -> Result<RepeatedView, WorkspaceError> {
-        let views = self
-            .sql
-            .read_views_belong_to(belong_to_id, conn)?
-            .into_iter()
-            .map(|view_table| view_table.into())
-            .collect::<Vec<View>>();
-
-        Ok(RepeatedView { items: views })
-    }
 }

+ 16 - 4
rust-lib/flowy-workspace/src/sql_tables/view/view_sql.rs

@@ -1,4 +1,5 @@
 use crate::{
+    entities::view::{RepeatedView, View},
     errors::WorkspaceError,
     sql_tables::view::{ViewTable, ViewTableChangeset},
 };
@@ -37,16 +38,27 @@ impl ViewTableSql {
         Ok(view_table)
     }
 
+    // belong_to_id will be the app_id or view_id.
     pub(crate) fn read_views_belong_to(
         &self,
         belong_to_id: &str,
+        is_trash: Option<bool>,
         conn: &SqliteConnection,
-    ) -> Result<Vec<ViewTable>, WorkspaceError> {
-        let view_tables = dsl::view_table
+    ) -> Result<RepeatedView, WorkspaceError> {
+        let mut filter = dsl::view_table
             .filter(view_table::belong_to_id.eq(belong_to_id))
-            .load::<ViewTable>(conn)?;
+            .into_boxed();
+        if let Some(is_trash) = is_trash {
+            filter = filter.filter(view_table::is_trash.eq(is_trash));
+        }
+        let view_tables = filter.load::<ViewTable>(conn)?;
+
+        let views = view_tables
+            .into_iter()
+            .map(|view_table| view_table.into())
+            .collect::<Vec<View>>();
 
-        Ok(view_tables)
+        Ok(RepeatedView { items: views })
     }
 
     pub(crate) fn update_view(