feat: support table align on desktop (#7034)

* feat: support table align on desktop

* test: update table align

* test: add integration test
This commit is contained in:
Lucas 2024-12-24 09:39:15 +08:00 committed by GitHub
parent 6e0534400b
commit 20bff9003e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 165 additions and 20 deletions

View File

@ -561,6 +561,72 @@ void main() {
final node = editorState.document.nodeAtPath([0, 0, 0])!;
expect(node.children.length, 1);
});
testWidgets('using option menu to set table align', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(
name: 'simple_table_test',
);
await tester.editor.tapLineOfEditorAt(0);
await tester.insertTableInDocument();
await tester.editor.hoverAndClickOptionMenuButton([0]);
final editorState = tester.editor.getCurrentEditorState();
final beforeAlign = editorState.document.nodeAtPath([0])!.tableAlign;
expect(beforeAlign, TableAlign.left);
await tester.tapButton(
find.text(
LocaleKeys.document_plugins_simpleTable_moreActions_align.tr(),
),
);
await tester.pumpAndSettle();
await tester.tapButton(
find.text(
LocaleKeys.document_plugins_optionAction_center.tr(),
),
);
await tester.pumpAndSettle();
final afterAlign = editorState.document.nodeAtPath([0])!.tableAlign;
expect(afterAlign, TableAlign.center);
await tester.editor.hoverAndClickOptionMenuButton([0]);
await tester.tapButton(
find.text(
LocaleKeys.document_plugins_simpleTable_moreActions_align.tr(),
),
);
await tester.pumpAndSettle();
await tester.tapButton(
find.text(
LocaleKeys.document_plugins_optionAction_right.tr(),
),
);
await tester.pumpAndSettle();
final afterAlign2 = editorState.document.nodeAtPath([0])!.tableAlign;
expect(afterAlign2, TableAlign.right);
await tester.editor.hoverAndClickOptionMenuButton([0]);
await tester.tapButton(
find.text(
LocaleKeys.document_plugins_simpleTable_moreActions_align.tr(),
),
);
await tester.pumpAndSettle();
await tester.tapButton(
find.text(
LocaleKeys.document_plugins_optionAction_left.tr(),
),
);
await tester.pumpAndSettle();
final afterAlign3 = editorState.document.nodeAtPath([0])!.tableAlign;
expect(afterAlign3, TableAlign.left);
});
}
extension on WidgetTester {

View File

@ -126,6 +126,14 @@ List<OptionAction> _buildOptionActions(BuildContext context, String type) {
standardActions.add(OptionAction.turnInto);
if (SimpleTableBlockKeys.type == type) {
standardActions.addAll([
OptionAction.divider,
OptionAction.setToPageWidth,
OptionAction.distributeColumnsEvenly,
]);
}
if (EditorOptionActionType.color.supportTypes.contains(type)) {
standardActions.addAll([OptionAction.divider, OptionAction.color]);
}
@ -138,14 +146,6 @@ List<OptionAction> _buildOptionActions(BuildContext context, String type) {
standardActions.addAll([OptionAction.divider, OptionAction.depth]);
}
if (SimpleTableBlockKeys.type == type) {
standardActions.addAll([
OptionAction.divider,
OptionAction.setToPageWidth,
OptionAction.distributeColumnsEvenly,
]);
}
return standardActions;
}

View File

@ -1,10 +1,10 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/simple_table/simple_table.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart';
enum OptionAlignType {
left,
@ -58,8 +58,8 @@ class AlignOptionAction extends PopoverActionCell {
Widget? leftIcon(Color iconColor) {
return FlowySvg(
align.svg,
size: const Size.square(12),
).padding(all: 2.0);
size: const Size.square(18),
);
}
@override
@ -102,7 +102,11 @@ class AlignOptionAction extends PopoverActionCell {
return HoverButton(
onTap: () => onTap(e.inner),
itemHeight: ActionListSizes.itemHeight,
leftIcon: leftIcon,
leftIcon: SizedBox(
width: 16,
height: 16,
child: leftIcon,
),
name: e.name,
rightIcon: rightIcon,
);
@ -115,7 +119,9 @@ class AlignOptionAction extends PopoverActionCell {
return OptionAlignType.center;
}
final node = editorState.getNodeAtPath(selection.start.path);
final align = node?.attributes[blockComponentAlign];
final align = node?.type == SimpleTableBlockKeys.type
? node?.tableAlign.key
: node?.attributes[blockComponentAlign];
return OptionAlignType.fromString(align);
}
@ -131,11 +137,20 @@ class AlignOptionAction extends PopoverActionCell {
if (node == null) {
return;
}
final transaction = editorState.transaction;
transaction.updateNode(node, {
blockComponentAlign: align.name,
});
await editorState.apply(transaction);
// the align attribute for simple table is not same as the align type,
// so we need to convert the align type to the align attribute
if (node.type == SimpleTableBlockKeys.type) {
await editorState.updateTableAlign(
tableNode: node,
align: TableAlign.fromString(align.name),
);
} else {
final transaction = editorState.transaction;
transaction.updateNode(node, {
blockComponentAlign: align.name,
});
await editorState.apply(transaction);
}
}
}

View File

@ -46,6 +46,7 @@ enum EditorOptionActionType {
case EditorOptionActionType.align:
return {
ImageBlockKeys.type,
SimpleTableBlockKeys.type,
};
case EditorOptionActionType.depth:
return {

View File

@ -348,7 +348,9 @@ class SimpleTableCellBlockWidgetState extends State<SimpleTableCellBlockWidget>
Widget _buildTableActionMenu() {
final tableNode = node.parentTableNode;
if (tableNode == null) {
// the table action menu is only available on mobile platform.
if (tableNode == null || UniversalPlatform.isDesktop) {
return const SizedBox.shrink();
}

View File

@ -16,6 +16,13 @@ enum TableAlign {
center,
right;
static TableAlign fromString(String align) {
return TableAlign.values.firstWhere(
(e) => e.key.toLowerCase() == align.toLowerCase(),
orElse: () => TableAlign.left,
);
}
String get name => switch (this) {
TableAlign.left => 'Left',
TableAlign.center => 'Center',
@ -808,4 +815,38 @@ extension TableNodeExtension on Node {
}
return children.last.getLastChildIndex();
}
/// Get table align of column
///
/// If one of the align is not same as the others, it will return TableAlign.left.
TableAlign get allColumnAlign {
final alignSet = columnAligns.values.toSet();
if (alignSet.length == 1) {
return TableAlign.fromString(alignSet.first);
}
return TableAlign.left;
}
/// Get table align of row
///
/// If one of the align is not same as the others, it will return TableAlign.left.
TableAlign get allRowAlign {
final alignSet = rowAligns.values.toSet();
if (alignSet.length == 1) {
return TableAlign.fromString(alignSet.first);
}
return TableAlign.left;
}
/// Get table align of the table.
///
/// If one of the align is not same as the others, it will return TableAlign.left.
TableAlign get tableAlign {
if (allColumnAlign != TableAlign.left) {
return allColumnAlign;
} else if (allRowAlign != TableAlign.left) {
return allRowAlign;
}
return TableAlign.left;
}
}

View File

@ -173,7 +173,8 @@ extension TableOptionOperation on EditorState {
for (var i = 0; i < tableNode.columnLength; i++) {
attributes = attributes.mergeValues(
SimpleTableBlockKeys.columnAligns,
attributes[SimpleTableBlockKeys.columnAligns],
attributes[SimpleTableBlockKeys.columnAligns] ??
SimpleTableColumnAlignMap(),
duplicatedEntry: MapEntry(i.toString(), align.key),
);
}

View File

@ -174,5 +174,24 @@ void main() {
'1': '0xFF0000FF',
});
});
test('update table align', () async {
final (editorState, tableNode) = createEditorStateAndTable(
rowCount: 2,
columnCount: 3,
);
for (final align in [
TableAlign.center,
TableAlign.right,
TableAlign.left,
]) {
await editorState.updateTableAlign(
tableNode: tableNode,
align: align,
);
expect(tableNode.tableAlign, align);
}
});
});
}