Skip to content

Commit

Permalink
feat: optimize the read recent views speed
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasXu0 committed Jul 15, 2024
1 parent a2336f5 commit a451ce3
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ class _MobileRecentFolderState extends State<MobileRecentFolder> {
builder: (context, state) {
final ids = <String>{};

List<ViewPB> recentViews =
state.views.reversed.map((e) => e.item).toList();
List<ViewPB> recentViews = state.views.map((e) => e.item).toList();
recentViews.retainWhere((element) => ids.add(element.id));

// only keep the first 20 items.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class _MobileRecentSpaceState extends State<MobileRecentSpace>

List<SectionViewPB> _filterRecentViews(List<SectionViewPB> recentViews) {
final ids = <String>{};
final filteredRecentViews = recentViews.reversed.toList();
final filteredRecentViews = recentViews.toList();
filteredRecentViews.retainWhere((e) => ids.add(e.item.id));
return filteredRecentViews;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/me
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
import 'package:appflowy/plugins/inline_actions/service_handler.dart';
import 'package:appflowy/shared/list_extension.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
Expand Down Expand Up @@ -64,11 +65,9 @@ class InlinePageReferenceService extends InlineActionsDelegate {

_recentViewsInitialized = true;

final views = (await _recentService.recentViews())
.reversed
.map((e) => e.item)
.toSet()
.toList();
final sectionViews = await _recentService.recentViews();
final views =
sectionViews.unique((e) => e.item.id).map((e) => e.item).toList();

// Filter by viewLayout
views.retainWhere(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import 'dart:async';

import 'package:appflowy/shared/list_extension.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/recent_listener.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/foundation.dart';

/// This is a lazy-singleton to share recent views across the application.
Expand Down Expand Up @@ -37,7 +39,7 @@ class CachedRecentService {

_listener.start(recentViewsUpdated: _recentViewsUpdated);
_recentViews = await _readRecentViews().fold(
(s) => s.items,
(s) => s.items.unique((e) => e.item.id),
(_) => [],
);
_completer.complete();
Expand Down Expand Up @@ -68,7 +70,8 @@ class CachedRecentService {

Future<FlowyResult<RepeatedRecentViewPB, FlowyError>>
_readRecentViews() async {
final result = await FolderEventReadRecentViews().send();
final payload = ReadRecentViewsPB(start: Int64(), limit: Int64(100));
final result = await FolderEventReadRecentViews(payload).send();
return result.fold(
(recentViews) {
return FlowyResult.success(
Expand Down Expand Up @@ -101,7 +104,7 @@ class CachedRecentService {
final viewIds = result.toNullable();
if (viewIds != null) {
_recentViews = await _readRecentViews().fold(
(s) => s.items,
(s) => s.items.unique((e) => e.item.id),
(_) => [],
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'package:flutter/material.dart';

import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/recent/recent_views_bloc.dart';
Expand All @@ -8,6 +6,7 @@ import 'package:appflowy/workspace/presentation/command_palette/widgets/recent_v
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class RecentViewsList extends StatelessWidget {
Expand All @@ -24,7 +23,7 @@ class RecentViewsList extends StatelessWidget {
builder: (context, state) {
// We remove duplicates by converting the list to a set first
final List<ViewPB> recentViews =
state.views.reversed.map((e) => e.item).toSet().toList();
state.views.map((e) => e.item).toSet().toList();

return ListView.separated(
shrinkWrap: true,
Expand Down
9 changes: 9 additions & 0 deletions frontend/rust-lib/flowy-folder/src/entities/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ pub struct RepeatedFavoriteViewPB {
pub items: Vec<SectionViewPB>,
}

#[derive(Eq, PartialEq, Debug, Default, ProtoBuf, Clone)]
pub struct ReadRecentViewsPB {
#[pb(index = 1)]
pub start: u64,

#[pb(index = 2)]
pub limit: u64,
}

#[derive(Eq, PartialEq, Debug, Default, ProtoBuf, Clone)]
pub struct RepeatedRecentViewPB {
#[pb(index = 1)]
Expand Down
30 changes: 20 additions & 10 deletions frontend/rust-lib/flowy-folder/src/event_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,20 +295,30 @@ pub(crate) async fn read_favorites_handler(

#[tracing::instrument(level = "debug", skip(folder), err)]
pub(crate) async fn read_recent_views_handler(
data: AFPluginData<ReadRecentViewsPB>,
folder: AFPluginState<Weak<FolderManager>>,
) -> DataResult<RepeatedRecentViewPB, FlowyError> {
let folder = upgrade_folder(folder)?;
let recent_items = folder.get_my_recent_sections().await;
let mut views = vec![];
for item in recent_items {
if let Ok(view) = folder.get_view_pb(&item.id).await {
views.push(SectionViewPB {
item: view,
timestamp: item.timestamp,
});
}
}
data_result_ok(RepeatedRecentViewPB { items: views })
let start = data.start;
let limit = data.limit;
let ids = recent_items
.iter()
.map(|item| item.id.clone())
.rev() // the most recent view is at the end of the list
.skip(start as usize)
.take(limit as usize)
.collect::<Vec<_>>();
let views = folder.get_view_pbs_without_children(ids).await?;
let items = views
.into_iter()
.zip(recent_items.into_iter())
.map(|(view, item)| SectionViewPB {
item: view,
timestamp: item.timestamp,
})
.collect::<Vec<_>>();
data_result_ok(RepeatedRecentViewPB { items })
}

#[tracing::instrument(level = "debug", skip(folder), err)]
Expand Down
2 changes: 1 addition & 1 deletion frontend/rust-lib/flowy-folder/src/event_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ pub enum FolderEvent {
#[event(input = "UpdateViewIconPayloadPB")]
UpdateViewIcon = 35,

#[event(output = "RepeatedRecentViewPB")]
#[event(input = "ReadRecentViewsPB", output = "RepeatedRecentViewPB")]
ReadRecentViews = 36,

// used for add or remove recent views, like history
Expand Down
32 changes: 32 additions & 0 deletions frontend/rust-lib/flowy-folder/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,38 @@ impl FolderManager {
}
}

/// Retrieves the views corresponding to the specified view IDs.
///
/// It is important to note that if the target view contains child views,
/// this method only provides access to the first level of child views.
///
/// Therefore, to access a nested child view within one of the initial child views, you must invoke this method
/// again using the ID of the child view you wish to access.
#[tracing::instrument(level = "debug", skip(self))]
pub async fn get_view_pbs_without_children(
&self,
view_ids: Vec<String>,
) -> FlowyResult<Vec<ViewPB>> {
let folder = self.mutex_folder.read();
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;

// trash views and other private views should not be accessed
let view_ids_should_be_filtered = self.get_view_ids_should_be_filtered(folder);

let views = view_ids
.into_iter()
.filter_map(|view_id| {
if view_ids_should_be_filtered.contains(&view_id) {
return None;
}
folder.views.get_view(&view_id)
})
.map(view_pb_without_child_views_from_arc)
.collect::<Vec<_>>();

Ok(views)
}

/// Retrieves all views.
///
/// It is important to note that this will return a flat map of all views,
Expand Down

0 comments on commit a451ce3

Please sign in to comment.