feat: mobile tool bar basic features (#161)
* refactor: refactor mobile toolbar * feat: add text decoration icon in AFMobileIcons * chore: update mobile parameter * feat: add text decoration basic feature * chore: replace text by AppFlowyEditorLocalizations * feat: add code toolbar item * chore: refactor code - add hasMenu in MToolbarItem - add const size * feat: add line input menu * chore: create toolbar items draft file * refactor: textDecorationMToolbarItem refactor * fix: add key to ensures MToolbarWidget is rebuilt whenever the selection changes * feat: add link toolbar item and the way to close item menu * chore: replace m by mobile * chore:replace BuiltInAttributeKey by FlowyRichTextKeys * chore: replace m by mobile * refactor: refactor MobileToolbarWidget * refactor: add MobileToolbarStyle to control all cosmetic parameters * refactor: refactor MobileToolbarItemMenuBtn to stateless widget * feat: add heading menu * fix: fix open the wrong menu * feat: add heading icon * feat: add todo list and list toolbar item * feat: add quote toolbar item * fix: fix selection service error * test: add mobile toolbar basic elements test * test: add item menu button test and helper widgets * test: add text decoration mobile toolbar item test * test: add code mobile toolbar item test * test: add heading mobile toolbar item test * test: add list mobile toolbar item test * chore: fix typo * test: add quote mobile toolbar item test * test: add todo list mobile toolbar item test * test: add link mobile toolbar item test * chore: update name and add Material widget * fix: flutter analyze * fix: flutter analyze in test mobile toolbar * chore: dart format test code * refactor: improve code * fix: fix refactor error * chore: move all the tests in mobile to test/mobile * chore: move toolbar/items to toolbar/desktop/items * chore: remove the mobileToolbarItemMenuStateKey * chore: add some comments * test: update testing --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
parent
c0dbd025e0
commit
6a4a8ae818
2 changed files with 1574 additions and 125 deletions
364
test/new/toolbar/desktop/items/color/color_picker_test.dart
Normal file
364
test/new/toolbar/desktop/items/color/color_picker_test.dart
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/color/color_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../../../../infra/testable_editor.dart';
|
||||
|
||||
void main() {
|
||||
setUpAll(() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
});
|
||||
|
||||
group('color_picker.dart widget test', () {
|
||||
testWidgets('test expansion tile widget in color picker', (tester) async {
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final key = GlobalKey();
|
||||
final widget = ColorPicker(
|
||||
key: key,
|
||||
editorState: editor.editorState,
|
||||
isTextColor: true,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {},
|
||||
selectedColorHex: '0xFFFFFFFF',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byKey(key), findsOneWidget);
|
||||
final expansionTile = find.byType(ExpansionTile);
|
||||
expect(expansionTile, findsOneWidget);
|
||||
|
||||
await tester.tap(expansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TextField), findsNWidgets(2));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'test if custom font color selector text field are initialised correctly when selectedFontColorhex is provided',
|
||||
(tester) async {
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: true,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {},
|
||||
selectedColorHex: '0xFAFFFF08',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final fontColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(fontColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final fontColorTextField = find.byType(TextField).at(0);
|
||||
final fontOpacityTexField = find.byType(TextField).at(1);
|
||||
|
||||
expect(
|
||||
(tester.widget(fontColorTextField) as TextField).controller!.text,
|
||||
'FFFF08',
|
||||
);
|
||||
expect(
|
||||
(tester.widget(fontOpacityTexField) as TextField).controller!.text,
|
||||
'98',
|
||||
);
|
||||
});
|
||||
testWidgets(
|
||||
'test if custom font color selector text field are initialised correctly when selectedFontColorhex is null',
|
||||
(tester) async {
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: true,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {},
|
||||
selectedColorHex: null,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final fontColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(fontColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final fontColorTextField = find.byType(TextField).at(0);
|
||||
final fontOpacityTexField = find.byType(TextField).at(1);
|
||||
|
||||
expect(
|
||||
(tester.widget(fontColorTextField) as TextField).controller!.text,
|
||||
'FFFFFF',
|
||||
);
|
||||
expect(
|
||||
(tester.widget(fontOpacityTexField) as TextField).controller!.text,
|
||||
'100',
|
||||
);
|
||||
});
|
||||
testWidgets(
|
||||
'test if custom background color selector text field are initialised correctly when selectedBackgroundColorHex is provided',
|
||||
(tester) async {
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: false,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {},
|
||||
selectedColorHex: '0xFBFFFF08',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final backgroundColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(backgroundColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final backgroundColorTextField = find.byType(TextField).at(0);
|
||||
final backgroundOpacityTextField = find.byType(TextField).at(1);
|
||||
expect(
|
||||
(tester.widget(backgroundColorTextField) as TextField).controller!.text,
|
||||
'FFFF08',
|
||||
);
|
||||
expect(
|
||||
(tester.widget(backgroundOpacityTextField) as TextField)
|
||||
.controller!
|
||||
.text,
|
||||
'98',
|
||||
);
|
||||
});
|
||||
testWidgets(
|
||||
'test if custom background color selector text field are initialised correctly when selectedBackgroundColorHex is null',
|
||||
(tester) async {
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: false,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {},
|
||||
selectedColorHex: null,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final backgroundColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(backgroundColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final backgroundColorTextField = find.byType(TextField).at(0);
|
||||
final backgroundOpacityTextField = find.byType(TextField).at(1);
|
||||
expect(
|
||||
(tester.widget(backgroundColorTextField) as TextField).controller!.text,
|
||||
'FFFFFF',
|
||||
);
|
||||
expect(
|
||||
(tester.widget(backgroundOpacityTextField) as TextField)
|
||||
.controller!
|
||||
.text,
|
||||
'100',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('test submitting font color and opacity', (tester) async {
|
||||
String fontColorHex = '0xFAFFFF08';
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: true,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {
|
||||
fontColorHex = color;
|
||||
},
|
||||
selectedColorHex: fontColorHex,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final fontColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(fontColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final fontColorTextField = find.byType(TextField).at(0);
|
||||
final fontOpacityTexField = find.byType(TextField).at(1);
|
||||
|
||||
await tester.enterText(fontColorTextField, '000000');
|
||||
await tester.enterText(fontOpacityTexField, '100');
|
||||
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
fontColorHex = fontColorHex.toLowerCase();
|
||||
expect(fontColorHex, '0xff000000');
|
||||
});
|
||||
|
||||
testWidgets('test submitting wrong font color and opacity', (tester) async {
|
||||
String fontColorHex = '0xFAFFFF08';
|
||||
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: true,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {
|
||||
fontColorHex = color;
|
||||
},
|
||||
selectedColorHex: fontColorHex,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final fontColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(fontColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final fontColorTextField = find.byType(TextField).at(0);
|
||||
final fontOpacityTexField = find.byType(TextField).at(1);
|
||||
|
||||
await tester.enterText(fontColorTextField, '====');
|
||||
await tester.enterText(fontOpacityTexField, '***');
|
||||
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
fontColorHex = fontColorHex.toLowerCase();
|
||||
expect(fontColorHex, '0xffffffff');
|
||||
});
|
||||
|
||||
testWidgets('test submitting background color and opacity',
|
||||
(tester) async {
|
||||
String backgroundColorHex = '0xFAFFFFAD';
|
||||
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: false,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {
|
||||
backgroundColorHex = color;
|
||||
},
|
||||
selectedColorHex: backgroundColorHex,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final backgroundColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(backgroundColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final backgroundColorTextField = find.byType(TextField).at(0);
|
||||
final backgroundOpacityTexField = find.byType(TextField).at(1);
|
||||
|
||||
await tester.enterText(backgroundColorTextField, '000000');
|
||||
await tester.enterText(backgroundOpacityTexField, '100');
|
||||
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
backgroundColorHex = backgroundColorHex.toLowerCase();
|
||||
expect(backgroundColorHex, '0xff000000');
|
||||
});
|
||||
|
||||
testWidgets('test submitting wrong background color and opacity',
|
||||
(tester) async {
|
||||
String backgroundColorHex = '0xFAFFFF08';
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
final widget = ColorPicker(
|
||||
editorState: editor.editorState,
|
||||
isTextColor: false,
|
||||
colorOptions: const [],
|
||||
onDismiss: () {},
|
||||
onSubmittedColorHex: (String color) {
|
||||
backgroundColorHex = color;
|
||||
},
|
||||
selectedColorHex: backgroundColorHex,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: widget,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final backgroundColorExpansionTile = find.byType(ExpansionTile);
|
||||
|
||||
await tester.tap(backgroundColorExpansionTile);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final backgroundColorTextField = find.byType(TextField).at(0);
|
||||
final backgroundOpacityTexField = find.byType(TextField).at(1);
|
||||
|
||||
await tester.enterText(backgroundColorTextField, '***');
|
||||
await tester.enterText(backgroundOpacityTexField, '===');
|
||||
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
backgroundColorHex = backgroundColorHex.toLowerCase();
|
||||
expect(backgroundColorHex, '0xffffffff');
|
||||
});
|
||||
});
|
||||
}
|
||||
96
test/new/toolbar/desktop/items/link/link_menu_test.dart
Normal file
96
test/new/toolbar/desktop/items/link/link_menu_test.dart
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import 'package:appflowy_editor/src/core/document/text_delta.dart';
|
||||
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/link/link_menu.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '../../../../infra/testable_editor.dart';
|
||||
|
||||
void main() async {
|
||||
setUpAll(() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
});
|
||||
|
||||
group('link_menu.dart', () {
|
||||
testWidgets('test empty link menu actions', (tester) async {
|
||||
const link = 'appflowy.io';
|
||||
var submittedText = '';
|
||||
final linkMenu = LinkMenu(
|
||||
onOpenLink: () {},
|
||||
onCopyLink: () {},
|
||||
onRemoveLink: () {},
|
||||
onSubmitted: (text) {
|
||||
submittedText = text;
|
||||
},
|
||||
);
|
||||
final editor = tester.editor;
|
||||
await editor.startTesting();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: linkMenu,
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(TextButton), findsNothing);
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.enterText(find.byType(TextField), link);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle(Duration(milliseconds: 500));
|
||||
|
||||
expect(submittedText, link);
|
||||
});
|
||||
|
||||
testWidgets('test tap linked text', (tester) async {
|
||||
const link = 'appflowy.io';
|
||||
|
||||
final editor = tester.editor;
|
||||
//create a link [appflowy.io](appflowy.io)
|
||||
editor.addParagraph(
|
||||
builder: (index) => Delta()..insert(link, attributes: {"href": link}),
|
||||
);
|
||||
|
||||
await editor.startTesting();
|
||||
await tester.pumpAndSettle();
|
||||
final finder = find.text(link, findRichText: true);
|
||||
expect(finder, findsOneWidget);
|
||||
|
||||
// tap the link
|
||||
await tester.tap(finder);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 350));
|
||||
final linkMenu = find.byType(LinkMenu);
|
||||
expect(linkMenu, findsOneWidget);
|
||||
expect(find.text(link, findRichText: true), findsNWidgets(2));
|
||||
|
||||
await editor.dispose();
|
||||
});
|
||||
|
||||
testWidgets('test tap linked text when editor not editable',
|
||||
(tester) async {
|
||||
const link = 'appflowy.io';
|
||||
|
||||
final editor = tester.editor;
|
||||
//create a link [appflowy.io](appflowy.io)
|
||||
editor.addParagraph(
|
||||
builder: (index) => Delta()..insert(link, attributes: {"href": link}),
|
||||
);
|
||||
await editor.startTesting(editable: false);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final finder = find.text(link, findRichText: true);
|
||||
expect(finder, findsOneWidget);
|
||||
|
||||
await tester.tap(finder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final linkMenu = find.byType(LinkMenu);
|
||||
expect(linkMenu, findsNothing);
|
||||
|
||||
expect(find.text(link, findRichText: true), findsOneWidget);
|
||||
|
||||
await editor.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue