Browse Source

fix: open latest after deleting current view

appflowy 2 years ago
parent
commit
e3a1384f7f

+ 5 - 3
frontend/app_flowy/lib/plugins/board/board.dart

@@ -68,9 +68,11 @@ class GridPluginDisplay extends PluginDisplay {
   @override
   Widget buildWidget(PluginContext context) {
     notifier.isDeleted.addListener(() {
-      if (notifier.isDeleted.value) {
-        context.onDeleted(view);
-      }
+      notifier.isDeleted.value.fold(() => null, (deletedView) {
+        if (deletedView.hasIndex()) {
+          context.onDeleted(view, deletedView.index);
+        }
+      });
     });
 
     return BoardPage(key: ValueKey(view.id), view: view);

+ 16 - 5
frontend/app_flowy/lib/plugins/doc/document.dart

@@ -74,15 +74,26 @@ class DocumentPlugin extends Plugin<int> {
 class DocumentPluginDisplay extends PluginDisplay with NavigationItem {
   final ViewPluginNotifier notifier;
   ViewPB get view => notifier.view;
+  int? deletedViewIndex;
 
   DocumentPluginDisplay({required this.notifier, Key? key});
 
   @override
-  Widget buildWidget(PluginContext context) => DocumentPage(
-        view: view,
-        onDeleted: () => context.onDeleted(view),
-        key: ValueKey(view.id),
-      );
+  Widget buildWidget(PluginContext context) {
+    notifier.isDeleted.addListener(() {
+      notifier.isDeleted.value.fold(() => null, (deletedView) {
+        if (deletedView.hasIndex()) {
+          deletedViewIndex = deletedView.index;
+        }
+      });
+    });
+
+    return DocumentPage(
+      view: view,
+      onDeleted: () => context.onDeleted(view, deletedViewIndex),
+      key: ValueKey(view.id),
+    );
+  }
 
   @override
   Widget get leftBarItem => ViewLeftBarItem(view: view);

+ 5 - 3
frontend/app_flowy/lib/plugins/grid/grid.dart

@@ -70,9 +70,11 @@ class GridPluginDisplay extends PluginDisplay {
   @override
   Widget buildWidget(PluginContext context) {
     notifier.isDeleted.addListener(() {
-      if (notifier.isDeleted.value) {
-        context.onDeleted(view);
-      }
+      notifier.isDeleted.value.fold(() => null, (deletedView) {
+        if (deletedView.hasIndex()) {
+          context.onDeleted(view, deletedView.index);
+        }
+      });
     });
 
     return GridPage(key: ValueKey(view.id), view: view);

+ 4 - 5
frontend/app_flowy/lib/plugins/util.dart

@@ -1,15 +1,16 @@
 import 'package:app_flowy/startup/plugin/plugin.dart';
 import 'package:app_flowy/workspace/application/view/view_listener.dart';
+import 'package:dartz/dartz.dart';
 import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
 import 'package:flutter/material.dart';
 
-class ViewPluginNotifier extends PluginNotifier {
+class ViewPluginNotifier extends PluginNotifier<Option<DeletedViewPB>> {
   final ViewListener? _viewListener;
   ViewPB view;
 
   @override
-  final ValueNotifier<bool> isDeleted = ValueNotifier(false);
+  final ValueNotifier<Option<DeletedViewPB>> isDeleted = ValueNotifier(none());
 
   @override
   final ValueNotifier<int> isDisplayChanged = ValueNotifier(0);
@@ -27,9 +28,7 @@ class ViewPluginNotifier extends PluginNotifier {
       );
     }, onViewMoveToTrash: (result) {
       result.fold(
-        (deletedView) {
-          isDeleted.value = true;
-        },
+        (deletedView) => isDeleted.value = some(deletedView),
         (err) => Log.error(err),
       );
     });

+ 3 - 3
frontend/app_flowy/lib/startup/plugin/plugin.dart

@@ -32,9 +32,9 @@ abstract class Plugin<T> {
   }
 }
 
-abstract class PluginNotifier {
+abstract class PluginNotifier<T> {
   /// Notify if the plugin get deleted
-  ValueNotifier<bool> get isDeleted;
+  ValueNotifier<T> get isDeleted;
 
   /// Notify if the [PluginDisplay]'s content was changed
   ValueNotifier<int> get isDisplayChanged;
@@ -67,7 +67,7 @@ abstract class PluginDisplay with NavigationItem {
 
 class PluginContext {
   // calls when widget of the plugin get deleted
-  final Function(ViewPB) onDeleted;
+  final Function(ViewPB, int?) onDeleted;
 
   PluginContext({required this.onDeleted});
 }

+ 3 - 3
frontend/app_flowy/lib/workspace/application/view/view_listener.dart

@@ -16,7 +16,7 @@ typedef UpdateViewNotifiedValue = Either<ViewPB, FlowyError>;
 // Restore the view from trash
 typedef RestoreViewNotifiedValue = Either<ViewPB, FlowyError>;
 // Move the view to trash
-typedef MoveToTrashNotifiedValue = Either<ViewIdPB, FlowyError>;
+typedef MoveToTrashNotifiedValue = Either<DeletedViewPB, FlowyError>;
 
 class ViewListener {
   StreamSubscription<SubscribeObject>? _subscription;
@@ -98,8 +98,8 @@ class ViewListener {
         break;
       case FolderNotification.ViewMoveToTrash:
         result.fold(
-          (payload) =>
-              _moveToTrashNotifier.value = left(ViewIdPB.fromBuffer(payload)),
+          (payload) => _moveToTrashNotifier.value =
+              left(DeletedViewPB.fromBuffer(payload)),
           (error) => _moveToTrashNotifier.value = right(error),
         );
         break;

+ 6 - 2
frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart

@@ -251,14 +251,18 @@ class HomeScreenStackAdaptor extends HomeStackDelegate {
   });
 
   @override
-  void didDeleteStackWidget(ViewPB view) {
+  void didDeleteStackWidget(ViewPB view, int? index) {
     final homeService = HomeService();
     homeService.readApp(appId: view.appId).then((result) {
       result.fold(
         (appPB) {
           final List<ViewPB> views = appPB.belongings.items;
           if (views.isNotEmpty) {
-            final lastView = views.last;
+            var lastView = views.last;
+            if (index != null && index != 0 && views.length > index - 1) {
+              lastView = views[index - 1];
+            }
+
             final plugin = makePlugin(
               pluginType: lastView.pluginType,
               data: lastView,

+ 7 - 5
frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart

@@ -18,7 +18,7 @@ import 'home_layout.dart';
 typedef NavigationCallback = void Function(String id);
 
 abstract class HomeStackDelegate {
-  void didDeleteStackWidget(ViewPB view);
+  void didDeleteStackWidget(ViewPB view, int? index);
 }
 
 class HomeStack extends StatelessWidget {
@@ -41,9 +41,11 @@ class HomeStack extends StatelessWidget {
           child: Container(
             color: theme.surface,
             child: FocusTraversalGroup(
-              child: getIt<HomeStackManager>().stackWidget(onDeleted: (view) {
-                delegate.didDeleteStackWidget(view);
-              }),
+              child: getIt<HomeStackManager>().stackWidget(
+                onDeleted: (view, index) {
+                  delegate.didDeleteStackWidget(view, index);
+                },
+              ),
             ),
           ),
         ),
@@ -168,7 +170,7 @@ class HomeStackManager {
     );
   }
 
-  Widget stackWidget({required Function(ViewPB) onDeleted}) {
+  Widget stackWidget({required Function(ViewPB, int?) onDeleted}) {
     return MultiProvider(
       providers: [ChangeNotifierProvider.value(value: _notifier)],
       child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) {

+ 9 - 0
frontend/rust-lib/flowy-folder/src/entities/view.rs

@@ -206,6 +206,15 @@ impl std::convert::From<&str> for ViewIdPB {
     }
 }
 
+#[derive(Default, ProtoBuf, Clone, Debug)]
+pub struct DeletedViewPB {
+    #[pb(index = 1)]
+    pub view_id: String,
+
+    #[pb(index = 2, one_of)]
+    pub index: Option<i32>,
+}
+
 impl std::ops::Deref for ViewIdPB {
     type Target = str;
 

+ 23 - 7
frontend/rust-lib/flowy-folder/src/services/view/controller.rs

@@ -1,5 +1,5 @@
 pub use crate::entities::view::ViewDataTypePB;
-use crate::entities::{ViewInfoPB, ViewLayoutTypePB};
+use crate::entities::{DeletedViewPB, ViewInfoPB, ViewLayoutTypePB};
 use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
 use crate::{
     dart_notification::{send_dart_notification, FolderNotification},
@@ -122,12 +122,12 @@ impl ViewController {
             .await
     }
 
-    #[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)]
-    pub(crate) async fn read_view(&self, view_id: ViewIdPB) -> Result<ViewRevision, FlowyError> {
+    #[tracing::instrument(level = "debug", skip(self, view_id), err)]
+    pub(crate) async fn read_view(&self, view_id: &str) -> Result<ViewRevision, FlowyError> {
         let view_rev = self
             .persistence
             .begin_transaction(|transaction| {
-                let view = transaction.read_view(&view_id.value)?;
+                let view = transaction.read_view(view_id)?;
                 let trash_ids = self.trash_controller.read_trash_ids(&transaction)?;
                 if trash_ids.contains(&view.id) {
                     return Err(FlowyError::record_not_found());
@@ -135,7 +135,6 @@ impl ViewController {
                 Ok(view)
             })
             .await?;
-        let _ = self.read_view_on_server(view_id);
         Ok(view_rev)
     }
 
@@ -201,9 +200,26 @@ impl ViewController {
                 let _ = KV::remove(LATEST_VIEW_ID);
             }
         }
-        let view_id_pb = ViewIdPB::from(view_id.as_str());
+
+        let deleted_view = self
+            .persistence
+            .begin_transaction(|transaction| {
+                let view = transaction.read_view(&view_id)?;
+                let views = read_belonging_views_on_local(&view.app_id, self.trash_controller.clone(), &transaction)?;
+
+                let index = views
+                    .iter()
+                    .position(|view| view.id == view_id)
+                    .and_then(|index| Some(index as i32));
+                Ok(DeletedViewPB {
+                    view_id: view_id.clone(),
+                    index,
+                })
+            })
+            .await?;
+
         send_dart_notification(&view_id, FolderNotification::ViewMoveToTrash)
-            .payload(view_id_pb)
+            .payload(deleted_view)
             .send();
 
         let processor = self.get_data_processor_from_view_id(&view_id).await?;

+ 1 - 1
frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs

@@ -31,7 +31,7 @@ pub(crate) async fn read_view_handler(
     controller: AppData<Arc<ViewController>>,
 ) -> DataResult<ViewPB, FlowyError> {
     let view_id: ViewIdPB = data.into_inner();
-    let view_rev = controller.read_view(view_id.clone()).await?;
+    let view_rev = controller.read_view(&view_id.value).await?;
     data_result(view_rev.into())
 }