feat: support align and upgrade appflowy_editor (#2712)
* feat: support align and upgrade appflowy_editor * chore: try to fix linux analyze error * fix: error after inserting callout block * feat: add inline board / grid plugin * feat: refactor insert_page * fix: ref view in document * chore: add asset name and description to option align type * fix: linux flutter analyze * chore: disable file export and log * fix: the window always back to center after relaunching * fix: potential data lost in nested list * feat: re-design login page * fix: can't remove background color * chore: rename bundle id and change the macos app to non sandbox app --------- Co-authored-by: nathan <nathan@appflowy.io>
10
frontend/appflowy_flutter/assets/images/common/archive.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_10_2941)">
|
||||
<path d="M17.9706 5.70199L17.9706 5.702L17.9712 5.70405L20.4218 13.6624C20.4393 13.7435 20.4508 13.8258 20.4561 13.9086V19.3106C20.4561 19.7769 20.078 20.1549 19.6117 20.1548H3.40062C2.93431 20.1549 2.55625 19.7769 2.55625 19.3106V13.9086C2.56155 13.8257 2.57301 13.7433 2.59054 13.6622L4.97263 5.70366C5.26597 4.72587 6.16595 4.05625 7.1868 4.05625L15.8285 4.05625C16.8329 4.05625 17.7119 4.7315 17.9706 5.70199ZM4.55716 12.99L4.53544 13.0624H4.61104H8.80431C9.02825 13.0624 9.24302 13.1514 9.40137 13.3097C9.55971 13.4681 9.64867 13.6828 9.64867 13.9068V14.8074V14.8636H9.70492H13.3074H13.3636V14.8074V13.9068C13.3636 13.6828 13.4526 13.4681 13.6109 13.3097C13.7693 13.1514 13.9841 13.0624 14.208 13.0624H18.4013H18.4769L18.4551 12.99L16.5342 6.5868C16.3843 6.08715 15.9244 5.74498 15.4028 5.74498H7.60955C7.0879 5.74498 6.62802 6.08715 6.47812 6.5868L4.55716 12.99ZM15.1086 14.7511H15.0524V14.8074V15.708C15.0524 15.8189 15.0305 15.9287 14.9881 16.0311C14.9457 16.1336 14.8835 16.2267 14.8051 16.3051C14.7267 16.3835 14.6336 16.4457 14.5311 16.4881C14.4287 16.5305 14.3189 16.5524 14.208 16.5524H8.80431C8.69343 16.5524 8.58363 16.5305 8.48118 16.4881C8.37874 16.4457 8.28566 16.3835 8.20725 16.3051C8.12885 16.2267 8.06665 16.1336 8.02422 16.0311C7.98178 15.9287 7.95994 15.8189 7.95994 15.708V14.8074V14.7511H7.90369H4.52623C4.3709 14.7511 4.24498 14.8771 4.24498 15.0324V18.1849C4.24498 18.3402 4.3709 18.4661 4.52623 18.4661H18.4861C18.6414 18.4661 18.7673 18.3402 18.7673 18.1849V15.0324C18.7673 14.8771 18.6414 14.7511 18.4861 14.7511H15.1086ZM8.80435 10.2481C8.58041 10.2481 8.36564 10.1591 8.20729 10.0007C8.04895 9.8424 7.95999 9.62763 7.95999 9.40369C7.95999 9.17975 8.04895 8.96498 8.20729 8.80663C8.36564 8.64829 8.58041 8.55933 8.80435 8.55933H14.208C14.432 8.55933 14.6468 8.64829 14.8051 8.80663C14.9635 8.96498 15.0524 9.17975 15.0524 9.40369C15.0524 9.62763 14.9635 9.8424 14.8051 10.0007C14.6468 10.1591 14.432 10.2481 14.208 10.2481H8.80435Z" fill="#333333" stroke="white" stroke-width="0.1125"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_10_2941">
|
||||
<rect width="18" height="16.2111" fill="white" transform="translate(2.5 4)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
@ -6,6 +6,8 @@
|
||||
"subscribeNewsletterText": "Subscribe to Newsletter",
|
||||
"letsGoButtonText": "Quick Start",
|
||||
"title": "Title",
|
||||
"youCanAlso": "You can also",
|
||||
"and": "and",
|
||||
"signUp": {
|
||||
"buttonText": "Sign Up",
|
||||
"title": "Sign Up to @:appName",
|
||||
@ -196,6 +198,7 @@
|
||||
"selectFiles": "Select the files that need to be export",
|
||||
"createNewFolder": "Create a new folder",
|
||||
"createNewFolderDesc": "Tell us where you want to store your data",
|
||||
"defineWhereYourDataIsStored": "Define where your data is stored",
|
||||
"open": "Open",
|
||||
"openFolder": "Open an existing folder",
|
||||
"openFolderDesc": "Read and write it to your existing AppFlowy folder",
|
||||
@ -204,6 +207,7 @@
|
||||
"locationDesc": "Pick a name for your AppFlowy data folder",
|
||||
"browser": "Browse",
|
||||
"create": "Create",
|
||||
"set": "Set",
|
||||
"folderPath": "Path to store your folder",
|
||||
"locationCannotBeEmpty": "Path cannot be empty",
|
||||
"pathCopiedSnackbar": "File storage path copied to clipboard!",
|
||||
@ -420,7 +424,12 @@
|
||||
"turnInto": "Turn into",
|
||||
"moveUp": "Move up",
|
||||
"moveDown": "Move down",
|
||||
"color": "Color"
|
||||
"color": "Color",
|
||||
"align": "Align",
|
||||
"left": "Left",
|
||||
"center": "Center",
|
||||
"right": "Right",
|
||||
"defaultColor": "Default"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document2/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart'
|
||||
show
|
||||
@ -31,11 +30,12 @@ class TransactionAdapter {
|
||||
final String documentId;
|
||||
|
||||
Future<void> apply(Transaction transaction, EditorState editorState) async {
|
||||
// Log.debug('transaction => ${transaction.toJson()}');
|
||||
final actions = transaction.operations
|
||||
.map((op) => op.toBlockAction(editorState))
|
||||
.whereNotNull()
|
||||
.expand((element) => element);
|
||||
Log.debug('actions => $actions');
|
||||
// Log.debug('actions => $actions');
|
||||
await documentService.applyAction(
|
||||
documentId: documentId,
|
||||
actions: actions,
|
||||
@ -85,6 +85,12 @@ extension on InsertOperation {
|
||||
..action = BlockActionTypePB.Insert
|
||||
..payload = payload,
|
||||
);
|
||||
if (node.children.isNotEmpty) {
|
||||
final childrenActions = node.children
|
||||
.map((e) => InsertOperation(e.path, [e]).toBlockAction(editorState))
|
||||
.expand((element) => element);
|
||||
actions.addAll(childrenActions);
|
||||
}
|
||||
previousNode = node;
|
||||
}
|
||||
return actions;
|
||||
|
@ -24,16 +24,6 @@ class AppFlowyEditorPage extends StatefulWidget {
|
||||
|
||||
class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
final scrollController = ScrollController();
|
||||
final slashMenuItems = [
|
||||
boardMenuItem,
|
||||
gridMenuItem,
|
||||
calloutItem,
|
||||
dividerMenuItem,
|
||||
mathEquationItem,
|
||||
codeBlockItem,
|
||||
emojiMenuItem,
|
||||
autoGeneratorMenuItem,
|
||||
];
|
||||
|
||||
final List<CommandShortcutEvent> commandShortcutEvents = [
|
||||
...codeBlockCommands,
|
||||
@ -53,6 +43,19 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
highlightColorItem,
|
||||
];
|
||||
|
||||
late final slashMenuItems = [
|
||||
dividerMenuItem,
|
||||
inlineGridMenuItem(documentBloc),
|
||||
referenceGridMenuItem,
|
||||
inlineBoardMenuItem(documentBloc),
|
||||
boardMenuItem,
|
||||
calloutItem,
|
||||
mathEquationItem,
|
||||
codeBlockItem,
|
||||
emojiMenuItem,
|
||||
autoGeneratorMenuItem,
|
||||
];
|
||||
|
||||
late final Map<String, BlockComponentBuilder> blockComponentBuilders =
|
||||
_customAppFlowyBlockComponentBuilders();
|
||||
late final List<CharacterShortcutEvent> characterShortcutEvents = [
|
||||
@ -170,7 +173,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
),
|
||||
textStyleBuilder: (level) => styleCustomizer.headingStyleBuilder(level),
|
||||
),
|
||||
ImageBlockKeys.type: ImageBlockComponentBuilder(),
|
||||
ImageBlockKeys.type: ImageBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
),
|
||||
BoardBlockKeys.type: BoardBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
),
|
||||
@ -225,14 +230,24 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
CalloutBlockKeys.type
|
||||
];
|
||||
|
||||
final supportAlignBuilderType = [
|
||||
ImageBlockKeys.type,
|
||||
];
|
||||
|
||||
final colorAction = [
|
||||
OptionAction.divider,
|
||||
OptionAction.color,
|
||||
];
|
||||
|
||||
final alignAction = [
|
||||
OptionAction.divider,
|
||||
OptionAction.align,
|
||||
];
|
||||
|
||||
final List<OptionAction> actions = [
|
||||
...standardActions,
|
||||
if (supportColorBuilderTypes.contains(entry.key)) ...colorAction,
|
||||
if (supportAlignBuilderType.contains(entry.key)) ...alignAction,
|
||||
];
|
||||
|
||||
builder.showActions = (_) => true;
|
||||
|
@ -24,14 +24,15 @@ class BlockOptionButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final popoverActions = actions.map((e) {
|
||||
if (e == OptionAction.divider) {
|
||||
return DividerOptionAction();
|
||||
} else if (e == OptionAction.color) {
|
||||
return ColorOptionAction(
|
||||
editorState: editorState,
|
||||
);
|
||||
} else {
|
||||
return OptionActionWrapper(e);
|
||||
switch (e) {
|
||||
case OptionAction.divider:
|
||||
return DividerOptionAction();
|
||||
case OptionAction.color:
|
||||
return ColorOptionAction(editorState: editorState);
|
||||
case OptionAction.align:
|
||||
return AlignOptionAction(editorState: editorState);
|
||||
default:
|
||||
return OptionActionWrapper(e);
|
||||
}
|
||||
}).toList();
|
||||
|
||||
@ -119,6 +120,7 @@ class BlockOptionButton extends StatelessWidget {
|
||||
case OptionAction.moveDown:
|
||||
transaction.moveNode(node.path.next.next, node);
|
||||
break;
|
||||
case OptionAction.align:
|
||||
case OptionAction.color:
|
||||
case OptionAction.divider:
|
||||
throw UnimplementedError();
|
||||
|
@ -1,12 +1,12 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/select_option_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg;
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
@ -18,6 +18,90 @@ enum OptionAction {
|
||||
moveDown,
|
||||
color,
|
||||
divider,
|
||||
align;
|
||||
|
||||
String get assetName {
|
||||
switch (this) {
|
||||
case OptionAction.delete:
|
||||
return 'editor/delete';
|
||||
case OptionAction.duplicate:
|
||||
return 'editor/duplicate';
|
||||
case OptionAction.turnInto:
|
||||
return 'editor/turn_into';
|
||||
case OptionAction.moveUp:
|
||||
return 'editor/move_up';
|
||||
case OptionAction.moveDown:
|
||||
return 'editor/move_down';
|
||||
case OptionAction.color:
|
||||
return 'editor/color';
|
||||
case OptionAction.divider:
|
||||
return 'editor/divider';
|
||||
case OptionAction.align:
|
||||
return 'editor/align/center';
|
||||
}
|
||||
}
|
||||
|
||||
String get description {
|
||||
switch (this) {
|
||||
case OptionAction.delete:
|
||||
return LocaleKeys.document_plugins_optionAction_delete.tr();
|
||||
case OptionAction.duplicate:
|
||||
return LocaleKeys.document_plugins_optionAction_duplicate.tr();
|
||||
case OptionAction.turnInto:
|
||||
return LocaleKeys.document_plugins_optionAction_turnInto.tr();
|
||||
case OptionAction.moveUp:
|
||||
return LocaleKeys.document_plugins_optionAction_moveUp.tr();
|
||||
case OptionAction.moveDown:
|
||||
return LocaleKeys.document_plugins_optionAction_moveDown.tr();
|
||||
case OptionAction.color:
|
||||
return LocaleKeys.document_plugins_optionAction_color.tr();
|
||||
case OptionAction.align:
|
||||
return LocaleKeys.document_plugins_optionAction_align.tr();
|
||||
case OptionAction.divider:
|
||||
throw UnsupportedError('Divider does not have description');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum OptionAlignType {
|
||||
left,
|
||||
center,
|
||||
right;
|
||||
|
||||
static OptionAlignType fromString(String? value) {
|
||||
switch (value) {
|
||||
case 'left':
|
||||
return OptionAlignType.left;
|
||||
case 'center':
|
||||
return OptionAlignType.center;
|
||||
case 'right':
|
||||
return OptionAlignType.right;
|
||||
default:
|
||||
return OptionAlignType.center;
|
||||
}
|
||||
}
|
||||
|
||||
String get assetName {
|
||||
switch (this) {
|
||||
case OptionAlignType.left:
|
||||
return 'editor/align/left';
|
||||
case OptionAlignType.center:
|
||||
return 'editor/align/center';
|
||||
case OptionAlignType.right:
|
||||
return 'editor/align/right';
|
||||
}
|
||||
}
|
||||
|
||||
String get description {
|
||||
switch (this) {
|
||||
case OptionAlignType.left:
|
||||
return LocaleKeys.document_plugins_optionAction_left.tr();
|
||||
case OptionAlignType.center:
|
||||
return LocaleKeys.document_plugins_optionAction_center.tr();
|
||||
case OptionAlignType.right:
|
||||
return LocaleKeys.document_plugins_optionAction_right.tr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DividerOptionAction extends CustomActionCell {
|
||||
@ -30,6 +114,98 @@ class DividerOptionAction extends CustomActionCell {
|
||||
}
|
||||
}
|
||||
|
||||
class AlignOptionAction extends PopoverActionCell {
|
||||
AlignOptionAction({
|
||||
required this.editorState,
|
||||
});
|
||||
|
||||
final EditorState editorState;
|
||||
|
||||
@override
|
||||
Widget? leftIcon(Color iconColor) {
|
||||
return FlowySvg(
|
||||
name: align.assetName,
|
||||
size: const Size.square(12),
|
||||
).padding(all: 2.0);
|
||||
}
|
||||
|
||||
@override
|
||||
String get name {
|
||||
return LocaleKeys.document_plugins_optionAction_align.tr();
|
||||
}
|
||||
|
||||
@override
|
||||
PopoverActionCellBuilder get builder =>
|
||||
(context, parentController, controller) {
|
||||
final selection = editorState.selection?.normalized;
|
||||
if (selection == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final children = buildAlignOptions(context, (align) async {
|
||||
await onAlignChanged(align);
|
||||
controller.close();
|
||||
parentController.close();
|
||||
});
|
||||
return IntrinsicHeight(
|
||||
child: IntrinsicWidth(
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
List<Widget> buildAlignOptions(
|
||||
BuildContext context,
|
||||
void Function(OptionAlignType) onTap,
|
||||
) {
|
||||
return OptionAlignType.values.map((e) => OptionAlignWrapper(e)).map((e) {
|
||||
final leftIcon = e.leftIcon(Theme.of(context).colorScheme.onSurface);
|
||||
final rightIcon = e.rightIcon(Theme.of(context).colorScheme.onSurface);
|
||||
return HoverButton(
|
||||
onTap: () => onTap(e.inner),
|
||||
itemHeight: ActionListSizes.itemHeight,
|
||||
leftIcon: leftIcon,
|
||||
name: e.name,
|
||||
rightIcon: rightIcon,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
OptionAlignType get align {
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return OptionAlignType.center;
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
final align = node?.attributes['align'];
|
||||
return OptionAlignType.fromString(align);
|
||||
}
|
||||
|
||||
Future<void> onAlignChanged(OptionAlignType align) async {
|
||||
if (align == this.align) {
|
||||
return;
|
||||
}
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return;
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
final transaction = editorState.transaction;
|
||||
transaction.updateNode(node, {
|
||||
'align': align.name,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
class ColorOptionAction extends PopoverActionCell {
|
||||
ColorOptionAction({
|
||||
required this.editorState,
|
||||
@ -46,60 +222,61 @@ class ColorOptionAction extends PopoverActionCell {
|
||||
}
|
||||
|
||||
@override
|
||||
String get name {
|
||||
return LocaleKeys.toolbar_color.tr();
|
||||
}
|
||||
String get name => LocaleKeys.document_plugins_optionAction_color.tr();
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext context, PopoverController controller)
|
||||
get builder => (context, controller) {
|
||||
final selection = editorState.selection?.normalized;
|
||||
if (selection == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final bgColor =
|
||||
node.attributes[blockComponentBackgroundColor] as String?;
|
||||
final selectedColor = convertHexToSelectOptionColorPB(
|
||||
bgColor,
|
||||
context,
|
||||
);
|
||||
|
||||
return SelectOptionColorList(
|
||||
selectedColor: selectedColor,
|
||||
onSelectedColor: (color) {
|
||||
controller.close();
|
||||
|
||||
final nodes = editorState.getNodesInSelection(selection);
|
||||
final transaction = editorState.transaction;
|
||||
for (final node in nodes) {
|
||||
transaction.updateNode(node, {
|
||||
blockComponentBackgroundColor:
|
||||
color.toColor(context).toHex(),
|
||||
});
|
||||
}
|
||||
editorState.apply(transaction);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
SelectOptionColorPB? convertHexToSelectOptionColorPB(
|
||||
String? hexColor,
|
||||
Widget Function(
|
||||
BuildContext context,
|
||||
) {
|
||||
if (hexColor == null) {
|
||||
return null;
|
||||
}
|
||||
for (final value in SelectOptionColorPB.values) {
|
||||
if (value.toColor(context).toHex() == hexColor) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
PopoverController parentController,
|
||||
PopoverController controller,
|
||||
) get builder => (context, parentController, controller) {
|
||||
final selection = editorState.selection?.normalized;
|
||||
if (selection == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final bgColor =
|
||||
node.attributes[blockComponentBackgroundColor] as String?;
|
||||
final selectedColor = bgColor?.toColor();
|
||||
|
||||
final colors = [
|
||||
// clear background color.
|
||||
FlowyColorOption(
|
||||
color: Colors.transparent,
|
||||
name: LocaleKeys.document_plugins_optionAction_defaultColor.tr(),
|
||||
),
|
||||
...FlowyTint.values.map(
|
||||
(e) => FlowyColorOption(
|
||||
color: e.color(context),
|
||||
name: e.tintName(AppFlowyEditorLocalizations.current),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
return FlowyColorPicker(
|
||||
colors: colors,
|
||||
selected: selectedColor,
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
width: 1,
|
||||
),
|
||||
onTap: (color, index) async {
|
||||
final transaction = editorState.transaction;
|
||||
final backgroundColor =
|
||||
color == Colors.transparent ? null : color.toHex();
|
||||
transaction.updateNode(node, {
|
||||
blockComponentBackgroundColor: backgroundColor,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
|
||||
controller.close();
|
||||
parentController.close();
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
class OptionActionWrapper extends ActionCell {
|
||||
@ -108,60 +285,20 @@ class OptionActionWrapper extends ActionCell {
|
||||
final OptionAction inner;
|
||||
|
||||
@override
|
||||
Widget? leftIcon(Color iconColor) {
|
||||
var name = '';
|
||||
// TODO: add icons.
|
||||
switch (inner) {
|
||||
case OptionAction.delete:
|
||||
name = 'editor/delete';
|
||||
break;
|
||||
case OptionAction.duplicate:
|
||||
name = 'editor/duplicate';
|
||||
break;
|
||||
case OptionAction.turnInto:
|
||||
name = 'editor/turn_into';
|
||||
break;
|
||||
case OptionAction.moveUp:
|
||||
name = 'editor/move_up';
|
||||
break;
|
||||
case OptionAction.moveDown:
|
||||
name = 'editor/move_down';
|
||||
break;
|
||||
default:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
if (name.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return FlowySvg(name: name);
|
||||
}
|
||||
Widget? leftIcon(Color iconColor) => FlowySvg(name: inner.assetName);
|
||||
|
||||
@override
|
||||
String get name {
|
||||
var description = '';
|
||||
switch (inner) {
|
||||
// TODO: l10n
|
||||
case OptionAction.delete:
|
||||
description = LocaleKeys.document_plugins_optionAction_delete.tr();
|
||||
break;
|
||||
case OptionAction.duplicate:
|
||||
description = LocaleKeys.document_plugins_optionAction_duplicate.tr();
|
||||
break;
|
||||
case OptionAction.turnInto:
|
||||
description = LocaleKeys.document_plugins_optionAction_turnInto.tr();
|
||||
break;
|
||||
case OptionAction.moveUp:
|
||||
description = LocaleKeys.document_plugins_optionAction_moveUp.tr();
|
||||
break;
|
||||
case OptionAction.moveDown:
|
||||
description = LocaleKeys.document_plugins_optionAction_moveDown.tr();
|
||||
break;
|
||||
case OptionAction.color:
|
||||
description = LocaleKeys.document_plugins_optionAction_color.tr();
|
||||
break;
|
||||
case OptionAction.divider:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
String get name => inner.description;
|
||||
}
|
||||
|
||||
class OptionAlignWrapper extends ActionCell {
|
||||
OptionAlignWrapper(this.inner);
|
||||
|
||||
final OptionAlignType inner;
|
||||
|
||||
@override
|
||||
Widget? leftIcon(Color iconColor) => FlowySvg(name: inner.assetName);
|
||||
|
||||
@override
|
||||
String get name => inner.description;
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class OptionActionList extends StatelessWidget {
|
||||
case OptionAction.moveDown:
|
||||
transaction.moveNode(node.path.next.next, node);
|
||||
break;
|
||||
case OptionAction.align:
|
||||
case OptionAction.color:
|
||||
case OptionAction.divider:
|
||||
throw UnimplementedError();
|
||||
|
@ -15,7 +15,31 @@ class DatabaseBlockKeys {
|
||||
}
|
||||
|
||||
extension InsertDatabase on EditorState {
|
||||
Future<void> insertPage(ViewPB parentView, ViewPB childView) async {
|
||||
Future<void> insertInlinePage(String parentViewId, ViewPB childView) async {
|
||||
final selection = this.selection;
|
||||
if (selection == null || !selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
final node = getNodeAtPath(selection.end.path);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final transaction = this.transaction;
|
||||
transaction.insertNode(
|
||||
selection.end.path,
|
||||
Node(
|
||||
type: _convertPageType(childView),
|
||||
attributes: {
|
||||
DatabaseBlockKeys.parentID: parentViewId,
|
||||
DatabaseBlockKeys.viewID: childView.id,
|
||||
},
|
||||
),
|
||||
);
|
||||
await apply(transaction);
|
||||
}
|
||||
|
||||
Future<void> insertReferencePage(ViewPB childView) async {
|
||||
final selection = this.selection;
|
||||
if (selection == null || !selection.isCollapsed) {
|
||||
return;
|
||||
|
@ -35,7 +35,7 @@ void showLinkToPageMenu(
|
||||
layoutType: pageType,
|
||||
hintText: pageType.toHintText(),
|
||||
onSelected: (appPB, viewPB) {
|
||||
editorState.insertPage(appPB, viewPB);
|
||||
editorState.insertReferencePage(viewPB);
|
||||
linkToPageMenuEntry.remove();
|
||||
},
|
||||
),
|
||||
|
@ -7,7 +7,7 @@ import 'package:appflowy/plugins/document/application/prelude.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/insert_page_command.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
SelectionMenuItem boardViewMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem inlineBoardMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
name: LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
@ -15,43 +15,21 @@ SelectionMenuItem boardViewMenuItem(DocumentBloc documentBloc) =>
|
||||
isSelected: onSelected,
|
||||
style: style,
|
||||
),
|
||||
keywords: ['board', 'kanban'],
|
||||
keywords: ['board', 'kanban', 'database'],
|
||||
handler: (editorState, menuService, context) async {
|
||||
if (!documentBloc.view.hasParentViewId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final appId = documentBloc.view.parentViewId;
|
||||
final service = ViewBackendService();
|
||||
|
||||
final result = (await ViewBackendService.createView(
|
||||
parentViewId: appId,
|
||||
final parentViewId = documentBloc.view.parentViewId;
|
||||
ViewBackendService.createView(
|
||||
parentViewId: parentViewId,
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layoutType: ViewLayoutPB.Board,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
|
||||
// If the result is null, then something went wrong here.
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final app = (await service.getView(result.viewId)).getLeftOrNull();
|
||||
// We should show an error dialog.
|
||||
if (app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final view = (await service.getChildView(
|
||||
parentViewId: result.viewId,
|
||||
childViewId: result.id,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
// As this.
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorState.insertPage(app, view);
|
||||
).then(
|
||||
(value) => value
|
||||
.swap()
|
||||
.map((r) => editorState.insertInlinePage(parentViewId, r)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -51,7 +51,7 @@ SelectionMenuItem calloutItem = SelectionMenuItem.node(
|
||||
nodeBuilder: (editorState) => calloutNode(),
|
||||
replace: (_, node) => node.delta?.isEmpty ?? false,
|
||||
updateSelection: (_, path, __, ___) {
|
||||
return Selection.single(path: [...path, 0], startOffset: 0);
|
||||
return Selection.single(path: path, startOffset: 0);
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -6,14 +6,14 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
SelectionMenuItem gridMenuItem = SelectionMenuItem(
|
||||
SelectionMenuItem referenceGridMenuItem = SelectionMenuItem(
|
||||
name: LocaleKeys.document_plugins_referencedGrid.tr(),
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
name: 'editor/board',
|
||||
name: 'editor/grid',
|
||||
isSelected: onSelected,
|
||||
style: style,
|
||||
),
|
||||
keywords: ['referenced', 'grid'],
|
||||
keywords: ['referenced', 'grid', 'database'],
|
||||
handler: (editorState, menuService, context) {
|
||||
final container = Overlay.of(context);
|
||||
showLinkToPageMenu(
|
||||
|
@ -7,7 +7,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
SelectionMenuItem gridViewMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem inlineGridMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
name: LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
@ -15,43 +15,22 @@ SelectionMenuItem gridViewMenuItem(DocumentBloc documentBloc) =>
|
||||
isSelected: onSelected,
|
||||
style: style,
|
||||
),
|
||||
keywords: ['grid'],
|
||||
keywords: ['grid', 'database'],
|
||||
handler: (editorState, menuService, context) async {
|
||||
if (!documentBloc.view.hasParentViewId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final appId = documentBloc.view.parentViewId;
|
||||
final service = ViewBackendService();
|
||||
|
||||
final result = (await ViewBackendService.createView(
|
||||
parentViewId: appId,
|
||||
final parentViewId = documentBloc.view.parentViewId;
|
||||
ViewBackendService.createView(
|
||||
parentViewId: parentViewId,
|
||||
openAfterCreate: false,
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layoutType: ViewLayoutPB.Grid,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
|
||||
// If the result is null, then something went wrong here.
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final app = (await service.getView(result.viewId)).getLeftOrNull();
|
||||
// We should show an error dialog.
|
||||
if (app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final view = (await service.getChildView(
|
||||
parentViewId: result.viewId,
|
||||
childViewId: result.id,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
// As this.
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorState.insertPage(app, view);
|
||||
).then(
|
||||
(value) => value
|
||||
.swap()
|
||||
.map((r) => editorState.insertInlinePage(parentViewId, r)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -8,12 +8,15 @@ import 'package:appflowy/startup/startup.dart';
|
||||
|
||||
class WindowSizeManager {
|
||||
static const double minWindowHeight = 400.0;
|
||||
static const double minWindowWidth = 600.0;
|
||||
static const double minWindowWidth = 800.0;
|
||||
|
||||
static const width = 'width';
|
||||
static const height = 'height';
|
||||
|
||||
Future<void> saveSize(Size size) async {
|
||||
final windowSize = {
|
||||
'height': max(size.height, minWindowHeight),
|
||||
'width': max(size.width, minWindowWidth),
|
||||
height: max(size.height, minWindowHeight),
|
||||
width: max(size.width, minWindowWidth),
|
||||
};
|
||||
|
||||
await getIt<KeyValueStorage>().set(
|
||||
@ -23,14 +26,11 @@ class WindowSizeManager {
|
||||
}
|
||||
|
||||
Future<Size> getSize() async {
|
||||
const defaultWindowSize = '{"height": 600.0, "width": 800.0}';
|
||||
final defaultWindowSize = jsonEncode({height: 600.0, width: 800.0});
|
||||
final windowSize = await getIt<KeyValueStorage>().get(KVKeys.windowSize);
|
||||
final size = json.decode(
|
||||
windowSize.fold(
|
||||
(l) => defaultWindowSize,
|
||||
(r) => r,
|
||||
),
|
||||
windowSize.getOrElse(() => defaultWindowSize),
|
||||
);
|
||||
return Size(size['width']!, size['height']!);
|
||||
return Size(size[width]!, size[height]!);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ class InitAppWindowTask extends LaunchTask with WindowListener {
|
||||
WindowSizeManager.minWindowWidth,
|
||||
WindowSizeManager.minWindowHeight,
|
||||
),
|
||||
center: true,
|
||||
title: title,
|
||||
);
|
||||
|
||||
|
@ -2,9 +2,13 @@ import 'dart:io';
|
||||
|
||||
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/buttons/secondary_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../../../generated/locale_keys.g.dart';
|
||||
import '../../../startup/startup.dart';
|
||||
@ -19,9 +23,9 @@ enum _FolderPage {
|
||||
|
||||
class FolderWidget extends StatefulWidget {
|
||||
const FolderWidget({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.createFolderCallback,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final Future<void> Function() createFolderCallback;
|
||||
|
||||
@ -41,9 +45,6 @@ class _FolderWidgetState extends State<FolderWidget> {
|
||||
switch (page) {
|
||||
case _FolderPage.options:
|
||||
return FolderOptionsWidget(
|
||||
onPressedCreate: () {
|
||||
setState(() => page = _FolderPage.create);
|
||||
},
|
||||
onPressedOpen: () {
|
||||
_openFolder();
|
||||
},
|
||||
@ -65,43 +66,36 @@ class _FolderWidgetState extends State<FolderWidget> {
|
||||
if (path != null) {
|
||||
await getIt<LocalFileStorage>().setPath(path);
|
||||
await widget.createFolderCallback();
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FolderOptionsWidget extends StatelessWidget {
|
||||
const FolderOptionsWidget({
|
||||
Key? key,
|
||||
required this.onPressedCreate,
|
||||
super.key,
|
||||
required this.onPressedOpen,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final VoidCallback onPressedCreate;
|
||||
final VoidCallback onPressedOpen;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
_FolderCard(
|
||||
title: LocaleKeys.settings_files_createNewFolder.tr(),
|
||||
subtitle: LocaleKeys.settings_files_createNewFolderDesc.tr(),
|
||||
return FutureBuilder(
|
||||
future: getIt<LocalFileStorage>().getPath(),
|
||||
builder: (context, result) {
|
||||
final subtitle = result.hasData ? result.data! : '';
|
||||
return _FolderCard(
|
||||
icon: const FlowySvg(name: 'common/archive'),
|
||||
title: LocaleKeys.settings_files_defineWhereYourDataIsStored.tr(),
|
||||
subtitle: subtitle,
|
||||
trailing: _buildTextButton(
|
||||
context,
|
||||
LocaleKeys.settings_files_create.tr(),
|
||||
onPressedCreate,
|
||||
),
|
||||
),
|
||||
_FolderCard(
|
||||
title: LocaleKeys.settings_files_openFolder.tr(),
|
||||
subtitle: LocaleKeys.settings_files_openFolderDesc.tr(),
|
||||
trailing: _buildTextButton(
|
||||
context,
|
||||
LocaleKeys.settings_files_open.tr(),
|
||||
LocaleKeys.settings_files_set.tr(),
|
||||
onPressedOpen,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -224,27 +218,24 @@ Widget _buildTextButton(
|
||||
String title,
|
||||
VoidCallback onPressed,
|
||||
) {
|
||||
return FlowyTextButton(
|
||||
return SecondaryTextButton(
|
||||
title,
|
||||
mode: SecondaryTextButtonMode.small,
|
||||
onPressed: onPressed,
|
||||
fillColor: Theme.of(context).colorScheme.primary,
|
||||
fontColor: Theme.of(context).colorScheme.onPrimary,
|
||||
hoverColor: Theme.of(context).colorScheme.primaryContainer,
|
||||
);
|
||||
}
|
||||
|
||||
class _FolderCard extends StatelessWidget {
|
||||
const _FolderCard({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
this.trailing,
|
||||
}) : super(key: key);
|
||||
this.icon,
|
||||
});
|
||||
|
||||
final String title;
|
||||
|
||||
final String subtitle;
|
||||
|
||||
final Widget? icon;
|
||||
final Widget? trailing;
|
||||
|
||||
@override
|
||||
@ -252,31 +243,35 @@ class _FolderCard extends StatelessWidget {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
vertical: 16.0,
|
||||
horizontal: 16.0,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
if (icon != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
child: icon!,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FlowyText.medium(
|
||||
FlowyText.regular(
|
||||
title,
|
||||
fontSize: FontSizes.s14,
|
||||
fontFamily: GoogleFonts.poppins(
|
||||
fontWeight: FontWeight.w500,
|
||||
).fontFamily,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
subtitle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style:
|
||||
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const VSpace(4),
|
||||
FlowyText.regular(
|
||||
subtitle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontSize: FontSizes.s12,
|
||||
fontFamily: GoogleFonts.poppins(
|
||||
fontWeight: FontWeight.w300,
|
||||
).fontFamily,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'package:appflowy/core/frameless_window.dart';
|
||||
import 'package:appflowy/startup/entry_point.dart';
|
||||
import 'package:appflowy/startup/launch_configuration.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:dartz/dartz.dart' as dartz;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -11,11 +13,10 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../generated/locale_keys.g.dart';
|
||||
import '../../startup/launch_configuration.dart';
|
||||
import '../../startup/startup.dart';
|
||||
import 'folder/folder_widget.dart';
|
||||
import 'router.dart';
|
||||
import 'widgets/background.dart';
|
||||
@ -35,6 +36,8 @@ class SkipLogInScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
||||
var _didCustomizeFolder = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -48,60 +51,64 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
||||
Widget _renderBody(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
FlowyLogoTitle(
|
||||
title: LocaleKeys.welcomeText.tr(),
|
||||
logoSize: const Size.square(60),
|
||||
logoSize: const Size.square(40),
|
||||
),
|
||||
const VSpace(40),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
GoButton(
|
||||
onPressed: () => _autoRegister(context),
|
||||
),
|
||||
],
|
||||
const VSpace(32),
|
||||
GoButton(
|
||||
onPressed: () {
|
||||
if (_didCustomizeFolder) {
|
||||
_relaunchAppAndAutoRegister();
|
||||
} else {
|
||||
_autoRegister(context);
|
||||
}
|
||||
},
|
||||
),
|
||||
const VSpace(20),
|
||||
const VSpace(32),
|
||||
_buildSubscribeButtons(context),
|
||||
const VSpace(32),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
width: MediaQuery.of(context).size.width * 0.5,
|
||||
child: FolderWidget(
|
||||
createFolderCallback: () async {
|
||||
await FlowyRunner.run(
|
||||
FlowyApp(),
|
||||
config: const LaunchConfiguration(
|
||||
autoRegistrationSupported: true,
|
||||
),
|
||||
);
|
||||
_didCustomizeFolder = true;
|
||||
},
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
_buildSubscribeButtons(context),
|
||||
const VSpace(64),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Row _buildSubscribeButtons(BuildContext context) {
|
||||
Widget _buildSubscribeButtons(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FlowyText.regular(
|
||||
LocaleKeys.youCanAlso.tr(),
|
||||
fontSize: FontSizes.s12,
|
||||
),
|
||||
FlowyTextButton(
|
||||
LocaleKeys.githubStarText.tr(),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: Theme.of(context).colorScheme.primary,
|
||||
decoration: TextDecoration.underline,
|
||||
hoverColor: Colors.transparent,
|
||||
fillColor: Colors.transparent,
|
||||
onPressed: () =>
|
||||
_launchURL('https://github.com/AppFlowy-IO/appflowy'),
|
||||
onPressed: () => _launchURL(
|
||||
'https://github.com/AppFlowy-IO/appflowy',
|
||||
),
|
||||
),
|
||||
FlowyText.regular(
|
||||
LocaleKeys.and.tr(),
|
||||
fontSize: FontSizes.s12,
|
||||
),
|
||||
const HSpace(20),
|
||||
FlowyTextButton(
|
||||
LocaleKeys.subscribeNewsletterText.tr(),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: Theme.of(context).colorScheme.primary,
|
||||
decoration: TextDecoration.underline,
|
||||
hoverColor: Colors.transparent,
|
||||
fillColor: Colors.transparent,
|
||||
onPressed: () => _launchURL('https://www.appflowy.io/blog'),
|
||||
@ -110,7 +117,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
_launchURL(String url) async {
|
||||
Future<void> _launchURL(String url) async {
|
||||
final uri = Uri.parse(url);
|
||||
if (await canLaunchUrl(uri)) {
|
||||
await launchUrl(uri);
|
||||
@ -133,6 +140,15 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _relaunchAppAndAutoRegister() async {
|
||||
await FlowyRunner.run(
|
||||
FlowyApp(),
|
||||
config: const LaunchConfiguration(
|
||||
autoRegistrationSupported: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openCurrentWorkspace(
|
||||
BuildContext context,
|
||||
UserProfilePB user,
|
||||
@ -162,8 +178,14 @@ class GoButton extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyTextButton(
|
||||
LocaleKeys.letsGoButtonText.tr(),
|
||||
fontSize: FontSizes.s16,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 80, vertical: 12.0),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 340,
|
||||
maxHeight: 48,
|
||||
),
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
fontSize: FontSizes.s14,
|
||||
fontFamily: GoogleFonts.poppins(fontWeight: FontWeight.w500).fontFamily,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14.0),
|
||||
onPressed: onPressed,
|
||||
fillColor: Theme.of(context).colorScheme.primary,
|
||||
fontColor: Theme.of(context).colorScheme.onPrimary,
|
||||
|
@ -5,6 +5,7 @@ import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class AuthFormContainer extends StatelessWidget {
|
||||
final List<Widget> children;
|
||||
@ -43,12 +44,14 @@ class FlowyLogoTitle extends StatelessWidget {
|
||||
children: [
|
||||
SizedBox.fromSize(
|
||||
size: logoSize,
|
||||
child: svgWidget("flowy_logo"),
|
||||
child: svgWidget('flowy_logo'),
|
||||
),
|
||||
const VSpace(30),
|
||||
FlowyText.semibold(
|
||||
const VSpace(40),
|
||||
FlowyText.regular(
|
||||
title,
|
||||
fontSize: FontSizes.s24,
|
||||
fontFamily:
|
||||
GoogleFonts.poppins(fontWeight: FontWeight.w500).fontFamily,
|
||||
color: Theme.of(context).colorScheme.tertiary,
|
||||
),
|
||||
],
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_export_file_widget.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_file_customize_location_view.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsFileSystemView extends StatefulWidget {
|
||||
@ -14,7 +15,8 @@ class SettingsFileSystemView extends StatefulWidget {
|
||||
class _SettingsFileSystemViewState extends State<SettingsFileSystemView> {
|
||||
late final _items = [
|
||||
const SettingsFileLocationCustomizer(),
|
||||
const SettingsExportFileWidget()
|
||||
// disable export data for v0.2.0 in release mode.
|
||||
if (kDebugMode) const SettingsExportFileWidget()
|
||||
];
|
||||
|
||||
@override
|
||||
|
@ -74,8 +74,7 @@ class _PopoverActionListState<T extends PopoverAction>
|
||||
);
|
||||
} else if (action is PopoverActionCell) {
|
||||
return PopoverActionCellWidget<T>(
|
||||
mutex: widget.mutex,
|
||||
// popoverController: popoverController,
|
||||
popoverController: popoverController,
|
||||
action: action,
|
||||
itemHeight: ActionListSizes.itemHeight,
|
||||
);
|
||||
@ -104,13 +103,18 @@ abstract class ActionCell extends PopoverAction {
|
||||
String get name;
|
||||
}
|
||||
|
||||
typedef PopoverActionCellBuilder = Widget Function(
|
||||
BuildContext context,
|
||||
PopoverController parentController,
|
||||
PopoverController controller,
|
||||
);
|
||||
|
||||
abstract class PopoverActionCell extends PopoverAction {
|
||||
Widget? leftIcon(Color iconColor) => null;
|
||||
Widget? rightIcon(Color iconColor) => null;
|
||||
String get name;
|
||||
|
||||
Widget Function(BuildContext context, PopoverController controller)
|
||||
get builder;
|
||||
PopoverActionCellBuilder get builder;
|
||||
}
|
||||
|
||||
abstract class CustomActionCell extends PopoverAction {
|
||||
@ -146,7 +150,7 @@ class ActionCellWidget<T extends PopoverAction> extends StatelessWidget {
|
||||
final rightIcon =
|
||||
actionCell.rightIcon(Theme.of(context).colorScheme.onSurface);
|
||||
|
||||
return _HoverButton(
|
||||
return HoverButton(
|
||||
itemHeight: itemHeight,
|
||||
leftIcon: leftIcon,
|
||||
rightIcon: rightIcon,
|
||||
@ -156,24 +160,30 @@ class ActionCellWidget<T extends PopoverAction> extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class PopoverActionCellWidget<T extends PopoverAction> extends StatelessWidget {
|
||||
PopoverActionCellWidget({
|
||||
Key? key,
|
||||
this.mutex,
|
||||
// required this.popoverController,
|
||||
class PopoverActionCellWidget<T extends PopoverAction> extends StatefulWidget {
|
||||
const PopoverActionCellWidget({
|
||||
super.key,
|
||||
required this.popoverController,
|
||||
required this.action,
|
||||
required this.itemHeight,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final T action;
|
||||
final double itemHeight;
|
||||
|
||||
final PopoverMutex? mutex;
|
||||
final PopoverController popoverController = PopoverController();
|
||||
final PopoverController popoverController;
|
||||
|
||||
@override
|
||||
State<PopoverActionCellWidget> createState() =>
|
||||
_PopoverActionCellWidgetState();
|
||||
}
|
||||
|
||||
class _PopoverActionCellWidgetState<T extends PopoverAction>
|
||||
extends State<PopoverActionCellWidget<T>> {
|
||||
final popoverController = PopoverController();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final actionCell = action as PopoverActionCell;
|
||||
final actionCell = widget.action as PopoverActionCell;
|
||||
final leftIcon =
|
||||
actionCell.leftIcon(Theme.of(context).colorScheme.onSurface);
|
||||
final rightIcon =
|
||||
@ -183,10 +193,11 @@ class PopoverActionCellWidget<T extends PopoverAction> extends StatelessWidget {
|
||||
asBarrier: true,
|
||||
popupBuilder: (context) => actionCell.builder(
|
||||
context,
|
||||
widget.popoverController,
|
||||
popoverController,
|
||||
),
|
||||
child: _HoverButton(
|
||||
itemHeight: itemHeight,
|
||||
child: HoverButton(
|
||||
itemHeight: widget.itemHeight,
|
||||
leftIcon: leftIcon,
|
||||
rightIcon: rightIcon,
|
||||
name: actionCell.name,
|
||||
@ -196,8 +207,9 @@ class PopoverActionCellWidget<T extends PopoverAction> extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _HoverButton extends StatelessWidget {
|
||||
const _HoverButton({
|
||||
class HoverButton extends StatelessWidget {
|
||||
const HoverButton({
|
||||
super.key,
|
||||
required this.onTap,
|
||||
required this.itemHeight,
|
||||
required this.leftIcon,
|
||||
|
@ -434,7 +434,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.macos;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
|
||||
PRODUCT_NAME = AppFlowy;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRIP_STYLE = "non-global";
|
||||
@ -567,7 +567,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.macos;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
|
||||
PRODUCT_NAME = AppFlowy;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRIP_STYLE = "non-global";
|
||||
@ -593,7 +593,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.macos;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
|
||||
PRODUCT_NAME = AppFlowy;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRIP_STYLE = "non-global";
|
||||
|
@ -2,19 +2,11 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
|
||||
<array>
|
||||
<string>/</string>
|
||||
</array>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -25,6 +25,17 @@
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string></string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>io.appflowy.appflowy-flutter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
@ -40,16 +51,5 @@
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string></string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>io.appflowy.appflowy-flutter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -6,11 +6,5 @@
|
||||
<array>
|
||||
<string>/</string>
|
||||
</array>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -121,6 +121,8 @@ class FlowyTextButton extends StatelessWidget {
|
||||
|
||||
final TextDecoration? decoration;
|
||||
|
||||
final String? fontFamily;
|
||||
|
||||
// final HoverDisplayConfig? hoverDisplay;
|
||||
const FlowyTextButton(
|
||||
this.text, {
|
||||
@ -139,6 +141,7 @@ class FlowyTextButton extends StatelessWidget {
|
||||
this.tooltip,
|
||||
this.constraints = const BoxConstraints(minWidth: 58.0, minHeight: 30.0),
|
||||
this.decoration,
|
||||
this.fontFamily,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -157,6 +160,7 @@ class FlowyTextButton extends StatelessWidget {
|
||||
color: fontColor,
|
||||
textAlign: TextAlign.center,
|
||||
decoration: decoration,
|
||||
fontFamily: fontFamily,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -2,8 +2,8 @@ import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorOption {
|
||||
const ColorOption({
|
||||
class FlowyColorOption {
|
||||
const FlowyColorOption({
|
||||
required this.color,
|
||||
required this.name,
|
||||
});
|
||||
@ -13,12 +13,13 @@ class ColorOption {
|
||||
}
|
||||
|
||||
class FlowyColorPicker extends StatelessWidget {
|
||||
final List<ColorOption> colors;
|
||||
final List<FlowyColorOption> colors;
|
||||
final Color? selected;
|
||||
final Function(Color color, int index)? onTap;
|
||||
final double separatorSize;
|
||||
final double iconSize;
|
||||
final double itemHeight;
|
||||
final Border? border;
|
||||
|
||||
const FlowyColorPicker({
|
||||
Key? key,
|
||||
@ -28,6 +29,7 @@ class FlowyColorPicker extends StatelessWidget {
|
||||
this.separatorSize = 4,
|
||||
this.iconSize = 16,
|
||||
this.itemHeight = 32,
|
||||
this.border,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -46,7 +48,10 @@ class FlowyColorPicker extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildColorOption(ColorOption option, int i) {
|
||||
Widget _buildColorOption(
|
||||
FlowyColorOption option,
|
||||
int i,
|
||||
) {
|
||||
Widget? checkmark;
|
||||
if (selected == option.color) {
|
||||
checkmark = svgWidget("grid/checkmark");
|
||||
@ -55,11 +60,11 @@ class FlowyColorPicker extends StatelessWidget {
|
||||
final colorIcon = SizedBox.square(
|
||||
dimension: iconSize,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: option.color,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: option.color,
|
||||
shape: BoxShape.circle,
|
||||
border: border,
|
||||
)),
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
|
@ -10,6 +10,7 @@ class FlowyText extends StatelessWidget {
|
||||
final Color? color;
|
||||
final TextDecoration? decoration;
|
||||
final bool selectable;
|
||||
final String? fontFamily;
|
||||
|
||||
const FlowyText(
|
||||
this.title, {
|
||||
@ -22,6 +23,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.maxLines = 1,
|
||||
this.decoration,
|
||||
this.selectable = false,
|
||||
this.fontFamily,
|
||||
}) : super(key: key);
|
||||
|
||||
const FlowyText.regular(
|
||||
@ -34,6 +36,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.maxLines = 1,
|
||||
this.decoration,
|
||||
this.selectable = false,
|
||||
this.fontFamily,
|
||||
}) : fontWeight = FontWeight.w400,
|
||||
super(key: key);
|
||||
|
||||
@ -47,6 +50,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.maxLines = 1,
|
||||
this.decoration,
|
||||
this.selectable = false,
|
||||
this.fontFamily,
|
||||
}) : fontWeight = FontWeight.w500,
|
||||
super(key: key);
|
||||
|
||||
@ -60,6 +64,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.maxLines = 1,
|
||||
this.decoration,
|
||||
this.selectable = false,
|
||||
this.fontFamily,
|
||||
}) : fontWeight = FontWeight.w600,
|
||||
super(key: key);
|
||||
|
||||
@ -78,6 +83,7 @@ class FlowyText extends StatelessWidget {
|
||||
fontWeight: fontWeight,
|
||||
color: color,
|
||||
decoration: decoration,
|
||||
fontFamily: fontFamily,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@ -91,6 +97,7 @@ class FlowyText extends StatelessWidget {
|
||||
fontWeight: fontWeight,
|
||||
color: color,
|
||||
decoration: decoration,
|
||||
fontFamily: fontFamily,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -53,10 +53,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: appflowy_editor
|
||||
sha256: "3561bd7bd99541508353034130a98ab2d9be54f690bb982f85c2b3eedb8fe63e"
|
||||
sha256: "5fa08d19842b402482aff5044b25d164dbef3eb6155015d123ef02925ba5b52d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0-dev.1"
|
||||
version: "1.0.0-dev.3"
|
||||
appflowy_popover:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1605,6 +1605,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
visibility_detector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: visibility_detector
|
||||
sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0+2"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -42,7 +42,7 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-board.git
|
||||
ref: a183c57
|
||||
appflowy_editor: 1.0.0-dev.1
|
||||
appflowy_editor: 1.0.0-dev.3
|
||||
appflowy_popover:
|
||||
path: packages/appflowy_popover
|
||||
|
||||
@ -163,6 +163,7 @@ flutter:
|
||||
assets:
|
||||
- assets/images/
|
||||
- assets/images/home/
|
||||
- assets/images/editor/align/
|
||||
- assets/images/editor/
|
||||
- assets/images/grid/
|
||||
- assets/images/emoji/
|
||||
|
@ -84,6 +84,7 @@ impl DatabaseManager2 {
|
||||
self.get_database(&database_id).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
||||
pub async fn get_database_id_with_view_id(&self, view_id: &str) -> FlowyResult<String> {
|
||||
let database_id = self.with_user_database(Err(FlowyError::internal()), |database| {
|
||||
database
|
||||
@ -98,6 +99,7 @@ impl DatabaseManager2 {
|
||||
return Ok(editor.clone());
|
||||
}
|
||||
|
||||
tracing::trace!("create new editor for database {}", database_id);
|
||||
let mut editors = self.editors.write().await;
|
||||
let database = MutexDatabase::new(self.with_user_database(
|
||||
Err(FlowyError::record_not_found()),
|
||||
@ -178,6 +180,7 @@ impl DatabaseManager2 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn create_linked_view(
|
||||
&self,
|
||||
name: String,
|
||||
@ -188,11 +191,8 @@ impl DatabaseManager2 {
|
||||
self.with_user_database(
|
||||
Err(FlowyError::internal().context("Create database view failed")),
|
||||
|user_database| {
|
||||
let database = user_database
|
||||
.get_database(&database_id)
|
||||
.ok_or_else(FlowyError::record_not_found)?;
|
||||
let params = CreateViewParams::new(database_id, database_view_id, name, layout.into());
|
||||
database.create_linked_view(params)?;
|
||||
user_database.create_database_linked_view(params)?;
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
@ -55,7 +55,6 @@ impl DocumentManager {
|
||||
}
|
||||
|
||||
pub fn open_document(&self, doc_id: String) -> FlowyResult<Arc<Document>> {
|
||||
tracing::debug!("open a document: {:?}", &doc_id);
|
||||
if let Some(doc) = self.documents.read().get(&doc_id) {
|
||||
return Ok(doc.clone());
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
@ -203,27 +203,26 @@ impl Folder2Manager {
|
||||
let handler = self.get_handler(&view_layout)?;
|
||||
let user_id = self.user.user_id()?;
|
||||
let meta = params.meta.clone();
|
||||
match params.initial_data.is_empty() {
|
||||
true => {
|
||||
tracing::trace!("Create view with build-in data");
|
||||
handler
|
||||
.create_built_in_view(user_id, ¶ms.view_id, ¶ms.name, view_layout.clone())
|
||||
.await?;
|
||||
},
|
||||
false => {
|
||||
tracing::trace!("Create view with view data");
|
||||
handler
|
||||
.create_view_with_view_data(
|
||||
user_id,
|
||||
¶ms.view_id,
|
||||
¶ms.name,
|
||||
params.initial_data.clone(),
|
||||
view_layout.clone(),
|
||||
meta,
|
||||
)
|
||||
.await?;
|
||||
},
|
||||
|
||||
if meta.is_empty() && params.initial_data.is_empty() {
|
||||
tracing::trace!("Create view with build-in data");
|
||||
handler
|
||||
.create_built_in_view(user_id, ¶ms.view_id, ¶ms.name, view_layout.clone())
|
||||
.await?;
|
||||
} else {
|
||||
tracing::trace!("Create view with view data");
|
||||
handler
|
||||
.create_view_with_view_data(
|
||||
user_id,
|
||||
¶ms.view_id,
|
||||
¶ms.name,
|
||||
params.initial_data.clone(),
|
||||
view_layout.clone(),
|
||||
meta,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let view = create_view(params, view_layout);
|
||||
self.with_folder((), |folder| {
|
||||
folder.insert_view(view.clone());
|
||||
@ -245,28 +244,6 @@ impl Folder2Manager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_view_with_data(
|
||||
&self,
|
||||
view_id: &str,
|
||||
name: &str,
|
||||
view_layout: ViewLayout,
|
||||
data: Vec<u8>,
|
||||
) -> FlowyResult<()> {
|
||||
let user_id = self.user.user_id()?;
|
||||
let handler = self.get_handler(&view_layout)?;
|
||||
handler
|
||||
.create_view_with_view_data(
|
||||
user_id,
|
||||
view_id,
|
||||
name,
|
||||
data,
|
||||
view_layout,
|
||||
HashMap::default(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the view with the given view id.
|
||||
/// The child views of the view will only access the first. So if you want to get the child view's
|
||||
/// child view, you need to call this method again.
|
||||
|