feat: position and selection

This commit is contained in:
Vincent Chan 2022-07-12 11:54:06 +08:00
parent 6bfc5c3fd4
commit 9c73a8cd9a
4 changed files with 131 additions and 0 deletions

View File

@ -1 +1,7 @@
import 'package:flutter/foundation.dart';
typedef Path = List<int>;
bool pathEquals(Path path1, Path path2) {
return listEquals(path1, path2);
}

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import './path.dart';
class Position {
final Path path;
final int offset;
Position({
required this.path,
this.offset = 0,
});
@override
bool operator==(Object other) {
if (other is! Position) {
return false;
}
return pathEquals(path, other.path) && offset == other.offset;
}
@override
int get hashCode {
final pathHash = hashList(path);
return pathHash ^ offset;
}
}

View File

@ -0,0 +1,28 @@
import './position.dart';
class Selection {
final Position start;
final Position end;
Selection({
required this.start,
required this.end,
});
factory Selection.collapsed(Position pos) {
return Selection(start: pos, end: pos);
}
Selection collapse({ bool atStart = false }) {
if (atStart) {
return Selection(start: start, end: start);
} else {
return Selection(start: end, end: end);
}
}
bool isCollapsed() {
return start == end;
}
}

View File

@ -2,6 +2,10 @@ import 'dart:convert';
import 'package:flowy_editor/document/node.dart';
import 'package:flowy_editor/document/state_tree.dart';
import 'package:flowy_editor/document/path.dart';
import 'package:flowy_editor/document/position.dart';
import 'package:flowy_editor/document/selection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@ -61,4 +65,69 @@ void main() {
expect(updatedNode != null, true);
expect(updatedNode!.attributes['text-type'], 'heading1');
});
test('test path utils 1', () {
final path1 = <int>[1];
final path2 = <int>[1];
expect(pathEquals(path1, path2), true);
expect(hashList(path1), hashList(path2));
});
test('test path utils 2', () {
final path1 = <int>[1];
final path2 = <int>[2];
expect(pathEquals(path1, path2), false);
expect(hashList(path1) != hashList(path2), true);
});
test('test position comparator', () {
final pos1 = Position(path: [1], offset: 0);
final pos2 = Position(path: [1], offset: 0);
expect(pos1 == pos2, true);
expect(pos1.hashCode == pos2.hashCode, true);
});
test('test position comparator with offset', () {
final pos1 = Position(path: [1, 1, 1, 1, 1], offset: 100);
final pos2 = Position(path: [1, 1, 1, 1, 1], offset: 100);
expect(pos1, pos2);
expect(pos1.hashCode, pos2.hashCode);
});
test('test position comparator false', () {
final pos1 = Position(path: [1, 1, 1, 1, 1], offset: 100);
final pos2 = Position(path: [1, 1, 2, 1, 1], offset: 100);
expect(pos1 == pos2, false);
expect(pos1.hashCode == pos2.hashCode, false);
});
test('test position comparator with offset false', () {
final pos1 = Position(path: [1, 1, 1, 1, 1], offset: 100);
final pos2 = Position(path: [1, 1, 1, 1, 1], offset: 101);
expect(pos1 == pos2, false);
expect(pos1.hashCode == pos2.hashCode, false);
});
test('test selection comparator', () {
final pos = Position(path: [0], offset: 0);
final sel = Selection.collapsed(pos);
expect(sel.start, sel.end);
expect(sel.isCollapsed(), true);
});
test('test selection collapse', () {
final start = Position(path: [0], offset: 0);
final end = Position(path: [0], offset: 10);
final sel = Selection(start: start, end: end);
final collapsedSelAtStart = sel.collapse(atStart: true);
expect(collapsedSelAtStart.start, start);
expect(collapsedSelAtStart.end, start);
final collapsedSelAtEnd = sel.collapse();
expect(collapsedSelAtEnd.start, end);
expect(collapsedSelAtEnd.end, end);
});
}