mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: optimize the read recent views speed (#5726)
* feat: optimize the read recent views speed * fix: order of recent views should be from the latest to the oldest
This commit is contained in:
parent
d2e3fdfefd
commit
253e7597c4
@ -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)
|
||||
@ -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`)
|
||||
@ -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:
|
||||
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
@ -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(
|
||||
|
@ -1,5 +1,6 @@
|
||||
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';
|
||||
@ -7,6 +8,7 @@ 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.
|
||||
@ -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();
|
||||
@ -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(
|
||||
@ -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),
|
||||
(_) => [],
|
||||
);
|
||||
}
|
||||
|
@ -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';
|
||||
@ -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 {
|
||||
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user