mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-25 15:17:28 -04:00
feat: observe mention block change and support block navigation (#6568)
* feat: observe mentioned block changes and navigate to block * test: add delete mentioned block test * chore: update editor version * feat: navigate block in same page * fix: sometimes turn into menu doesn't work * test: add test * fix: integration test
This commit is contained in:
parent
7cad04bbf4
commit
0413100e2b
14 changed files with 296 additions and 34 deletions
|
@ -1,7 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
|
@ -21,6 +19,7 @@ import 'package:appflowy/workspace/application/view/prelude.dart';
|
|||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
@ -31,12 +30,14 @@ class DocumentPage extends StatefulWidget {
|
|||
required this.view,
|
||||
required this.onDeleted,
|
||||
this.initialSelection,
|
||||
this.initialBlockId,
|
||||
this.fixedTitle,
|
||||
});
|
||||
|
||||
final ViewPB view;
|
||||
final VoidCallback onDeleted;
|
||||
final Selection? initialSelection;
|
||||
final String? initialBlockId;
|
||||
final String? fixedTitle;
|
||||
|
||||
@override
|
||||
|
@ -124,13 +125,18 @@ class _DocumentPageState extends State<DocumentPage>
|
|||
BuildContext context,
|
||||
DocumentState state,
|
||||
) {
|
||||
final editorState = state.editorState;
|
||||
if (editorState == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final width = context.read<DocumentAppearanceCubit>().state.width;
|
||||
|
||||
final Widget child;
|
||||
if (UniversalPlatform.isMobile) {
|
||||
child = BlocBuilder<DocumentPageStyleBloc, DocumentPageStyleState>(
|
||||
builder: (context, styleState) => AppFlowyEditorPage(
|
||||
editorState: state.editorState!,
|
||||
editorState: editorState,
|
||||
// if the view's name is empty, focus on the title
|
||||
autoFocus: widget.view.name.isEmpty ? false : null,
|
||||
styleCustomizer: EditorStyleCustomizer(
|
||||
|
@ -145,10 +151,10 @@ class _DocumentPageState extends State<DocumentPage>
|
|||
} else {
|
||||
child = EditorDropHandler(
|
||||
viewId: widget.view.id,
|
||||
editorState: state.editorState!,
|
||||
editorState: editorState,
|
||||
isLocalMode: context.read<DocumentBloc>().isLocalMode,
|
||||
child: AppFlowyEditorPage(
|
||||
editorState: state.editorState!,
|
||||
editorState: editorState,
|
||||
// if the view's name is empty, focus on the title
|
||||
autoFocus: widget.view.name.isEmpty ? false : null,
|
||||
styleCustomizer: EditorStyleCustomizer(
|
||||
|
@ -157,7 +163,7 @@ class _DocumentPageState extends State<DocumentPage>
|
|||
padding: EditorStyleCustomizer.documentPadding,
|
||||
),
|
||||
header: buildCoverAndIcon(context, state),
|
||||
initialSelection: widget.initialSelection,
|
||||
initialSelection: _calculateInitialSelection(editorState),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -242,16 +248,54 @@ class _DocumentPageState extends State<DocumentPage>
|
|||
BuildContext context,
|
||||
ActionNavigationState state,
|
||||
) {
|
||||
if (state.action != null && state.action!.type == ActionType.jumpToBlock) {
|
||||
final path = state.action?.arguments?[ActionArgumentKeys.nodePath];
|
||||
final action = state.action;
|
||||
if (action == null ||
|
||||
action.type != ActionType.jumpToBlock ||
|
||||
action.objectId != widget.view.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
final editorState = context.read<DocumentBloc>().state.editorState;
|
||||
if (editorState != null && widget.view.id == state.action?.objectId) {
|
||||
editorState.updateSelectionWithReason(
|
||||
Selection.collapsed(Position(path: [path])),
|
||||
);
|
||||
final editorState = context.read<DocumentBloc>().state.editorState;
|
||||
if (editorState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Path? path = _getPathFromAction(action, editorState);
|
||||
if (path != null) {
|
||||
debugPrint('jump to block: $path');
|
||||
editorState.updateSelectionWithReason(
|
||||
Selection.collapsed(Position(path: path)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Path? _getPathFromAction(NavigationAction action, EditorState editorState) {
|
||||
Path? path = action.arguments?[ActionArgumentKeys.nodePath];
|
||||
if (path == null || path.isEmpty) {
|
||||
final blockId = action.arguments?[ActionArgumentKeys.blockId];
|
||||
if (blockId != null) {
|
||||
path = _findNodePathByBlockId(editorState, blockId);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Path? _findNodePathByBlockId(EditorState editorState, String blockId) {
|
||||
final document = editorState.document;
|
||||
final startNode = document.root.children.firstOrNull;
|
||||
if (startNode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final nodeIterator = NodeIterator(document: document, startNode: startNode);
|
||||
while (nodeIterator.moveNext()) {
|
||||
final node = nodeIterator.current;
|
||||
if (node.id == blockId) {
|
||||
return node.path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool shouldRebuildDocument(DocumentState previous, DocumentState current) {
|
||||
|
@ -362,4 +406,24 @@ class _DocumentPageState extends State<DocumentPage>
|
|||
isPaste = false;
|
||||
}
|
||||
}
|
||||
|
||||
Selection? _calculateInitialSelection(EditorState editorState) {
|
||||
if (widget.initialSelection != null) {
|
||||
return widget.initialSelection;
|
||||
}
|
||||
|
||||
if (widget.initialBlockId != null) {
|
||||
final path = _findNodePathByBlockId(editorState, widget.initialBlockId!);
|
||||
if (path != null) {
|
||||
editorState.selectionType = SelectionType.block;
|
||||
return Selection.collapsed(
|
||||
Position(
|
||||
path: path,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue