mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: optimize selection implement by binary search
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -9,12 +9,6 @@
|
|||||||
"image_src": "https://s1.ax1x.com/2022/07/28/vCgz1x.png"
|
"image_src": "https://s1.ax1x.com/2022/07/28/vCgz1x.png"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "youtube_link",
|
|
||||||
"attributes": {
|
|
||||||
"youtube_link": "https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"delta": [
|
"delta": [
|
||||||
|
@ -99,6 +99,15 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
},
|
},
|
||||||
icon: const Icon(Icons.text_fields),
|
icon: const Icon(Icons.text_fields),
|
||||||
),
|
),
|
||||||
|
ActionButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (page == 3) return;
|
||||||
|
setState(() {
|
||||||
|
page = 3;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.email),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -111,6 +120,8 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
return _buildFlowyEditorWithEmptyDocument();
|
return _buildFlowyEditorWithEmptyDocument();
|
||||||
} else if (page == 2) {
|
} else if (page == 2) {
|
||||||
return _buildTextField();
|
return _buildTextField();
|
||||||
|
} else if (page == 3) {
|
||||||
|
return _buildFlowyEditorWithBigDocument();
|
||||||
}
|
}
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
@ -205,4 +216,34 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
child: TextField(),
|
child: TextField(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildFlowyEditorWithBigDocument() {
|
||||||
|
return FutureBuilder<String>(
|
||||||
|
future: rootBundle.loadString('assets/big_document.json'),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final data = Map<String, Object>.from(json.decode(snapshot.data!));
|
||||||
|
final document = StateTree.fromJson(data);
|
||||||
|
_editorState = EditorState(
|
||||||
|
document: document,
|
||||||
|
);
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 20),
|
||||||
|
child: FlowyEditor(
|
||||||
|
key: editorKey,
|
||||||
|
editorState: _editorState,
|
||||||
|
keyEventHandlers: const [],
|
||||||
|
customBuilders: {
|
||||||
|
'image': ImageNodeBuilder(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ flutter:
|
|||||||
assets:
|
assets:
|
||||||
- document.json
|
- document.json
|
||||||
- example.json
|
- example.json
|
||||||
|
- big_document.json
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
@ -19,4 +19,12 @@ extension NodeExtensions on Node {
|
|||||||
return selection.end.path <= path && path <= selection.start.path;
|
return selection.end.path <= path && path <= selection.start.path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rect get rect {
|
||||||
|
if (renderBox != null) {
|
||||||
|
final boxOffset = renderBox!.localToGlobal(Offset.zero);
|
||||||
|
return boxOffset & renderBox!.size;
|
||||||
|
}
|
||||||
|
return Rect.zero;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,12 +359,14 @@ class _FlowySelectionState extends State<FlowySelection>
|
|||||||
panStartOffsetWithScrollDyGap =
|
panStartOffsetWithScrollDyGap =
|
||||||
panStartOffsetWithScrollDyGap.translate(0, panStartScrollDy! - dy);
|
panStartOffsetWithScrollDyGap.translate(0, panStartScrollDy! - dy);
|
||||||
}
|
}
|
||||||
final nodes = getNodesInRange(panStartOffsetWithScrollDyGap, panEndOffset!);
|
|
||||||
if (nodes.isEmpty) {
|
final sortedNodes =
|
||||||
return;
|
editorState.document.root.children.toList(growable: false);
|
||||||
}
|
final first = _lowerBound(
|
||||||
final first = nodes.first.selectable;
|
sortedNodes, panStartOffsetWithScrollDyGap, 0, sortedNodes.length)
|
||||||
final last = nodes.last.selectable;
|
.selectable;
|
||||||
|
final last = _upperBound(sortedNodes, panEndOffset!, 0, sortedNodes.length)
|
||||||
|
.selectable;
|
||||||
|
|
||||||
// compute the selection in range.
|
// compute the selection in range.
|
||||||
if (first != null && last != null) {
|
if (first != null && last != null) {
|
||||||
@ -559,6 +561,41 @@ class _FlowySelectionState extends State<FlowySelection>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find the first node's rect.top <= offset.dy
|
||||||
|
Node _lowerBound(List<Node> sortedNodes, Offset offset, int start, int end) {
|
||||||
|
var min = start;
|
||||||
|
var max = end;
|
||||||
|
while (min <= max) {
|
||||||
|
final mid = min + ((max - min) >> 1);
|
||||||
|
if (sortedNodes[mid].rect.bottom <= offset.dy) {
|
||||||
|
min = mid + 1;
|
||||||
|
} else {
|
||||||
|
max = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sortedNodes[min];
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the first node's rect.top < offset.dy
|
||||||
|
Node _upperBound(
|
||||||
|
List<Node> sortedNodes,
|
||||||
|
Offset offset,
|
||||||
|
int start,
|
||||||
|
int end,
|
||||||
|
) {
|
||||||
|
var min = start;
|
||||||
|
var max = end;
|
||||||
|
while (min <= max) {
|
||||||
|
final mid = min + ((max - min) >> 1);
|
||||||
|
if (sortedNodes[mid].rect.top < offset.dy) {
|
||||||
|
min = mid + 1;
|
||||||
|
} else {
|
||||||
|
max = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sortedNodes[max];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Because the flutter's [DoubleTapGestureRecognizer] will block the [TapGestureRecognizer]
|
/// Because the flutter's [DoubleTapGestureRecognizer] will block the [TapGestureRecognizer]
|
||||||
|
Reference in New Issue
Block a user