From f0d8eee8a022eab2800e1ad72fc03624ed7dc903 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 8 Apr 2024 14:06:05 +0800 Subject: [PATCH] fix: doc state refresh (#5086) --- .../document/application/doc_bloc.dart | 9 ++++---- .../application/doc_collab_adapter.dart | 17 ++++++++++++-- .../appflowy_flutter/lib/util/debounce.dart | 5 ++-- .../appflowy_flutter/lib/util/throttle.dart | 23 +++++++++++++++++++ frontend/appflowy_flutter/pubspec.lock | 4 ++-- frontend/appflowy_flutter/pubspec.yaml | 2 +- 6 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 frontend/appflowy_flutter/lib/util/throttle.dart diff --git a/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart b/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart index aefa957358..9a7c3bf442 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart @@ -16,6 +16,7 @@ import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/util/color_generator/color_generator.dart'; import 'package:appflowy/util/color_to_hex_string.dart'; import 'package:appflowy/util/debounce.dart'; +import 'package:appflowy/util/throttle.dart'; import 'package:appflowy/workspace/application/view/view_listener.dart'; import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart'; @@ -66,7 +67,7 @@ class DocumentBloc extends Bloc { StreamSubscription? _transactionSubscription; final _updateSelectionDebounce = Debounce(); - final _syncDocDebounce = Debounce(); + final _syncThrottle = Throttler(duration: const Duration(milliseconds: 500)); bool get isLocalMode { final userProfilePB = state.userProfilePB; @@ -155,7 +156,7 @@ class DocumentBloc extends Bloc { /// subscribe to the document content change void _onDocumentChanged() { _documentListener.start( - onDocEventUpdate: _debounceSyncDoc, + onDocEventUpdate: _throttleSyncDoc, onDocAwarenessUpdate: _onAwarenessStatesUpdate, ); @@ -290,8 +291,8 @@ class DocumentBloc extends Bloc { _updateSelectionDebounce.call(_onSelectionUpdate); } - void _debounceSyncDoc(DocEventPB docEvent) { - _syncDocDebounce.call(() { + void _throttleSyncDoc(DocEventPB docEvent) { + _syncThrottle.call(() { _onDocumentStateUpdate(docEvent); }); } diff --git a/frontend/appflowy_flutter/lib/plugins/document/application/doc_collab_adapter.dart b/frontend/appflowy_flutter/lib/plugins/document/application/doc_collab_adapter.dart index fc67e14ece..b5b9a04847 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/application/doc_collab_adapter.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/application/doc_collab_adapter.dart @@ -77,17 +77,30 @@ class DocumentCollabAdapter { final ops = diffNodes(editorState.document.root, document.root); if (ops.isEmpty) { - debugPrint('[collab] received empty ops'); + Log.info('Doc diff, no changes'); return; } - debugPrint('[collab] received ops: $ops'); + prettyPrintJson(ops.map((op) => op.toJson()).toList()); final transaction = editorState.transaction; for (final op in ops) { transaction.add(op); } await editorState.apply(transaction, isRemote: true); + + // Use for debugging, DO NOT REMOVE + // assert(() { + // final local = editorState.document.root.toJson(); + // final remote = document.root.toJson(); + // if (!const DeepCollectionEquality().equals(local, remote)) { + // Log.error('Invalid diff status'); + // Log.error('Local: $local'); + // Log.error('Remote: $remote'); + // return false; + // } + // return true; + // }()); } Future _syncUpdated( diff --git a/frontend/appflowy_flutter/lib/util/debounce.dart b/frontend/appflowy_flutter/lib/util/debounce.dart index 46881ab0a0..1929d07328 100644 --- a/frontend/appflowy_flutter/lib/util/debounce.dart +++ b/frontend/appflowy_flutter/lib/util/debounce.dart @@ -1,7 +1,5 @@ import 'dart:async'; -import 'package:flutter/material.dart'; - class Debounce { Debounce({ this.duration = const Duration(milliseconds: 1000), @@ -10,8 +8,9 @@ class Debounce { final Duration duration; Timer? _timer; - void call(VoidCallback action) { + void call(Function action) { dispose(); + _timer = Timer(duration, () { action(); }); diff --git a/frontend/appflowy_flutter/lib/util/throttle.dart b/frontend/appflowy_flutter/lib/util/throttle.dart new file mode 100644 index 0000000000..c8c6dcf0ca --- /dev/null +++ b/frontend/appflowy_flutter/lib/util/throttle.dart @@ -0,0 +1,23 @@ +import 'dart:async'; + +class Throttler { + Throttler({ + this.duration = const Duration(milliseconds: 1000), + }); + + final Duration duration; + Timer? _timer; + + void call(Function callback) { + if (_timer?.isActive ?? false) return; + + _timer = Timer(duration, () { + callback(); + }); + } + + void dispose() { + _timer?.cancel(); + _timer = null; + } +} diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index 4d5825b09f..c76ce2bf82 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -53,8 +53,8 @@ packages: dependency: "direct main" description: path: "." - ref: a9c77a9 - resolved-ref: a9c77a918b05c02f134128813b1c04a5b6856ae4 + ref: c8cd407 + resolved-ref: c8cd4071e36ca6b1fb6d9ef803abb61e9a743c8b url: "https://github.com/AppFlowy-IO/appflowy-editor.git" source: git version: "2.3.3" diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index fe825d34d6..6e69e81591 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -169,7 +169,7 @@ dependency_overrides: appflowy_editor: git: url: https://github.com/AppFlowy-IO/appflowy-editor.git - ref: "a9c77a9" + ref: "c8cd407" sheet: git: