manager.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. use std::collections::{HashMap, HashSet};
  2. use std::ops::Deref;
  3. use std::sync::{Arc, Weak};
  4. use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
  5. use collab::core::collab_state::CollabState;
  6. use collab_folder::core::{
  7. Folder, FolderContext, TrashChange, TrashChangeReceiver, TrashInfo, TrashRecord, View,
  8. ViewChange, ViewChangeReceiver, ViewLayout, Workspace,
  9. };
  10. use parking_lot::Mutex;
  11. use tokio_stream::wrappers::WatchStream;
  12. use tokio_stream::StreamExt;
  13. use tracing::{event, Level};
  14. use flowy_error::{ErrorCode, FlowyError, FlowyResult};
  15. use lib_infra::util::timestamp;
  16. use crate::deps::{FolderCloudService, FolderUser};
  17. use crate::entities::{
  18. view_pb_with_child_views, CreateViewParams, CreateWorkspaceParams, DeletedViewPB,
  19. RepeatedTrashPB, RepeatedViewPB, RepeatedWorkspacePB, UpdateViewParams, ViewPB,
  20. };
  21. use crate::notification::{
  22. send_notification, send_workspace_notification, send_workspace_setting_notification,
  23. FolderNotification,
  24. };
  25. use crate::share::ImportParams;
  26. use crate::user_default::DefaultFolderBuilder;
  27. use crate::view_operation::{
  28. create_view, gen_view_id, FolderOperationHandler, FolderOperationHandlers,
  29. };
  30. pub struct Folder2Manager {
  31. mutex_folder: Arc<MutexFolder>,
  32. collab_builder: Arc<AppFlowyCollabBuilder>,
  33. user: Arc<dyn FolderUser>,
  34. operation_handlers: FolderOperationHandlers,
  35. cloud_service: Arc<dyn FolderCloudService>,
  36. }
  37. unsafe impl Send for Folder2Manager {}
  38. unsafe impl Sync for Folder2Manager {}
  39. impl Folder2Manager {
  40. pub async fn new(
  41. user: Arc<dyn FolderUser>,
  42. collab_builder: Arc<AppFlowyCollabBuilder>,
  43. operation_handlers: FolderOperationHandlers,
  44. cloud_service: Arc<dyn FolderCloudService>,
  45. ) -> FlowyResult<Self> {
  46. let mutex_folder = Arc::new(MutexFolder::default());
  47. let manager = Self {
  48. user,
  49. mutex_folder,
  50. collab_builder,
  51. operation_handlers,
  52. cloud_service,
  53. };
  54. Ok(manager)
  55. }
  56. pub async fn get_current_workspace(&self) -> FlowyResult<Workspace> {
  57. match self.with_folder(None, |folder| folder.get_current_workspace()) {
  58. None => Err(FlowyError::record_not_found().context("Can not find the workspace")),
  59. Some(workspace) => Ok(workspace),
  60. }
  61. }
  62. /// Return a list of views of the current workspace.
  63. /// Only the first level of child views are included.
  64. pub async fn get_current_workspace_views(&self) -> FlowyResult<Vec<ViewPB>> {
  65. let workspace_id = self
  66. .mutex_folder
  67. .lock()
  68. .as_ref()
  69. .map(|folder| folder.get_current_workspace_id());
  70. if let Some(Some(workspace_id)) = workspace_id {
  71. self.get_workspace_views(&workspace_id).await
  72. } else {
  73. Ok(vec![])
  74. }
  75. }
  76. pub async fn get_workspace_views(&self, workspace_id: &str) -> FlowyResult<Vec<ViewPB>> {
  77. let views = self.with_folder(vec![], |folder| {
  78. get_workspace_view_pbs(workspace_id, folder)
  79. });
  80. Ok(views)
  81. }
  82. /// Called immediately after the application launched fi the user already sign in/sign up.
  83. #[tracing::instrument(level = "debug", skip(self), err)]
  84. pub async fn initialize(&self, uid: i64, workspace_id: &str) -> FlowyResult<()> {
  85. let workspace_id = workspace_id.to_string();
  86. if let Ok(collab_db) = self.user.collab_db() {
  87. let collab = self
  88. .collab_builder
  89. .build(uid, &workspace_id, "workspace", collab_db);
  90. let (view_tx, view_rx) = tokio::sync::broadcast::channel(100);
  91. let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100);
  92. let folder_context = FolderContext {
  93. view_change_tx: view_tx,
  94. trash_change_tx: trash_tx,
  95. };
  96. let folder = Folder::get_or_create(collab, folder_context);
  97. let folder_state_rx = folder.subscribe_state_change();
  98. *self.mutex_folder.lock() = Some(folder);
  99. let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
  100. listen_on_folder_state_change(workspace_id, folder_state_rx, &weak_mutex_folder);
  101. listen_on_trash_change(trash_rx, &weak_mutex_folder);
  102. listen_on_view_change(view_rx, &weak_mutex_folder);
  103. }
  104. Ok(())
  105. }
  106. /// Called after the user sign up / sign in
  107. pub async fn initialize_with_new_user(
  108. &self,
  109. user_id: i64,
  110. token: &str,
  111. workspace_id: &str,
  112. ) -> FlowyResult<()> {
  113. self.initialize(user_id, workspace_id).await?;
  114. let (folder_data, workspace_pb) = DefaultFolderBuilder::build(
  115. self.user.user_id()?,
  116. workspace_id.to_string(),
  117. &self.operation_handlers,
  118. )
  119. .await;
  120. self.with_folder((), |folder| {
  121. folder.create_with_data(folder_data);
  122. });
  123. send_notification(token, FolderNotification::DidCreateWorkspace)
  124. .payload(RepeatedWorkspacePB {
  125. items: vec![workspace_pb],
  126. })
  127. .send();
  128. Ok(())
  129. }
  130. /// Called when the current user logout
  131. ///
  132. pub async fn clear(&self, _user_id: i64) {}
  133. pub async fn create_workspace(&self, params: CreateWorkspaceParams) -> FlowyResult<Workspace> {
  134. let workspace = self
  135. .cloud_service
  136. .create_workspace(self.user.user_id()?, &params.name)
  137. .await?;
  138. self.with_folder((), |folder| {
  139. folder.workspaces.create_workspace(workspace.clone());
  140. folder.set_current_workspace(&workspace.id);
  141. });
  142. let repeated_workspace = RepeatedWorkspacePB {
  143. items: vec![workspace.clone().into()],
  144. };
  145. send_workspace_notification(FolderNotification::DidCreateWorkspace, repeated_workspace);
  146. Ok(workspace)
  147. }
  148. pub async fn open_workspace(&self, workspace_id: &str) -> FlowyResult<Workspace> {
  149. self.with_folder(Err(FlowyError::internal()), |folder| {
  150. let workspace = folder
  151. .workspaces
  152. .get_workspace(workspace_id)
  153. .ok_or_else(|| {
  154. FlowyError::record_not_found().context("Can't open not existing workspace")
  155. })?;
  156. folder.set_current_workspace(workspace_id);
  157. Ok::<Workspace, FlowyError>(workspace)
  158. })
  159. }
  160. pub async fn get_workspace(&self, workspace_id: &str) -> Option<Workspace> {
  161. self.with_folder(None, |folder| folder.workspaces.get_workspace(workspace_id))
  162. }
  163. fn with_folder<F, Output>(&self, default_value: Output, f: F) -> Output
  164. where
  165. F: FnOnce(&Folder) -> Output,
  166. {
  167. let folder = self.mutex_folder.lock();
  168. match &*folder {
  169. None => default_value,
  170. Some(folder) => f(folder),
  171. }
  172. }
  173. pub async fn get_all_workspaces(&self) -> Vec<Workspace> {
  174. self.with_folder(vec![], |folder| folder.workspaces.get_all_workspaces())
  175. }
  176. pub async fn create_view_with_params(&self, params: CreateViewParams) -> FlowyResult<View> {
  177. let view_layout: ViewLayout = params.layout.clone().into();
  178. let handler = self.get_handler(&view_layout)?;
  179. let user_id = self.user.user_id()?;
  180. let meta = params.meta.clone();
  181. match params.initial_data.is_empty() {
  182. true => {
  183. tracing::trace!("Create view with build-in data");
  184. handler
  185. .create_built_in_view(user_id, &params.view_id, &params.name, view_layout.clone())
  186. .await?;
  187. },
  188. false => {
  189. tracing::trace!("Create view with view data");
  190. handler
  191. .create_view_with_view_data(
  192. user_id,
  193. &params.view_id,
  194. &params.name,
  195. params.initial_data.clone(),
  196. view_layout.clone(),
  197. meta,
  198. )
  199. .await?;
  200. },
  201. }
  202. let view = create_view(params, view_layout);
  203. self.with_folder((), |folder| {
  204. folder.insert_view(view.clone());
  205. });
  206. notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id.clone()]);
  207. Ok(view)
  208. }
  209. #[tracing::instrument(level = "debug", skip(self), err)]
  210. pub(crate) async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
  211. let view = self
  212. .with_folder(None, |folder| folder.views.get_view(view_id))
  213. .ok_or_else(|| {
  214. FlowyError::record_not_found().context("Can't find the view when closing the view")
  215. })?;
  216. let handler = self.get_handler(&view.layout)?;
  217. handler.close_view(view_id).await?;
  218. Ok(())
  219. }
  220. pub async fn create_view_with_data(
  221. &self,
  222. view_id: &str,
  223. name: &str,
  224. view_layout: ViewLayout,
  225. data: Vec<u8>,
  226. ) -> FlowyResult<()> {
  227. let user_id = self.user.user_id()?;
  228. let handler = self.get_handler(&view_layout)?;
  229. handler
  230. .create_view_with_view_data(
  231. user_id,
  232. view_id,
  233. name,
  234. data,
  235. view_layout,
  236. HashMap::default(),
  237. )
  238. .await?;
  239. Ok(())
  240. }
  241. /// Returns the view with the given view id.
  242. /// The child views of the view will only access the first. So if you want to get the child view's
  243. /// child view, you need to call this method again.
  244. #[tracing::instrument(level = "debug", skip(self, view_id), err)]
  245. pub async fn get_view(&self, view_id: &str) -> FlowyResult<ViewPB> {
  246. let view_id = view_id.to_string();
  247. let folder = self.mutex_folder.lock();
  248. let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
  249. let trash_ids = folder
  250. .trash
  251. .get_all_trash()
  252. .into_iter()
  253. .map(|trash| trash.id)
  254. .collect::<Vec<String>>();
  255. if trash_ids.contains(&view_id) {
  256. return Err(FlowyError::record_not_found());
  257. }
  258. match folder.views.get_view(&view_id) {
  259. None => Err(FlowyError::record_not_found()),
  260. Some(mut view) => {
  261. view.children.retain(|b| !trash_ids.contains(&b.id));
  262. let child_views = folder
  263. .views
  264. .get_views_belong_to(&view.id)
  265. .into_iter()
  266. .filter(|view| !trash_ids.contains(&view.id))
  267. .collect::<Vec<View>>();
  268. let view_pb = view_pb_with_child_views(view, child_views);
  269. Ok(view_pb)
  270. },
  271. }
  272. }
  273. /// Move the view to trash. If the view is the current view, then set the current view to empty.
  274. /// When the view is moved to trash, all the child views will be moved to trash as well.
  275. #[tracing::instrument(level = "debug", skip(self), err)]
  276. pub async fn move_view_to_trash(&self, view_id: &str) -> FlowyResult<()> {
  277. self.with_folder((), |folder| {
  278. folder.trash.add_trash(vec![TrashRecord {
  279. id: view_id.to_string(),
  280. created_at: timestamp(),
  281. }]);
  282. if let Some(view) = folder.get_current_view() {
  283. if view == view_id {
  284. folder.set_current_view("");
  285. }
  286. }
  287. // notify the parent view that the view is moved to trash
  288. send_notification(view_id, FolderNotification::DidMoveViewToTrash)
  289. .payload(DeletedViewPB {
  290. view_id: view_id.to_string(),
  291. index: None,
  292. })
  293. .send();
  294. });
  295. Ok(())
  296. }
  297. /// Move the view from one position to another position.
  298. #[tracing::instrument(level = "debug", skip(self), err)]
  299. pub async fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
  300. let view = self.with_folder(None, |folder| {
  301. folder.move_view(view_id, from as u32, to as u32)
  302. });
  303. match view {
  304. None => tracing::error!("Couldn't find the view. It should not be empty"),
  305. Some(view) => {
  306. notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id]);
  307. },
  308. }
  309. Ok(())
  310. }
  311. /// Return a list of views that belong to the given parent view id.
  312. #[tracing::instrument(level = "debug", skip(self, parent_view_id), err)]
  313. pub async fn get_views_belong_to(&self, parent_view_id: &str) -> FlowyResult<Vec<View>> {
  314. let views = self.with_folder(vec![], |folder| {
  315. folder.views.get_views_belong_to(parent_view_id)
  316. });
  317. Ok(views)
  318. }
  319. /// Update the view with the given params.
  320. #[tracing::instrument(level = "trace", skip(self), err)]
  321. pub async fn update_view_with_params(&self, params: UpdateViewParams) -> FlowyResult<()> {
  322. let value = self.with_folder(None, |folder| {
  323. let old_view = folder.views.get_view(&params.view_id);
  324. let new_view = folder.views.update_view(&params.view_id, |update| {
  325. update
  326. .set_name_if_not_none(params.name)
  327. .set_desc_if_not_none(params.desc)
  328. .set_layout_if_not_none(params.layout)
  329. .done()
  330. });
  331. Some((old_view, new_view))
  332. });
  333. if let Some((Some(old_view), Some(new_view))) = value {
  334. if let Ok(handler) = self.get_handler(&old_view.layout) {
  335. handler.did_update_view(&old_view, &new_view).await?;
  336. }
  337. }
  338. if let Ok(view_pb) = self.get_view(&params.view_id).await {
  339. notify_parent_view_did_change(
  340. self.mutex_folder.clone(),
  341. vec![view_pb.parent_view_id.clone()],
  342. );
  343. send_notification(&view_pb.id, FolderNotification::DidUpdateView)
  344. .payload(view_pb)
  345. .send();
  346. }
  347. Ok(())
  348. }
  349. /// Duplicate the view with the given view id.
  350. #[tracing::instrument(level = "debug", skip(self), err)]
  351. pub(crate) async fn duplicate_view(&self, view_id: &str) -> Result<(), FlowyError> {
  352. let view = self
  353. .with_folder(None, |folder| folder.views.get_view(view_id))
  354. .ok_or_else(|| FlowyError::record_not_found().context("Can't duplicate the view"))?;
  355. let handler = self.get_handler(&view.layout)?;
  356. let view_data = handler.duplicate_view(&view.id).await?;
  357. let duplicate_params = CreateViewParams {
  358. parent_view_id: view.parent_view_id.clone(),
  359. name: format!("{} (copy)", &view.name),
  360. desc: view.desc,
  361. layout: view.layout.into(),
  362. initial_data: view_data.to_vec(),
  363. view_id: gen_view_id(),
  364. meta: Default::default(),
  365. set_as_current: true,
  366. };
  367. let _ = self.create_view_with_params(duplicate_params).await?;
  368. Ok(())
  369. }
  370. #[tracing::instrument(level = "trace", skip(self), err)]
  371. pub(crate) async fn set_current_view(&self, view_id: &str) -> Result<(), FlowyError> {
  372. let folder = self.mutex_folder.lock();
  373. let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
  374. folder.set_current_view(view_id);
  375. let workspace = folder.get_current_workspace();
  376. let view = folder
  377. .get_current_view()
  378. .and_then(|view_id| folder.views.get_view(&view_id));
  379. send_workspace_setting_notification(workspace, view);
  380. Ok(())
  381. }
  382. #[tracing::instrument(level = "trace", skip(self))]
  383. pub(crate) async fn get_current_view(&self) -> Option<ViewPB> {
  384. let view_id = self.with_folder(None, |folder| folder.get_current_view())?;
  385. self.get_view(&view_id).await.ok()
  386. }
  387. #[tracing::instrument(level = "trace", skip(self))]
  388. pub(crate) async fn get_all_trash(&self) -> Vec<TrashInfo> {
  389. self.with_folder(vec![], |folder| folder.trash.get_all_trash())
  390. }
  391. #[tracing::instrument(level = "trace", skip(self))]
  392. pub(crate) async fn restore_all_trash(&self) {
  393. self.with_folder((), |folder| {
  394. folder.trash.clear();
  395. });
  396. send_notification("trash", FolderNotification::DidUpdateTrash)
  397. .payload(RepeatedTrashPB { items: vec![] })
  398. .send();
  399. }
  400. #[tracing::instrument(level = "trace", skip(self))]
  401. pub(crate) async fn restore_trash(&self, trash_id: &str) {
  402. self.with_folder((), |folder| {
  403. folder.trash.delete_trash(vec![trash_id]);
  404. });
  405. }
  406. /// Delete all the trash permanently.
  407. #[tracing::instrument(level = "trace", skip(self))]
  408. pub(crate) async fn delete_all_trash(&self) {
  409. let deleted_trash = self.with_folder(vec![], |folder| folder.trash.get_all_trash());
  410. for trash in deleted_trash {
  411. let _ = self.delete_trash(&trash.id).await;
  412. }
  413. send_notification("trash", FolderNotification::DidUpdateTrash)
  414. .payload(RepeatedTrashPB { items: vec![] })
  415. .send();
  416. }
  417. /// Delete the trash permanently.
  418. /// Delete the view will delete all the resources that the view holds. For example, if the view
  419. /// is a database view. Then the database will be deleted as well.
  420. #[tracing::instrument(level = "debug", skip(self, view_id), err)]
  421. pub async fn delete_trash(&self, view_id: &str) -> FlowyResult<()> {
  422. let view = self.with_folder(None, |folder| folder.views.get_view(view_id));
  423. self.with_folder((), |folder| {
  424. folder.trash.delete_trash(vec![view_id]);
  425. folder.views.delete_views(vec![view_id]);
  426. });
  427. if let Some(view) = view {
  428. if let Ok(handler) = self.get_handler(&view.layout) {
  429. handler.delete_view(view_id).await?;
  430. }
  431. }
  432. Ok(())
  433. }
  434. pub(crate) async fn import(&self, import_data: ImportParams) -> FlowyResult<View> {
  435. if import_data.data.is_none() && import_data.file_path.is_none() {
  436. return Err(FlowyError::new(
  437. ErrorCode::InvalidData,
  438. "data or file_path is required",
  439. ));
  440. }
  441. let handler = self.get_handler(&import_data.view_layout)?;
  442. let view_id = gen_view_id();
  443. if let Some(data) = import_data.data {
  444. handler
  445. .import_from_bytes(&view_id, &import_data.name, import_data.import_type, data)
  446. .await?;
  447. }
  448. if let Some(file_path) = import_data.file_path {
  449. handler
  450. .import_from_file_path(&view_id, &import_data.name, file_path)
  451. .await?;
  452. }
  453. let params = CreateViewParams {
  454. parent_view_id: import_data.parent_view_id,
  455. name: import_data.name,
  456. desc: "".to_string(),
  457. layout: import_data.view_layout.clone().into(),
  458. initial_data: vec![],
  459. view_id,
  460. meta: Default::default(),
  461. set_as_current: false,
  462. };
  463. let view = create_view(params, import_data.view_layout);
  464. self.with_folder((), |folder| {
  465. folder.insert_view(view.clone());
  466. });
  467. notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id.clone()]);
  468. Ok(view)
  469. }
  470. /// Returns a handler that implements the [FolderOperationHandler] trait
  471. fn get_handler(
  472. &self,
  473. view_layout: &ViewLayout,
  474. ) -> FlowyResult<Arc<dyn FolderOperationHandler + Send + Sync>> {
  475. match self.operation_handlers.get(view_layout) {
  476. None => Err(FlowyError::internal().context(format!(
  477. "Get data processor failed. Unknown layout type: {:?}",
  478. view_layout
  479. ))),
  480. Some(processor) => Ok(processor.clone()),
  481. }
  482. }
  483. }
  484. /// Listen on the [ViewChange] after create/delete/update events happened
  485. fn listen_on_view_change(mut rx: ViewChangeReceiver, weak_mutex_folder: &Weak<MutexFolder>) {
  486. let weak_mutex_folder = weak_mutex_folder.clone();
  487. tokio::spawn(async move {
  488. while let Ok(value) = rx.recv().await {
  489. if let Some(folder) = weak_mutex_folder.upgrade() {
  490. tracing::trace!("Did receive view change: {:?}", value);
  491. match value {
  492. ViewChange::DidCreateView { view } => {
  493. notify_parent_view_did_change(folder.clone(), vec![view.parent_view_id]);
  494. },
  495. ViewChange::DidDeleteView { views: _ } => {},
  496. ViewChange::DidUpdate { view } => {
  497. notify_parent_view_did_change(folder.clone(), vec![view.parent_view_id]);
  498. },
  499. };
  500. }
  501. }
  502. });
  503. }
  504. fn listen_on_folder_state_change(
  505. workspace_id: String,
  506. mut folder_state_rx: WatchStream<CollabState>,
  507. weak_mutex_folder: &Weak<MutexFolder>,
  508. ) {
  509. let weak_mutex_folder = weak_mutex_folder.clone();
  510. tokio::spawn(async move {
  511. while let Some(state) = folder_state_rx.next().await {
  512. if state.is_root_changed() {
  513. if let Some(mutex_folder) = weak_mutex_folder.upgrade() {
  514. let folder = mutex_folder.lock().take();
  515. if let Some(folder) = folder {
  516. tracing::trace!("🔥Reload folder");
  517. let reload_folder = folder.reload();
  518. notify_did_update_workspace(&workspace_id, &reload_folder);
  519. *mutex_folder.lock() = Some(reload_folder);
  520. }
  521. }
  522. }
  523. }
  524. });
  525. }
  526. /// Listen on the [TrashChange]s and notify the frontend some views were changed.
  527. fn listen_on_trash_change(mut rx: TrashChangeReceiver, weak_mutex_folder: &Weak<MutexFolder>) {
  528. let weak_mutex_folder = weak_mutex_folder.clone();
  529. tokio::spawn(async move {
  530. while let Ok(value) = rx.recv().await {
  531. if let Some(folder) = weak_mutex_folder.upgrade() {
  532. let mut unique_ids = HashSet::new();
  533. tracing::trace!("Did receive trash change: {:?}", value);
  534. let ids = match value {
  535. TrashChange::DidCreateTrash { ids } => ids,
  536. TrashChange::DidDeleteTrash { ids } => ids,
  537. };
  538. if let Some(folder) = folder.lock().as_ref() {
  539. let views = folder.views.get_views(&ids);
  540. for view in views {
  541. unique_ids.insert(view.parent_view_id);
  542. }
  543. let repeated_trash: RepeatedTrashPB = folder.trash.get_all_trash().into();
  544. send_notification("trash", FolderNotification::DidUpdateTrash)
  545. .payload(repeated_trash)
  546. .send();
  547. }
  548. let parent_view_ids = unique_ids.into_iter().collect();
  549. notify_parent_view_did_change(folder.clone(), parent_view_ids);
  550. }
  551. }
  552. });
  553. }
  554. fn get_workspace_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
  555. let trash_ids = folder
  556. .trash
  557. .get_all_trash()
  558. .into_iter()
  559. .map(|trash| trash.id)
  560. .collect::<Vec<String>>();
  561. let mut views = folder.get_workspace_views(workspace_id);
  562. views.retain(|view| !trash_ids.contains(&view.id));
  563. views
  564. .into_iter()
  565. .map(|view| {
  566. // Get child views
  567. let child_views = folder
  568. .views
  569. .get_views_belong_to(&view.id)
  570. .into_iter()
  571. .collect();
  572. view_pb_with_child_views(view, child_views)
  573. })
  574. .collect()
  575. }
  576. fn notify_did_update_workspace(workspace_id: &str, folder: &Folder) {
  577. let repeated_view: RepeatedViewPB = get_workspace_view_pbs(workspace_id, folder).into();
  578. tracing::trace!("Did update workspace views: {:?}", repeated_view);
  579. send_notification(workspace_id, FolderNotification::DidUpdateWorkspaceViews)
  580. .payload(repeated_view)
  581. .send();
  582. }
  583. /// Notify the the list of parent view ids that its child views were changed.
  584. #[tracing::instrument(level = "debug", skip(folder, parent_view_ids))]
  585. fn notify_parent_view_did_change<T: AsRef<str>>(
  586. folder: Arc<MutexFolder>,
  587. parent_view_ids: Vec<T>,
  588. ) -> Option<()> {
  589. let folder = folder.lock();
  590. let folder = folder.as_ref()?;
  591. let workspace_id = folder.get_current_workspace_id()?;
  592. let trash_ids = folder
  593. .trash
  594. .get_all_trash()
  595. .into_iter()
  596. .map(|trash| trash.id)
  597. .collect::<Vec<String>>();
  598. for parent_view_id in parent_view_ids {
  599. let parent_view_id = parent_view_id.as_ref();
  600. // if the view's parent id equal to workspace id. Then it will fetch the current
  601. // workspace views. Because the the workspace is not a view stored in the views map.
  602. if parent_view_id == workspace_id {
  603. notify_did_update_workspace(&workspace_id, folder)
  604. } else {
  605. // Parent view can contain a list of child views. Currently, only get the first level
  606. // child views.
  607. let parent_view = folder.views.get_view(parent_view_id)?;
  608. let mut child_views = folder.views.get_views_belong_to(parent_view_id);
  609. child_views.retain(|view| !trash_ids.contains(&view.id));
  610. event!(Level::DEBUG, child_views_count = child_views.len());
  611. // Post the notification
  612. let parent_view_pb = view_pb_with_child_views(parent_view, child_views);
  613. send_notification(parent_view_id, FolderNotification::DidUpdateChildViews)
  614. .payload(parent_view_pb)
  615. .send();
  616. }
  617. }
  618. None
  619. }
  620. fn folder_not_init_error() -> FlowyError {
  621. FlowyError::internal().context("Folder not initialized")
  622. }
  623. #[derive(Clone, Default)]
  624. pub struct MutexFolder(Arc<Mutex<Option<Folder>>>);
  625. impl Deref for MutexFolder {
  626. type Target = Arc<Mutex<Option<Folder>>>;
  627. fn deref(&self) -> &Self::Target {
  628. &self.0
  629. }
  630. }
  631. unsafe impl Sync for MutexFolder {}
  632. unsafe impl Send for MutexFolder {}