diff --git a/frontend/app_flowy/lib/plugins/board/board.dart b/frontend/app_flowy/lib/plugins/board/board.dart index 73fff5b639..a53739f00a 100644 --- a/frontend/app_flowy/lib/plugins/board/board.dart +++ b/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); diff --git a/frontend/app_flowy/lib/plugins/doc/document.dart b/frontend/app_flowy/lib/plugins/doc/document.dart index b9cd952bd8..7403a01a91 100644 --- a/frontend/app_flowy/lib/plugins/doc/document.dart +++ b/frontend/app_flowy/lib/plugins/doc/document.dart @@ -74,15 +74,26 @@ class DocumentPlugin extends Plugin { 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); diff --git a/frontend/app_flowy/lib/plugins/grid/grid.dart b/frontend/app_flowy/lib/plugins/grid/grid.dart index 45dabb6fb5..5d7f4b3bdb 100644 --- a/frontend/app_flowy/lib/plugins/grid/grid.dart +++ b/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); diff --git a/frontend/app_flowy/lib/plugins/util.dart b/frontend/app_flowy/lib/plugins/util.dart index 9d3e5bf528..db57d7f526 100644 --- a/frontend/app_flowy/lib/plugins/util.dart +++ b/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> { final ViewListener? _viewListener; ViewPB view; @override - final ValueNotifier isDeleted = ValueNotifier(false); + final ValueNotifier> isDeleted = ValueNotifier(none()); @override final ValueNotifier 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), ); }); diff --git a/frontend/app_flowy/lib/startup/plugin/plugin.dart b/frontend/app_flowy/lib/startup/plugin/plugin.dart index 9c65f804d3..a8f58562fb 100644 --- a/frontend/app_flowy/lib/startup/plugin/plugin.dart +++ b/frontend/app_flowy/lib/startup/plugin/plugin.dart @@ -32,9 +32,9 @@ abstract class Plugin { } } -abstract class PluginNotifier { +abstract class PluginNotifier { /// Notify if the plugin get deleted - ValueNotifier get isDeleted; + ValueNotifier get isDeleted; /// Notify if the [PluginDisplay]'s content was changed ValueNotifier 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}); } diff --git a/frontend/app_flowy/lib/workspace/application/view/view_listener.dart b/frontend/app_flowy/lib/workspace/application/view/view_listener.dart index 7629b71edc..6c575375f3 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_listener.dart @@ -16,7 +16,7 @@ typedef UpdateViewNotifiedValue = Either; // Restore the view from trash typedef RestoreViewNotifiedValue = Either; // Move the view to trash -typedef MoveToTrashNotifiedValue = Either; +typedef MoveToTrashNotifiedValue = Either; class ViewListener { StreamSubscription? _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; diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart index 2839e8eeb2..1d46ade005 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/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 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, diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart index 9617abac53..4ae0420b36 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart +++ b/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().stackWidget(onDeleted: (view) { - delegate.didDeleteStackWidget(view); - }), + child: getIt().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) { diff --git a/frontend/rust-lib/flowy-folder/src/entities/view.rs b/frontend/rust-lib/flowy-folder/src/entities/view.rs index af66502907..61e63c53cb 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/view.rs +++ b/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, +} + impl std::ops::Deref for ViewIdPB { type Target = str; diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs index 402a68813b..b2ad1b8284 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs +++ b/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 { + #[tracing::instrument(level = "debug", skip(self, view_id), err)] + pub(crate) async fn read_view(&self, view_id: &str) -> Result { 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?; diff --git a/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs index be7d61d9fe..2a7736e05e 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs @@ -31,7 +31,7 @@ pub(crate) async fn read_view_handler( controller: AppData>, ) -> DataResult { 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()) }