فهرست منبع

fix: some UI issues were present in version 0.3.1. (#3401)

Lucas.Xu 1 سال پیش
والد
کامیت
26a2bffcd1
21فایلهای تغییر یافته به همراه292 افزوده شده و 83 حذف شده
  1. 3 5
      frontend/appflowy_flutter/integration_test/sidebar/sidebar_test.dart
  2. 26 3
      frontend/appflowy_flutter/integration_test/util/base.dart
  3. 11 1
      frontend/appflowy_flutter/integration_test/util/common_operations.dart
  4. 28 0
      frontend/appflowy_flutter/lib/core/config/kv.dart
  5. 6 0
      frontend/appflowy_flutter/lib/core/config/kv_keys.dart
  6. 10 4
      frontend/appflowy_flutter/lib/plugins/document/application/editor_transaction_adapter.dart
  7. 5 1
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/block_action_option_button.dart
  8. 44 22
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/align_toolbar_item/align_toolbar_item.dart
  9. 7 7
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart
  10. 4 1
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/toggle/toggle_block_component.dart
  11. 29 0
      frontend/appflowy_flutter/lib/workspace/application/settings/create_file_settings_cubit.dart
  12. 2 1
      frontend/appflowy_flutter/lib/workspace/application/settings/prelude.dart
  13. 8 8
      frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart
  14. 35 0
      frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/rename_view_dialog.dart
  15. 12 16
      frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart
  16. 8 8
      frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_item.dart
  17. 37 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_appearance/create_file_setting.dart
  18. 2 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart
  19. 4 3
      frontend/appflowy_flutter/packages/flowy_infra_ui/lib/widget/dialog/styled_dialogs.dart
  20. 10 2
      frontend/appflowy_flutter/pubspec.lock
  21. 1 1
      frontend/appflowy_flutter/pubspec.yaml

+ 3 - 5
frontend/appflowy_flutter/integration_test/sidebar/sidebar_test.dart

@@ -1,3 +1,4 @@
+import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
 import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
@@ -7,7 +8,7 @@ import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
 import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
 import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
 import 'package:appflowy_editor/appflowy_editor.dart';
-import 'package:flutter/material.dart';
+import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:integration_test/integration_test.dart';
 
@@ -22,14 +23,11 @@ void main() {
       await tester.tapGoButton();
 
       // create a new page
-      const name = 'Hello AppFlowy';
       await tester.tapNewPageButton();
-      await tester.enterText(find.byType(TextFormField), name);
-      await tester.tapOKButton();
 
       // expect to see a new document
       tester.expectToSeePageName(
-        name,
+        LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
       );
       // and with one paragraph block
       expect(find.byType(TextBlockComponentWidget), findsOneWidget);

+ 26 - 3
frontend/appflowy_flutter/integration_test/util/base.dart

@@ -1,7 +1,9 @@
+import 'dart:async';
 import 'dart:io';
 
 import 'package:appflowy/startup/entry_point.dart';
 import 'package:appflowy/startup/startup.dart';
+import 'package:appflowy/user/presentation/presentation.dart';
 import 'package:appflowy/workspace/application/settings/prelude.dart';
 import 'package:flowy_infra/uuid.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -9,8 +11,8 @@ import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
-import 'package:path_provider/path_provider.dart';
 import 'package:path/path.dart' as p;
+import 'package:path_provider/path_provider.dart';
 
 class FlowyTestContext {
   FlowyTestContext({
@@ -39,8 +41,8 @@ extension AppFlowyTestBase on WidgetTester {
       IntegrationMode.integrationTest,
     );
 
-    await wait(3000);
-    await pumpAndSettle(const Duration(seconds: 2));
+    await waitUntilSignInPageShow();
+
     return FlowyTestContext(
       applicationDataDirectory: directory,
     );
@@ -78,6 +80,27 @@ extension AppFlowyTestBase on WidgetTester {
     return directory.path;
   }
 
+  Future<void> waitUntilSignInPageShow() async {
+    final finder = find.byType(GoButton);
+    await pumpUntilFound(finder);
+    expect(finder, findsOneWidget);
+  }
+
+  Future<void> pumpUntilFound(
+    Finder finder, {
+    Duration timeout = const Duration(seconds: 10),
+  }) async {
+    bool timerDone = false;
+    final timer = Timer(timeout, () => timerDone = true);
+    while (timerDone != true) {
+      await pump();
+      if (any(finder)) {
+        timerDone = true;
+      }
+    }
+    timer.cancel();
+  }
+
   Future<void> tapButton(
     Finder finder, {
     int? pointer,

+ 11 - 1
frontend/appflowy_flutter/integration_test/util/common_operations.dart

@@ -1,6 +1,9 @@
+import 'package:appflowy/core/config/kv.dart';
+import 'package:appflowy/core/config/kv_keys.dart';
 import 'package:appflowy/generated/flowy_svgs.g.dart';
 import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
+import 'package:appflowy/startup/startup.dart';
 import 'package:appflowy/user/presentation/screens/screens.dart';
 import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
 import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
@@ -279,7 +282,14 @@ extension CommonOperations on WidgetTester {
     // create a new page
     await tapAddViewButton(name: parentName ?? gettingStarted);
     await tapButtonWithName(layout.menuName);
-    await tapOKButton();
+    final settingsOrFailure = await getIt<KeyValueStorage>().getWithFormat(
+      KVKeys.showRenameDialogWhenCreatingNewFile,
+      (value) => bool.parse(value),
+    );
+    final showRenameDialog = settingsOrFailure.fold((l) => false, (r) => r);
+    if (showRenameDialog) {
+      await tapOKButton();
+    }
     await pumpAndSettle();
 
     // hover on it and change it's name

+ 28 - 0
frontend/appflowy_flutter/lib/core/config/kv.dart

@@ -7,6 +7,10 @@ import 'package:shared_preferences/shared_preferences.dart';
 abstract class KeyValueStorage {
   Future<void> set(String key, String value);
   Future<Either<FlowyError, String>> get(String key);
+  Future<Either<FlowyError, T>> getWithFormat<T>(
+    String key,
+    T Function(String value) formatter,
+  );
   Future<void> remove(String key);
   Future<void> clear();
 }
@@ -26,6 +30,18 @@ class DartKeyValue implements KeyValueStorage {
     return Left(FlowyError());
   }
 
+  @override
+  Future<Either<FlowyError, T>> getWithFormat<T>(
+    String key,
+    T Function(String value) formatter,
+  ) async {
+    final value = await get(key);
+    return value.fold(
+      (l) => left(l),
+      (r) => right(formatter(r)),
+    );
+  }
+
   @override
   Future<void> remove(String key) async {
     await _initSharedPreferencesIfNeeded();
@@ -71,6 +87,18 @@ class RustKeyValue implements KeyValueStorage {
     return response.swap().map((r) => r.value);
   }
 
+  @override
+  Future<Either<FlowyError, T>> getWithFormat<T>(
+    String key,
+    T Function(String value) formatter,
+  ) async {
+    final value = await get(key);
+    return value.fold(
+      (l) => left(l),
+      (r) => right(formatter(r)),
+    );
+  }
+
   @override
   Future<void> remove(String key) async {
     await ConfigEventRemoveKeyValue(

+ 6 - 0
frontend/appflowy_flutter/lib/core/config/kv_keys.dart

@@ -43,4 +43,10 @@ class KVKeys {
   /// The value is a json string with the following format:
   ///  {'SidebarFolderCategoryType.value': true}
   static const String expandedFolders = 'expandedFolders';
+
+  /// The key for saving if showing the rename dialog when creating a new file
+  ///
+  /// The value is a boolean string.
+  static const String showRenameDialogWhenCreatingNewFile =
+      'showRenameDialogWhenCreatingNewFile';
 }

+ 10 - 4
frontend/appflowy_flutter/lib/plugins/document/application/editor_transaction_adapter.dart

@@ -34,11 +34,13 @@ class TransactionAdapter {
   final DocumentService documentService;
   final String documentId;
 
-  final bool _enableDebug = false;
+  final bool _enableDebug = true;
 
   Future<void> apply(Transaction transaction, EditorState editorState) async {
     final stopwatch = Stopwatch()..start();
-    Log.debug('transaction => ${transaction.toJson()}');
+    if (_enableDebug) {
+      Log.debug('transaction => ${transaction.toJson()}');
+    }
     final actions = transaction.operations
         .map((op) => op.toBlockAction(editorState, documentId))
         .whereNotNull()
@@ -58,14 +60,18 @@ class TransactionAdapter {
           textId: payload.textId,
           delta: payload.delta,
         );
-        Log.debug('create external text: ${payload.delta}');
+        if (_enableDebug) {
+          Log.debug('create external text: ${payload.delta}');
+        }
       } else if (type == TextDeltaType.update) {
         await documentService.updateExternalText(
           documentId: payload.documentId,
           textId: payload.textId,
           delta: payload.delta,
         );
-        Log.debug('update external text: ${payload.delta}');
+        if (_enableDebug) {
+          Log.debug('update external text: ${payload.delta}');
+        }
       }
     }
     final blockActions =

+ 5 - 1
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/block_action_option_button.dart

@@ -40,12 +40,16 @@ class BlockOptionButton extends StatelessWidget {
     return PopoverActionList<PopoverAction>(
       direction: PopoverDirection.leftWithCenterAligned,
       actions: popoverActions,
-      onPopupBuilder: () => blockComponentState.alwaysShowActions = true,
+      onPopupBuilder: () {
+        keepEditorFocusNotifier.value += 1;
+        blockComponentState.alwaysShowActions = true;
+      },
       onClosed: () {
         WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
           editorState.selectionType = null;
           editorState.selection = null;
           blockComponentState.alwaysShowActions = false;
+          keepEditorFocusNotifier.value -= 1;
         });
       },
       onSelected: (action, controller) {

+ 44 - 22
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/align_toolbar_item/align_toolbar_item.dart

@@ -1,6 +1,8 @@
 import 'package:appflowy/generated/flowy_svgs.g.dart';
+import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:appflowy_editor/appflowy_editor.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
+import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/material.dart';
 
@@ -31,24 +33,31 @@ final alignToolbarItem = ToolbarItem(
       data = FlowySvgs.toolbar_align_right_s;
     }
 
-    final child = FlowySvg(
-      data,
-      size: const Size.square(16),
-      color: isHighlight ? highlightColor : Colors.white,
+    final child = MouseRegion(
+      cursor: SystemMouseCursors.click,
+      child: FlowySvg(
+        data,
+        size: const Size.square(20),
+        color: isHighlight ? highlightColor : Colors.white,
+      ),
     );
-    return _AlignmentButtons(
-      child: child,
-      onAlignChanged: (align) async {
-        await editorState.updateNode(
-          selection,
-          (node) => node.copyWith(
-            attributes: {
-              ...node.attributes,
-              blockComponentAlign: align,
-            },
-          ),
-        );
-      },
+
+    return Padding(
+      padding: const EdgeInsets.symmetric(horizontal: 4.0),
+      child: _AlignmentButtons(
+        child: child,
+        onAlignChanged: (align) async {
+          await editorState.updateNode(
+            selection,
+            (node) => node.copyWith(
+              attributes: {
+                ...node.attributes,
+                blockComponentAlign: align,
+              },
+            ),
+          );
+        },
+      ),
     );
   },
 );
@@ -71,11 +80,15 @@ class _AlignmentButtonsState extends State<_AlignmentButtons> {
   Widget build(BuildContext context) {
     return AppFlowyPopover(
       windowPadding: const EdgeInsets.all(0),
-      margin: const EdgeInsets.all(0),
+      margin: const EdgeInsets.all(4),
       direction: PopoverDirection.bottomWithCenterAligned,
       offset: const Offset(0, 10),
-      child: widget.child,
+      decoration: BoxDecoration(
+        color: Theme.of(context).colorScheme.onTertiary,
+        borderRadius: const BorderRadius.all(Radius.circular(4)),
+      ),
       popupBuilder: (_) => _AlignButtons(onAlignChanged: widget.onAlignChanged),
+      child: widget.child,
     );
   }
 }
@@ -97,16 +110,19 @@ class _AlignButtons extends StatelessWidget {
           const HSpace(4),
           _AlignButton(
             icon: FlowySvgs.toolbar_align_left_s,
+            tooltips: LocaleKeys.document_plugins_optionAction_left.tr(),
             onTap: () => onAlignChanged('left'),
           ),
           const _Divider(),
           _AlignButton(
             icon: FlowySvgs.toolbar_align_center_s,
+            tooltips: LocaleKeys.document_plugins_optionAction_center.tr(),
             onTap: () => onAlignChanged('center'),
           ),
           const _Divider(),
           _AlignButton(
             icon: FlowySvgs.toolbar_align_right_s,
+            tooltips: LocaleKeys.document_plugins_optionAction_right.tr(),
             onTap: () => onAlignChanged('right'),
           ),
           const HSpace(4),
@@ -119,19 +135,25 @@ class _AlignButtons extends StatelessWidget {
 class _AlignButton extends StatelessWidget {
   const _AlignButton({
     required this.icon,
+    required this.tooltips,
     required this.onTap,
   });
 
   final FlowySvgData icon;
+  final String tooltips;
   final VoidCallback onTap;
 
   @override
   Widget build(BuildContext context) {
     return GestureDetector(
       onTap: onTap,
-      child: FlowySvg(
-        icon,
-        size: const Size.square(16),
+      child: Tooltip(
+        message: tooltips,
+        child: FlowySvg(
+          icon,
+          size: const Size.square(16),
+          color: Colors.white,
+        ),
       ),
     );
   }

+ 7 - 7
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart

@@ -168,7 +168,7 @@ class OutlineItemWidget extends StatelessWidget {
         hoverColor: Theme.of(context).hoverColor,
       ),
       child: GestureDetector(
-        onTap: () => updateBlockSelection(context),
+        onTap: () => scrollToBlock(context),
         child: Container(
           padding: EdgeInsets.only(left: node.leftIndent),
           child: Text(
@@ -180,14 +180,14 @@ class OutlineItemWidget extends StatelessWidget {
     );
   }
 
-  void updateBlockSelection(BuildContext context) async {
+  void scrollToBlock(BuildContext context) {
     final editorState = context.read<EditorState>();
-    editorState.selectionType = SelectionType.block;
-    editorState.selection = Selection.collapsed(
-      Position(path: node.path, offset: node.delta?.length ?? 0),
-    );
+    final editorScrollController = context.read<EditorScrollController>();
+    editorScrollController.itemScrollController.jumpTo(index: node.path.first);
     WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
-      editorState.selectionType = null;
+      editorState.selection = Selection.collapsed(
+        Position(path: node.path, offset: node.delta?.length ?? 0),
+      );
     });
   }
 }

+ 4 - 1
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/toggle/toggle_block_component.dart

@@ -146,7 +146,10 @@ class _ToggleListBlockComponentWidgetState
   }
 
   @override
-  Widget buildComponent(BuildContext context) {
+  Widget buildComponent(
+    BuildContext context, {
+    bool withBackgroundColor = false,
+  }) {
     final textDirection = calculateTextDirection(
       layoutDirection: Directionality.maybeOf(context),
     );

+ 29 - 0
frontend/appflowy_flutter/lib/workspace/application/settings/create_file_settings_cubit.dart

@@ -0,0 +1,29 @@
+import 'package:appflowy/core/config/kv.dart';
+import 'package:appflowy/core/config/kv_keys.dart';
+import 'package:appflowy/startup/startup.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class CreateFileSettingsCubit extends Cubit<bool> {
+  CreateFileSettingsCubit(super.initialState) {
+    getInitialSettings();
+  }
+
+  Future<void> toggle({bool? value}) async {
+    await getIt<KeyValueStorage>().set(
+      KVKeys.showRenameDialogWhenCreatingNewFile,
+      (value ?? !state).toString(),
+    );
+    emit(value ?? !state);
+  }
+
+  Future<void> getInitialSettings() async {
+    final settingsOrFailure = await getIt<KeyValueStorage>().getWithFormat(
+      KVKeys.showRenameDialogWhenCreatingNewFile,
+      (value) => bool.parse(value),
+    );
+    settingsOrFailure.fold(
+      (_) => emit(false),
+      (settings) => emit(settings),
+    );
+  }
+}

+ 2 - 1
frontend/appflowy_flutter/lib/workspace/application/settings/prelude.dart

@@ -1,2 +1,3 @@
-export 'settings_dialog_bloc.dart';
 export 'application_data_storage.dart';
+export 'create_file_settings_cubit.dart';
+export 'settings_dialog_bloc.dart';

+ 8 - 8
frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart

@@ -4,8 +4,8 @@ import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:appflowy/workspace/application/menu/menu_bloc.dart';
 import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
 import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
+import 'package:appflowy/workspace/presentation/home/menu/sidebar/rename_view_dialog.dart';
 import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
-import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
 import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -118,14 +118,14 @@ class _PersonalFolderHeaderState extends State<PersonalFolderHeader> {
               width: iconSize,
               icon: const FlowySvg(FlowySvgs.add_s),
               onPressed: () {
-                NavigatorTextFieldDialog(
-                  title: LocaleKeys.newPageText.tr(),
-                  value: '',
-                  confirm: (value) {
-                    if (value.isNotEmpty) {
+                createViewAndShowRenameDialogIfNeeded(
+                  context,
+                  LocaleKeys.newPageText.tr(),
+                  (viewName) {
+                    if (viewName.isNotEmpty) {
                       context.read<MenuBloc>().add(
                             MenuEvent.createApp(
-                              value,
+                              viewName,
                               index: 0,
                             ),
                           );
@@ -133,7 +133,7 @@ class _PersonalFolderHeaderState extends State<PersonalFolderHeader> {
                       widget.onAdded();
                     }
                   },
-                ).show(context);
+                );
               },
             ),
           ]

+ 35 - 0
frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/rename_view_dialog.dart

@@ -0,0 +1,35 @@
+import 'package:appflowy/core/config/kv.dart';
+import 'package:appflowy/core/config/kv_keys.dart';
+import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/startup/startup.dart';
+import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+/// Creates a new view and shows the rename dialog if needed.
+///
+/// If the user has enabled the setting to show the rename dialog when creating a new view,
+/// this function will show the rename dialog.
+///
+/// Otherwise, it will just create the view with default name.
+Future<void> createViewAndShowRenameDialogIfNeeded(
+  BuildContext context,
+  String dialogTitle,
+  void Function(String viewName) createView,
+) async {
+  final value = await getIt<KeyValueStorage>().getWithFormat(
+    KVKeys.showRenameDialogWhenCreatingNewFile,
+    (value) => bool.parse(value),
+  );
+  final showRenameDialog = value.fold((l) => false, (r) => r);
+  if (context.mounted && showRenameDialog) {
+    NavigatorTextFieldDialog(
+      title: dialogTitle,
+      value: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
+      autoSelectAllText: true,
+      confirm: createView,
+    ).show(context);
+  } else {
+    createView(LocaleKeys.menuAppHeader_defaultNewPageName.tr());
+  }
+}

+ 12 - 16
frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart

@@ -1,11 +1,11 @@
 import 'package:appflowy/generated/flowy_svgs.g.dart';
+import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:appflowy/workspace/application/menu/menu_bloc.dart';
-import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
+import 'package:appflowy/workspace/presentation/home/menu/sidebar/rename_view_dialog.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flutter/material.dart';
 import 'package:flowy_infra_ui/style_widget/extension.dart';
-import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
 class SidebarNewPageButton extends StatelessWidget {
@@ -20,7 +20,15 @@ class SidebarNewPageButton extends StatelessWidget {
       fillColor: Colors.transparent,
       hoverColor: Colors.transparent,
       fontColor: Theme.of(context).colorScheme.tertiary,
-      onPressed: () async => await _showCreatePageDialog(context),
+      onPressed: () async => await createViewAndShowRenameDialogIfNeeded(
+        context,
+        LocaleKeys.newPageText.tr(),
+        (viewName) {
+          if (viewName.isNotEmpty) {
+            context.read<MenuBloc>().add(MenuEvent.createApp(viewName));
+          }
+        },
+      ),
       heading: Container(
         width: 16,
         height: 16,
@@ -44,16 +52,4 @@ class SidebarNewPageButton extends StatelessWidget {
       ),
     );
   }
-
-  Future<void> _showCreatePageDialog(BuildContext context) async {
-    return NavigatorTextFieldDialog(
-      title: LocaleKeys.newPageText.tr(),
-      value: '',
-      confirm: (value) {
-        if (value.isNotEmpty) {
-          context.read<MenuBloc>().add(MenuEvent.createApp(value));
-        }
-      },
-    ).show(context);
-  }
 }

+ 8 - 8
frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_item.dart

@@ -7,6 +7,7 @@ import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
 import 'package:appflowy/workspace/application/view/view_bloc.dart';
 import 'package:appflowy/workspace/application/view/view_ext.dart';
 import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
+import 'package:appflowy/workspace/presentation/home/menu/sidebar/rename_view_dialog.dart';
 import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
 import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
 import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
@@ -350,22 +351,21 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
           createNewView,
         ) {
           if (createNewView) {
-            NavigatorTextFieldDialog(
-              title: _convertLayoutToHintText(pluginBuilder.layoutType!),
-              value: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
-              autoSelectAllText: true,
-              confirm: (value) {
-                if (value.isNotEmpty) {
+            createViewAndShowRenameDialogIfNeeded(
+              context,
+              _convertLayoutToHintText(pluginBuilder.layoutType!),
+              (viewName) {
+                if (viewName.isNotEmpty) {
                   context.read<ViewBloc>().add(
                         ViewEvent.createView(
-                          value,
+                          viewName,
                           pluginBuilder.layoutType!,
                           openAfterCreated: openAfterCreated,
                         ),
                       );
                 }
               },
-            ).show(context);
+            );
           }
           context.read<ViewBloc>().add(
                 const ViewEvent.setIsExpanded(true),

+ 37 - 0
frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_appearance/create_file_setting.dart

@@ -0,0 +1,37 @@
+import 'package:appflowy/workspace/application/settings/prelude.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/theme_setting_entry_template.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+bool _prevSetting = false;
+
+class CreateFileSettings extends StatelessWidget {
+  CreateFileSettings({
+    super.key,
+  });
+
+  final cubit = CreateFileSettingsCubit(_prevSetting);
+
+  @override
+  Widget build(BuildContext context) {
+    return ThemeSettingEntryTemplateWidget(
+      label: 'Show rename dialog when creating a new file',
+      trailing: [
+        BlocProvider.value(
+          value: cubit,
+          child: BlocBuilder<CreateFileSettingsCubit, bool>(
+            builder: (context, state) {
+              return Switch(
+                value: state,
+                onChanged: (value) {
+                  cubit.toggle(value: value);
+                  _prevSetting = value;
+                },
+              );
+            },
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 2 - 0
frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart

@@ -1,4 +1,5 @@
 import 'package:appflowy/workspace/application/appearance.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/create_file_setting.dart';
 import 'package:flowy_infra/plugins/bloc/dynamic_plugin_bloc.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -34,6 +35,7 @@ class SettingsAppearanceView extends StatelessWidget {
                 TextDirectionSetting(
                   currentTextDirection: state.textDirection,
                 ),
+                CreateFileSettings(),
               ],
             );
           },

+ 4 - 3
frontend/appflowy_flutter/packages/flowy_infra_ui/lib/widget/dialog/styled_dialogs.dart

@@ -1,9 +1,10 @@
-import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
+import 'dart:ui';
+
 import 'package:flowy_infra/size.dart';
+import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
 import 'package:flowy_infra_ui/widget/dialog/dialog_size.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
-import 'dart:ui';
 
 extension IntoDialog on Widget {
   Future<dynamic> show(BuildContext context) async {
@@ -71,7 +72,7 @@ class StyledDialog extends StatelessWidget {
             maxWidth: maxWidth ?? double.infinity,
           ),
           child: ClipRRect(
-            borderRadius: borderRadius,
+            borderRadius: borderRadius ?? BorderRadius.zero,
             child: SingleChildScrollView(
               physics: StyledScrollPhysics(),
               //https://medium.com/saugo360/https-medium-com-saugo360-flutter-using-overlay-to-display-floating-widgets-2e6d0e8decb9

+ 10 - 2
frontend/appflowy_flutter/pubspec.lock

@@ -54,8 +54,8 @@ packages:
     dependency: "direct main"
     description:
       path: "."
-      ref: "6d68f90"
-      resolved-ref: "6d68f9003fa023d215dc5f20e8900f985c2cdaa1"
+      ref: a97c816
+      resolved-ref: a97c816c1d8cfbc5644a8be49deae334c47261e3
       url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
     source: git
     version: "1.3.0"
@@ -1430,6 +1430,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.2.0"
+  string_validator:
+    dependency: transitive
+    description:
+      name: string_validator
+      sha256: b419cf5d21d608522e6e7cafed4deb34b6f268c43df866e63c320bab98a08cf6
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
   styled_widget:
     dependency: "direct main"
     description:

+ 1 - 1
frontend/appflowy_flutter/pubspec.yaml

@@ -47,7 +47,7 @@ dependencies:
   appflowy_editor:
     git:
       url: https://github.com/AppFlowy-IO/appflowy-editor.git
-      ref: 6d68f90
+      ref: a97c816
   appflowy_popover:
     path: packages/appflowy_popover