소스 검색

Merge remote-tracking branch 'origin/main' into develop

# Conflicts:
#	frontend/appflowy_flutter/lib/plugins/database_view/application/database_view_service.dart
#	frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/base/link_to_page_widget.dart
#	frontend/appflowy_flutter/lib/plugins/trash/application/trash_bloc.dart
#	frontend/appflowy_flutter/lib/plugins/trash/application/trash_service.dart
#	frontend/appflowy_flutter/lib/workspace/application/app/app_bloc.dart
#	frontend/appflowy_flutter/lib/workspace/application/app/app_service.dart
#	frontend/appflowy_flutter/lib/workspace/application/menu/menu_bloc.dart
#	frontend/appflowy_flutter/lib/workspace/application/workspace/workspace_service.dart
#	frontend/appflowy_flutter/lib/workspace/presentation/home/menu/app/header/header.dart
#	frontend/appflowy_flutter/test/bloc_test/grid_test/filter/filter_util.dart
#	frontend/appflowy_flutter/test/bloc_test/grid_test/grid_bloc_test.dart
#	frontend/appflowy_flutter/test/bloc_test/grid_test/util.dart
#	frontend/appflowy_flutter/test/bloc_test/home_test/view_bloc_test.dart
#	frontend/rust-lib/flowy-database/src/services/database/database_editor.rs
#	frontend/rust-lib/flowy-database/src/services/persistence/migration/database_view_migration.rs
Lucas.Xu 2 년 전
부모
커밋
c009347735
100개의 변경된 파일1715개의 추가작업 그리고 1396개의 파일을 삭제
  1. 1 4
      .dockerignore
  2. 0 0
      .github/PULL_REQUEST_TEMPLATE.md
  3. 47 0
      .github/workflows/docker_ci.yml
  4. 2 1
      .github/workflows/flutter_ci.yaml
  5. 7 4
      .github/workflows/integration_test.yml
  6. 6 1
      frontend/Makefile.toml
  7. 2 5
      frontend/appflowy_flutter/analysis_options.yaml
  8. 0 112
      frontend/appflowy_flutter/assets/images/flowy_logo_dark_mode.svg
  9. 156 147
      frontend/appflowy_flutter/assets/translations/de-DE.json
  10. 6 3
      frontend/appflowy_flutter/assets/translations/en.json
  11. 2 2
      frontend/appflowy_flutter/assets/translations/eu-ES.json
  12. 1 1
      frontend/appflowy_flutter/assets/translations/fr-FR.json
  13. 1 1
      frontend/appflowy_flutter/assets/translations/ko-KR.json
  14. 4 4
      frontend/appflowy_flutter/assets/translations/pt-BR.json
  15. 146 147
      frontend/appflowy_flutter/assets/translations/pt-PT.json
  16. 413 348
      frontend/appflowy_flutter/assets/translations/ru-RU.json
  17. 1 1
      frontend/appflowy_flutter/assets/translations/sv.json
  18. 1 1
      frontend/appflowy_flutter/assets/translations/zh-CN.json
  19. 1 1
      frontend/appflowy_flutter/assets/translations/zh-TW.json
  20. 3 1
      frontend/appflowy_flutter/integration_test/board_test.dart
  21. 33 22
      frontend/appflowy_flutter/integration_test/empty_document_test.dart
  22. 3 1
      frontend/appflowy_flutter/integration_test/util/data.dart
  23. 4 2
      frontend/appflowy_flutter/integration_test/util/keyboard.dart
  24. 4 3
      frontend/appflowy_flutter/lib/core/folder_notification.dart
  25. 7 4
      frontend/appflowy_flutter/lib/core/grid_notification.dart
  26. 6 5
      frontend/appflowy_flutter/lib/core/notification_helper.dart
  27. 7 4
      frontend/appflowy_flutter/lib/core/user_notification.dart
  28. 29 21
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller.dart
  29. 3 1
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_listener.dart
  30. 62 39
      frontend/appflowy_flutter/lib/plugins/database_view/application/database_controller.dart
  31. 8 5
      frontend/appflowy_flutter/lib/plugins/database_view/application/database_view_service.dart
  32. 14 10
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_cell_bloc.dart
  33. 59 51
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_controller.dart
  34. 7 5
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_editor_bloc.dart
  35. 6 4
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_listener.dart
  36. 15 6
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/date_bloc.dart
  37. 14 10
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/number_format_bloc.dart
  38. 4 2
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/select_option_type_option_bloc.dart
  39. 3 1
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/type_option_context.dart
  40. 2 1
      frontend/appflowy_flutter/lib/plugins/database_view/application/filter/filter_listener.dart
  41. 2 1
      frontend/appflowy_flutter/lib/plugins/database_view/application/filter/filter_service.dart
  42. 3 2
      frontend/appflowy_flutter/lib/plugins/database_view/application/layout/calendar_setting_listener.dart
  43. 13 6
      frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_cache.dart
  44. 6 4
      frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_data_controller.dart
  45. 6 4
      frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_list.dart
  46. 5 2
      frontend/appflowy_flutter/lib/plugins/database_view/application/setting/group_bloc.dart
  47. 11 6
      frontend/appflowy_flutter/lib/plugins/database_view/application/setting/property_bloc.dart
  48. 7 4
      frontend/appflowy_flutter/lib/plugins/database_view/application/setting/setting_bloc.dart
  49. 8 6
      frontend/appflowy_flutter/lib/plugins/database_view/application/setting/setting_controller.dart
  50. 5 3
      frontend/appflowy_flutter/lib/plugins/database_view/application/view/view_cache.dart
  51. 30 19
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/board_bloc.dart
  52. 34 32
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/group_controller.dart
  53. 5 3
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/toolbar/board_setting_bloc.dart
  54. 4 12
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/board_page.dart
  55. 6 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_setting.dart
  56. 1 0
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_toolbar.dart
  57. 30 18
      frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_bloc.dart
  58. 6 4
      frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_setting_bloc.dart
  59. 39 25
      frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_day.dart
  60. 5 3
      frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart
  61. 17 14
      frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart
  62. 2 2
      frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_setting.dart
  63. 8 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/checkbox_filter_editor_bloc.dart
  64. 8 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/checklist_filter_bloc.dart
  65. 9 6
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/filter_menu_bloc.dart
  66. 14 8
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/select_option_filter_bloc.dart
  67. 24 12
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/select_option_filter_list_bloc.dart
  68. 8 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/text_filter_editor_bloc.dart
  69. 5 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_accessory_bloc.dart
  70. 14 9
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_bloc.dart
  71. 7 2
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_header_bloc.dart
  72. 10 7
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/row/row_bloc.dart
  73. 2 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/row/row_detail_bloc.dart
  74. 4 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/sort/sort_create_bloc.dart
  75. 3 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/sort/sort_editor_bloc.dart
  76. 7 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/sort/sort_menu_bloc.dart
  77. 10 8
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/grid_page.dart
  78. 3 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/grid_scroll.dart
  79. 1 4
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/layout/sizes.dart
  80. 5 4
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/accessory_menu.dart
  81. 3 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart
  82. 5 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart
  83. 4 2
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/choicechip.dart
  84. 9 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart
  85. 3 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/text.dart
  86. 4 2
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/condition_button.dart
  87. 4 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/create_filter_list.dart
  88. 12 7
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_cell.dart
  89. 21 19
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_cell_action_sheet.dart
  90. 7 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart
  91. 28 11
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/grid_header.dart
  92. 7 6
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/builder.dart
  93. 2 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/checklist.dart
  94. 2 0
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart
  95. 75 58
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/number.dart
  96. 5 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/select_option.dart
  97. 15 8
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/select_option_editor.dart
  98. 19 14
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/row/row.dart
  99. 4 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/sort/create_sort_list.dart
  100. 9 7
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/sort/sort_editor.dart

+ 1 - 4
.dockerignore

@@ -1,4 +1 @@
-frontend/appflowy_flutter/
-frontend/scripts/
-frontend/rust-lib/target
-shared-lib/target/
+.git

+ 0 - 0
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md → .github/PULL_REQUEST_TEMPLATE.md


+ 47 - 0
.github/workflows/docker_ci.yml

@@ -0,0 +1,47 @@
+name: Docker-CI
+
+on:
+  push:
+    branches:
+      - main
+      - release/*
+    paths:
+      - frontend/**
+
+  pull_request:
+    branches:
+      - main
+      - release/*
+    paths:
+      - frontend/**
+    types:
+      - opened
+      - synchronize
+      - reopened
+      - unlocked
+      - ready_for_review
+
+jobs:
+  build-app:
+    if: github.event.pull_request.draft != true
+    concurrency: 
+      group: docker_ci-${{ github.event.pull_request.number || github.ref }}
+      cancel-in-progress: true
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout source code
+        uses: actions/checkout@v3
+
+      - name: Build the app
+        shell: bash
+        run: |
+          set -eu -o pipefail
+          cd frontend/scripts/docker-buildfiles
+          docker-compose build --no-cache --progress=plain \
+          | while read line; do \
+              if [[ "$line" =~ ^Step[[:space:]] ]]; then \
+                echo "$(date -u '+%H:%M:%S') | $line"; \
+              else \
+                echo "$line"; \
+              fi; \
+            done \

+ 2 - 1
.github/workflows/flutter_ci.yaml

@@ -99,7 +99,8 @@ jobs:
 
       - name: Flutter Analyzer
         working-directory: frontend/appflowy_flutter
-        run: flutter analyze
+        run: |
+          flutter analyze .
 
       - name: Run Flutter unit tests
         working-directory: frontend

+ 7 - 4
.github/workflows/integration_test.yml

@@ -22,7 +22,7 @@ jobs:
   tests:
     strategy:
       matrix:
-        os: [macos-latest]
+        os: [ubuntu-latest]
 
     runs-on: ${{ matrix.os }}
 
@@ -105,11 +105,14 @@ jobs:
         working-directory: frontend/appflowy_flutter
         run: |
           if [ "$RUNNER_OS" == "Linux" ]; then
-            flutter test integration_test/runner.dart -d Linux --coverage
+            export DISPLAY=:99
+            sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
+            sudo apt-get install network-manager
+            flutter test integration_test/runner.dart -d Linux --coverage --verbose
           elif [ "$RUNNER_OS" == "macOS" ]; then
-            flutter test integration_test/runner.dart -d macOS --coverage
+            flutter test integration_test/runner.dart -d macOS --coverage --verbose
           elif [ "$RUNNER_OS" == "Windows" ]; then
-            flutter test integration_test/runner.dart -d Windows --coverage
+            flutter test integration_test/runner.dart -d Windows --coverage --verbose
           fi
         shell: bash
 

+ 6 - 1
frontend/Makefile.toml

@@ -205,12 +205,17 @@ script = [
 ]
 script_runner = "@duckscript"
 
-[env.test-macos]
+[env.test-macos-x86_64]
 TEST_CRATE_TYPE = "cdylib"
 TEST_LIB_EXT = "dylib"
 # For the moment, the DynamicLibrary only supports open x86_64 architectures binary.
 TEST_COMPILE_TARGET = "x86_64-apple-darwin"
 
+[env.test-macos-arm64]
+TEST_CRATE_TYPE = "cdylib"
+TEST_LIB_EXT = "dylib"
+TEST_COMPILE_TARGET = "aarch64-apple-darwin"
+
 [env.test-linux]
 TEST_CRATE_TYPE = "cdylib"
 TEST_LIB_EXT = "so"

+ 2 - 5
frontend/appflowy_flutter/analysis_options.yaml

@@ -14,9 +14,7 @@ analyzer:
   exclude:
     - "**/*.g.dart"
     - "**/*.freezed.dart"
-    - "packages/appflowy_editor/**"
-    - "packages/editor/**"
-    # - "packages/flowy_infra_ui/**"
+
 linter:
   # The lint rules applied to this project can be customized in the
   # section below to disable rules from the `package:flutter_lints/flutter.yaml`
@@ -30,8 +28,7 @@ linter:
   # `// ignore_for_file: name_of_lint` syntax on the line or in the file
   # producing the lint.
   rules:
-    # avoid_print: false  # Uncomment to disable the `avoid_print` rule
-    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule
+    - require_trailing_commas
 
 # Additional information about this file can be found at
 # https://dart.dev/guides/language/analysis-options

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 112
frontend/appflowy_flutter/assets/images/flowy_logo_dark_mode.svg


+ 156 - 147
frontend/appflowy_flutter/assets/translations/de-DE.json

@@ -1,150 +1,159 @@
 {
-    "appName": "AppFlowy",
-    "defaultUsername": "Ich",
-    "welcomeText": "Willkommen bei @:appName",
-    "githubStarText": "GitHub Star vergeben",
-    "subscribeNewsletterText": "Abonniere den Newsletter",
-    "letsGoButtonText": "Los geht's",
-    "title": "Titel",
-    "signUp": {
-      "buttonText": "Registrieren",
-      "title": "Registriere dich bei @:appName",
-      "getStartedText": "Erste Schritte",
-      "emptyPasswordError": "Passwort darf nicht leer sein",
-      "repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
-      "unmatchedPasswordError": "Passwörter stimmen nicht überein",
-      "alreadyHaveAnAccount": "Bereits registriert?",
-      "emailHint": "E-Mail",
-      "passwordHint": "Passwort",
-      "repeatPasswordHint": "Wiederhole Passwort"
-    },
-    "signIn": {
-      "loginTitle": "Bei @:appName einloggen",
-      "loginButtonText": "Anmelden",
-      "buttonText": "Anmelden",
-      "forgotPassword": "Passwort vergessen?",
-      "emailHint": "E-Mail",
-      "passwordHint": "Passwort",
-      "dontHaveAnAccount": "Du besitzt noch kein Konto?",
-      "repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
-      "unmatchedPasswordError": "Passwörter stimmen nicht überein"
-    },
-    "workspace": {
-      "create": "Arbeitsbereich erstellen",
-      "hint": "Arbeitsbereich",
-      "notFoundError": "Arbeitsbereich nicht gefunden"
-    },
-    "shareAction": {
-      "buttonText": "Teilen",
-      "workInProgress": "Demnächst verfügbar",
-      "markdown": "Markdown",
-      "copyLink": "Link kopieren"
-    },
-    "disclosureAction": {
-      "rename": "Umbenennen",
-      "delete": "Löschen",
-      "duplicate": "Duplizieren"
-    },
-    "blankPageTitle": "Leere Seite",
-    "newPageText": "Neue Seite",
-    "trash": {
-      "text": "Papierkorb",
-      "restoreAll": "Alles wiederherstellen",
-      "deleteAll": "Alles löschen",
-      "pageHeader": {
-        "fileName": "Dateiname",
-        "lastModified": "Letzte Änderung",
-        "created": "Erstellt"
-      }
-    },
-    "deletePagePrompt": {
-      "text": "Diese Seite ist im Papierkorb",
-      "restore": "Seite wiederherstellen",
-      "deletePermanent": "Dauerhaft löschen"
-    },
-    "dialogCreatePageNameHint": "Seitenname",
-    "questionBubble": {
-      "whatsNew": "Was gibt es Neues?",
-      "help": "Hilfe & Support",
-      "debug": {
-        "name": "Debug-Informationen",
-        "success": "Debug-Informationen in die Zwischenablage kopiert!",
-        "fail": "Debug-Informationen können nicht in die Zwischenablage kopiert werden"
-      }
-    },
-    "menuAppHeader": {
-      "addPageTooltip": "Schnell eine Seite innerhalb hinzufügen",
-      "defaultNewPageName": "Unbenannt",
-      "renameDialog": "Umbenennen"
-    },
-    "toolbar": {
-      "undo": "Rückgängig",
-      "redo": "Wiederherstellen",
-      "bold": "Fett",
-      "italic": "Kursiv",
-      "underline": "Unterstreichen",
-      "strike": "Durchstreichen",
-      "numList": "Nummerierte Liste",
-      "bulletList": "Aufzählung",
-      "checkList": "Checkliste",
-      "inlineCode": "Inline-Code",
-      "quote": "Zitat",
-      "header": "Überschrift",
-      "highlight": "Hervorhebung"
-    },
-    "tooltip": {
-      "lightMode": "In den hellen Modus wechseln",
-      "darkMode": "In den dunklen Modus wechseln"
-    },
-    "contactsPage": {
-      "title": "Kontakte",
-      "whatsHappening": "Was geschieht diese Woche?",
-      "addContact": "Kontakt hinzufügen",
-      "editContact": "Kontakt bearbeiten"
-    },
-    "button": {
-      "OK": "OK",
-      "Cancel": "Abbrechen",
-      "signIn": "Anmelden",
-      "signOut": "Abmelden",
-      "complete": "Fertig",
-      "save": "Speichern"
-    },
-    "label": {
-      "welcome": "Willkommen!",
-      "firstName": "Vorname",
-      "middleName": "Zweiter Vorname",
-      "lastName": "Nachname",
-      "stepX": "Schritt {X}"
-    },
-    "oAuth": {
-      "err": {
-        "failedTitle": "Keine Verbindung zu Ihrem Konto möglich.",
-        "failedMsg": "Bitte vergewissern Sie sich, dass Sie den Anmeldevorgang in Ihrem Browser abgeschlossen haben."
-      },
-      "google": {
-        "title": "GOOGLE ANMELDUNG",
-        "instruction1": "Um Ihre Google-Kontakte zu importieren, müssen Sie diese Anwendung über Ihren Webbrowser autorisieren.",
-        "instruction2": "Kopieren Sie diesen Code in Ihre Zwischenablage, indem Sie auf das Symbol klicken oder den Text auswählen:",
-        "instruction3": "Rufen Sie den folgenden Link in Ihrem Webbrowser auf, und geben Sie den obigen Code ein:",
-        "instruction4": "Klicken Sie unten auf die Schaltfläche, wenn Sie die Anmeldung abgeschlossen haben:"
-      }
-    },
-    "settings": {
-      "title": "Einstellungen",
-      "menu": {
-        "appearance": "Aussehen",
-        "language": "Sprache",
-        "open": "Einstellungen öffnen"
-      },
-      "appearance": {
-        "lightLabel": "Heller Modus",
-        "darkLabel": "Dunkler Modus"
-      }
-    },
-    "sideBar": {
-      "openSidebar": "Open sidebar",
-      "closeSidebar": "Close sidebar"
+  "appName": "AppFlowy",
+  "defaultUsername": "Ich",
+  "welcomeText": "Willkommen bei @:appName",
+  "githubStarText": "GitHub Star vergeben",
+  "subscribeNewsletterText": "Abonniere den Newsletter",
+  "letsGoButtonText": "Los geht's",
+  "title": "Titel",
+  "signUp": {
+    "buttonText": "Registrieren",
+    "title": "Registriere dich bei @:appName",
+    "getStartedText": "Erste Schritte",
+    "emptyPasswordError": "Passwort darf nicht leer sein",
+    "repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
+    "unmatchedPasswordError": "Passwörter stimmen nicht überein",
+    "alreadyHaveAnAccount": "Bereits registriert?",
+    "emailHint": "E-Mail",
+    "passwordHint": "Passwort",
+    "repeatPasswordHint": "Wiederhole Passwort"
+  },
+  "signIn": {
+    "loginTitle": "Bei @:appName einloggen",
+    "loginButtonText": "Anmelden",
+    "buttonText": "Anmelden",
+    "forgotPassword": "Passwort vergessen?",
+    "emailHint": "E-Mail",
+    "passwordHint": "Passwort",
+    "dontHaveAnAccount": "Du besitzt noch kein Konto?",
+    "repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
+    "unmatchedPasswordError": "Passwörter stimmen nicht überein"
+  },
+  "workspace": {
+    "create": "Arbeitsbereich erstellen",
+    "hint": "Arbeitsbereich",
+    "notFoundError": "Arbeitsbereich nicht gefunden"
+  },
+  "shareAction": {
+    "buttonText": "Teilen",
+    "workInProgress": "Demnächst verfügbar",
+    "markdown": "Markdown",
+    "copyLink": "Link kopieren"
+  },
+  "disclosureAction": {
+    "rename": "Umbenennen",
+    "delete": "Löschen",
+    "duplicate": "Duplizieren"
+  },
+  "blankPageTitle": "Leere Seite",
+  "newPageText": "Neue Seite",
+  "trash": {
+    "text": "Papierkorb",
+    "restoreAll": "Alles wiederherstellen",
+    "deleteAll": "Alles löschen",
+    "pageHeader": {
+      "fileName": "Dateiname",
+      "lastModified": "Letzte Änderung",
+      "created": "Erstellt"
+    }
+  },
+  "deletePagePrompt": {
+    "text": "Diese Seite ist im Papierkorb",
+    "restore": "Seite wiederherstellen",
+    "deletePermanent": "Dauerhaft löschen"
+  },
+  "dialogCreatePageNameHint": "Seitenname",
+  "questionBubble": {
+    "whatsNew": "Was gibt es Neues?",
+    "help": "Hilfe & Support",
+    "debug": {
+      "name": "Debug-Informationen",
+      "success": "Debug-Informationen in die Zwischenablage kopiert!",
+      "fail": "Debug-Informationen können nicht in die Zwischenablage kopiert werden"
+    },
+    "shortcuts": "Abkürzungen"
+  },
+  "menuAppHeader": {
+    "addPageTooltip": "Schnell eine Seite innerhalb hinzufügen",
+    "defaultNewPageName": "Unbenannt",
+    "renameDialog": "Umbenennen"
+  },
+  "toolbar": {
+    "undo": "Rückgängig",
+    "redo": "Wiederherstellen",
+    "bold": "Fett",
+    "italic": "Kursiv",
+    "underline": "Unterstreichen",
+    "strike": "Durchstreichen",
+    "numList": "Nummerierte Liste",
+    "bulletList": "Aufzählung",
+    "checkList": "Checkliste",
+    "inlineCode": "Inline-Code",
+    "quote": "Zitat",
+    "header": "Überschrift",
+    "highlight": "Hervorhebung",
+    "color": "Farbe"
+  },
+  "tooltip": {
+    "lightMode": "In den hellen Modus wechseln",
+    "darkMode": "In den dunklen Modus wechseln",
+    "openAsPage": "Als Seite öffnen"
+  },
+  "contactsPage": {
+    "title": "Kontakte",
+    "whatsHappening": "Was geschieht diese Woche?",
+    "addContact": "Kontakt hinzufügen",
+    "editContact": "Kontakt bearbeiten"
+  },
+  "button": {
+    "OK": "OK",
+    "Cancel": "Abbrechen",
+    "signIn": "Anmelden",
+    "signOut": "Abmelden",
+    "complete": "Fertig",
+    "save": "Speichern"
+  },
+  "label": {
+    "welcome": "Willkommen!",
+    "firstName": "Vorname",
+    "middleName": "Zweiter Vorname",
+    "lastName": "Nachname",
+    "stepX": "Schritt {X}"
+  },
+  "oAuth": {
+    "err": {
+      "failedTitle": "Keine Verbindung zu Ihrem Konto möglich.",
+      "failedMsg": "Bitte vergewissern Sie sich, dass Sie den Anmeldevorgang in Ihrem Browser abgeschlossen haben."
+    },
+    "google": {
+      "title": "GOOGLE ANMELDUNG",
+      "instruction1": "Um Ihre Google-Kontakte zu importieren, müssen Sie diese Anwendung über Ihren Webbrowser autorisieren.",
+      "instruction2": "Kopieren Sie diesen Code in Ihre Zwischenablage, indem Sie auf das Symbol klicken oder den Text auswählen:",
+      "instruction3": "Rufen Sie den folgenden Link in Ihrem Webbrowser auf, und geben Sie den obigen Code ein:",
+      "instruction4": "Klicken Sie unten auf die Schaltfläche, wenn Sie die Anmeldung abgeschlossen haben:"
+    }
+  },
+  "settings": {
+    "title": "Einstellungen",
+    "menu": {
+      "appearance": "Aussehen",
+      "language": "Sprache",
+      "open": "Einstellungen öffnen"
+    },
+    "appearance": {
+      "lightLabel": "Heller Modus",
+      "darkLabel": "Dunkler Modus"
     }
+  },
+  "sideBar": {
+    "openSidebar": "Open sidebar",
+    "closeSidebar": "Close sidebar"
+  },
+  "moreAction": {
+    "small": "klein",
+    "medium": "mittel",
+    "large": "groß",
+    "fontSize": "Schriftgröße",
+    "import": "Importieren"
   }
-  
+}

+ 6 - 3
frontend/appflowy_flutter/assets/translations/en.json

@@ -282,6 +282,7 @@
       "dateFormatISO": "Year-Month-Day",
       "dateFormatLocal": "Month/Day/Year",
       "dateFormatUS": "Year/Month/Day",
+      "dateFormatDayMonthYear": "Day/Month/Year",
       "timeFormat": "Time format",
       "invalidTimeFormat": "Invalid format",
       "timeFormatTwelveHour": "12 hour",
@@ -290,7 +291,7 @@
       "optionTitle": "Options",
       "addOption": "Add option",
       "editProperty": "Edit property",
-      "newColumn": "New column",
+      "newProperty": "New property",
       "deleteFieldPromptMessage": "Are you sure? This property will be deleted"
     },
     "sort": {
@@ -383,7 +384,9 @@
         "pickFromFiles": "Pick from files",
         "couldNotFetchImage": "Could not fetch image",
         "imageSavingFailed": "Image Saving Failed",
-        "addIcon": "Add Icon"
+        "addIcon": "Add Icon",
+        "coverRemoveAlert": "It will be removed from cover after it is deleted.",
+        "alertDialogConfirmation": "Are you sure, you want to continue?"
       }
     }
   },
@@ -410,4 +413,4 @@
       "layoutDateField": "Layout calendar by"
     }
   }
-}
+}

+ 2 - 2
frontend/appflowy_flutter/assets/translations/eu-ES.json

@@ -271,7 +271,7 @@
       "optionTitle": "Aukerak",
       "addOption": "Gehitu aukera",
       "editProperty": "Editatu propietatea",
-      "newColumn": "Zutabe berria",
+      "newProperty": "Zutabe berria",
       "deleteFieldPromptMessage": "Ziur al zaude? Propietate hau ezabatu egingo da"
     },
     "sort": {
@@ -330,4 +330,4 @@
       "nextMonth": "Hurrengo hilabetea"
     }
   }
-}
+}

+ 1 - 1
frontend/appflowy_flutter/assets/translations/fr-FR.json

@@ -195,7 +195,7 @@
       "optionTitle": "Options",
       "addOption": "Ajouter une option",
       "editProperty": "Modifier la propriété",
-      "newColumn": "Nouvelle colonne",
+      "newProperty": "Nouvelle colonne",
       "deleteFieldPromptMessage": "Vous voulez supprimer cette propriété ?"
     },
     "row": {

+ 1 - 1
frontend/appflowy_flutter/assets/translations/ko-KR.json

@@ -191,7 +191,7 @@
       "optionTitle": "옵션",
       "addOption": "옵션 추가",
       "editProperty": "속성 편집",
-      "newColumn": "열 추가",
+      "newProperty": "열 추가",
       "deleteFieldPromptMessage": "해당 속성을 삭제 하시겠습니까?"
     },
     "row": {

+ 4 - 4
frontend/appflowy_flutter/assets/translations/pt-BR.json

@@ -39,7 +39,7 @@
     "workInProgress": "Em breve",
     "markdown": "Marcador",
     "copyLink": "Copiar link"
-    },
+  },
   "moreAction": {
     "small": "pequeno",
     "medium": "médio",
@@ -177,7 +177,7 @@
         "system": "Adaptar-se ao sistema"
       },
       "theme": "Tema"
-  },
+    },
     "files": {
       "defaultLocation": "Onde os seus dados ficam armazenados",
       "doubleTapToCopy": "Clique duas vezes para copiar o caminho",
@@ -287,7 +287,7 @@
       "optionTitle": "Opções",
       "addOption": "Adicioar opção",
       "editProperty": "Editar propriedade",
-      "newColumn": "Nova coluna",
+      "newProperty": "Nova coluna",
       "deleteFieldPromptMessage": "Tem certeza? Esta propriedade será excluída"
     },
     "sort": {
@@ -320,7 +320,7 @@
       "pannelTitle": "Escolha uma opção ou crie uma",
       "searchOption": "Procurar uma opção"
     },
-        "checklist": {
+    "checklist": {
       "panelTitle": "Adicionar um item"
     },
     "menuName": "Grade"

+ 146 - 147
frontend/appflowy_flutter/assets/translations/pt-PT.json

@@ -1,150 +1,149 @@
 {
-    "appName": "AppFlowy",
-    "defaultUsername": "Me",
-    "welcomeText": "Bem vindo ao @:appName",
-    "githubStarText": "Star on GitHub",
-    "subscribeNewsletterText": "Inscreve-te ao Newsletter",
-    "letsGoButtonText": "Bora",
-    "title": "Título",
-    "signUp": {
-      "buttonText": "Inscreve-te",
-      "title": "Inscreve-te ao @:appName",
-      "getStartedText": "Começar",
-      "emptyPasswordError": "A palavra-passe não pode estar em branco.",
-      "repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
-      "unmatchedPasswordError": "As palavras-passes não coincidem.",
-      "alreadyHaveAnAccount": "Já possuis uma conta?",
-      "emailHint": "Email",
-      "passwordHint": "Password",
-      "repeatPasswordHint": "Confirma a tua password"
-    },
-    "signIn": {
-      "loginTitle": "Entre no @:appName",
-      "loginButtonText": "Login",
-      "buttonText": "Entre",
-      "forgotPassword": "Esqueceste-te da tua palavra-passe?",
-      "emailHint": "Email",
-      "passwordHint": "Palavra-passe",
-      "dontHaveAnAccount": "Não possuis uma conta?",
-      "repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
-      "unmatchedPasswordError": "As palavras-passes não conferem."
-    },
-    "workspace": {
-      "create": "Cria um ambiente de trabalho",
-      "hint": "ambiente de trabalho",
-      "notFoundError": "Ambiente de trabalho não encontrada"
-    },
-    "shareAction": {
-      "buttonText": "Partilhar",
-      "workInProgress": "Em breve",
-      "markdown": "Markdown",
-      "copyLink": "Copiar o link"
-    },
-    "disclosureAction": {
-      "rename": "Renomear",
-      "delete": "Apagar",
-      "duplicate": "Duplicar"
-    },
-    "blankPageTitle": "Página em branco",
-    "newPageText": "Nova página",
-    "trash": {
-      "text": "Lixo",
-      "restoreAll": "Restaurar todos",
-      "deleteAll": "Apagar todos",
-      "pageHeader": {
-        "fileName": "Nome do ficheiro",
-        "lastModified": "Última modificação",
-        "created": "Criado"
-      }
-    },
-    "deletePagePrompt": {
-      "text": "Esta página está no lixo",
-      "restore": "Restaurar a página",
-      "deletePermanent": "Apagar permanentemente"
-    },
-    "dialogCreatePageNameHint": "Nome da página",
-    "questionBubble": {
-      "whatsNew": "O que há de novo?",
-      "help": "Ajuda & Suporte",
-      "debug": {
-        "name": "Informação de depuração",
-        "success": "Copiar informação de depuração para o clipboard!",
-        "fail": "Falha em copiar a informação de depuração para o clipboard"
-      }
-    },
-    "menuAppHeader": {
-      "addPageTooltip": "Adiciona uma nova página.",
-      "defaultNewPageName": "Sem título",
-      "renameDialog": "Renomear"
-    },
-    "toolbar": {
-      "undo": "Desfazer",
-      "redo": "Refazer",
-      "bold": "Negrito",
-      "italic": "Itálico",
-      "underline": "Sublinhado",
-      "strike": "Riscado",
-      "numList": "Lista numerada",
-      "bulletList": "Lista com marcadores",
-      "checkList": "Lista de verificação",
-      "inlineCode": "Embutir código",
-      "quote": "Citação em bloco",
-      "header": "Cabeçalho",
-      "highlight": "Realçar"
-    },
-    "tooltip": {
-      "lightMode": "Mudar para o modo Claro.",
-      "darkMode": "Mudar para o modo Escuro."
-    },
-    "contactsPage": {
-      "title": "Conctatos",
-      "whatsHappening": "O que está a acontecer nesta semana?",
-      "addContact": "Adicionar um conctato",
-      "editContact": "Editar um conctato"
-    },
-    "button": {
-      "OK": "OK",
-      "Cancel": "Cancelar",
-      "signIn": "Entrar",
-      "signOut": "Sair",
-      "complete": "Completar",
-      "save": "Guardar"
-    },
-    "label": {
-      "welcome": "Bem vindo!",
-      "firstName": "Nome",
-      "middleName": "Nome do Meio",
-      "lastName": "Apelido",
-      "stepX": "Passo {X}"
-    },
-    "oAuth": {
-      "err": {
-        "failedTitle": "Erro ao conectar à sua conta.",
-        "failedMsg": "Verifica se concluiste o processo de login no teu navegador."
-      },
-      "google": {
-        "title": "GOOGLE SIGN-IN",
-        "instruction1": "Para importar os teus Conctatos do Google, tens de autorizar esta aplicação usando o teu navegador web.",
-        "instruction2": "Copia este código para a tua área de transferências clicando no ícone ou selecionando o texto:",
-        "instruction3": "Navega até o link a seguir no seu navegador e digite o código acima:",
-        "instruction4": "Clica no botão abaixo ao concluir a inscrição:"
-      }
-    },
-    "settings": {
-      "title": "Definições",
-      "menu": {
-        "appearance": "Aparência",
-        "language": "Idioma",
-        "open": "Abrir as Definições"
-      },
-      "appearance": {
-        "lightLabel": "Modo Claro",
-        "darkLabel": "Modo Escuro"
-      }
-    },
-    "sideBar": {
-      "openSidebar": "Open sidebar",
-      "closeSidebar": "Close sidebar"
+  "appName": "AppFlowy",
+  "defaultUsername": "Me",
+  "welcomeText": "Bem vindo ao @:appName",
+  "githubStarText": "Star on GitHub",
+  "subscribeNewsletterText": "Inscreve-te ao Newsletter",
+  "letsGoButtonText": "Bora",
+  "title": "Título",
+  "signUp": {
+    "buttonText": "Inscreve-te",
+    "title": "Inscreve-te ao @:appName",
+    "getStartedText": "Começar",
+    "emptyPasswordError": "A palavra-passe não pode estar em branco.",
+    "repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
+    "unmatchedPasswordError": "As palavras-passes não coincidem.",
+    "alreadyHaveAnAccount": "Já possuis uma conta?",
+    "emailHint": "Email",
+    "passwordHint": "Password",
+    "repeatPasswordHint": "Confirma a tua password"
+  },
+  "signIn": {
+    "loginTitle": "Entre no @:appName",
+    "loginButtonText": "Login",
+    "buttonText": "Entre",
+    "forgotPassword": "Esqueceste-te da tua palavra-passe?",
+    "emailHint": "Email",
+    "passwordHint": "Palavra-passe",
+    "dontHaveAnAccount": "Não possuis uma conta?",
+    "repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
+    "unmatchedPasswordError": "As palavras-passes não conferem."
+  },
+  "workspace": {
+    "create": "Cria um ambiente de trabalho",
+    "hint": "ambiente de trabalho",
+    "notFoundError": "Ambiente de trabalho não encontrada"
+  },
+  "shareAction": {
+    "buttonText": "Partilhar",
+    "workInProgress": "Em breve",
+    "markdown": "Markdown",
+    "copyLink": "Copiar o link"
+  },
+  "disclosureAction": {
+    "rename": "Renomear",
+    "delete": "Apagar",
+    "duplicate": "Duplicar"
+  },
+  "blankPageTitle": "Página em branco",
+  "newPageText": "Nova página",
+  "trash": {
+    "text": "Lixo",
+    "restoreAll": "Restaurar todos",
+    "deleteAll": "Apagar todos",
+    "pageHeader": {
+      "fileName": "Nome do ficheiro",
+      "lastModified": "Última modificação",
+      "created": "Criado"
+    }
+  },
+  "deletePagePrompt": {
+    "text": "Esta página está no lixo",
+    "restore": "Restaurar a página",
+    "deletePermanent": "Apagar permanentemente"
+  },
+  "dialogCreatePageNameHint": "Nome da página",
+  "questionBubble": {
+    "whatsNew": "O que há de novo?",
+    "help": "Ajuda & Suporte",
+    "debug": {
+      "name": "Informação de depuração",
+      "success": "Copiar informação de depuração para o clipboard!",
+      "fail": "Falha em copiar a informação de depuração para o clipboard"
+    }
+  },
+  "menuAppHeader": {
+    "addPageTooltip": "Adiciona uma nova página.",
+    "defaultNewPageName": "Sem título",
+    "renameDialog": "Renomear"
+  },
+  "toolbar": {
+    "undo": "Desfazer",
+    "redo": "Refazer",
+    "bold": "Negrito",
+    "italic": "Itálico",
+    "underline": "Sublinhado",
+    "strike": "Riscado",
+    "numList": "Lista numerada",
+    "bulletList": "Lista com marcadores",
+    "checkList": "Lista de verificação",
+    "inlineCode": "Embutir código",
+    "quote": "Citação em bloco",
+    "header": "Cabeçalho",
+    "highlight": "Realçar"
+  },
+  "tooltip": {
+    "lightMode": "Mudar para o modo Claro.",
+    "darkMode": "Mudar para o modo Escuro."
+  },
+  "contactsPage": {
+    "title": "Conctatos",
+    "whatsHappening": "O que está a acontecer nesta semana?",
+    "addContact": "Adicionar um conctato",
+    "editContact": "Editar um conctato"
+  },
+  "button": {
+    "OK": "OK",
+    "Cancel": "Cancelar",
+    "signIn": "Entrar",
+    "signOut": "Sair",
+    "complete": "Completar",
+    "save": "Guardar"
+  },
+  "label": {
+    "welcome": "Bem vindo!",
+    "firstName": "Nome",
+    "middleName": "Nome do Meio",
+    "lastName": "Apelido",
+    "stepX": "Passo {X}"
+  },
+  "oAuth": {
+    "err": {
+      "failedTitle": "Erro ao conectar à sua conta.",
+      "failedMsg": "Verifica se concluiste o processo de login no teu navegador."
+    },
+    "google": {
+      "title": "GOOGLE SIGN-IN",
+      "instruction1": "Para importar os teus Conctatos do Google, tens de autorizar esta aplicação usando o teu navegador web.",
+      "instruction2": "Copia este código para a tua área de transferências clicando no ícone ou selecionando o texto:",
+      "instruction3": "Navega até o link a seguir no seu navegador e digite o código acima:",
+      "instruction4": "Clica no botão abaixo ao concluir a inscrição:"
+    }
+  },
+  "settings": {
+    "title": "Definições",
+    "menu": {
+      "appearance": "Aparência",
+      "language": "Idioma",
+      "open": "Abrir as Definições"
+    },
+    "appearance": {
+      "lightLabel": "Modo Claro",
+      "darkLabel": "Modo Escuro"
     }
+  },
+  "sideBar": {
+    "openSidebar": "Open sidebar",
+    "closeSidebar": "Close sidebar"
   }
-
+}

+ 413 - 348
frontend/appflowy_flutter/assets/translations/ru-RU.json

@@ -1,348 +1,413 @@
-{
-    "appName": "AppFlowy",
-    "defaultUsername": "Я",
-    "welcomeText": "Добро пожаловать в @:appName",
-    "githubStarText": "Поставить звезду на GitHub",
-    "subscribeNewsletterText": "Подписаться на рассылку",
-    "letsGoButtonText": "Начнём",
-    "title": "Заголовок",
-    "signUp": {
-        "buttonText": "Зарегистрироваться",
-        "title": "Регистрация в @:appName",
-        "getStartedText": "Начать",
-        "emptyPasswordError": "Пароль не может быть пустым",
-        "repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
-        "unmatchedPasswordError": "Пароли не совпадают",
-        "alreadyHaveAnAccount": "Уже есть аккаунт?",
-        "emailHint": "Электронная почта",
-        "passwordHint": "Пароль",
-        "repeatPasswordHint": "Повторите пароль"
-    },
-    "signIn": {
-        "loginTitle": "Войти в @:appName",
-        "loginButtonText": "Войти",
-        "buttonText": "Авторизация",
-        "forgotPassword": "Забыли пароль?",
-        "emailHint": "Электронная почта",
-        "passwordHint": "Пароль",
-        "dontHaveAnAccount": "Нет аккаунта?",
-        "repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
-        "unmatchedPasswordError": "Пароли не совпадают"
-    },
-    "workspace": {
-        "create": "Создать рабочее пространство",
-        "hint": "рабочее пространство",
-        "notFoundError": "Нет такого рабочего пространства"
-    },
-    "shareAction": {
-        "buttonText": "Поделиться",
-        "workInProgress": "В разработке",
-        "markdown": "Markdown",
-        "copyLink": "Скопировать ссылку"
-    },
-    "moreAction": {
-        "small": "маленький",
-        "medium": "средний",
-        "large": "большой",
-        "fontSize": "Размер шрифта"
-    },
-    "disclosureAction": {
-        "rename": "Переименовать",
-        "delete": "Удалить",
-        "duplicate": "Дублировать"
-    },
-    "blankPageTitle": "Пустая страница",
-    "newPageText": "Новая страница",
-    "trash": {
-        "text": "Корзина",
-        "restoreAll": "Восстановить всё",
-        "deleteAll": "Очистить",
-        "pageHeader": {
-            "fileName": "Имя",
-            "lastModified": "Последнее изменение",
-            "created": "Создан"
-        }
-    },
-    "deletePagePrompt": {
-        "text": "Эта страница в Корзине",
-        "restore": "Восстановить страницу",
-        "deletePermanent": "Удалить навсегда"
-    },
-    "dialogCreatePageNameHint": "Имя страницы",
-    "questionBubble": {
-        "whatsNew": "Что нового?",
-        "help": "Помощь",
-        "debug": {
-            "name": "Отладочная информация",
-            "success": "Скопировано в буфер обмена!",
-            "fail": "Не получилось скопировать"
-        }
-    },
-    "menuAppHeader": {
-        "addPageTooltip": "Быстро добавить новую страницу",
-        "defaultNewPageName": "Без заголовка",
-        "renameDialog": "Переименовать"
-    },
-    "toolbar": {
-        "undo": "Отменить",
-        "redo": "Повторить",
-        "bold": "Жирный",
-        "italic": "Курсив",
-        "underline": "Подчёркнутый",
-        "strike": "Зачёркнутый",
-        "numList": "Нумерованный список",
-        "bulletList": "Маркированный список",
-        "checkList": "Список To-Do",
-        "inlineCode": "Код",
-        "quote": "Цитата",
-        "header": "Заголовок",
-        "highlight": "Выделение",
-        "color": "Цвет"
-    },
-    "tooltip": {
-        "lightMode": "Переключить на светлую тему",
-        "darkMode": "Переключить на тёмную тему",
-        "openAsPage": "Открыть как страницу",
-        "addNewRow": "Добавить новую строку",
-        "openMenu": "Открыть меню",
-        "viewDataBase": "Просмотр базы данных",
-        "referencePage": "Ссылаются на {name}"
-    },
-    "sideBar": {
-        "closeSidebar": "Закрыть боковое меню",
-        "openSidebar": "Открыть боковое меню"
-    },
-    "notifications": {
-        "export": {
-            "markdown": "Заметка экспортирована в Markdown",
-            "path": "Документы/flowy"
-        }
-    },
-    "contactsPage": {
-        "title": "Контакты",
-        "whatsHappening": "Какие события на этой неделе?",
-        "addContact": "Добавить контакт",
-        "editContact": "Редактировать контакт"
-    },
-    "button": {
-        "OK": "OK",
-        "Cancel": "Отмена",
-        "signIn": "Войти",
-        "signOut": "Выйти",
-        "complete": "Завершить",
-        "save": "Сохранить"
-    },
-    "label": {
-        "welcome": "Добро пожаловать!",
-        "firstName": "Имя",
-        "middleName": "Отчество",
-        "lastName": "Фамилия",
-        "stepX": "Этап {X}"
-    },
-    "oAuth": {
-        "err": {
-            "failedTitle": "Не удалось подключиться к вашей учетной записи.",
-            "failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
-        },
-        "google": {
-            "title": "Вход через Google",
-            "instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
-            "instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
-            "instruction3": "Пройдите по ссылке и введите этот код:",
-            "instruction4": "Нажмите на кнопку ниже, когда завершите вход:"
-        }
-    },
-    "settings": {
-        "title": "Настройки",
-        "menu": {
-            "appearance": "Внешний вид",
-            "language": "Язык",
-            "user": "Пользователь",
-            "files": "Файлы",
-            "open": "Открыть настройки"
-        },
-        "appearance": {
-            "themeMode": {
-                "label": "Режим темы",
-                "light": "Светлая",
-                "dark": "Тёмная",
-                "system": "Системная"
-            },
-            "theme": "Тема"
-        },
-        "files": {
-            "defaultLocation": "Где сейчас хранятся ваши данные",
-            "doubleTapToCopy": "Нажмите дважды, чтобы скопировать путь",
-            "restoreLocation": "Восстановить путь AppFlowy по умолчанию",
-            "customizeLocation": "Открыть другую папку",
-            "restartApp": "Пожалуйста, перезапустите приложение, чтобы изменения вступили в силу.",
-            "exportDatabase": "Экспорт базы данных",
-            "selectFiles": "Выбрать файлы, которые необходимо экспортировать",
-            "createNewFolder": "Создать новую папку",
-            "createNewFolderDesc": "Указать, где хранить свои данные ...",
-            "open": "Открыть",
-            "openFolder": "Открыть существующую папку",
-            "openFolderDesc": "Чтение и запись в существующую папку AppFlowy ...",
-            "folderHintText": "имя папки",
-            "location": "Создание новой папки",
-            "locationDesc": "Выбрать имя папки данных AppFlowy",
-            "browser": "Обзор",
-            "create": "Создать",
-            "folderPath": "Путь к вашей папке",
-            "locationCannotBeEmpty": "Путь не может быть пустым"
-        }
-    },
-    "grid": {
-        "settings": {
-            "filter": "Фильтр",
-            "sort": "Сортировать",
-            "sortBy": "Сортировать по",
-            "Properties": "Свойства",
-            "group": "Группировать",
-            "addFilter": "Добавить фильтр",
-            "deleteFilter": "Удалить фильтр",
-            "filterBy": "Фильтровать по...",
-            "typeAValue": "Введите значение..."
-        },
-        "textFilter": {
-            "contains": "Содержит",
-            "doesNotContain": "Не содержит",
-            "endsWith": "Заканчивается на",
-            "startWith": "Начинается с",
-            "is": "Является",
-            "isNot": "Не является",
-            "isEmpty": "Пусто",
-            "isNotEmpty": "Не пусто",
-            "choicechipPrefix": {
-                "isNot": "Не является",
-                "startWith": "Начинается с",
-                "endWith": "Заканчивается на",
-                "isEmpty": "пусто",
-                "isNotEmpty": "не пусто"
-            }
-        },
-        "checkboxFilter": {
-            "isChecked": "Отмечено",
-            "isUnchecked": "Не отмечено",
-            "choicechipPrefix": {
-                "is": "является"
-            }
-        },
-        "checklistFilter": {
-            "isComplete": "завершено",
-            "isIncomplted": "не завершено"
-        },
-        "singleSelectOptionFilter": {
-            "is": "Является",
-            "isNot": "Не является",
-            "isEmpty": "Пусто",
-            "isNotEmpty": "Не пусто"
-        },
-        "multiSelectOptionFilter": {
-            "contains": "Содержит",
-            "doesNotContain": "Не содержит",
-            "isEmpty": "Пусто",
-            "isNotEmpty": "Не пусто"
-        },
-        "field": {
-            "hide": "Скрыть",
-            "insertLeft": "Вставить слева",
-            "insertRight": "Вставить справа",
-            "duplicate": "Дублировать",
-            "delete": "Удалить",
-            "textFieldName": "Текст",
-            "checkboxFieldName": "Чекбокс",
-            "dateFieldName": "Дата",
-            "numberFieldName": "Число",
-            "singleSelectFieldName": "Выбор",
-            "multiSelectFieldName": "Выбор нескольких",
-            "urlFieldName": "URL",
-            "checklistFieldName": "Контрольный список",
-            "numberFormat": "Формат числа",
-            "dateFormat": "Формат даты",
-            "includeTime": "Время",
-            "dateFormatFriendly": "День Месяц, Год",
-            "dateFormatISO": "Год-Месяц-День",
-            "dateFormatLocal": "Месяц/День/Год",
-            "dateFormatUS": "Год/Месяц/День",
-            "timeFormat": "Форматировать время",
-            "invalidTimeFormat": "Неверный формат",
-            "timeFormatTwelveHour": "12 часов",
-            "timeFormatTwentyFourHour": "24 часа",
-            "addSelectOption": "Добавить вариант",
-            "optionTitle": "Варианты",
-            "addOption": "Добавить",
-            "editProperty": "Редактировать свойство",
-            "newColumn": "Добавить колонку",
-            "deleteFieldPromptMessage": "Вы уверены? Свойство будет удалено"
-        },
-        "sort": {
-            "ascending": "По возрастанию",
-            "descending": "По убыванию",
-            "deleteSort": "Удалить сортировку",
-            "addSort": "Добавить сортировку"
-        },
-        "row": {
-            "duplicate": "Дублировать",
-            "delete": "Удалить",
-            "textPlaceholder": "Пусто",
-            "copyProperty": "Свойство скопировано",
-            "count": "Количество",
-            "newRow": "Новая строка"
-        },
-        "selectOption": {
-            "create": "Создать",
-            "purpleColor": "Фиолетовый",
-            "pinkColor": "Розовый",
-            "lightPinkColor": "Светло-розовый",
-            "orangeColor": "Оранжевый",
-            "yellowColor": "Желтый",
-            "limeColor": "Ярко-зелёный",
-            "greenColor": "Зелёный",
-            "aquaColor": "Бирюзовый",
-            "blueColor": "Синий",
-            "deleteTag": "Удалить вариант",
-            "colorPanelTitle": "Цвета",
-            "panelTitle": "Выберите или создайте вариант",
-            "searchOption": "Поиск"
-        },
-        "checklist": {
-            "panelTitle": "Добавить элемент"
-        },
-        "menuName": "Сетка"
-    },
-    "document": {
-        "menuName": "Документ",
-        "date": {
-            "timeHintTextInTwelveHour": "01:00 PM",
-            "timeHintTextInTwentyFourHour": "13:00"
-        },
-        "slashMenu": {
-            "board": {
-                "selectABoardToLinkTo": "Выбрать доску для связи с"
-            },
-            "grid": {
-                "selectAGridToLinkTo": "Выберите сетку для связи с"
-            }
-        },
-        "plugins": {
-            "referencedBoard": "Связанные доски",
-            "referencedGrid": "Связанные сетки"
-        }
-    },
-    "board": {
-        "column": {
-            "create_new_card": "Создать"
-        },
-        "menuName": "Доска"
-    },
-    "calendar": {
-        "menuName": "Календарь",
-        "navigation": {
-            "today": "Сегодня",
-            "jumpToday": "Перейти к сегодняшнему дню",
-            "previousMonth": "Предыдущий месяц",
-            "nextMonth": "Следующий месяц"
-        }
-    }
-}
+{
+  "appName": "AppFlowy",
+  "defaultUsername": "Я",
+  "welcomeText": "Добро пожаловать в @:appName",
+  "githubStarText": "Поставить звезду на GitHub",
+  "subscribeNewsletterText": "Подписаться на рассылку",
+  "letsGoButtonText": "Начнём",
+  "title": "Заголовок",
+  "signUp": {
+    "buttonText": "Зарегистрироваться",
+    "title": "Регистрация в @:appName",
+    "getStartedText": "Начать",
+    "emptyPasswordError": "Пароль не может быть пустым",
+    "repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
+    "unmatchedPasswordError": "Пароли не совпадают",
+    "alreadyHaveAnAccount": "Уже есть аккаунт?",
+    "emailHint": "Электронная почта",
+    "passwordHint": "Пароль",
+    "repeatPasswordHint": "Повторите пароль"
+  },
+  "signIn": {
+    "loginTitle": "Войти в @:appName",
+    "loginButtonText": "Войти",
+    "buttonText": "Авторизация",
+    "forgotPassword": "Забыли пароль?",
+    "emailHint": "Электронная почта",
+    "passwordHint": "Пароль",
+    "dontHaveAnAccount": "Нет аккаунта?",
+    "repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
+    "unmatchedPasswordError": "Пароли не совпадают"
+  },
+  "workspace": {
+    "create": "Создать рабочее пространство",
+    "hint": "рабочее пространство",
+    "notFoundError": "Нет такого рабочего пространства"
+  },
+  "shareAction": {
+    "buttonText": "Поделиться",
+    "workInProgress": "В разработке",
+    "markdown": "Markdown",
+    "copyLink": "Скопировать ссылку"
+  },
+  "moreAction": {
+    "small": "маленький",
+    "medium": "средний",
+    "large": "большой",
+    "fontSize": "Размер шрифта"
+  },
+  "disclosureAction": {
+    "rename": "Переименовать",
+    "delete": "Удалить",
+    "duplicate": "Дублировать"
+  },
+  "blankPageTitle": "Пустая страница",
+  "newPageText": "Новая страница",
+  "trash": {
+    "text": "Корзина",
+    "restoreAll": "Восстановить всё",
+    "deleteAll": "Очистить",
+    "pageHeader": {
+      "fileName": "Имя",
+      "lastModified": "Последнее изменение",
+      "created": "Создан"
+    }
+  },
+  "deletePagePrompt": {
+    "text": "Эта страница в Корзине",
+    "restore": "Восстановить страницу",
+    "deletePermanent": "Удалить навсегда"
+  },
+  "dialogCreatePageNameHint": "Имя страницы",
+  "questionBubble": {
+    "whatsNew": "Что нового?",
+    "help": "Помощь",
+    "debug": {
+      "name": "Отладочная информация",
+      "success": "Скопировано в буфер обмена!",
+      "fail": "Не получилось скопировать"
+    }
+  },
+  "menuAppHeader": {
+    "addPageTooltip": "Быстро добавить новую страницу",
+    "defaultNewPageName": "Без заголовка",
+    "renameDialog": "Переименовать"
+  },
+  "toolbar": {
+    "undo": "Отменить",
+    "redo": "Повторить",
+    "bold": "Жирный",
+    "italic": "Курсив",
+    "underline": "Подчёркнутый",
+    "strike": "Зачёркнутый",
+    "numList": "Нумерованный список",
+    "bulletList": "Маркированный список",
+    "checkList": "Список To-Do",
+    "inlineCode": "Код",
+    "quote": "Цитата",
+    "header": "Заголовок",
+    "highlight": "Выделение",
+    "color": "Цвет"
+  },
+  "tooltip": {
+    "lightMode": "Переключить на светлую тему",
+    "darkMode": "Переключить на тёмную тему",
+    "openAsPage": "Открыть как страницу",
+    "addNewRow": "Добавить новую строку",
+    "openMenu": "Открыть меню",
+    "viewDataBase": "Просмотр базы данных",
+    "referencePage": "Ссылаются на {name}"
+  },
+  "sideBar": {
+    "closeSidebar": "Закрыть боковое меню",
+    "openSidebar": "Открыть боковое меню"
+  },
+  "notifications": {
+    "export": {
+      "markdown": "Заметка экспортирована в Markdown",
+      "path": "Документы/flowy"
+    }
+  },
+  "contactsPage": {
+    "title": "Контакты",
+    "whatsHappening": "Какие события на этой неделе?",
+    "addContact": "Добавить контакт",
+    "editContact": "Редактировать контакт"
+  },
+  "button": {
+    "OK": "OK",
+    "Cancel": "Отмена",
+    "signIn": "Войти",
+    "signOut": "Выйти",
+    "complete": "Завершить",
+    "save": "Сохранить",
+    "generate": "Сгенерировать",
+    "esc": "ESC",
+    "keep": "Оставить",
+    "tryAgain": "Повторить",
+    "discard": "Отменить",
+    "replace": "Заменить",
+    "insertBelow": "Вставить ниже"
+  },
+  "label": {
+    "welcome": "Добро пожаловать!",
+    "firstName": "Имя",
+    "middleName": "Отчество",
+    "lastName": "Фамилия",
+    "stepX": "Этап {X}"
+  },
+  "oAuth": {
+    "err": {
+      "failedTitle": "Не удалось подключиться к вашей учетной записи.",
+      "failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
+    },
+    "google": {
+      "title": "Вход через Google",
+      "instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
+      "instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
+      "instruction3": "Пройдите по ссылке и введите этот код:",
+      "instruction4": "Нажмите на кнопку ниже, когда завершите вход:"
+    }
+  },
+  "settings": {
+    "title": "Настройки",
+    "menu": {
+      "appearance": "Внешний вид",
+      "language": "Язык",
+      "user": "Пользователь",
+      "files": "Файлы",
+      "open": "Открыть настройки"
+    },
+    "appearance": {
+      "themeMode": {
+        "label": "Режим темы",
+        "light": "Светлая",
+        "dark": "Тёмная",
+        "system": "Системная"
+      },
+      "theme": "Тема"
+    },
+    "files": {
+      "defaultLocation": "Где сейчас хранятся ваши данные",
+      "doubleTapToCopy": "Нажмите дважды, чтобы скопировать путь",
+      "restoreLocation": "Восстановить путь AppFlowy по умолчанию",
+      "customizeLocation": "Открыть другую папку",
+      "restartApp": "Пожалуйста, перезапустите приложение, чтобы изменения вступили в силу.",
+      "exportDatabase": "Экспорт базы данных",
+      "selectFiles": "Выбрать файлы, которые необходимо экспортировать",
+      "createNewFolder": "Создать новую папку",
+      "createNewFolderDesc": "Указать, где хранить свои данные ...",
+      "open": "Открыть",
+      "openFolder": "Открыть существующую папку",
+      "openFolderDesc": "Чтение и запись в существующую папку AppFlowy ...",
+      "folderHintText": "имя папки",
+      "location": "Создание новой папки",
+      "locationDesc": "Выбрать имя папки данных AppFlowy",
+      "browser": "Обзор",
+      "create": "Создать",
+      "folderPath": "Путь к вашей папке",
+      "locationCannotBeEmpty": "Путь не может быть пустым",
+      "pathCopiedSnackbar": "File storage path copied to clipboard!"
+    },
+    "user": {
+      "name": "Имя",
+      "icon": "Иконка",
+      "selectAnIcon": "Выбрать иконку",
+      "pleaseInputYourOpenAIKey": "Введите токен OpenAI"
+    }
+  },
+  "grid": {
+    "settings": {
+      "filter": "Фильтр",
+      "sort": "Сортировать",
+      "sortBy": "Сортировать по",
+      "Properties": "Свойства",
+      "group": "Группировать",
+      "addFilter": "Добавить фильтр",
+      "deleteFilter": "Удалить фильтр",
+      "filterBy": "Фильтровать по...",
+      "typeAValue": "Введите значение..."
+    },
+    "textFilter": {
+      "contains": "Содержит",
+      "doesNotContain": "Не содержит",
+      "endsWith": "Заканчивается на",
+      "startWith": "Начинается с",
+      "is": "Является",
+      "isNot": "Не является",
+      "isEmpty": "Пусто",
+      "isNotEmpty": "Не пусто",
+      "choicechipPrefix": {
+        "isNot": "Не является",
+        "startWith": "Начинается с",
+        "endWith": "Заканчивается на",
+        "isEmpty": "пусто",
+        "isNotEmpty": "не пусто"
+      }
+    },
+    "checkboxFilter": {
+      "isChecked": "Отмечено",
+      "isUnchecked": "Не отмечено",
+      "choicechipPrefix": {
+        "is": "является"
+      }
+    },
+    "checklistFilter": {
+      "isComplete": "завершено",
+      "isIncomplted": "не завершено"
+    },
+    "singleSelectOptionFilter": {
+      "is": "Является",
+      "isNot": "Не является",
+      "isEmpty": "Пусто",
+      "isNotEmpty": "Не пусто"
+    },
+    "multiSelectOptionFilter": {
+      "contains": "Содержит",
+      "doesNotContain": "Не содержит",
+      "isEmpty": "Пусто",
+      "isNotEmpty": "Не пусто"
+    },
+    "field": {
+      "hide": "Скрыть",
+      "insertLeft": "Вставить слева",
+      "insertRight": "Вставить справа",
+      "duplicate": "Дублировать",
+      "delete": "Удалить",
+      "textFieldName": "Текст",
+      "checkboxFieldName": "Чекбокс",
+      "dateFieldName": "Дата",
+      "numberFieldName": "Число",
+      "singleSelectFieldName": "Выбор",
+      "multiSelectFieldName": "Выбор нескольких",
+      "urlFieldName": "URL",
+      "checklistFieldName": "Контрольный список",
+      "numberFormat": "Формат числа",
+      "dateFormat": "Формат даты",
+      "includeTime": "Время",
+      "dateFormatFriendly": "День Месяц, Год",
+      "dateFormatISO": "Год-Месяц-День",
+      "dateFormatLocal": "Месяц/День/Год",
+      "dateFormatUS": "Год/Месяц/День",
+      "dateFormatDayMonthYear": "День/Mесяц/Год",
+      "timeFormat": "Формат времени",
+      "invalidTimeFormat": "Неверный формат",
+      "timeFormatTwelveHour": "12 часов",
+      "timeFormatTwentyFourHour": "24 часа",
+      "addSelectOption": "Добавить вариант",
+      "optionTitle": "Варианты",
+      "addOption": "Добавить",
+      "editProperty": "Редактировать свойство",
+      "newProperty": "Добавить колонку",
+      "deleteFieldPromptMessage": "Вы уверены? Свойство будет удалено"
+    },
+    "sort": {
+      "ascending": "По возрастанию",
+      "descending": "По убыванию",
+      "deleteSort": "Удалить сортировку",
+      "addSort": "Добавить сортировку"
+    },
+    "row": {
+      "duplicate": "Дублировать",
+      "delete": "Удалить",
+      "textPlaceholder": "Пусто",
+      "copyProperty": "Свойство скопировано",
+      "count": "Количество",
+      "newRow": "Новая строка"
+    },
+    "selectOption": {
+      "create": "Создать",
+      "purpleColor": "Фиолетовый",
+      "pinkColor": "Розовый",
+      "lightPinkColor": "Светло-розовый",
+      "orangeColor": "Оранжевый",
+      "yellowColor": "Желтый",
+      "limeColor": "Ярко-зелёный",
+      "greenColor": "Зелёный",
+      "aquaColor": "Бирюзовый",
+      "blueColor": "Синий",
+      "deleteTag": "Удалить вариант",
+      "colorPanelTitle": "Цвета",
+      "panelTitle": "Выберите или создайте вариант",
+      "searchOption": "Поиск"
+    },
+    "checklist": {
+      "panelTitle": "Добавить элемент"
+    },
+    "menuName": "Сетка",
+    "referencedGridPrefix": "Просмотр"
+  },
+  "document": {
+    "menuName": "Документ",
+    "date": {
+      "timeHintTextInTwelveHour": "01:00 PM",
+      "timeHintTextInTwentyFourHour": "13:00"
+    },
+    "slashMenu": {
+      "board": {
+        "selectABoardToLinkTo": "Выбрать доску для связи с",
+        "createANewBoard": "Создать доску"
+      },
+      "grid": {
+        "selectAGridToLinkTo": "Выберите сетку для связи с",
+        "createANewGrid": "Создать сетку"
+      }
+    },
+    "plugins": {
+      "referencedBoard": "Связанные доски",
+      "referencedGrid": "Связанные сетки",
+      "autoGeneratorMenuItemName": "Генератор OpenAI",
+      "autoGeneratorTitleName": "OpenAI: попросить ИИ написать что угодно...",
+      "autoGeneratorLearnMore": "Узнать больше",
+      "autoGeneratorGenerate": "Генерировать",
+      "autoGeneratorHintText": "Спросить OpenAI ...",
+      "autoGeneratorCantGetOpenAIKey": "Не могу получить токен OpenAI",
+      "smartEdit": "ИИ ассистенты",
+      "openAI": "OpenAI",
+      "smartEditFixSpelling": "Исправить правописание",
+      "warning": "⚠️ Ответы ИИ могут быть неправильными или неточными.",
+      "smartEditSummarize": "Выделить суть",
+      "smartEditCouldNotFetchResult": "Не могу получить ответ от OpenAI",
+      "smartEditCouldNotFetchKey": "Не могу получить токен OpenAI",
+      "smartEditDisabled": "Подключить OpenAI",
+      "discardResponse": "Хотите убрать ответы ИИ?",
+      "cover": {
+        "changeCover": "Сменить обложку",
+        "colors": "Цвета",
+        "images": "Изображения",
+        "clearAll": "Очистить",
+        "abstract": "Абстракные",
+        "addCover": "Добавить обложку",
+        "addLocalImage": "Добавить изображение с диска",
+        "invalidImageUrl": "Некорректная ссылка на изображение",
+        "failedToAddImageToGallery": "Ошибка добавления изображения в галерею",
+        "enterImageUrl": "Введите ссылку на изображение",
+        "add": "Добавить",
+        "back": "Назад",
+        "saveToGallery": "Сохранить в галерею",
+        "removeIcon": "Удалить иконку",
+        "pasteImageUrl": "Вставить ссылку на изображение",
+        "or": "ИЛИ",
+        "pickFromFiles": "Выбрать с диска",
+        "couldNotFetchImage": "Не удалось получить изображение",
+        "imageSavingFailed": "Не удалось сохранить изображение",
+        "addIcon": "Добавить иконку",
+        "coverRemoveAlert": "Изображение будет удалено с обложки",
+        "alertDialogConfirmation": "Вы хотите продолжить?"
+      }
+    }
+  },
+  "board": {
+    "column": {
+      "create_new_card": "Создать"
+    },
+    "menuName": "Доска",
+    "referencedBoardPrefix": "Просмотр"
+  },
+  "calendar": {
+    "menuName": "Календарь",
+    "defaultNewCalendarTitle": "Безымянный",
+    "navigation": {
+      "today": "Сегодня",
+      "jumpToday": "Перейти к сегодняшнему дню",
+      "previousMonth": "Предыдущий месяц",
+      "nextMonth": "Следующий месяц"
+    },
+    "settings": {
+      "showWeekNumbers": "Показывать номера недель",
+      "showWeekends": "Показывать выходные",
+      "firstDayOfWeek": "Первый день недели",
+      "layoutDateField": "Вид календаря"
+    }
+  }
+}

+ 1 - 1
frontend/appflowy_flutter/assets/translations/sv.json

@@ -195,7 +195,7 @@
       "optionTitle": "Alternativ",
       "addOption": "Lägg till alternativ",
       "editProperty": "Redigera egenskap",
-      "newColumn": "Ny kolumn",
+      "newProperty": "Ny kolumn",
       "deleteFieldPromptMessage": "Är du säker? Denna egenskap kommer att raderas."
     },
     "row": {

+ 1 - 1
frontend/appflowy_flutter/assets/translations/zh-CN.json

@@ -195,7 +195,7 @@
       "optionTitle": "标签",
       "addOption": "添加标签",
       "editProperty": "编辑列属性",
-      "newColumn": "增加一列",
+      "newProperty": "增加一列",
       "deleteFieldPromptMessage": "确定要删除这个属性吗? "
     },
     "row": {

+ 1 - 1
frontend/appflowy_flutter/assets/translations/zh-TW.json

@@ -290,7 +290,7 @@
       "optionTitle": "選項",
       "addOption": "新增選項",
       "editProperty": "編輯內容",
-      "newColumn": "新欄位",
+      "newProperty": "新欄位",
       "deleteFieldPromptMessage": "你確定嗎?這個內容將被刪除"
     },
     "sort": {

+ 3 - 1
frontend/appflowy_flutter/integration_test/board_test.dart

@@ -35,7 +35,9 @@ void main() {
     setUpAll(() async => await service.setUpAll());
     setUp(() async => await service.setUp());
 
-    testWidgets('integration test unzips the proper workspace and loads it correctly.', (tester) async {
+    testWidgets(
+        'integration test unzips the proper workspace and loads it correctly.',
+        (tester) async {
       await tester.initializeAppFlowy();
       expect(find.byType(AppFlowyBoard), findsOneWidget);
     });

+ 33 - 22
frontend/appflowy_flutter/integration_test/empty_document_test.dart

@@ -31,7 +31,8 @@ void main() {
     setUpAll(() async => await service.setUpAll());
     setUp(() async => await service.setUp());
 
-    testWidgets('/board shortcut creates a new board and view of the board', (tester) async {
+    testWidgets('/board shortcut creates a new board and view of the board',
+        (tester) async {
       await tester.initializeAppFlowy();
 
       // Needs tab to obtain focus for the app flowy editor.
@@ -44,24 +45,30 @@ void main() {
       // does not contain any EditableText widgets.
       // to interact with the app during an integration test,
       // simulate physical keyboard events.
-      await FlowyTestKeyboard.simulateKeyDownEvent([
-        LogicalKeyboardKey.slash,
-        LogicalKeyboardKey.keyB,
-        LogicalKeyboardKey.keyO,
-        LogicalKeyboardKey.keyA,
-        LogicalKeyboardKey.keyR,
-        LogicalKeyboardKey.keyD,
-        LogicalKeyboardKey.arrowDown,
-      ], tester: tester);
+      await FlowyTestKeyboard.simulateKeyDownEvent(
+        [
+          LogicalKeyboardKey.slash,
+          LogicalKeyboardKey.keyB,
+          LogicalKeyboardKey.keyO,
+          LogicalKeyboardKey.keyA,
+          LogicalKeyboardKey.keyR,
+          LogicalKeyboardKey.keyD,
+          LogicalKeyboardKey.arrowDown,
+        ],
+        tester: tester,
+      );
 
       // Checks whether the options in the selection menu
       // for /board exist.
       expect(find.byType(SelectionMenuItemWidget), findsAtLeastNWidgets(2));
 
       // Finalizes the slash command that creates the board.
-      await FlowyTestKeyboard.simulateKeyDownEvent([
-        LogicalKeyboardKey.enter,
-      ], tester: tester);
+      await FlowyTestKeyboard.simulateKeyDownEvent(
+        [
+          LogicalKeyboardKey.enter,
+        ],
+        tester: tester,
+      );
 
       // Checks whether new board is referenced and properly on the page.
       expect(find.byType(BuiltInPageWidget), findsOneWidget);
@@ -75,7 +82,8 @@ void main() {
       expect(find.text(viewOfBoardLabel), findsNWidgets(2));
     });
 
-    testWidgets('/grid shortcut creates a new grid and view of the grid', (tester) async {
+    testWidgets('/grid shortcut creates a new grid and view of the grid',
+        (tester) async {
       await tester.initializeAppFlowy();
 
       // Needs tab to obtain focus for the app flowy editor.
@@ -88,14 +96,17 @@ void main() {
       // does not contain any EditableText widgets.
       // to interact with the app during an integration test,
       // simulate physical keyboard events.
-      await FlowyTestKeyboard.simulateKeyDownEvent([
-        LogicalKeyboardKey.slash,
-        LogicalKeyboardKey.keyG,
-        LogicalKeyboardKey.keyR,
-        LogicalKeyboardKey.keyI,
-        LogicalKeyboardKey.keyD,
-        LogicalKeyboardKey.arrowDown,
-      ], tester: tester);
+      await FlowyTestKeyboard.simulateKeyDownEvent(
+        [
+          LogicalKeyboardKey.slash,
+          LogicalKeyboardKey.keyG,
+          LogicalKeyboardKey.keyR,
+          LogicalKeyboardKey.keyI,
+          LogicalKeyboardKey.keyD,
+          LogicalKeyboardKey.arrowDown,
+        ],
+        tester: tester,
+      );
 
       // Checks whether the options in the selection menu
       // for /grid exist.

+ 3 - 1
frontend/appflowy_flutter/integration_test/util/data.dart

@@ -61,6 +61,8 @@ class TestWorkspaceService {
         InputFileStream(await workspace.zip.then((value) => value.path));
     final archive = ZipDecoder().decodeBuffer(inputStream);
     extractArchiveToDisk(
-        archive, await TestWorkspace._parent.then((value) => value.path));
+      archive,
+      await TestWorkspace._parent.then((value) => value.path),
+    );
   }
 }

+ 4 - 2
frontend/appflowy_flutter/integration_test/util/keyboard.dart

@@ -2,8 +2,10 @@ import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart' as flutter_test;
 
 class FlowyTestKeyboard {
-  static Future<void> simulateKeyDownEvent(List<LogicalKeyboardKey> keys,
-      {required flutter_test.WidgetTester tester}) async {
+  static Future<void> simulateKeyDownEvent(
+    List<LogicalKeyboardKey> keys, {
+    required flutter_test.WidgetTester tester,
+  }) async {
     for (final LogicalKeyboardKey key in keys) {
       await flutter_test.simulateKeyDownEvent(key);
       await tester.pumpAndSettle();

+ 4 - 3
frontend/appflowy_flutter/lib/core/folder_notification.dart

@@ -16,9 +16,10 @@ typedef FolderNotificationCallback = void Function(
 
 class FolderNotificationParser
     extends NotificationParser<FolderNotification, FlowyError> {
-  FolderNotificationParser(
-      {String? id, required FolderNotificationCallback callback})
-      : super(
+  FolderNotificationParser({
+    String? id,
+    required FolderNotificationCallback callback,
+  }) : super(
           id: id,
           callback: callback,
           tyParser: (ty) => FolderNotification.valueOf(ty),

+ 7 - 4
frontend/appflowy_flutter/lib/core/grid_notification.dart

@@ -16,9 +16,10 @@ typedef DatabaseNotificationCallback = void Function(
 
 class DatabaseNotificationParser
     extends NotificationParser<DatabaseNotification, FlowyError> {
-  DatabaseNotificationParser(
-      {String? id, required DatabaseNotificationCallback callback})
-      : super(
+  DatabaseNotificationParser({
+    String? id,
+    required DatabaseNotificationCallback callback,
+  }) : super(
           id: id,
           callback: callback,
           tyParser: (ty) => DatabaseNotification.valueOf(ty),
@@ -27,7 +28,9 @@ class DatabaseNotificationParser
 }
 
 typedef DatabaseNotificationHandler = Function(
-    DatabaseNotification ty, Either<Uint8List, FlowyError> result);
+  DatabaseNotification ty,
+  Either<Uint8List, FlowyError> result,
+);
 
 class DatabaseNotificationListener {
   StreamSubscription<SubscribeObject>? _subscription;

+ 6 - 5
frontend/appflowy_flutter/lib/core/notification_helper.dart

@@ -9,11 +9,12 @@ class NotificationParser<T, E> {
   T? Function(int) tyParser;
   E Function(Uint8List) errorParser;
 
-  NotificationParser(
-      {this.id,
-      required this.callback,
-      required this.errorParser,
-      required this.tyParser});
+  NotificationParser({
+    this.id,
+    required this.callback,
+    required this.errorParser,
+    required this.tyParser,
+  });
   void parse(SubscribeObject subject) {
     if (id != null) {
       if (subject.id != id) {

+ 7 - 4
frontend/appflowy_flutter/lib/core/user_notification.dart

@@ -16,9 +16,10 @@ typedef UserNotificationCallback = void Function(
 
 class UserNotificationParser
     extends NotificationParser<UserNotification, FlowyError> {
-  UserNotificationParser(
-      {required String id, required UserNotificationCallback callback})
-      : super(
+  UserNotificationParser({
+    required String id,
+    required UserNotificationCallback callback,
+  }) : super(
           id: id,
           callback: callback,
           tyParser: (ty) => UserNotification.valueOf(ty),
@@ -27,7 +28,9 @@ class UserNotificationParser
 }
 
 typedef UserNotificationHandler = Function(
-    UserNotification ty, Either<Uint8List, FlowyError> result);
+  UserNotification ty,
+  Either<Uint8List, FlowyError> result,
+);
 
 class UserNotificationListener {
   StreamSubscription<SubscribeObject>? _subscription;

+ 29 - 21
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller.dart

@@ -73,28 +73,35 @@ class CellController<T, D> extends Equatable {
     /// For example:
     ///  user input: 12
     ///  cell display: $12
-    _cellListener?.start(onCellChanged: (result) {
-      result.fold(
-        (_) {
-          _cellCache.remove(_cacheKey);
-          _loadData();
-        },
-        (err) => Log.error(err),
-      );
-    });
+    _cellListener?.start(
+      onCellChanged: (result) {
+        result.fold(
+          (_) {
+            _cellCache.remove(_cacheKey);
+            _loadData();
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
 
     /// 2.Listen on the field event and load the cell data if needed.
-    _fieldListener.start(onFieldChanged: (result) {
-      result.fold((fieldPB) {
-        /// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
-        /// For example:
-        ///   ¥12 -> $12
-        if (_cellDataLoader.reloadOnFieldChanged) {
-          _loadData();
-        }
-        _onCellFieldChanged?.call();
-      }, (err) => Log.error(err));
-    });
+    _fieldListener.start(
+      onFieldChanged: (result) {
+        result.fold(
+          (fieldPB) {
+            /// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
+            /// For example:
+            ///   ¥12 -> $12
+            if (_cellDataLoader.reloadOnFieldChanged) {
+              _loadData();
+            }
+            _onCellFieldChanged?.call();
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
   }
 
   /// Listen on the cell content or field changes
@@ -130,7 +137,8 @@ class CellController<T, D> extends Equatable {
   /// Return the TypeOptionPB that can be parsed into corresponding class using the [parser].
   /// [PD] is the type that the parser return.
   Future<Either<PD, FlowyError>> getTypeOption<PD, P extends TypeOptionParser>(
-      P parser) {
+    P parser,
+  ) {
     return _fieldBackendSvc
         .getFieldTypeOptionData(fieldType: fieldType)
         .then((result) {

+ 3 - 1
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_listener.dart

@@ -19,7 +19,9 @@ class CellListener {
   void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) {
     _updateCellNotifier?.addPublishListener(onCellChanged);
     _listener = DatabaseNotificationListener(
-        objectId: "$rowId:$fieldId", handler: _handler);
+      objectId: "$rowId:$fieldId",
+      handler: _handler,
+    );
   }
 
   void _handler(DatabaseNotification ty, Either<Uint8List, FlowyError> result) {

+ 62 - 39
frontend/appflowy_flutter/lib/plugins/database_view/application/database_controller.dart

@@ -187,8 +187,10 @@ class DatabaseController {
     );
   }
 
-  Future<Either<Unit, FlowyError>> moveGroup(
-      {required String fromGroupId, required String toGroupId}) {
+  Future<Either<Unit, FlowyError>> moveGroup({
+    required String fromGroupId,
+    required String toGroupId,
+  }) {
     return _databaseViewBackendSvc.moveGroup(
       fromGroupId: fromGroupId,
       toGroupId: toGroupId,
@@ -196,7 +198,8 @@ class DatabaseController {
   }
 
   Future<void> updateCalenderLayoutSetting(
-      CalendarLayoutSettingsPB layoutSetting) async {
+    CalendarLayoutSettingsPB layoutSetting,
+  ) async {
     await _databaseViewBackendSvc
         .updateLayoutSetting(calendarLayoutSetting: layoutSetting)
         .then((result) {
@@ -234,16 +237,20 @@ class DatabaseController {
   }
 
   void _listenOnRowsChanged() {
-    final callbacks =
-        DatabaseViewCallbacks(onRowsChanged: (rows, rowByRowId, reason) {
-      _databaseCallbacks?.onRowsChanged?.call(rows, rowByRowId, reason);
-    }, onRowsDeleted: (ids) {
-      _databaseCallbacks?.onRowsDeleted?.call(ids);
-    }, onRowsUpdated: (ids) {
-      _databaseCallbacks?.onRowsUpdated?.call(ids);
-    }, onRowsCreated: (ids) {
-      _databaseCallbacks?.onRowsCreated?.call(ids);
-    });
+    final callbacks = DatabaseViewCallbacks(
+      onRowsChanged: (rows, rowByRowId, reason) {
+        _databaseCallbacks?.onRowsChanged?.call(rows, rowByRowId, reason);
+      },
+      onRowsDeleted: (ids) {
+        _databaseCallbacks?.onRowsDeleted?.call(ids);
+      },
+      onRowsUpdated: (ids) {
+        _databaseCallbacks?.onRowsUpdated?.call(ids);
+      },
+      onRowsCreated: (ids) {
+        _databaseCallbacks?.onRowsCreated?.call(ids);
+      },
+    );
     _viewCache.addListener(callbacks);
   }
 
@@ -261,42 +268,58 @@ class DatabaseController {
   void _listenOnGroupChanged() {
     groupListener.start(
       onNumOfGroupsChanged: (result) {
-        result.fold((changeset) {
-          if (changeset.updateGroups.isNotEmpty) {
-            _groupCallbacks?.onUpdateGroup?.call(changeset.updateGroups);
-          }
-
-          if (changeset.deletedGroups.isNotEmpty) {
-            _groupCallbacks?.onDeleteGroup?.call(changeset.deletedGroups);
-          }
-
-          for (final insertedGroup in changeset.insertedGroups) {
-            _groupCallbacks?.onInsertGroup?.call(insertedGroup);
-          }
-        }, (r) => Log.error(r));
+        result.fold(
+          (changeset) {
+            if (changeset.updateGroups.isNotEmpty) {
+              _groupCallbacks?.onUpdateGroup?.call(changeset.updateGroups);
+            }
+
+            if (changeset.deletedGroups.isNotEmpty) {
+              _groupCallbacks?.onDeleteGroup?.call(changeset.deletedGroups);
+            }
+
+            for (final insertedGroup in changeset.insertedGroups) {
+              _groupCallbacks?.onInsertGroup?.call(insertedGroup);
+            }
+          },
+          (r) => Log.error(r),
+        );
       },
       onGroupByNewField: (result) {
-        result.fold((groups) {
-          _groupCallbacks?.onGroupByField?.call(groups);
-        }, (r) => Log.error(r));
+        result.fold(
+          (groups) {
+            _groupCallbacks?.onGroupByField?.call(groups);
+          },
+          (r) => Log.error(r),
+        );
       },
     );
   }
 
   void _listenOnLayoutChanged() {
-    layoutListener.start(onLayoutChanged: (result) {
-      result.fold((l) {
-        _layoutCallbacks?.onLayoutChanged(l);
-      }, (r) => Log.error(r));
-    });
+    layoutListener.start(
+      onLayoutChanged: (result) {
+        result.fold(
+          (l) {
+            _layoutCallbacks?.onLayoutChanged(l);
+          },
+          (r) => Log.error(r),
+        );
+      },
+    );
   }
 
   void _listenOnCalendarLayoutChanged() {
-    calendarLayoutListener.start(onCalendarLayoutChanged: (result) {
-      result.fold((l) {
-        _calendarLayoutCallbacks?.onCalendarLayoutChanged(l);
-      }, (r) => Log.error(r));
-    });
+    calendarLayoutListener.start(
+      onCalendarLayoutChanged: (result) {
+        result.fold(
+          (l) {
+            _calendarLayoutCallbacks?.onCalendarLayoutChanged(l);
+          },
+          (r) => Log.error(r),
+        );
+      },
+    );
   }
 }
 

+ 8 - 5
frontend/appflowy_flutter/lib/plugins/database_view/application/database_view_service.dart

@@ -73,8 +73,9 @@ class DatabaseViewBackendService {
     return DatabaseEventMoveGroup(payload).send();
   }
 
-  Future<Either<List<FieldPB>, FlowyError>> getFields(
-      {List<FieldIdPB>? fieldIds}) {
+  Future<Either<List<FieldPB>, FlowyError>> getFields({
+    List<FieldIdPB>? fieldIds,
+  }) {
     var payload = GetFieldPayloadPB.create()..viewId = viewId;
 
     if (fieldIds != null) {
@@ -86,15 +87,17 @@ class DatabaseViewBackendService {
   }
 
   Future<Either<LayoutSettingPB, FlowyError>> getLayoutSetting(
-      DatabaseLayoutPB layoutType) {
+    DatabaseLayoutPB layoutType,
+  ) {
     final payload = DatabaseLayoutIdPB.create()
       ..viewId = viewId
       ..layout = layoutType;
     return DatabaseEventGetLayoutSetting(payload).send();
   }
 
-  Future<Either<Unit, FlowyError>> updateLayoutSetting(
-      {CalendarLayoutSettingsPB? calendarLayoutSetting}) {
+  Future<Either<Unit, FlowyError>> updateLayoutSetting({
+    CalendarLayoutSettingsPB? calendarLayoutSetting,
+  }) {
     final layoutSetting = LayoutSettingPB.create();
     if (calendarLayoutSetting != null) {
       layoutSetting.calendar = calendarLayoutSetting;

+ 14 - 10
frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_cell_bloc.dart

@@ -17,7 +17,9 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
     required FieldCellContext cellContext,
   })  : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
         _fieldBackendSvc = FieldBackendService(
-            viewId: cellContext.viewId, fieldId: cellContext.field.id),
+          viewId: cellContext.viewId,
+          fieldId: cellContext.field.id,
+        ),
         super(FieldCellState.initial(cellContext)) {
     on<FieldCellEvent>(
       (event, emit) async {
@@ -49,15 +51,17 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
   }
 
   void _startListening() {
-    _fieldListener.start(onFieldChanged: (result) {
-      if (isClosed) {
-        return;
-      }
-      result.fold(
-        (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
-        (err) => Log.error(err),
-      );
-    });
+    _fieldListener.start(
+      onFieldChanged: (result) {
+        if (isClosed) {
+          return;
+        }
+        result.fold(
+          (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
+          (err) => Log.error(err),
+        );
+      },
+    );
   }
 }
 

+ 59 - 51
frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_controller.dart

@@ -255,24 +255,26 @@ class FieldController {
       }
     }
 
-    _filtersListener.start(onFilterChanged: (result) {
-      result.fold(
-        (FilterChangesetNotificationPB changeset) {
-          final List<FilterInfo> filters = filterInfos;
-          // Deletes the filters
-          deleteFilterFromChangeset(filters, changeset);
-
-          // Inserts the new filter if it's not exist
-          insertFilterFromChangeset(filters, changeset);
-
-          updateFilterFromChangeset(filters, changeset);
-
-          _updateFieldInfos();
-          _filterNotifier?.filters = filters;
-        },
-        (err) => Log.error(err),
-      );
-    });
+    _filtersListener.start(
+      onFilterChanged: (result) {
+        result.fold(
+          (FilterChangesetNotificationPB changeset) {
+            final List<FilterInfo> filters = filterInfos;
+            // Deletes the filters
+            deleteFilterFromChangeset(filters, changeset);
+
+            // Inserts the new filter if it's not exist
+            insertFilterFromChangeset(filters, changeset);
+
+            updateFilterFromChangeset(filters, changeset);
+
+            _updateFieldInfos();
+            _filterNotifier?.filters = filters;
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
   }
 
   void _listenOnSortChanged() {
@@ -347,48 +349,54 @@ class FieldController {
       }
     }
 
-    _sortsListener.start(onSortChanged: (result) {
-      result.fold(
-        (SortChangesetNotificationPB changeset) {
-          final List<SortInfo> newSortInfos = sortInfos;
-          deleteSortFromChangeset(newSortInfos, changeset);
-          insertSortFromChangeset(newSortInfos, changeset);
-          updateSortFromChangeset(newSortInfos, changeset);
+    _sortsListener.start(
+      onSortChanged: (result) {
+        result.fold(
+          (SortChangesetNotificationPB changeset) {
+            final List<SortInfo> newSortInfos = sortInfos;
+            deleteSortFromChangeset(newSortInfos, changeset);
+            insertSortFromChangeset(newSortInfos, changeset);
+            updateSortFromChangeset(newSortInfos, changeset);
 
-          _updateFieldInfos();
-          _sortNotifier?.sorts = newSortInfos;
-        },
-        (err) => Log.error(err),
-      );
-    });
+            _updateFieldInfos();
+            _sortNotifier?.sorts = newSortInfos;
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
   }
 
   void _listenOnSettingChanges() {
     //Listen on setting changes
-    _settingListener.start(onSettingUpdated: (result) {
-      result.fold(
-        (setting) => _updateSetting(setting),
-        (r) => Log.error(r),
-      );
-    });
+    _settingListener.start(
+      onSettingUpdated: (result) {
+        result.fold(
+          (setting) => _updateSetting(setting),
+          (r) => Log.error(r),
+        );
+      },
+    );
   }
 
   void _listenOnFieldChanges() {
     //Listen on field's changes
-    _fieldListener.start(onFieldsChanged: (result) {
-      result.fold(
-        (changeset) {
-          _deleteFields(changeset.deletedFields);
-          _insertFields(changeset.insertedFields);
-
-          final updatedFields = _updateFields(changeset.updatedFields);
-          for (final listener in _updatedFieldCallbacks.values) {
-            listener(updatedFields);
-          }
-        },
-        (err) => Log.error(err),
-      );
-    });
+    _fieldListener.start(
+      onFieldsChanged: (result) {
+        result.fold(
+          (changeset) {
+            _deleteFields(changeset.deletedFields);
+            _insertFields(changeset.insertedFields);
+
+            final updatedFields = _updateFields(changeset.updatedFields);
+            for (final listener in _updatedFieldCallbacks.values) {
+              listener(updatedFields);
+            }
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
   }
 
   void _updateSetting(DatabaseViewSettingPB setting) {

+ 7 - 5
frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_editor_bloc.dart

@@ -36,11 +36,13 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
             }
           },
           didReceiveFieldChanged: (FieldPB field) {
-            emit(state.copyWith(
-              field: Some(field),
-              name: field.name,
-              canDelete: field.isPrimary,
-            ));
+            emit(
+              state.copyWith(
+                field: Some(field),
+                name: field.name,
+                canDelete: field.isPrimary,
+              ),
+            );
           },
           deleteField: () {
             state.field.fold(

+ 6 - 4
frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_listener.dart

@@ -17,8 +17,9 @@ class SingleFieldListener {
 
   SingleFieldListener({required this.fieldId});
 
-  void start(
-      {required void Function(UpdateFieldNotifiedValue) onFieldChanged}) {
+  void start({
+    required void Function(UpdateFieldNotifiedValue) onFieldChanged,
+  }) {
     _updateFieldNotifier?.addPublishListener(onFieldChanged);
     _listener = DatabaseNotificationListener(
       objectId: fieldId,
@@ -60,8 +61,9 @@ class FieldsListener {
   DatabaseNotificationListener? _listener;
   FieldsListener({required this.viewId});
 
-  void start(
-      {required void Function(UpdateFieldsNotifiedValue) onFieldsChanged}) {
+  void start({
+    required void Function(UpdateFieldsNotifiedValue) onFieldsChanged,
+  }) {
     updateFieldsNotifier?.addPublishListener(onFieldsChanged);
     _listener = DatabaseNotificationListener(
       objectId: viewId,

+ 15 - 6
frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/date_bloc.dart

@@ -15,16 +15,25 @@ class DateTypeOptionBloc
       (event, emit) async {
         event.map(
           didSelectDateFormat: (_DidSelectDateFormat value) {
-            emit(state.copyWith(
-                typeOption: _updateTypeOption(dateFormat: value.format)));
+            emit(
+              state.copyWith(
+                typeOption: _updateTypeOption(dateFormat: value.format),
+              ),
+            );
           },
           didSelectTimeFormat: (_DidSelectTimeFormat value) {
-            emit(state.copyWith(
-                typeOption: _updateTypeOption(timeFormat: value.format)));
+            emit(
+              state.copyWith(
+                typeOption: _updateTypeOption(timeFormat: value.format),
+              ),
+            );
           },
           includeTime: (_IncludeTime value) {
-            emit(state.copyWith(
-                typeOption: _updateTypeOption(includeTime: value.includeTime)));
+            emit(
+              state.copyWith(
+                typeOption: _updateTypeOption(includeTime: value.includeTime),
+              ),
+            );
           },
         );
       },

+ 14 - 10
frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/number_format_bloc.dart

@@ -7,16 +7,20 @@ class NumberFormatBloc extends Bloc<NumberFormatEvent, NumberFormatState> {
   NumberFormatBloc() : super(NumberFormatState.initial()) {
     on<NumberFormatEvent>(
       (event, emit) async {
-        event.map(setFilter: (_SetFilter value) {
-          final List<NumberFormat> formats = List.from(NumberFormat.values);
-          if (value.filter.isNotEmpty) {
-            formats.retainWhere((element) => element
-                .title()
-                .toLowerCase()
-                .contains(value.filter.toLowerCase()));
-          }
-          emit(state.copyWith(formats: formats, filter: value.filter));
-        });
+        event.map(
+          setFilter: (_SetFilter value) {
+            final List<NumberFormat> formats = List.from(NumberFormat.values);
+            if (value.filter.isNotEmpty) {
+              formats.retainWhere(
+                (element) => element
+                    .title()
+                    .toLowerCase()
+                    .contains(value.filter.toLowerCase()),
+              );
+            }
+            emit(state.copyWith(formats: formats, filter: value.filter));
+          },
+        );
       },
     );
   }

+ 4 - 2
frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/select_option_type_option_bloc.dart

@@ -59,9 +59,11 @@ class SelectOptionTypeOptionEvent with _$SelectOptionTypeOptionEvent {
   const factory SelectOptionTypeOptionEvent.endAddingOption() =
       _EndAddingOption;
   const factory SelectOptionTypeOptionEvent.updateOption(
-      SelectOptionPB option) = _UpdateOption;
+    SelectOptionPB option,
+  ) = _UpdateOption;
   const factory SelectOptionTypeOptionEvent.deleteOption(
-      SelectOptionPB option) = _DeleteOption;
+    SelectOptionPB option,
+  ) = _DeleteOption;
 }
 
 @freezed

+ 3 - 1
frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/type_option_context.dart

@@ -158,7 +158,9 @@ abstract class IFieldTypeOptionLoader {
   Future<Either<TypeOptionPB, FlowyError>> load();
 
   Future<Either<Unit, FlowyError>> switchToField(
-      String fieldId, FieldType fieldType) {
+    String fieldId,
+    FieldType fieldType,
+  ) {
     final payload = UpdateFieldTypePayloadPB.create()
       ..viewId = viewId
       ..fieldId = fieldId

+ 2 - 1
frontend/appflowy_flutter/lib/plugins/database_view/application/filter/filter_listener.dart

@@ -107,7 +107,8 @@ class FilterListener {
       case DatabaseNotification.DidUpdateFilter:
         result.fold(
           (payload) => handleChangeset(
-              FilterChangesetNotificationPB.fromBuffer(payload)),
+            FilterChangesetNotificationPB.fromBuffer(payload),
+          ),
           (error) {},
         );
         break;

+ 2 - 1
frontend/appflowy_flutter/lib/plugins/database_view/application/filter/filter_service.dart

@@ -97,7 +97,8 @@ class FilterBackendService {
         filter.end = $fixnum.Int64(end);
       } else {
         throw Exception(
-            "Start and end should not be null if the timestamp is null");
+          "Start and end should not be null if the timestamp is null",
+        );
       }
     }
 

+ 3 - 2
frontend/appflowy_flutter/lib/plugins/database_view/application/layout/calendar_setting_listener.dart

@@ -15,8 +15,9 @@ class DatabaseCalendarLayoutListener {
   DatabaseNotificationListener? _listener;
   DatabaseCalendarLayoutListener(this.viewId);
 
-  void start(
-      {required void Function(NewLayoutFieldValue) onCalendarLayoutChanged}) {
+  void start({
+    required void Function(NewLayoutFieldValue) onCalendarLayoutChanged,
+  }) {
     _newLayoutFieldNotifier?.addPublishListener(onCalendarLayoutChanged);
     _listener = DatabaseNotificationListener(
       objectId: viewId,

+ 13 - 6
frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_cache.dart

@@ -102,11 +102,16 @@ class RowCache {
     final rowInfo = _rowList.get(reorderRow.rowId);
     if (rowInfo != null) {
       _rowList.moveRow(
-          reorderRow.rowId, reorderRow.oldIndex, reorderRow.newIndex);
-      _rowChangeReasonNotifier.receive(RowsChangedReason.reorderSingleRow(
-        reorderRow,
-        rowInfo,
-      ));
+        reorderRow.rowId,
+        reorderRow.oldIndex,
+        reorderRow.newIndex,
+      );
+      _rowChangeReasonNotifier.receive(
+        RowsChangedReason.reorderSingleRow(
+          reorderRow,
+          rowInfo,
+        ),
+      );
     }
   }
 
@@ -325,7 +330,9 @@ class RowsChangedReason with _$RowsChangedReason {
   const factory RowsChangedReason.initial() = InitialListState;
   const factory RowsChangedReason.reorderRows() = _ReorderRows;
   const factory RowsChangedReason.reorderSingleRow(
-      ReorderSingleRowPB reorderRow, RowInfo rowInfo) = _ReorderSingleRow;
+    ReorderSingleRowPB reorderRow,
+    RowInfo rowInfo,
+  ) = _ReorderSingleRow;
 }
 
 class InsertedIndex {

+ 6 - 4
frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_data_controller.dart

@@ -23,10 +23,12 @@ class RowController {
   }
 
   void addListener({OnRowChanged? onRowChanged}) {
-    _onRowChangedListeners.add(_rowCache.addListener(
-      rowId: rowId,
-      onCellUpdated: onRowChanged,
-    ));
+    _onRowChangedListeners.add(
+      _rowCache.addListener(
+        rowId: rowId,
+        onCellUpdated: onRowChanged,
+      ),
+    );
   }
 
   void dispose() {

+ 6 - 4
frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_list.dart

@@ -85,10 +85,12 @@ class RowList {
       insert(index, builder(insertRow.row));
 
       if (!isContains) {
-        insertIndexs.add(InsertedIndex(
-          index: index,
-          rowId: insertRow.row.id,
-        ));
+        insertIndexs.add(
+          InsertedIndex(
+            index: index,
+            rowId: insertRow.row.id,
+          ),
+        );
       }
     }
     return insertIndexs;

+ 5 - 2
frontend/appflowy_flutter/lib/plugins/database_view/application/setting/group_bloc.dart

@@ -67,7 +67,8 @@ class DatabaseGroupEvent with _$DatabaseGroupEvent {
     FieldType fieldType,
   ) = _DatabaseGroupEvent;
   const factory DatabaseGroupEvent.didReceiveFieldUpdate(
-      List<FieldInfo> fields) = _DidReceiveFieldUpdate;
+    List<FieldInfo> fields,
+  ) = _DidReceiveFieldUpdate;
 }
 
 @freezed
@@ -78,7 +79,9 @@ class DatabaseGroupState with _$DatabaseGroupState {
   }) = _DatabaseGroupState;
 
   factory DatabaseGroupState.initial(
-          String viewId, List<FieldInfo> fieldContexts) =>
+    String viewId,
+    List<FieldInfo> fieldContexts,
+  ) =>
       DatabaseGroupState(
         viewId: viewId,
         fieldContexts: fieldContexts,

+ 11 - 6
frontend/appflowy_flutter/lib/plugins/database_view/application/setting/property_bloc.dart

@@ -13,11 +13,13 @@ class DatabasePropertyBloc
   final FieldController _fieldController;
   Function(List<FieldInfo>)? _onFieldsFn;
 
-  DatabasePropertyBloc(
-      {required String viewId, required FieldController fieldController})
-      : _fieldController = fieldController,
+  DatabasePropertyBloc({
+    required String viewId,
+    required FieldController fieldController,
+  })  : _fieldController = fieldController,
         super(
-            DatabasePropertyState.initial(viewId, fieldController.fieldInfos)) {
+          DatabasePropertyState.initial(viewId, fieldController.fieldInfos),
+        ) {
     on<DatabasePropertyEvent>(
       (event, emit) async {
         await event.map(
@@ -68,9 +70,12 @@ class DatabasePropertyBloc
 class DatabasePropertyEvent with _$DatabasePropertyEvent {
   const factory DatabasePropertyEvent.initial() = _Initial;
   const factory DatabasePropertyEvent.setFieldVisibility(
-      String fieldId, bool visibility) = _SetFieldVisibility;
+    String fieldId,
+    bool visibility,
+  ) = _SetFieldVisibility;
   const factory DatabasePropertyEvent.didReceiveFieldUpdate(
-      List<FieldInfo> fields) = _DidReceiveFieldUpdate;
+    List<FieldInfo> fields,
+  ) = _DidReceiveFieldUpdate;
   const factory DatabasePropertyEvent.moveField(int fromIndex, int toIndex) =
       _MoveField;
 }

+ 7 - 4
frontend/appflowy_flutter/lib/plugins/database_view/application/setting/setting_bloc.dart

@@ -11,9 +11,11 @@ class DatabaseSettingBloc
       : super(DatabaseSettingState.initial()) {
     on<DatabaseSettingEvent>(
       (event, emit) async {
-        event.map(performAction: (_PerformAction value) {
-          emit(state.copyWith(selectedAction: Some(value.action)));
-        });
+        event.map(
+          performAction: (_PerformAction value) {
+            emit(state.copyWith(selectedAction: Some(value.action)));
+          },
+        );
       },
     );
   }
@@ -22,7 +24,8 @@ class DatabaseSettingBloc
 @freezed
 class DatabaseSettingEvent with _$DatabaseSettingEvent {
   const factory DatabaseSettingEvent.performAction(
-      DatabaseSettingAction action) = _PerformAction;
+    DatabaseSettingAction action,
+  ) = _PerformAction;
 }
 
 @freezed

+ 8 - 6
frontend/appflowy_flutter/lib/plugins/database_view/application/setting/setting_controller.dart

@@ -28,12 +28,14 @@ class SettingController {
     });
 
     // Listen on the setting changes
-    _listener.start(onSettingUpdated: (result) {
-      result.fold(
-        (newSetting) => updateSetting(newSetting),
-        (err) => _onError?.call(err),
-      );
-    });
+    _listener.start(
+      onSettingUpdated: (result) {
+        result.fold(
+          (newSetting) => updateSetting(newSetting),
+          (err) => _onError?.call(err),
+        );
+      },
+    );
   }
 
   void startListening({

+ 5 - 3
frontend/appflowy_flutter/lib/plugins/database_view/application/view/view_cache.dart

@@ -69,9 +69,11 @@ class DatabaseViewCache {
             }
 
             if (changeset.insertedRows.isNotEmpty) {
-              _callbacks?.onRowsCreated?.call(changeset.insertedRows
-                  .map((insertedRow) => insertedRow.row.id)
-                  .toList());
+              _callbacks?.onRowsCreated?.call(
+                changeset.insertedRows
+                    .map((insertedRow) => insertedRow.row.id)
+                    .toList(),
+              );
             }
           },
           (err) => Log.error(err),

+ 30 - 19
frontend/appflowy_flutter/lib/plugins/database_view/board/application/board_bloc.dart

@@ -105,23 +105,31 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
             );
           },
           didCreateRow: (group, row, int? index) {
-            emit(state.copyWith(
-              editingRow: Some(BoardEditingRow(
-                group: group,
-                row: row,
-                index: index,
-              )),
-            ));
+            emit(
+              state.copyWith(
+                editingRow: Some(
+                  BoardEditingRow(
+                    group: group,
+                    row: row,
+                    index: index,
+                  ),
+                ),
+              ),
+            );
             _groupItemStartEditing(group, row, true);
           },
           startEditingRow: (group, row) {
-            emit(state.copyWith(
-              editingRow: Some(BoardEditingRow(
-                group: group,
-                row: row,
-                index: null,
-              )),
-            ));
+            emit(
+              state.copyWith(
+                editingRow: Some(
+                  BoardEditingRow(
+                    group: group,
+                    row: row,
+                    index: null,
+                  ),
+                ),
+              ),
+            );
             _groupItemStartEditing(group, row, true);
           },
           endEditingRow: (rowId) {
@@ -175,10 +183,12 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
     groupControllers.clear();
     boardController.clear();
 
-    boardController.addGroups(groups
-        .where((group) => fieldController.getField(group.fieldId) != null)
-        .map((group) => initializeGroupData(group))
-        .toList());
+    boardController.addGroups(
+      groups
+          .where((group) => fieldController.getField(group.fieldId) != null)
+          .map((group) => initializeGroupData(group))
+          .toList(),
+    );
 
     for (final group in groups) {
       final controller = initializeGroupController(group);
@@ -334,7 +344,8 @@ class BoardState with _$BoardState {
 class GridLoadingState with _$GridLoadingState {
   const factory GridLoadingState.loading() = _Loading;
   const factory GridLoadingState.finish(
-      Either<Unit, FlowyError> successOrFail) = _Finish;
+    Either<Unit, FlowyError> successOrFail,
+  ) = _Finish;
 }
 
 class GridFieldEquatable extends Equatable {

+ 34 - 32
frontend/appflowy_flutter/lib/plugins/database_view/board/application/group_controller.dart

@@ -41,44 +41,46 @@ class GroupController {
   }
 
   void startListening() {
-    _listener.start(onGroupChanged: (result) {
-      result.fold(
-        (GroupRowsNotificationPB changeset) {
-          for (final deletedRow in changeset.deletedRows) {
-            group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
-            delegate.removeRow(group, deletedRow);
-          }
-
-          for (final insertedRow in changeset.insertedRows) {
-            final index = insertedRow.hasIndex() ? insertedRow.index : null;
-            if (insertedRow.hasIndex() &&
-                group.rows.length > insertedRow.index) {
-              group.rows.insert(insertedRow.index, insertedRow.row);
-            } else {
-              group.rows.add(insertedRow.row);
+    _listener.start(
+      onGroupChanged: (result) {
+        result.fold(
+          (GroupRowsNotificationPB changeset) {
+            for (final deletedRow in changeset.deletedRows) {
+              group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
+              delegate.removeRow(group, deletedRow);
             }
 
-            if (insertedRow.isNew) {
-              delegate.addNewRow(group, insertedRow.row, index);
-            } else {
-              delegate.insertRow(group, insertedRow.row, index);
+            for (final insertedRow in changeset.insertedRows) {
+              final index = insertedRow.hasIndex() ? insertedRow.index : null;
+              if (insertedRow.hasIndex() &&
+                  group.rows.length > insertedRow.index) {
+                group.rows.insert(insertedRow.index, insertedRow.row);
+              } else {
+                group.rows.add(insertedRow.row);
+              }
+
+              if (insertedRow.isNew) {
+                delegate.addNewRow(group, insertedRow.row, index);
+              } else {
+                delegate.insertRow(group, insertedRow.row, index);
+              }
             }
-          }
 
-          for (final updatedRow in changeset.updatedRows) {
-            final index = group.rows.indexWhere(
-              (rowPB) => rowPB.id == updatedRow.id,
-            );
+            for (final updatedRow in changeset.updatedRows) {
+              final index = group.rows.indexWhere(
+                (rowPB) => rowPB.id == updatedRow.id,
+              );
 
-            if (index != -1) {
-              group.rows[index] = updatedRow;
-              delegate.updateRow(group, updatedRow);
+              if (index != -1) {
+                group.rows[index] = updatedRow;
+                delegate.updateRow(group, updatedRow);
+              }
             }
-          }
-        },
-        (err) => Log.error(err),
-      );
-    });
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
   }
 
   Future<void> dispose() async {

+ 5 - 3
frontend/appflowy_flutter/lib/plugins/database_view/board/application/toolbar/board_setting_bloc.dart

@@ -10,9 +10,11 @@ class BoardSettingBloc extends Bloc<BoardSettingEvent, BoardSettingState> {
       : super(BoardSettingState.initial()) {
     on<BoardSettingEvent>(
       (event, emit) async {
-        event.when(performAction: (action) {
-          emit(state.copyWith(selectedAction: Some(action)));
-        });
+        event.when(
+          performAction: (action) {
+            emit(state.copyWith(selectedAction: Some(action)));
+          },
+        );
       },
     );
   }

+ 4 - 12
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/board_page.dart

@@ -80,8 +80,8 @@ class _BoardContentState extends State<BoardContent> {
   late AppFlowyBoardScrollController scrollManager;
   final cardConfiguration = CardConfiguration<String>();
 
-  final config = AppFlowyBoardConfig(
-    groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
+  final config = const AppFlowyBoardConfig(
+    groupBackgroundColor: Color(0xffF7F8FC),
   );
 
   @override
@@ -292,9 +292,10 @@ class _BoardContentState extends State<BoardContent> {
       color: Theme.of(context).dividerColor,
       width: 1.0,
     );
+    final isLightMode = Theme.of(context).brightness == Brightness.light;
     return BoxDecoration(
       color: Theme.of(context).colorScheme.surface,
-      border: Border.fromBorderSide(borderSide),
+      border: isLightMode ? Border.fromBorderSide(borderSide) : null,
       borderRadius: const BorderRadius.all(Radius.circular(6)),
     );
   }
@@ -349,15 +350,6 @@ class _ToolbarBlocAdaptor extends StatelessWidget {
   }
 }
 
-extension HexColor on Color {
-  static Color fromHex(String hexString) {
-    final buffer = StringBuffer();
-    if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
-    buffer.write(hexString.replaceFirst('#', ''));
-    return Color(int.parse(buffer.toString(), radix: 16));
-  }
-}
-
 Widget? _buildHeaderIcon(GroupData customData) {
   Widget? widget;
   switch (customData.fieldType) {

+ 6 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_setting.dart

@@ -7,6 +7,7 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar
 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/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
@@ -104,8 +105,12 @@ class _SettingItem extends StatelessWidget {
     return SizedBox(
       height: 30,
       child: FlowyButton(
+        hoverColor: AFThemeExtension.of(context).lightGreyHover,
         isSelected: isSelected,
-        text: FlowyText.medium(action.title()),
+        text: FlowyText.medium(
+          action.title(),
+          color: AFThemeExtension.of(context).textColor,
+        ),
         onTap: () {
           context
               .read<BoardSettingBloc>()

+ 1 - 0
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_toolbar.dart

@@ -71,6 +71,7 @@ class _SettingButtonState extends State<_SettingButton> {
       margin: EdgeInsets.zero,
       child: FlowyTextButton(
         LocaleKeys.settings_title.tr(),
+        fontColor: AFThemeExtension.of(context).textColor,
         fillColor: Colors.transparent,
         hoverColor: AFThemeExtension.of(context).lightGreyHover,
         padding: GridSize.typeOptionContentInsets,

+ 30 - 18
frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_bloc.dart

@@ -67,16 +67,20 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
             if (index != -1) {
               allEvents[index] = eventData;
             }
-            emit(state.copyWith(
-              allEvents: allEvents,
-              updateEvent: eventData,
-            ));
+            emit(
+              state.copyWith(
+                allEvents: allEvents,
+                updateEvent: eventData,
+              ),
+            );
           },
           didReceiveNewEvent: (CalendarEventData<CalendarDayEvent> event) {
-            emit(state.copyWith(
-              allEvents: [...state.allEvents, event],
-              newEvent: event,
-            ));
+            emit(
+              state.copyWith(
+                allEvents: [...state.allEvents, event],
+                newEvent: event,
+              ),
+            );
           },
           didDeleteEvents: (List<String> deletedRowIds) {
             var events = [...state.allEvents];
@@ -155,7 +159,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
   }
 
   Future<void> _updateCalendarLayoutSetting(
-      CalendarLayoutSettingsPB layoutSetting) async {
+    CalendarLayoutSettingsPB layoutSetting,
+  ) async {
     return _databaseController.updateCalenderLayoutSetting(layoutSetting);
   }
 
@@ -198,7 +203,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
   }
 
   CalendarEventData<CalendarDayEvent>? _calendarEventDataFromEventPB(
-      CalendarEventPB eventPB) {
+    CalendarEventPB eventPB,
+  ) {
     final fieldInfo = fieldInfoByFieldId[eventPB.titleFieldId];
     if (fieldInfo != null) {
       final cellId = CellIdentifier(
@@ -214,7 +220,6 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
 
       final date = DateTime.fromMillisecondsSinceEpoch(
         eventPB.timestamp.toInt() * 1000,
-        isUtc: true,
       );
       return CalendarEventData(
         title: eventPB.title,
@@ -267,7 +272,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
     );
 
     final onCalendarLayoutFieldChanged = CalendarLayoutCallbacks(
-        onCalendarLayoutChanged: _didReceiveNewLayoutField);
+      onCalendarLayoutChanged: _didReceiveNewLayoutField,
+    );
 
     _databaseController.addListener(
       onDatabaseChanged: onDatabaseChanged,
@@ -299,7 +305,8 @@ class CalendarEvent with _$CalendarEvent {
 
   // Called after loading the calendar layout setting from the backend
   const factory CalendarEvent.didReceiveCalendarSettings(
-      CalendarLayoutSettingsPB settings) = _ReceiveCalendarSettings;
+    CalendarLayoutSettingsPB settings,
+  ) = _ReceiveCalendarSettings;
 
   // Called after loading all the current evnets
   const factory CalendarEvent.didLoadAllEvents(Events events) =
@@ -307,11 +314,13 @@ class CalendarEvent with _$CalendarEvent {
 
   // Called when specific event was updated
   const factory CalendarEvent.didUpdateEvent(
-      CalendarEventData<CalendarDayEvent> event) = _DidUpdateEvent;
+    CalendarEventData<CalendarDayEvent> event,
+  ) = _DidUpdateEvent;
 
   // Called after creating a new event
   const factory CalendarEvent.didReceiveNewEvent(
-      CalendarEventData<CalendarDayEvent> event) = _DidReceiveNewEvent;
+    CalendarEventData<CalendarDayEvent> event,
+  ) = _DidReceiveNewEvent;
 
   // Called when deleting events
   const factory CalendarEvent.didDeleteEvents(List<String> rowIds) =
@@ -323,13 +332,15 @@ class CalendarEvent with _$CalendarEvent {
 
   // Called when updating the calendar's layout settings
   const factory CalendarEvent.updateCalendarLayoutSetting(
-      CalendarLayoutSettingsPB layoutSetting) = _UpdateCalendarLayoutSetting;
+    CalendarLayoutSettingsPB layoutSetting,
+  ) = _UpdateCalendarLayoutSetting;
 
   const factory CalendarEvent.didReceiveDatabaseUpdate(DatabasePB database) =
       _ReceiveDatabaseUpdate;
 
   const factory CalendarEvent.didReceiveNewLayoutField(
-      CalendarLayoutSettingsPB layoutSettings) = _DidReceiveNewLayoutField;
+    CalendarLayoutSettingsPB layoutSettings,
+  ) = _DidReceiveNewLayoutField;
 }
 
 @freezed
@@ -361,7 +372,8 @@ class CalendarState with _$CalendarState {
 class DatabaseLoadingState with _$DatabaseLoadingState {
   const factory DatabaseLoadingState.loading() = _Loading;
   const factory DatabaseLoadingState.finish(
-      Either<Unit, FlowyError> successOrFail) = _Finish;
+    Either<Unit, FlowyError> successOrFail,
+  ) = _Finish;
 }
 
 class CalendarEditingRow {

+ 6 - 4
frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_setting_bloc.dart

@@ -22,7 +22,6 @@ class CalendarSettingBloc
       );
     });
   }
-
 }
 
 @freezed
@@ -33,7 +32,8 @@ class CalendarSettingState with _$CalendarSettingState {
   }) = _CalendarSettingState;
 
   factory CalendarSettingState.initial(
-          CalendarLayoutSettingsPB? layoutSettings) =>
+    CalendarLayoutSettingsPB? layoutSettings,
+  ) =>
       CalendarSettingState(
         selectedAction: none(),
         layoutSetting: layoutSettings == null ? none() : Some(layoutSettings),
@@ -43,9 +43,11 @@ class CalendarSettingState with _$CalendarSettingState {
 @freezed
 class CalendarSettingEvent with _$CalendarSettingEvent {
   const factory CalendarSettingEvent.performAction(
-      CalendarSettingAction action) = _PerformAction;
+    CalendarSettingAction action,
+  ) = _PerformAction;
   const factory CalendarSettingEvent.updateLayoutSetting(
-      CalendarLayoutSettingsPB setting) = _UpdateLayoutSetting;
+    CalendarLayoutSettingsPB setting,
+  ) = _UpdateLayoutSetting;
 }
 
 enum CalendarSettingAction {

+ 39 - 25
frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_day.dart

@@ -62,30 +62,32 @@ class CalendarDayCard extends StatelessWidget {
           );
         }).toList();
 
-        final child = Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: Column(
-              mainAxisSize: MainAxisSize.min,
-              children: [
-                _Header(
-                  date: date,
-                  isInMonth: isInMonth,
-                  isToday: isToday,
-                  onCreate: () => onCreateEvent(date),
-                ),
-                VSpace(GridSize.typeOptionSeparatorHeight),
-                Flexible(
-                  child: ListView.separated(
-                    itemBuilder: (BuildContext context, int index) {
-                      return children[index];
-                    },
-                    itemCount: children.length,
-                    separatorBuilder: (BuildContext context, int index) =>
-                        VSpace(GridSize.typeOptionSeparatorHeight),
-                  ),
-                ),
-              ],
-            ));
+        final child = Column(
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            Padding(
+              padding: const EdgeInsets.all(8.0),
+              child: _Header(
+                date: date,
+                isInMonth: isInMonth,
+                isToday: isToday,
+                onCreate: () => onCreateEvent(date),
+              ),
+            ),
+            VSpace(GridSize.typeOptionSeparatorHeight),
+            Flexible(
+              child: ListView.separated(
+                itemBuilder: (BuildContext context, int index) {
+                  return children[index];
+                },
+                itemCount: children.length,
+                padding: const EdgeInsets.symmetric(horizontal: 8.0),
+                separatorBuilder: (BuildContext context, int index) =>
+                    VSpace(GridSize.typeOptionSeparatorHeight),
+              ),
+            ),
+          ],
+        );
 
         return Container(
           color: backgroundColor,
@@ -93,7 +95,10 @@ class CalendarDayCard extends StatelessWidget {
             cursor: SystemMouseCursors.click,
             onEnter: (p) => notifyEnter(context, true),
             onExit: (p) => notifyEnter(context, false),
-            child: child,
+            child: Padding(
+              padding: const EdgeInsets.symmetric(vertical: 8.0),
+              child: child,
+            ),
           ),
         );
       }),
@@ -148,6 +153,15 @@ class _DayEventCell extends StatelessWidget {
         onTap: onClick,
         child: Container(
           padding: const EdgeInsets.symmetric(horizontal: 8),
+          decoration: BoxDecoration(
+            border: Border.fromBorderSide(
+              BorderSide(
+                color: Theme.of(context).dividerColor,
+                width: 1.0,
+              ),
+            ),
+            borderRadius: Corners.s6Border,
+          ),
           child: child,
         ),
       ),

+ 5 - 3
frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart

@@ -73,9 +73,11 @@ class _CalendarPageState extends State<CalendarPage> {
               listenWhen: (p, c) => p.updateEvent != c.updateEvent,
               listener: (context, state) {
                 if (state.updateEvent != null) {
-                  _eventController.removeWhere((element) =>
-                      state.updateEvent!.event!.eventId ==
-                      element.event!.eventId);
+                  _eventController.removeWhere(
+                    (element) =>
+                        state.updateEvent!.event!.eventId ==
+                        element.event!.eventId,
+                  );
                   _eventController.add(state.updateEvent!);
                 }
               },

+ 17 - 14
frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart

@@ -18,6 +18,8 @@ import 'package:protobuf/protobuf.dart';
 
 import 'calendar_setting.dart';
 
+/// Widget that displays a list of settings that alters the appearance of the
+/// calendar
 class CalendarLayoutSetting extends StatefulWidget {
   final CalendarSettingContext settingContext;
   final Function(CalendarLayoutSettingsPB? layoutSettings) onUpdated;
@@ -96,18 +98,15 @@ class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> {
                 fieldId: settings.layoutFieldId,
                 popoverMutex: popoverMutex,
                 onUpdated: (fieldId) {
-                  _updateLayoutSettings(context,
-                      onUpdated: widget.onUpdated, layoutFieldId: fieldId);
+                  _updateLayoutSettings(
+                    context,
+                    onUpdated: widget.onUpdated,
+                    layoutFieldId: fieldId,
+                  );
                 },
               );
             default:
-              return ShowWeekends(
-                showWeekends: settings.showWeekends,
-                onUpdated: (showWeekends) {
-                  _updateLayoutSettings(context,
-                      onUpdated: widget.onUpdated, showWeekends: showWeekends);
-                },
-              );
+              return const SizedBox();
           }
         }).toList();
 
@@ -129,7 +128,8 @@ class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> {
   }
 
   List<CalendarLayoutSettingAction> _availableCalendarSettings(
-      CalendarLayoutSettingsPB layoutSettings) {
+    CalendarLayoutSettingsPB layoutSettings,
+  ) {
     List<CalendarLayoutSettingAction> settings = [
       CalendarLayoutSettingAction.layoutField,
       // CalendarLayoutSettingAction.layoutType,
@@ -220,8 +220,9 @@ class LayoutDateField extends StatelessWidget {
       popupBuilder: (context) {
         return BlocProvider(
           create: (context) => getIt<DatabasePropertyBloc>(
-              param1: viewId, param2: fieldController)
-            ..add(const DatabasePropertyEvent.initial()),
+            param1: viewId,
+            param2: fieldController,
+          )..add(const DatabasePropertyEvent.initial()),
           child: BlocBuilder<DatabasePropertyBloc, DatabasePropertyState>(
             builder: (context, state) {
               final items = state.fieldContexts
@@ -264,7 +265,8 @@ class LayoutDateField extends StatelessWidget {
         child: FlowyButton(
           margin: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 10.0),
           text: FlowyText.medium(
-              LocaleKeys.calendar_settings_layoutDateField.tr()),
+            LocaleKeys.calendar_settings_layoutDateField.tr(),
+          ),
         ),
       ),
     );
@@ -368,7 +370,8 @@ class FirstDayOfWeek extends StatelessWidget {
         child: FlowyButton(
           margin: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 10.0),
           text: FlowyText.medium(
-              LocaleKeys.calendar_settings_firstDayOfWeek.tr()),
+            LocaleKeys.calendar_settings_firstDayOfWeek.tr(),
+          ),
         ),
       ),
     );

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_setting.dart

@@ -15,8 +15,8 @@ import 'package:styled_widget/styled_widget.dart';
 import 'calendar_layout_setting.dart';
 
 /// The highest-level widget shown in the popover triggered by clicking the
-/// "Settings" button. By default, shows [AllCalendarSettings] but upon
-/// selecting a category, replaces contents with contents of the submenu.
+/// "Settings" button. Shows [AllCalendarSettings] by default, but replaces its
+/// contents with the submenu when a category is selected.
 class CalendarSetting extends StatelessWidget {
   final CalendarSettingContext settingContext;
   final CalendarLayoutSettingsPB? layoutSettings;

+ 8 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/checkbox_filter_editor_bloc.dart

@@ -45,10 +45,12 @@ class CheckboxFilterEditorBloc
           didReceiveFilter: (FilterPB filter) {
             final filterInfo = state.filterInfo.copyWith(filter: filter);
             final checkboxFilter = filterInfo.checkboxFilter()!;
-            emit(state.copyWith(
-              filterInfo: filterInfo,
-              filter: checkboxFilter,
-            ));
+            emit(
+              state.copyWith(
+                filterInfo: filterInfo,
+                filter: checkboxFilter,
+              ),
+            );
           },
         );
       },
@@ -79,7 +81,8 @@ class CheckboxFilterEditorEvent with _$CheckboxFilterEditorEvent {
   const factory CheckboxFilterEditorEvent.didReceiveFilter(FilterPB filter) =
       _DidReceiveFilter;
   const factory CheckboxFilterEditorEvent.updateCondition(
-      CheckboxFilterConditionPB condition) = _UpdateCondition;
+    CheckboxFilterConditionPB condition,
+  ) = _UpdateCondition;
   const factory CheckboxFilterEditorEvent.delete() = _Delete;
 }
 

+ 8 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/checklist_filter_bloc.dart

@@ -46,10 +46,12 @@ class ChecklistFilterEditorBloc
           didReceiveFilter: (FilterPB filter) {
             final filterInfo = state.filterInfo.copyWith(filter: filter);
             final checklistFilter = filterInfo.checklistFilter()!;
-            emit(state.copyWith(
-              filterInfo: filterInfo,
-              filter: checklistFilter,
-            ));
+            emit(
+              state.copyWith(
+                filterInfo: filterInfo,
+                filter: checklistFilter,
+              ),
+            );
           },
         );
       },
@@ -82,7 +84,8 @@ class ChecklistFilterEditorEvent with _$ChecklistFilterEditorEvent {
   const factory ChecklistFilterEditorEvent.didReceiveFilter(FilterPB filter) =
       _DidReceiveFilter;
   const factory ChecklistFilterEditorEvent.updateCondition(
-      ChecklistFilterConditionPB condition) = _UpdateCondition;
+    ChecklistFilterConditionPB condition,
+  ) = _UpdateCondition;
   const factory ChecklistFilterEditorEvent.delete() = _Delete;
 }
 

+ 9 - 6
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/filter_menu_bloc.dart

@@ -14,11 +14,13 @@ class GridFilterMenuBloc
   void Function(List<FieldInfo>)? _onFieldFn;
 
   GridFilterMenuBloc({required this.viewId, required this.fieldController})
-      : super(GridFilterMenuState.initial(
-          viewId,
-          fieldController.filterInfos,
-          fieldController.fieldInfos,
-        )) {
+      : super(
+          GridFilterMenuState.initial(
+            viewId,
+            fieldController.filterInfos,
+            fieldController.fieldInfos,
+          ),
+        ) {
     on<GridFilterMenuEvent>(
       (event, emit) async {
         event.when(
@@ -82,7 +84,8 @@ class GridFilterMenuBloc
 class GridFilterMenuEvent with _$GridFilterMenuEvent {
   const factory GridFilterMenuEvent.initial() = _Initial;
   const factory GridFilterMenuEvent.didReceiveFilters(
-      List<FilterInfo> filters) = _DidReceiveFilters;
+    List<FilterInfo> filters,
+  ) = _DidReceiveFilters;
   const factory GridFilterMenuEvent.didReceiveFields(List<FieldInfo> fields) =
       _DidReceiveFields;
   const factory GridFilterMenuEvent.toggleMenu() = _SetMenuVisibility;

+ 14 - 8
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/select_option_filter_bloc.dart

@@ -61,10 +61,12 @@ class SelectOptionFilterEditorBloc
           didReceiveFilter: (FilterPB filter) {
             final filterInfo = state.filterInfo.copyWith(filter: filter);
             final selectOptionFilter = filterInfo.selectOptionFilter()!;
-            emit(state.copyWith(
-              filterInfo: filterInfo,
-              filter: selectOptionFilter,
-            ));
+            emit(
+              state.copyWith(
+                filterInfo: filterInfo,
+                filter: selectOptionFilter,
+              ),
+            );
           },
           updateFilterDescription: (String desc) {
             emit(state.copyWith(filterDesc: desc));
@@ -112,13 +114,17 @@ class SelectOptionFilterEditorBloc
 class SelectOptionFilterEditorEvent with _$SelectOptionFilterEditorEvent {
   const factory SelectOptionFilterEditorEvent.initial() = _Initial;
   const factory SelectOptionFilterEditorEvent.didReceiveFilter(
-      FilterPB filter) = _DidReceiveFilter;
+    FilterPB filter,
+  ) = _DidReceiveFilter;
   const factory SelectOptionFilterEditorEvent.updateCondition(
-      SelectOptionConditionPB condition) = _UpdateCondition;
+    SelectOptionConditionPB condition,
+  ) = _UpdateCondition;
   const factory SelectOptionFilterEditorEvent.updateContent(
-      List<String> optionIds) = _UpdateContent;
+    List<String> optionIds,
+  ) = _UpdateContent;
   const factory SelectOptionFilterEditorEvent.updateFilterDescription(
-      String desc) = _UpdateDesc;
+    String desc,
+  ) = _UpdateDesc;
   const factory SelectOptionFilterEditorEvent.delete() = _Delete;
 }
 

+ 24 - 12
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/select_option_filter_list_bloc.dart

@@ -43,15 +43,22 @@ class SelectOptionFilterListBloc<T>
           didReceiveOptions: (newOptions) {
             List<SelectOptionPB> options = List.from(newOptions);
             options.retainWhere(
-                (element) => element.name.contains(state.predicate));
+              (element) => element.name.contains(state.predicate),
+            );
 
             final visibleOptions = options.map((option) {
               return VisibleSelectOption(
-                  option, state.selectedOptionIds.contains(option.id));
+                option,
+                state.selectedOptionIds.contains(option.id),
+              );
             }).toList();
 
-            emit(state.copyWith(
-                options: options, visibleOptions: visibleOptions));
+            emit(
+              state.copyWith(
+                options: options,
+                visibleOptions: visibleOptions,
+              ),
+            );
           },
           filterOption: (optionName) {
             _updateSelectOptions(predicate: optionName, emit: emit);
@@ -71,11 +78,13 @@ class SelectOptionFilterListBloc<T>
       selectedOptionIds ?? state.selectedOptionIds,
     );
 
-    emit(state.copyWith(
-      predicate: predicate ?? state.predicate,
-      visibleOptions: visibleOptions,
-      selectedOptionIds: selectedOptionIds ?? state.selectedOptionIds,
-    ));
+    emit(
+      state.copyWith(
+        predicate: predicate ?? state.predicate,
+        visibleOptions: visibleOptions,
+        selectedOptionIds: selectedOptionIds ?? state.selectedOptionIds,
+      ),
+    );
   }
 
   List<VisibleSelectOption> _makeVisibleOptions(
@@ -105,11 +114,14 @@ class SelectOptionFilterListBloc<T>
 class SelectOptionFilterListEvent with _$SelectOptionFilterListEvent {
   const factory SelectOptionFilterListEvent.initial() = _Initial;
   const factory SelectOptionFilterListEvent.selectOption(
-      SelectOptionPB option) = _SelectOption;
+    SelectOptionPB option,
+  ) = _SelectOption;
   const factory SelectOptionFilterListEvent.unselectOption(
-      SelectOptionPB option) = _UnSelectOption;
+    SelectOptionPB option,
+  ) = _UnSelectOption;
   const factory SelectOptionFilterListEvent.didReceiveOptions(
-      List<SelectOptionPB> options) = _DidReceiveOptions;
+    List<SelectOptionPB> options,
+  ) = _DidReceiveOptions;
   const factory SelectOptionFilterListEvent.filterOption(String optionName) =
       _SelectOptionFilter;
 }

+ 8 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/text_filter_editor_bloc.dart

@@ -54,10 +54,12 @@ class TextFilterEditorBloc
           didReceiveFilter: (FilterPB filter) {
             final filterInfo = state.filterInfo.copyWith(filter: filter);
             final textFilter = filterInfo.textFilter()!;
-            emit(state.copyWith(
-              filterInfo: filterInfo,
-              filter: textFilter,
-            ));
+            emit(
+              state.copyWith(
+                filterInfo: filterInfo,
+                filter: textFilter,
+              ),
+            );
           },
         );
       },
@@ -88,7 +90,8 @@ class TextFilterEditorEvent with _$TextFilterEditorEvent {
   const factory TextFilterEditorEvent.didReceiveFilter(FilterPB filter) =
       _DidReceiveFilter;
   const factory TextFilterEditorEvent.updateCondition(
-      TextFilterConditionPB condition) = _UpdateCondition;
+    TextFilterConditionPB condition,
+  ) = _UpdateCondition;
   const factory TextFilterEditorEvent.updateContent(String content) =
       _UpdateContent;
   const factory TextFilterEditorEvent.delete() = _Delete;

+ 5 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_accessory_bloc.dart

@@ -8,9 +8,11 @@ class GridAccessoryMenuBloc
   final String viewId;
 
   GridAccessoryMenuBloc({required this.viewId})
-      : super(GridAccessoryMenuState.initial(
-          viewId,
-        )) {
+      : super(
+          GridAccessoryMenuState.initial(
+            viewId,
+          ),
+        ) {
     on<GridAccessoryMenuEvent>(
       (event, emit) async {
         event.when(

+ 14 - 9
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_bloc.dart

@@ -39,16 +39,20 @@ class GridBloc extends Bloc<GridEvent, GridState> {
             emit(state.copyWith(grid: Some(grid)));
           },
           didReceiveFieldUpdate: (fields) {
-            emit(state.copyWith(
-              fields: GridFieldEquatable(fields),
-            ));
+            emit(
+              state.copyWith(
+                fields: GridFieldEquatable(fields),
+              ),
+            );
           },
           didReceiveRowUpdate: (newRowInfos, reason) {
-            emit(state.copyWith(
-              rowInfos: newRowInfos,
-              rowCount: newRowInfos.length,
-              reason: reason,
-            ));
+            emit(
+              state.copyWith(
+                rowInfos: newRowInfos,
+                rowCount: newRowInfos.length,
+                reason: reason,
+              ),
+            );
           },
         );
       },
@@ -146,7 +150,8 @@ class GridState with _$GridState {
 class GridLoadingState with _$GridLoadingState {
   const factory GridLoadingState.loading() = _Loading;
   const factory GridLoadingState.finish(
-      Either<Unit, FlowyError> successOrFail) = _Finish;
+    Either<Unit, FlowyError> successOrFail,
+  ) = _Finish;
 }
 
 class GridFieldEquatable extends Equatable {

+ 7 - 2
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_header_bloc.dart

@@ -40,7 +40,9 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
   }
 
   Future<void> _moveField(
-      _MoveField value, Emitter<GridHeaderState> emit) async {
+    _MoveField value,
+    Emitter<GridHeaderState> emit,
+  ) async {
     final fields = List<FieldInfo>.from(state.fields);
     fields.insert(value.toIndex, fields.removeAt(value.fromIndex));
     emit(state.copyWith(fields: fields));
@@ -69,7 +71,10 @@ class GridHeaderEvent with _$GridHeaderEvent {
   const factory GridHeaderEvent.didReceiveFieldUpdate(List<FieldInfo> fields) =
       _DidReceiveFieldUpdate;
   const factory GridHeaderEvent.moveField(
-      FieldPB field, int fromIndex, int toIndex) = _MoveField;
+    FieldPB field,
+    int fromIndex,
+    int toIndex,
+  ) = _MoveField;
 }
 
 @freezed

+ 10 - 7
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/row/row_bloc.dart

@@ -35,11 +35,13 @@ class RowBloc extends Bloc<RowEvent, RowState> {
             final cells = cellByFieldId.values
                 .map((e) => GridCellEquatable(e.fieldInfo))
                 .toList();
-            emit(state.copyWith(
-              cellByFieldId: cellByFieldId,
-              cells: UnmodifiableListView(cells),
-              changeReason: reason,
-            ));
+            emit(
+              state.copyWith(
+                cellByFieldId: cellByFieldId,
+                cells: UnmodifiableListView(cells),
+                changeReason: reason,
+              ),
+            );
           },
         );
       },
@@ -68,8 +70,9 @@ class RowEvent with _$RowEvent {
   const factory RowEvent.initial() = _InitialRow;
   const factory RowEvent.createRow() = _CreateRow;
   const factory RowEvent.didReceiveCells(
-          CellByFieldId cellsByFieldId, RowsChangedReason reason) =
-      _DidReceiveCells;
+    CellByFieldId cellsByFieldId,
+    RowsChangedReason reason,
+  ) = _DidReceiveCells;
 }
 
 @freezed

+ 2 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/row/row_detail_bloc.dart

@@ -59,7 +59,8 @@ class RowDetailEvent with _$RowDetailEvent {
   const factory RowDetailEvent.initial() = _Initial;
   const factory RowDetailEvent.deleteField(String fieldId) = _DeleteField;
   const factory RowDetailEvent.didReceiveCellDatas(
-      List<CellIdentifier> gridCells) = _DidReceiveCellDatas;
+    List<CellIdentifier> gridCells,
+  ) = _DidReceiveCellDatas;
 }
 
 @freezed

+ 4 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/sort/sort_create_bloc.dart

@@ -82,9 +82,10 @@ class CreateSortBloc extends Bloc<CreateSortEvent, CreateSortState> {
 
   Future<Either<Unit, FlowyError>> _createDefaultSort(FieldInfo field) async {
     final result = await _sortBackendSvc.insertSort(
-        fieldId: field.id,
-        fieldType: field.fieldType,
-        condition: SortConditionPB.Ascending);
+      fieldId: field.id,
+      fieldType: field.fieldType,
+      condition: SortConditionPB.Ascending,
+    );
 
     return result;
   }

+ 3 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/sort/sort_editor_bloc.dart

@@ -100,7 +100,9 @@ class SortEditorEvent with _$SortEditorEvent {
   const factory SortEditorEvent.didReceiveSorts(List<SortInfo> sortInfos) =
       _DidReceiveSorts;
   const factory SortEditorEvent.setCondition(
-      SortInfo sortInfo, SortConditionPB condition) = _SetCondition;
+    SortInfo sortInfo,
+    SortConditionPB condition,
+  ) = _SetCondition;
   const factory SortEditorEvent.deleteSort(SortInfo sortInfo) = _DeleteSort;
   const factory SortEditorEvent.deleteAllSorts() = _DeleteAllSorts;
 }

+ 7 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/sort/sort_menu_bloc.dart

@@ -14,11 +14,13 @@ class SortMenuBloc extends Bloc<SortMenuEvent, SortMenuState> {
   void Function(List<FieldInfo>)? _onFieldFn;
 
   SortMenuBloc({required this.viewId, required this.fieldController})
-      : super(SortMenuState.initial(
-          viewId,
-          fieldController.sortInfos,
-          fieldController.fieldInfos,
-        )) {
+      : super(
+          SortMenuState.initial(
+            viewId,
+            fieldController.sortInfos,
+            fieldController.fieldInfos,
+          ),
+        ) {
     on<SortMenuEvent>(
       (event, emit) async {
         event.when(

+ 10 - 8
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/grid_page.dart

@@ -117,7 +117,8 @@ class FlowyGrid extends StatefulWidget {
 
 class _FlowyGridState extends State<FlowyGrid> {
   final _scrollController = GridScrollController(
-      scrollGroupController: LinkedScrollControllerGroup());
+    scrollGroupController: LinkedScrollControllerGroup(),
+  );
   late ScrollController headerScrollController;
 
   @override
@@ -319,13 +320,14 @@ class _GridRowsState extends State<_GridRows> {
     );
 
     FlowyOverlay.show(
-        context: context,
-        builder: (BuildContext context) {
-          return RowDetailPage(
-            cellBuilder: cellBuilder,
-            dataController: dataController,
-          );
-        });
+      context: context,
+      builder: (BuildContext context) {
+        return RowDetailPage(
+          cellBuilder: cellBuilder,
+          dataController: dataController,
+        );
+      },
+    );
   }
 }
 

+ 3 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/grid_scroll.dart

@@ -8,9 +8,9 @@ class GridScrollController {
 
   final List<ScrollController> _linkHorizontalControllers = [];
 
-  GridScrollController(
-      {required LinkedScrollControllerGroup scrollGroupController})
-      : _scrollGroupController = scrollGroupController,
+  GridScrollController({
+    required LinkedScrollControllerGroup scrollGroupController,
+  })  : _scrollGroupController = scrollGroupController,
         verticalController = ScrollController(),
         horizontalController = scrollGroupController.addAndGet();
 

+ 1 - 4
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/layout/sizes.dart

@@ -28,10 +28,7 @@ class GridSize {
         vertical: GridSize.cellVPadding,
       );
 
-  static EdgeInsets get typeOptionContentInsets => const EdgeInsets.symmetric(
-        horizontal: 6,
-        vertical: 2,
-      );
+  static EdgeInsets get typeOptionContentInsets => const EdgeInsets.all(4);
 
   static EdgeInsets get footerContentInsets => EdgeInsets.fromLTRB(
         GridSize.leadingHeaderPadding,

+ 5 - 4
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/accessory_menu.dart

@@ -21,10 +21,11 @@ class GridAccessoryMenu extends StatelessWidget {
       child: MultiBlocListener(
         listeners: [
           BlocListener<GridFilterMenuBloc, GridFilterMenuState>(
-              listenWhen: (p, c) => p.isVisible != c.isVisible,
-              listener: (context, state) => context
-                  .read<GridAccessoryMenuBloc>()
-                  .add(const GridAccessoryMenuEvent.toggleMenu())),
+            listenWhen: (p, c) => p.isVisible != c.isVisible,
+            listener: (context, state) => context
+                .read<GridAccessoryMenuBloc>()
+                .add(const GridAccessoryMenuEvent.toggleMenu()),
+          ),
           BlocListener<SortMenuBloc, SortMenuState>(
             listenWhen: (p, c) => p.isVisible != c.isVisible,
             listener: (context, state) => context

+ 3 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart

@@ -100,7 +100,9 @@ class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> {
   }
 
   Widget _buildFilterPanel(
-      BuildContext context, CheckboxFilterEditorState state) {
+    BuildContext context,
+    CheckboxFilterEditorState state,
+  ) {
     return SizedBox(
       height: 20,
       child: Row(

+ 5 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart

@@ -70,9 +70,11 @@ class _ChecklistFilterChoicechipState extends State<ChecklistFilterChoicechip> {
 class ChecklistFilterEditor extends StatefulWidget {
   final ChecklistFilterEditorBloc bloc;
   final PopoverMutex popoverMutex;
-  const ChecklistFilterEditor(
-      {required this.bloc, required this.popoverMutex, Key? key})
-      : super(key: key);
+  const ChecklistFilterEditor({
+    required this.bloc,
+    required this.popoverMutex,
+    Key? key,
+  }) : super(key: key);
 
   @override
   ChecklistState createState() => ChecklistState();

+ 4 - 2
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/choicechip.dart

@@ -65,8 +65,10 @@ class _ChoicechipFilterDesc extends StatelessWidget {
   Widget build(BuildContext context) {
     final arrow = Transform.rotate(
       angle: -math.pi / 2,
-      child: svgWidget("home/arrow_left",
-          color: AFThemeExtension.of(context).textColor),
+      child: svgWidget(
+        "home/arrow_left",
+        color: AFThemeExtension.of(context).textColor,
+      ),
     );
     return Padding(
       padding: const EdgeInsets.symmetric(horizontal: 2),

+ 9 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart

@@ -110,7 +110,10 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
                   selectedOptionIds: state.filter.optionIds,
                   onSelectedOptions: (optionIds) {
                     context.read<SelectOptionFilterEditorBloc>().add(
-                        SelectOptionFilterEditorEvent.updateContent(optionIds));
+                          SelectOptionFilterEditorEvent.updateContent(
+                            optionIds,
+                          ),
+                        );
                   },
                 ),
               ),
@@ -132,7 +135,9 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
   }
 
   Widget _buildFilterPanel(
-      BuildContext context, SelectOptionFilterEditorState state) {
+    BuildContext context,
+    SelectOptionFilterEditorState state,
+  ) {
     return SizedBox(
       height: 20,
       child: Row(
@@ -144,7 +149,8 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
             popoverMutex: popoverMutex,
             onCondition: (condition) {
               context.read<SelectOptionFilterEditorBloc>().add(
-                  SelectOptionFilterEditorEvent.updateCondition(condition));
+                    SelectOptionFilterEditorEvent.updateCondition(condition),
+                  );
             },
           ),
           const Spacer(),

+ 3 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/choicechip/text.dart

@@ -147,7 +147,9 @@ class _TextFilterEditorState extends State<TextFilterEditor> {
   }
 
   Widget _buildFilterTextField(
-      BuildContext context, TextFilterEditorState state) {
+    BuildContext context,
+    TextFilterEditorState state,
+  ) {
     return FlowyTextField(
       text: state.filter.content,
       hintText: LocaleKeys.grid_settings_typeAValue.tr(),

+ 4 - 2
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/condition_button.dart

@@ -18,8 +18,10 @@ class ConditionButton extends StatelessWidget {
   Widget build(BuildContext context) {
     final arrow = Transform.rotate(
       angle: -math.pi / 2,
-      child: svgWidget("home/arrow_left",
-          color: AFThemeExtension.of(context).textColor),
+      child: svgWidget(
+        "home/arrow_left",
+        color: AFThemeExtension.of(context).textColor,
+      ),
     );
 
     return SizedBox(

+ 4 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/filter/create_filter_list.dart

@@ -117,7 +117,10 @@ class _FilterTextFieldDelegate extends SliverPersistentHeaderDelegate {
 
   @override
   Widget build(
-      BuildContext context, double shrinkOffset, bool overlapsContent) {
+    BuildContext context,
+    double shrinkOffset,
+    bool overlapsContent,
+  ) {
     return Container(
       padding: const EdgeInsets.only(top: 4),
       height: fixHeight,

+ 12 - 7
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_cell.dart

@@ -95,17 +95,20 @@ class _GridHeaderCellContainer extends StatelessWidget {
       width: 1.0,
     );
     final decoration = BoxDecoration(
-        border: Border(
-      top: borderSide,
-      right: borderSide,
-      bottom: borderSide,
-    ));
+      border: Border(
+        top: borderSide,
+        right: borderSide,
+        bottom: borderSide,
+      ),
+    );
 
     return Container(
       width: width,
       decoration: decoration,
       child: ConstrainedBox(
-          constraints: const BoxConstraints.expand(), child: child),
+        constraints: const BoxConstraints.expand(),
+        child: child,
+      ),
     );
   }
 }
@@ -149,10 +152,12 @@ class FieldCellButton extends StatelessWidget {
   final VoidCallback onTap;
   final FieldPB field;
   final int? maxLines;
+  final BorderRadius? radius;
   const FieldCellButton({
     required this.field,
     required this.onTap,
     this.maxLines = 1,
+    this.radius = BorderRadius.zero,
     Key? key,
   }) : super(key: key);
 
@@ -169,7 +174,7 @@ class FieldCellButton extends StatelessWidget {
       leftIcon: FlowySvg(
         name: field.fieldType.iconName(),
       ),
-      radius: BorderRadius.zero,
+      radius: radius,
       text: FlowyText.medium(
         text,
         maxLines: maxLines,

+ 21 - 19
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_cell_action_sheet.dart

@@ -101,25 +101,27 @@ class _FieldOperationList extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Column(children: [
-      Flex(
-        direction: Axis.horizontal,
-        children: [
-          _actionCell(FieldAction.hide),
-          HSpace(GridSize.typeOptionSeparatorHeight),
-          _actionCell(FieldAction.duplicate),
-        ],
-      ),
-      VSpace(GridSize.typeOptionSeparatorHeight),
-      Flex(
-        direction: Axis.horizontal,
-        children: [
-          _actionCell(FieldAction.delete),
-          HSpace(GridSize.typeOptionSeparatorHeight),
-          const Spacer(),
-        ],
-      ),
-    ]);
+    return Column(
+      children: [
+        Flex(
+          direction: Axis.horizontal,
+          children: [
+            _actionCell(FieldAction.hide),
+            HSpace(GridSize.typeOptionSeparatorHeight),
+            _actionCell(FieldAction.duplicate),
+          ],
+        ),
+        VSpace(GridSize.typeOptionSeparatorHeight),
+        Flex(
+          direction: Axis.horizontal,
+          children: [
+            _actionCell(FieldAction.delete),
+            HSpace(GridSize.typeOptionSeparatorHeight),
+            const Spacer(),
+          ],
+        ),
+      ],
+    );
   }
 
   Widget _actionCell(FieldAction action) {

+ 7 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart

@@ -90,11 +90,13 @@ class _SwitchFieldButton extends StatelessWidget {
       mutex: popoverMutex,
       offset: const Offset(8, 0),
       popupBuilder: (popOverContext) {
-        return FieldTypeList(onSelectField: (newFieldType) {
-          context
-              .read<FieldTypeOptionEditBloc>()
-              .add(FieldTypeOptionEditEvent.switchToField(newFieldType));
-        });
+        return FieldTypeList(
+          onSelectField: (newFieldType) {
+            context
+                .read<FieldTypeOptionEditBloc>()
+                .add(FieldTypeOptionEditEvent.switchToField(newFieldType));
+          },
+        );
       },
       child: Padding(
         padding: const EdgeInsets.symmetric(horizontal: 12.0),

+ 28 - 11
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/grid_header.dart

@@ -39,7 +39,9 @@ class _GridHeaderSliverAdaptorState extends State<GridHeaderSliverAdaptor> {
     return BlocProvider(
       create: (context) {
         final bloc = getIt<GridHeaderBloc>(
-            param1: widget.viewId, param2: widget.fieldController);
+          param1: widget.viewId,
+          param2: widget.fieldController,
+        );
         bloc.add(const GridHeaderEvent.initial());
         return bloc;
       },
@@ -98,10 +100,16 @@ class _GridHeaderState extends State<_GridHeader> {
       builder: (context, state) {
         final cells = state.fields
             .where((field) => field.visibility)
-            .map((field) =>
-                FieldCellContext(viewId: widget.viewId, field: field.field))
-            .map((ctx) =>
-                GridFieldCell(key: _getKeyById(ctx.field.id), cellContext: ctx))
+            .map(
+              (field) =>
+                  FieldCellContext(viewId: widget.viewId, field: field.field),
+            )
+            .map(
+              (ctx) => GridFieldCell(
+                key: _getKeyById(ctx.field.id),
+                cellContext: ctx,
+              ),
+            )
             .toList();
 
         return Container(
@@ -124,8 +132,12 @@ class _GridHeaderState extends State<_GridHeader> {
     );
   }
 
-  void _onReorder(List<GridFieldCell> cells, int oldIndex, BuildContext context,
-      int newIndex) {
+  void _onReorder(
+    List<GridFieldCell> cells,
+    int oldIndex,
+    BuildContext context,
+    int newIndex,
+  ) {
     if (cells.length > oldIndex) {
       final field = cells[oldIndex].cellContext.field;
       context
@@ -177,7 +189,7 @@ class CreateFieldButton extends StatelessWidget {
       constraints: BoxConstraints.loose(const Size(240, 600)),
       child: FlowyButton(
         radius: BorderRadius.zero,
-        text: FlowyText.medium(LocaleKeys.grid_field_newColumn.tr()),
+        text: FlowyText.medium(LocaleKeys.grid_field_newProperty.tr()),
         hoverColor: AFThemeExtension.of(context).greyHover,
         onTap: () {},
         leftIcon: const FlowySvg(name: 'home/add'),
@@ -197,12 +209,17 @@ class SliverHeaderDelegateImplementation
   final String gridId;
   final List<FieldPB> fields;
 
-  SliverHeaderDelegateImplementation(
-      {required this.gridId, required this.fields});
+  SliverHeaderDelegateImplementation({
+    required this.gridId,
+    required this.fields,
+  });
 
   @override
   Widget build(
-      BuildContext context, double shrinkOffset, bool overlapsContent) {
+    BuildContext context,
+    double shrinkOffset,
+    bool overlapsContent,
+  ) {
     return _GridHeader(viewId: gridId);
   }
 

+ 7 - 6
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/builder.dart

@@ -76,12 +76,13 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
       );
     case FieldType.DateTime:
       return DateTypeOptionWidgetBuilder(
-          makeTypeOptionContextWithDataController<DateTypeOptionPB>(
-            viewId: viewId,
-            fieldType: fieldType,
-            dataController: dataController,
-          ),
-          popoverMutex);
+        makeTypeOptionContextWithDataController<DateTypeOptionPB>(
+          viewId: viewId,
+          fieldType: fieldType,
+          dataController: dataController,
+        ),
+        popoverMutex,
+      );
     case FieldType.SingleSelect:
       return SingleSelectTypeOptionWidgetBuilder(
         makeTypeOptionContextWithDataController<SingleSelectTypeOptionPB>(

+ 2 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/checklist.dart

@@ -4,7 +4,8 @@ import 'builder.dart';
 
 class ChecklistTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
   ChecklistTypeOptionWidgetBuilder(
-      ChecklistTypeOptionContext typeOptionContext);
+    ChecklistTypeOptionContext typeOptionContext,
+  );
 
   @override
   Widget? build(BuildContext context) => null;

+ 2 - 0
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart

@@ -299,6 +299,8 @@ extension DateFormatExtension on DateFormat {
         return LocaleKeys.grid_field_dateFormatLocal.tr();
       case DateFormat.US:
         return LocaleKeys.grid_field_dateFormatUS.tr();
+      case DateFormat.DayMonthYear:
+        return LocaleKeys.grid_field_dateFormatDayMonthYear.tr();
       default:
         throw UnimplementedError;
     }

+ 75 - 58
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/number.dart

@@ -3,6 +3,7 @@ import 'package:appflowy/plugins/database_view/application/field/type_option/num
 import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
 import 'package:appflowy_popover/appflowy_popover.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:appflowy_backend/protobuf/flowy-database/format.pbenum.dart';
 import 'package:flutter/material.dart';
@@ -28,10 +29,13 @@ class NumberTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
 
   @override
   Widget? build(BuildContext context) {
-    return Column(children: [
-      VSpace(GridSize.typeOptionSeparatorHeight),
-      _widget,
-    ]);
+    return Column(
+      children: [
+        VSpace(GridSize.typeOptionSeparatorHeight),
+        const TypeOptionSeparator(),
+        _widget,
+      ],
+    );
   }
 }
 
@@ -49,55 +53,65 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
     return BlocProvider(
       create: (context) =>
           NumberTypeOptionBloc(typeOptionContext: typeOptionContext),
-      child: SizedBox(
-        height: GridSize.popoverItemHeight,
-        child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
-          listener: (context, state) =>
-              typeOptionContext.typeOption = state.typeOption,
-          builder: (context, state) {
-            final button = SizedBox(
-              height: GridSize.popoverItemHeight,
-              child: FlowyButton(
-                margin: GridSize.typeOptionContentInsets,
-                rightIcon: svgWidget(
-                  "grid/more",
-                  color: Theme.of(context).iconTheme.color,
-                ),
-                text: Row(
-                  children: [
-                    FlowyText.medium(LocaleKeys.grid_field_numberFormat.tr()),
-                    const Spacer(),
-                    FlowyText.regular(state.typeOption.format.title()),
-                  ],
-                ),
+      child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
+        listener: (context, state) =>
+            typeOptionContext.typeOption = state.typeOption,
+        builder: (context, state) {
+          final selectNumUnitButton = SizedBox(
+            height: GridSize.popoverItemHeight,
+            child: FlowyButton(
+              hoverColor: AFThemeExtension.of(context).lightGreyHover,
+              margin: GridSize.typeOptionContentInsets,
+              rightIcon: svgWidget(
+                "grid/more",
+                color: AFThemeExtension.of(context).textColor,
               ),
-            );
-
-            return AppFlowyPopover(
-              mutex: popoverMutex,
-              triggerActions:
-                  PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
-              offset: const Offset(8, 0),
-              constraints: BoxConstraints.loose(const Size(460, 440)),
-              margin: EdgeInsets.zero,
-              child: Padding(
-                padding: const EdgeInsets.symmetric(horizontal: 12.0),
-                child: button,
+              text: FlowyText.regular(
+                state.typeOption.format.title(),
+                color: AFThemeExtension.of(context).textColor,
               ),
-              popupBuilder: (BuildContext popoverContext) {
-                return NumberFormatList(
-                  onSelected: (format) {
-                    context
-                        .read<NumberTypeOptionBloc>()
-                        .add(NumberTypeOptionEvent.didSelectFormat(format));
-                    PopoverContainer.of(popoverContext).close();
+            ),
+          );
+
+          final numFormatTitle = Container(
+            padding: const EdgeInsets.only(left: 6),
+            height: GridSize.popoverItemHeight,
+            alignment: Alignment.centerLeft,
+            child: FlowyText.medium(
+              LocaleKeys.grid_field_numberFormat.tr(),
+              color: AFThemeExtension.of(context).textColor,
+            ),
+          );
+          return Padding(
+            padding: const EdgeInsets.symmetric(horizontal: 12),
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                numFormatTitle,
+                AppFlowyPopover(
+                  mutex: popoverMutex,
+                  triggerActions:
+                      PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
+                  offset: const Offset(8, 0),
+                  constraints: BoxConstraints.loose(const Size(460, 440)),
+                  margin: EdgeInsets.zero,
+                  child: selectNumUnitButton,
+                  popupBuilder: (BuildContext popoverContext) {
+                    return NumberFormatList(
+                      onSelected: (format) {
+                        context
+                            .read<NumberTypeOptionBloc>()
+                            .add(NumberTypeOptionEvent.didSelectFormat(format));
+                        PopoverContainer.of(popoverContext).close();
+                      },
+                      selectedFormat: state.typeOption.format,
+                    );
                   },
-                  selectedFormat: state.typeOption.format,
-                );
-              },
-            );
-          },
-        ),
+                ),
+              ],
+            ),
+          );
+        },
       ),
     );
   }
@@ -108,9 +122,11 @@ typedef SelectNumberFormatCallback = Function(NumberFormat format);
 class NumberFormatList extends StatelessWidget {
   final SelectNumberFormatCallback onSelected;
   final NumberFormat selectedFormat;
-  const NumberFormatList(
-      {required this.selectedFormat, required this.onSelected, Key? key})
-      : super(key: key);
+  const NumberFormatList({
+    required this.selectedFormat,
+    required this.onSelected,
+    Key? key,
+  }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
@@ -127,11 +143,12 @@ class NumberFormatList extends StatelessWidget {
               builder: (context, state) {
                 final cells = state.formats.map((format) {
                   return NumberFormatCell(
-                      isSelected: format == selectedFormat,
-                      format: format,
-                      onSelected: (format) {
-                        onSelected(format);
-                      });
+                    isSelected: format == selectedFormat,
+                    format: format,
+                    onSelected: (format) {
+                      onSelected(format);
+                    },
+                  );
                 }).toList();
 
                 final list = ListView.separated(

+ 5 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/select_option.dart

@@ -71,9 +71,11 @@ class OptionTitle extends StatelessWidget {
     return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTypeOptionState>(
       builder: (context, state) {
         List<Widget> children = [
-          FlowyText.medium(
-            LocaleKeys.grid_field_optionTitle.tr(),
-            color: Theme.of(context).hintColor,
+          Padding(
+            padding: const EdgeInsets.only(left: 9),
+            child: FlowyText.medium(
+              LocaleKeys.grid_field_optionTitle.tr(),
+            ),
           )
         ];
         if (state.options.isNotEmpty && !state.isEditingOption) {

+ 15 - 8
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/select_option_editor.dart

@@ -66,7 +66,8 @@ class SelectOptionTypeOptionEditor extends StatelessWidget {
             if (showOptions) {
               cells.add(const TypeOptionSeparator());
               cells.add(
-                  SelectOptionColorList(selectedColor: state.option.color));
+                SelectOptionColorList(selectedColor: state.option.color),
+              );
             }
 
             return SizedBox(
@@ -126,9 +127,11 @@ class _DeleteTag extends StatelessWidget {
 class _OptionNameTextField extends StatelessWidget {
   final String name;
   final bool autoFocus;
-  const _OptionNameTextField(
-      {required this.name, required this.autoFocus, Key? key})
-      : super(key: key);
+  const _OptionNameTextField({
+    required this.name,
+    required this.autoFocus,
+    Key? key,
+  }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
@@ -157,7 +160,9 @@ class SelectOptionColorList extends StatelessWidget {
   Widget build(BuildContext context) {
     final cells = SelectOptionColorPB.values.map((color) {
       return _SelectOptionColorCell(
-          color: color, isSelected: selectedColor == color);
+        color: color,
+        isSelected: selectedColor == color,
+      );
     }).toList();
 
     return Column(
@@ -195,9 +200,11 @@ class SelectOptionColorList extends StatelessWidget {
 class _SelectOptionColorCell extends StatelessWidget {
   final SelectOptionColorPB color;
   final bool isSelected;
-  const _SelectOptionColorCell(
-      {required this.color, required this.isSelected, Key? key})
-      : super(key: key);
+  const _SelectOptionColorCell({
+    required this.color,
+    required this.isSelected,
+    Key? key,
+  }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {

+ 19 - 14
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/row/row.dart

@@ -68,11 +68,13 @@ class _GridRowState extends State<GridRow> {
               ),
             );
 
-            return Row(children: [
-              const _RowLeading(),
-              content,
-              const _RowTrailing(),
-            ]);
+            return Row(
+              children: [
+                const _RowLeading(),
+                content,
+                const _RowTrailing(),
+              ],
+            );
           },
         ),
       ),
@@ -129,9 +131,11 @@ class _RowLeadingState extends State<_RowLeading> {
       mainAxisAlignment: MainAxisAlignment.center,
       children: [
         const _InsertButton(),
-        _MenuButton(openMenu: () {
-          popoverController.show();
-        }),
+        _MenuButton(
+          openMenu: () {
+            popoverController.show();
+          },
+        ),
       ],
     );
   }
@@ -216,12 +220,13 @@ class RowContent extends StatelessWidget {
           !listEquals(previous.cells, current.cells),
       builder: (context, state) {
         return IntrinsicHeight(
-            child: Row(
-          mainAxisSize: MainAxisSize.max,
-          mainAxisAlignment: MainAxisAlignment.start,
-          crossAxisAlignment: CrossAxisAlignment.stretch,
-          children: _makeCells(context, state.cellByFieldId),
-        ));
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.stretch,
+            children: _makeCells(context, state.cellByFieldId),
+          ),
+        );
       },
     );
   }

+ 4 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/sort/create_sort_list.dart

@@ -116,7 +116,10 @@ class _FilterTextFieldDelegate extends SliverPersistentHeaderDelegate {
 
   @override
   Widget build(
-      BuildContext context, double shrinkOffset, bool overlapsContent) {
+    BuildContext context,
+    double shrinkOffset,
+    bool overlapsContent,
+  ) {
     return Container(
       padding: const EdgeInsets.only(top: 4),
       height: fixHeight,

+ 9 - 7
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/sort/sort_editor.dart

@@ -76,13 +76,15 @@ class _SortList extends StatelessWidget {
     return BlocBuilder<SortEditorBloc, SortEditorState>(
       builder: (context, state) {
         final List<Widget> children = state.sortInfos
-            .map((info) => Padding(
-                  padding: const EdgeInsets.symmetric(vertical: 6),
-                  child: _SortItem(
-                    sortInfo: info,
-                    popoverMutex: popoverMutex,
-                  ),
-                ))
+            .map(
+              (info) => Padding(
+                padding: const EdgeInsets.symmetric(vertical: 6),
+                child: _SortItem(
+                  sortInfo: info,
+                  popoverMutex: popoverMutex,
+                ),
+              ),
+            )
             .toList();
 
         return Column(

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.