mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-29 16:17:14 +00:00
feat: auto-fix table block data when duplicating it (#6185)
* fix: remove camera permission and update photo usage description * feat: optimize the error block style in document * feat: auto-fix table block when duplicating it
This commit is contained in:
parent
589f5c1298
commit
8e34951477
@ -4,7 +4,8 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/bl
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/option_action.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -64,7 +65,7 @@ class BlockOptionButton extends StatelessWidget {
|
||||
},
|
||||
onSelected: (action, controller) {
|
||||
if (action is OptionActionWrapper) {
|
||||
_onSelectAction(action.inner);
|
||||
_onSelectAction(context, action.inner);
|
||||
controller.close();
|
||||
}
|
||||
},
|
||||
@ -121,7 +122,7 @@ class BlockOptionButton extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _onSelectAction(OptionAction action) {
|
||||
void _onSelectAction(BuildContext context, OptionAction action) {
|
||||
final node = blockComponentContext.node;
|
||||
final transaction = editorState.transaction;
|
||||
switch (action) {
|
||||
@ -129,10 +130,7 @@ class BlockOptionButton extends StatelessWidget {
|
||||
transaction.deleteNode(node);
|
||||
break;
|
||||
case OptionAction.duplicate:
|
||||
transaction.insertNode(
|
||||
node.path.next,
|
||||
node.copyWith(),
|
||||
);
|
||||
_duplicateBlock(context, transaction, node);
|
||||
break;
|
||||
case OptionAction.turnInto:
|
||||
break;
|
||||
@ -150,4 +148,102 @@ class BlockOptionButton extends StatelessWidget {
|
||||
}
|
||||
editorState.apply(transaction);
|
||||
}
|
||||
|
||||
void _duplicateBlock(
|
||||
BuildContext context,
|
||||
Transaction transaction,
|
||||
Node node,
|
||||
) {
|
||||
// 1. verify the node integrity
|
||||
final type = node.type;
|
||||
final builder =
|
||||
context.read<EditorState>().renderer.blockComponentBuilder(type);
|
||||
|
||||
if (builder == null) {
|
||||
Log.error('Block type $type is not supported');
|
||||
return;
|
||||
}
|
||||
|
||||
final valid = builder.validate(node);
|
||||
if (!valid) {
|
||||
Log.error('Block type $type is not valid');
|
||||
}
|
||||
|
||||
// 2. duplicate the node
|
||||
// the _copyBlock will fix the table block
|
||||
final newNode = _copyBlock(context, node);
|
||||
|
||||
// 3. insert the node to the next of the current node
|
||||
transaction.insertNode(
|
||||
node.path.next,
|
||||
newNode,
|
||||
);
|
||||
}
|
||||
|
||||
Node _copyBlock(BuildContext context, Node node) {
|
||||
Node copiedNode = node.copyWith();
|
||||
|
||||
final type = node.type;
|
||||
final builder =
|
||||
context.read<EditorState>().renderer.blockComponentBuilder(type);
|
||||
|
||||
if (builder == null) {
|
||||
Log.error('Block type $type is not supported');
|
||||
} else {
|
||||
final valid = builder.validate(node);
|
||||
if (!valid) {
|
||||
Log.error('Block type $type is not valid');
|
||||
if (node.type == TableBlockKeys.type) {
|
||||
copiedNode = _fixTableBlock(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copiedNode;
|
||||
}
|
||||
|
||||
Node _fixTableBlock(Node node) {
|
||||
if (node.type != TableBlockKeys.type) {
|
||||
return node;
|
||||
}
|
||||
|
||||
// the table node should contains colsLen and rowsLen
|
||||
final colsLen = node.attributes[TableBlockKeys.colsLen];
|
||||
final rowsLen = node.attributes[TableBlockKeys.rowsLen];
|
||||
if (colsLen == null || rowsLen == null) {
|
||||
return node;
|
||||
}
|
||||
|
||||
final newChildren = <Node>[];
|
||||
final children = node.children;
|
||||
|
||||
// based on the colsLen and rowsLen, iterate the children and fix the data
|
||||
for (var i = 0; i < rowsLen; i++) {
|
||||
for (var j = 0; j < colsLen; j++) {
|
||||
final cell = children
|
||||
.where(
|
||||
(n) =>
|
||||
n.attributes[TableCellBlockKeys.rowPosition] == i &&
|
||||
n.attributes[TableCellBlockKeys.colPosition] == j,
|
||||
)
|
||||
.firstOrNull;
|
||||
if (cell != null) {
|
||||
newChildren.add(cell.copyWith());
|
||||
} else {
|
||||
newChildren.add(
|
||||
tableCellNode('', i, j),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node.copyWith(
|
||||
children: newChildren,
|
||||
attributes: {
|
||||
...node.attributes,
|
||||
TableBlockKeys.colsLen: colsLen,
|
||||
TableBlockKeys.rowsLen: rowsLen,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/animated_gesture.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -59,25 +60,15 @@ class _ErrorBlockComponentWidgetState extends State<ErrorBlockComponentWidget>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget child = DecoratedBox(
|
||||
Widget child = Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: FlowyButton(
|
||||
onTap: () async {
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
LocaleKeys.document_errorBlock_blockContentHasBeenCopied.tr(),
|
||||
);
|
||||
await getIt<ClipboardService>().setData(
|
||||
ClipboardServiceData(plainText: jsonEncode(node.toJson())),
|
||||
);
|
||||
},
|
||||
text: PlatformExtension.isDesktopOrWeb
|
||||
? _buildDesktopErrorBlock(context)
|
||||
: _buildMobileErrorBlock(context),
|
||||
),
|
||||
child: PlatformExtension.isDesktopOrWeb
|
||||
? _buildDesktopErrorBlock(context)
|
||||
: _buildMobileErrorBlock(context),
|
||||
);
|
||||
|
||||
child = Padding(
|
||||
@ -107,40 +98,61 @@ class _ErrorBlockComponentWidgetState extends State<ErrorBlockComponentWidget>
|
||||
Widget _buildDesktopErrorBlock(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
child: Row(
|
||||
children: [
|
||||
const HSpace(4),
|
||||
const HSpace(12),
|
||||
FlowyText.regular(
|
||||
LocaleKeys.document_errorBlock_theBlockIsNotSupported.tr(),
|
||||
LocaleKeys.document_errorBlock_parseError.tr(args: [node.type]),
|
||||
),
|
||||
const HSpace(4),
|
||||
FlowyText.regular(
|
||||
'(${LocaleKeys.document_errorBlock_clickToCopyTheBlockContent.tr()})',
|
||||
color: Theme.of(context).hintColor,
|
||||
const Spacer(),
|
||||
OutlinedRoundedButton(
|
||||
text: LocaleKeys.document_errorBlock_copyBlockContent.tr(),
|
||||
onTap: _copyBlockContent,
|
||||
),
|
||||
const HSpace(12),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMobileErrorBlock(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FlowyText.regular(
|
||||
LocaleKeys.document_errorBlock_theBlockIsNotSupported.tr(),
|
||||
),
|
||||
const VSpace(6),
|
||||
FlowyText.regular(
|
||||
'(${LocaleKeys.document_errorBlock_clickToCopyTheBlockContent.tr()})',
|
||||
color: Theme.of(context).hintColor,
|
||||
fontSize: 12.0,
|
||||
),
|
||||
],
|
||||
return AnimatedGestureDetector(
|
||||
onTapUp: _copyBlockContent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4.0, right: 24.0),
|
||||
child: FlowyText.regular(
|
||||
LocaleKeys.document_errorBlock_parseError.tr(args: [node.type]),
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
const VSpace(6),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: FlowyText.regular(
|
||||
'(${LocaleKeys.document_errorBlock_clickToCopyTheBlockContent.tr()})',
|
||||
color: Theme.of(context).hintColor,
|
||||
fontSize: 12.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _copyBlockContent() {
|
||||
showToastNotification(
|
||||
context,
|
||||
message: LocaleKeys.document_errorBlock_blockContentHasBeenCopied.tr(),
|
||||
);
|
||||
|
||||
getIt<ClipboardService>().setData(
|
||||
ClipboardServiceData(plainText: jsonEncode(node.toJson())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,8 +53,8 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: da0a56c
|
||||
resolved-ref: da0a56cf721c55dc2ab944d0769d2821aba509b7
|
||||
ref: "44989c5"
|
||||
resolved-ref: "44989c568e71fbf41970ec390cbb62f0db99b6e5"
|
||||
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
|
||||
source: git
|
||||
version: "3.2.0"
|
||||
|
||||
@ -190,7 +190,7 @@ dependency_overrides:
|
||||
appflowy_editor:
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
||||
ref: "da0a56c"
|
||||
ref: "44989c5"
|
||||
|
||||
appflowy_editor_plugins:
|
||||
git:
|
||||
|
||||
@ -1798,7 +1798,9 @@
|
||||
"errorBlock": {
|
||||
"theBlockIsNotSupported": "Unable to parse the block content",
|
||||
"clickToCopyTheBlockContent": "Click to copy the block content",
|
||||
"blockContentHasBeenCopied": "The block content has been copied."
|
||||
"blockContentHasBeenCopied": "The block content has been copied.",
|
||||
"parseError": "An error occurred while parsing the {} block.",
|
||||
"copyBlockContent": "Copy block content"
|
||||
},
|
||||
"mobilePageSelector": {
|
||||
"title": "Select page",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user