Skip to content

Commit

Permalink
feat: optimize the read recent views speed (AppFlowy-IO#5726)
Browse files Browse the repository at this point in the history
* feat: optimize the read recent views speed

* fix: order of recent views should be from the latest to the oldest
  • Loading branch information
LucasXu0 committed Jul 15, 2024
1 parent 31c54d3 commit ad67331
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 26 deletions.
6 changes: 6 additions & 0 deletions frontend/appflowy_flutter/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- printing (1.0.0):
- Flutter
- ReachabilitySwift (5.0.0)
- SDWebImage (5.14.2):
- SDWebImage/Core (= 5.14.2)
Expand Down Expand Up @@ -101,6 +103,7 @@ DEPENDENCIES:
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- printing (from `.symlinks/plugins/printing/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
Expand Down Expand Up @@ -149,6 +152,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
printing:
:path: ".symlinks/plugins/printing/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
Expand Down Expand Up @@ -179,6 +184,7 @@ SPEC CHECKSUMS:
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
Expand Down
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()
.rev() // the most recent view is at the end of the list
.map(|item| item.id.clone())
.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().rev())
.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 @@ -508,6 +508,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 ad67331

Please sign in to comment.