diff --git a/.github/workflows/appflowy_editor_test.yml b/.github/workflows/appflowy_editor_test.yml
index c007259bf8..229ef85efd 100644
--- a/.github/workflows/appflowy_editor_test.yml
+++ b/.github/workflows/appflowy_editor_test.yml
@@ -4,10 +4,12 @@ on:
push:
branches:
- "main"
+ - "release/*"
pull_request:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/app_flowy/packages/appflowy_editor/**"
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index e3ca2c3a76..dca1ecb2ec 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -4,10 +4,12 @@ on:
push:
branches:
- "main"
+ - "release/*"
pull_request:
branches:
- "main"
+ - "release/*"
jobs:
build:
@@ -62,6 +64,8 @@ jobs:
sudo apt-get update
sudo apt-get install -y dart curl build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
+ elif [ "$RUNNER_OS" == "Windows" ]; then
+ vcpkg integrate install
elif [ "$RUNNER_OS" == "macOS" ]; then
echo 'do nothing'
fi
@@ -85,7 +89,7 @@ jobs:
flutter config --enable-linux-desktop
elif [ "$RUNNER_OS" == "macOS" ]; then
flutter config --enable-macos-desktop
- elif [ "$RUNNER_OS" == "windows" ]; then
+ elif [ "$RUNNER_OS" == "Windows" ]; then
flutter config --enable-windows-desktop
fi
shell: bash
diff --git a/.github/workflows/dart_lint.yml b/.github/workflows/dart_lint.yml
index 6ce8630b8d..678677e3d4 100644
--- a/.github/workflows/dart_lint.yml
+++ b/.github/workflows/dart_lint.yml
@@ -9,12 +9,14 @@ on:
push:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/app_flowy/**"
pull_request:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/app_flowy/**"
@@ -73,7 +75,7 @@ jobs:
run: |
cargo make --profile development-linux-x86_64 flowy-sdk-dev
- - name: Code Generation
+ - name: Flutter Code Generation
working-directory: frontend/app_flowy
run: |
flutter packages pub run easy_localization:generate -f keys -o locale_keys.g.dart -S assets/translations -s en.json
diff --git a/.github/workflows/dart_test.yml b/.github/workflows/dart_test.yml
index 17694e3fec..39a938628e 100644
--- a/.github/workflows/dart_test.yml
+++ b/.github/workflows/dart_test.yml
@@ -1,15 +1,17 @@
-name: Unit test(Flutter)
+name: Frontend test
on:
push:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/app_flowy/**"
pull_request:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/app_flowy/**"
@@ -21,7 +23,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
-
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable-2022-04-07"
@@ -53,10 +54,6 @@ jobs:
working-directory: frontend
run: |
cargo install cargo-make
-
- - name: Cargo make flowy dev
- working-directory: frontend
- run: |
cargo make flowy_dev
- name: Flutter Deps
@@ -64,12 +61,12 @@ jobs:
run: |
flutter config --enable-linux-desktop
- - name: Build FlowySDK
+ - name: Build Test lib
working-directory: frontend
run: |
- cargo make --profile test-linux test-lib-build
+ cargo make --profile test-linux build-test-lib
- - name: Code Generation
+ - name: Flutter Code Generation
working-directory: frontend/app_flowy
run: |
flutter packages pub get
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d7e22b4b46..03f2bb13db 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -28,7 +28,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
- release_name: Release ${{ github.ref }}
+ release_name: v${{ github.ref }}
body_path: ${{ env.RELEASE_NOTES_PATH }}
build-linux-x86:
@@ -37,6 +37,7 @@ jobs:
env:
LINUX_APP_RELEASE_PATH: frontend/app_flowy/product/${{ github.ref_name }}/linux/Release
LINUX_ZIP_NAME: AppFlowy-linux-x86.tar.gz
+ LINUX_PACKAGE_NAME: AppFlowy_${{ github.ref_name }}_linux-amd64.deb
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -70,6 +71,46 @@ jobs:
flutter config --enable-linux-desktop
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-linux-x86_64 appflowy
+ - name: Build Linux package
+ working-directory: ${{ env.LINUX_APP_RELEASE_PATH }}
+ run: |
+ mkdir -p package/opt && mv AppFlowy package/opt/
+ cd package && mkdir DEBIAN
+ # Create control file
+ printf 'Package: AppFlowy
+ Version: %s
+ Architecture: amd64
+ Essential: no
+ Priority: optional
+ Maintainer: AppFlowy
+ Description: An Open Source Alternative to Notion\n' "${{ github.ref_name }}" > DEBIAN/control
+
+ # postinst script for creating symlink
+ printf '#!/bin/bash
+ if [ -e /usr/local/bin/appflowy ]; then
+ echo "Symlink already exists, skipping."
+ else
+ echo "Creating Symlink in /usr/local/bin/appflowy"
+ ln -s /opt/AppFlowy/app_flowy /usr/local/bin/appflowy
+ fi' > DEBIAN/postinst
+ chmod 0755 DEBIAN/postinst
+
+ # postrm script for cleaning up residuals
+ printf '#!/bin/bash
+ if [ -e /usr/local/bin/appflowy ]; then
+ rm /usr/local/bin/appflowy
+ fi' > DEBIAN/postrm
+ chmod 0755 DEBIAN/postrm
+
+ mkdir -p usr/share/applications
+ # Update Exec & icon path in desktop entry
+ grep -rl "\[CHANGE_THIS\]" ./opt/AppFlowy/appflowy.desktop.temp | xargs sed -i "s/\[CHANGE_THIS\]/\/opt/"
+ # Add desktop entry in package
+ mv ./opt/AppFlowy/appflowy.desktop.temp ./usr/share/applications/appflowy.desktop
+
+ # Build
+ cd ../ && dpkg-deb --build --root-owner-group package ${{ env.LINUX_PACKAGE_NAME }}
+
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
@@ -81,12 +122,24 @@ jobs:
asset_name: ${{ env.LINUX_ZIP_NAME }}
asset_content_type: application/octet-stream
+ - name: Upload Release Asset Install Package
+ id: upload-release-asset-install-package
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ needs.create-release.outputs.upload_url }}
+ asset_path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_NAME }}
+ asset_name: ${{ env.LINUX_PACKAGE_NAME }}
+ asset_content_type: application/octet-stream
+
build-macos-x86_64:
runs-on: macos-latest
needs: create-release
env:
MACOS_APP_RELEASE_PATH: frontend/app_flowy/product/${{ github.ref_name }}/macos/Release
MACOS_X86_ZIP_NAME: Appflowy-macos-x86_64.zip
+ MACOS_DMG_NAME: Appflowy-macos-x86_64-installer
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -116,6 +169,21 @@ jobs:
flutter config --enable-macos-desktop
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-mac-x86_64 appflowy
+ - name: Create MacOS dmg
+ working-directory: frontend
+ run: |
+ brew install create-dmg
+ create-dmg \
+ --volname ${{ env.MACOS_DMG_NAME }} \
+ --hide-extension "AppFlowy.app" \
+ --background scripts/dmg_assets/AppFlowyInstallerBackground.jpg \
+ --window-size 600 450 \
+ --icon-size 94 \
+ --icon "AppFlowy.app" 141 249 \
+ --app-drop-link 458 249 \
+ "${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \
+ "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app"
+
- name: Archive macOS app
working-directory: ${{ env.MACOS_APP_RELEASE_PATH }}
run: zip --symlinks -qr ${{ env.MACOS_X86_ZIP_NAME }} AppFlowy.app
@@ -129,6 +197,15 @@ jobs:
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_X86_ZIP_NAME }}
asset_name: ${{ env.MACOS_X86_ZIP_NAME }}
asset_content_type: application/octet-stream
+ - name: Upload DMG Release Asset
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ needs.create-release.outputs.upload_url }}
+ asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg
+ asset_name: ${{ env.MACOS_DMG_NAME }}.dmg
+ asset_content_type: application/octet-stream
build-windows-x86_64:
runs-on: windows-latest
diff --git a/.github/workflows/rust_coverage.yml b/.github/workflows/rust_coverage.yml
index b63d0c2202..512796cb93 100644
--- a/.github/workflows/rust_coverage.yml
+++ b/.github/workflows/rust_coverage.yml
@@ -4,6 +4,7 @@ on:
push:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -11,6 +12,7 @@ on:
pull_request:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
diff --git a/.github/workflows/rust_lint.yml b/.github/workflows/rust_lint.yml
index 2221ad02a0..4ea8ba40a2 100644
--- a/.github/workflows/rust_lint.yml
+++ b/.github/workflows/rust_lint.yml
@@ -4,6 +4,7 @@ on:
push:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -11,6 +12,7 @@ on:
pull_request:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
diff --git a/.github/workflows/rust_test.yml b/.github/workflows/rust_test.yml
index 3a42f9074f..3f49d5085b 100644
--- a/.github/workflows/rust_test.yml
+++ b/.github/workflows/rust_test.yml
@@ -1,9 +1,10 @@
-name: Unit test(Rust)
+name: Backend test
on:
push:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -11,6 +12,7 @@ on:
pull_request:
branches:
- "main"
+ - "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 954e319b52..7fcb348030 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,24 @@
# Release Notes
+## Version 0.0.6.2 - 10/30/2022
+- Fix some bugs
+
+## Version 0.0.6.1 - 10/26/2022
+### New features
+- Optimzie appflowy_editor dark mode style
+
+### Bug Fixes
+- Unable to copy the text with checkbox or link style
+
+## Version 0.0.6 - 10/23/2022
+
+### New features
+- Integrate **appflowy_editor**
+
+
## Version 0.0.5.3 - 09/26/2022
-New features
+### New features
- Open the next page automatically after deleting the current page
- Refresh the Kanban board after altering a property type
@@ -16,7 +32,7 @@ New features
## Version 0.0.5.2 - 09/16/2022
-New features
+### New features
- Enable adding a new card to the "No Status" group
- Fix some bugs
@@ -27,19 +43,19 @@ New features
## Version 0.0.5.1 - 09/14/2022
-New features
+### New features
- Enable deleting a field in board
- Fix some bugs
## Version 0.0.5 - 09/08/2022
-New Features - Kanban Board like Notion and Trello beta
+### New features - Kanban Board like Notion and Trello beta
Boards are the best way to manage projects & tasks. Use them to group your databases by select, multiselect, and checkbox.
-- Set up columns that represent a specific phase of the project cycle and use cards to represent each project / task
-- Drag and drop a card from one phase / column to another phase / column
+- Set up columns that represent a specific phase of the project cycle and use cards to represent each project/task
+- Drag and drop a card from one phase/column to another phase/column
- Update database properties in the Board view by clicking on a property and making edits on the card
### Other Features & Improvements
@@ -49,7 +65,7 @@ Boards are the best way to manage projects & tasks. Use them to group your datab
## Version 0.0.5 - beta.2 - beta.1 - 09/01/2022
-New features
+### New features
- Board-view database
- Support start editing after creating a new card
- Support editing the card directly by clicking the edit button
@@ -61,7 +77,7 @@ New features
## Version 0.0.5 - beta.1 - 08/25/2022
-New features
+### New features
- Board-view database
- Group by single select
- drag and drop cards
@@ -84,7 +100,7 @@ New features
## Version 0.0.4 - beta.3 - 05/02/2022
- Drag to reorder app/ view/ field
-- Row record open as a page
+- Row record opens as a page
- Auto resize the height of the row in the grid
- Support more number formats
- Search column options, supporting Single-select, Multi-select, and number format
@@ -108,7 +124,7 @@ New features
## Version 0.0.4 - beta.1 - 04/08/2022
v0.0.4 - beta.1 is pre-release
-New features
+### New features
- Table-view database
- supported column types: Text, Checkbox, Single-select, Multi-select, Numbers
- hide / delete columns
@@ -117,12 +133,12 @@ New features
## Version 0.0.3 - 02/23/2022
v0.0.3 is production ready, available on Linux, macOS, and Windows
-New features
+### New features
- Dark Mode
- Support new languages: French, Italian, Russian, Simplified Chinese, Spanish
- Add Settings: Toggle on Dark Mode; Select a language
- Show device info
-- Add tooltip on toolbar icons
+- Add tooltip on the toolbar icons
Bug fixes and improvements
- Increased height of action
diff --git a/README.md b/README.md
index 2a53db9b24..93d6a11c70 100644
--- a/README.md
+++ b/README.md
@@ -23,13 +23,15 @@ You are in charge of your data and customizations.
Twitter
-
+
## User Installation
-Please view the [documentation](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods) for OS specific installation instructions.
+* [Windows/Mac/Linux](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages)
+* [Docker](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker)
+* [Source](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source)
## Built With
@@ -49,7 +51,9 @@ Please view the [documentation](https://appflowy.gitbook.io/docs/essential-docum
- [AppFlowy Roadmap ReadMe](https://appflowy.gitbook.io/docs/essential-documentation/roadmap)
- [AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12)
-If you'd like to propose a feature, submit an issue [here](https://github.com/AppFlowy-IO/appflowy/issues).
+
+If you'd like to propose a feature, submit a feature request [here](https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&template=feature_request.yaml&title=%5BFR%5D+)
+If you'd like to report a bug, submit bug report [here](https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&template=bug_report.yaml&title=%5BBug%5D+)
## **Releases**
@@ -91,7 +95,7 @@ To be honest, we do not claim to outperform Notion in terms of functionality and
## License
-Distributed under the AGPLv3 License. See `LICENSE.md` for more information.
+Distributed under the AGPLv3 License. See [`LICENSE.md`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/LICENSE) for more information.
## Acknowledgements
diff --git a/frontend/Makefile.toml b/frontend/Makefile.toml
index 332a8e72db..92a2ce040e 100644
--- a/frontend/Makefile.toml
+++ b/frontend/Makefile.toml
@@ -22,7 +22,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
-CURRENT_APP_VERSION = "0.0.5.2"
+CURRENT_APP_VERSION = "0.0.6.2"
FEATURES = "flutter"
PRODUCT_NAME = "AppFlowy"
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
@@ -47,6 +47,7 @@ PROTOBUF_DERIVE_CACHE = "../shared-lib/flowy-derive/src/derive_cache/derive_cach
# Test default config
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "dylib"
+TEST_RUST_LOG = "info"
TEST_BUILD_FLAG = "debug"
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
diff --git a/frontend/app_flowy/android/README.md b/frontend/app_flowy/android/README.md
index a073fde807..52f0dd3e6f 100644
--- a/frontend/app_flowy/android/README.md
+++ b/frontend/app_flowy/android/README.md
@@ -12,8 +12,8 @@ When compiling for android we need the following pre-requisites:
- [Download](https://developer.android.com/ndk/downloads/) Android NDK version 24.
- When downloading Android NDK you can get the compressed version as a standalone from the site.
Or you can download it through [Android Studio](https://developer.android.com/studio).
-- After downloading the two you need to set the environment variables. For Windows that's a seperate process.
- On MacOs and Linux the process is similar.
+- After downloading the two you need to set the environment variables. For Windows that's a separate process.
+ On macOS and Linux the process is similar.
- The variables needed are '$ANDROID_NDK_HOME', this will point to where the NDK is located.
---
@@ -48,9 +48,9 @@ linker = "/home/user/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux
**Folder path: 'Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux'.**
After that you have to copy this file into three different folders namely aarch64, arm, i386 and x86_64.
-We have to do this so we Android NDK can find clang on our system, if we used NDK 22 we wouldnt have to do this process.
-Though using NDK v22 will not give us alot of features to work with.
-This github [issue](https://github.com/fzyzcjy/flutter_rust_bridge/issues/419) explains the reason why we are doing this.
+We have to do this so we Android NDK can find clang on our system, if we used NDK 22 we wouldn't have to do this process.
+Though using NDK v22 will not give us a lot of features to work with.
+This GitHub [issue](https://github.com/fzyzcjy/flutter_rust_bridge/issues/419) explains the reason why we are doing this.
---
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/OFL.txt b/frontend/app_flowy/assets/google_fonts/Poppins/OFL.txt
new file mode 100644
index 0000000000..246c977c9f
--- /dev/null
+++ b/frontend/app_flowy/assets/google_fonts/Poppins/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Black.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Black.ttf
new file mode 100644
index 0000000000..71c0f995ee
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Black.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-BlackItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-BlackItalic.ttf
new file mode 100644
index 0000000000..7aeb58bd1b
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-BlackItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Bold.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Bold.ttf
new file mode 100644
index 0000000000..00559eeb29
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Bold.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-BoldItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-BoldItalic.ttf
new file mode 100644
index 0000000000..e61e8e88bd
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-BoldItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraBold.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraBold.ttf
new file mode 100644
index 0000000000..df7093608a
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraBold.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraBoldItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraBoldItalic.ttf
new file mode 100644
index 0000000000..14d2b375dc
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraBoldItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraLight.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraLight.ttf
new file mode 100644
index 0000000000..e76ec69a65
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraLight.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraLightItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraLightItalic.ttf
new file mode 100644
index 0000000000..89513d9469
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ExtraLightItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Italic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Italic.ttf
new file mode 100644
index 0000000000..12b7b3c40b
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Italic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Light.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Light.ttf
new file mode 100644
index 0000000000..bc36bcc242
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Light.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-LightItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-LightItalic.ttf
new file mode 100644
index 0000000000..9e70be6a9e
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-LightItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Medium.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Medium.ttf
new file mode 100644
index 0000000000..6bcdcc27f2
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Medium.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-MediumItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-MediumItalic.ttf
new file mode 100644
index 0000000000..be67410fd0
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-MediumItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Regular.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Regular.ttf
new file mode 100644
index 0000000000..9f0c71b70a
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Regular.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-SemiBold.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-SemiBold.ttf
new file mode 100644
index 0000000000..74c726e327
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-SemiBold.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-SemiBoldItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-SemiBoldItalic.ttf
new file mode 100644
index 0000000000..3e6c942233
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-SemiBoldItalic.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Thin.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Thin.ttf
new file mode 100644
index 0000000000..03e736613a
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-Thin.ttf differ
diff --git a/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ThinItalic.ttf b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ThinItalic.ttf
new file mode 100644
index 0000000000..e26db5dd3d
Binary files /dev/null and b/frontend/app_flowy/assets/google_fonts/Poppins/Poppins-ThinItalic.ttf differ
diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json
index 2381d5b288..70ebe3245f 100644
--- a/frontend/app_flowy/assets/translations/en.json
+++ b/frontend/app_flowy/assets/translations/en.json
@@ -221,7 +221,7 @@
"menuName": "Grid"
},
"document": {
- "menuName": "Doc",
+ "menuName": "Document",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
@@ -232,4 +232,4 @@
"create_new_card": "New"
}
}
-}
+}
\ No newline at end of file
diff --git a/frontend/app_flowy/assets/translations/fr-FR.json b/frontend/app_flowy/assets/translations/fr-FR.json
index 2de9e63704..0900cafa2f 100644
--- a/frontend/app_flowy/assets/translations/fr-FR.json
+++ b/frontend/app_flowy/assets/translations/fr-FR.json
@@ -221,7 +221,7 @@
"menuName": "Grille"
},
"document": {
- "menuName": "Doc",
+ "menuName": "Document",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
@@ -232,4 +232,4 @@
"create_new_card": "Nouveau"
}
}
-}
+}
\ No newline at end of file
diff --git a/frontend/app_flowy/assets/translations/id-ID.json b/frontend/app_flowy/assets/translations/id-ID.json
index 1239194266..38f4e7d805 100644
--- a/frontend/app_flowy/assets/translations/id-ID.json
+++ b/frontend/app_flowy/assets/translations/id-ID.json
@@ -209,7 +209,7 @@
"menuName": "Grid"
},
"document": {
- "menuName": "Doc",
+ "menuName": "Dokter",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
diff --git a/frontend/app_flowy/assets/translations/pt-BR.json b/frontend/app_flowy/assets/translations/pt-BR.json
index 4bea9c6a3d..65e5879673 100644
--- a/frontend/app_flowy/assets/translations/pt-BR.json
+++ b/frontend/app_flowy/assets/translations/pt-BR.json
@@ -220,10 +220,10 @@
"menuName": "Grade"
},
"document": {
- "menuName": "Doc",
+ "menuName": "Documento",
"date": {
- "timeHintTextInTwelveHour": "12:00 AM",
- "timeHintTextInTwentyFourHour": "12:00"
+ "timeHintTextInTwelveHour": "01:00 PM",
+ "timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
diff --git a/frontend/app_flowy/assets/translations/sv.json b/frontend/app_flowy/assets/translations/sv.json
new file mode 100644
index 0000000000..e6cf4c6ff2
--- /dev/null
+++ b/frontend/app_flowy/assets/translations/sv.json
@@ -0,0 +1,235 @@
+{
+ "appName": "AppFlowy",
+ "defaultUsername": "Jag",
+ "welcomeText": "Välkommen till @:appName",
+ "githubStarText": "Stärnmärk på GitHub",
+ "subscribeNewsletterText": "Prenumerera på nyhetsbrev",
+ "letsGoButtonText": "Kör igång",
+ "title": "Namn",
+ "signUp": {
+ "buttonText": "Registrera dig",
+ "title": "Registrera dig på @:appName",
+ "getStartedText": "Sätt igång",
+ "emptyPasswordError": "Lösenordet kan inte vara tomt",
+ "repeatPasswordEmptyError": "Upprepat lösenord kan inte vara tomt",
+ "unmatchedPasswordError": "Upprepat lösenord är inte samma som det första",
+ "alreadyHaveAnAccount": "Har du redan ett konto?",
+ "emailHint": "E-post",
+ "passwordHint": "Lösenord",
+ "repeatPasswordHint": "Uprepa lösenordet"
+ },
+ "signIn": {
+ "loginTitle": "Logga in till @:appName",
+ "loginButtonText": "Logga in",
+ "buttonText": "Registrering",
+ "forgotPassword": "Glömt lösenordet?",
+ "emailHint": "E-post",
+ "passwordHint": "Lösenord",
+ "dontHaveAnAccount": "Har du inget konto?",
+ "repeatPasswordEmptyError": "Upprepat lösenord kan inte vara tomt",
+ "unmatchedPasswordError": "Upprepat lösenord är inte samma som det första"
+ },
+ "workspace": {
+ "create": "Skapa arbetsyta",
+ "hint": "Arbetsyta",
+ "notFoundError": "Hittade ingen arbetsyta"
+ },
+ "shareAction": {
+ "buttonText": "Dela",
+ "workInProgress": "Kommer snart",
+ "markdown": "Markdown",
+ "copyLink": "Kopiera länk"
+ },
+ "disclosureAction": {
+ "rename": "Byt namn",
+ "delete": "Ta bort",
+ "duplicate": "Klona"
+ },
+ "blankPageTitle": "Tom sida",
+ "newPageText": "Ny sida",
+ "trash": {
+ "text": "Skräp",
+ "restoreAll": "Återställ alla",
+ "deleteAll": "Ta bort alla",
+ "pageHeader": {
+ "fileName": "Filnamn",
+ "lastModified": "Ändrad",
+ "created": "Skapad"
+ }
+ },
+ "deletePagePrompt": {
+ "text": "Denna sida är i skräpmappen",
+ "restore": "Återställ sida",
+ "deletePermanent": "Radera permanent"
+ },
+ "dialogCreatePageNameHint": "Sidnamn",
+ "questionBubble": {
+ "whatsNew": "Vad nytt?",
+ "help": "Hjälp & Support",
+ "debug": {
+ "name": "Felsökningsinfo",
+ "success": "Kopierade felsökningsinfo till urklipp!",
+ "fail": "Kunde inte kopiera felsökningsinfo till urklipp"
+ }
+ },
+ "menuAppHeader": {
+ "addPageTooltip": "Lägg snabbt till en sida inuti",
+ "defaultNewPageName": "Namnlös",
+ "renameDialog": "Byt namn"
+ },
+ "toolbar": {
+ "undo": "Ångra",
+ "redo": "Upprepa",
+ "bold": "Fet",
+ "italic": "Kursiv",
+ "underline": "Understruken",
+ "strike": "Genomstruken",
+ "numList": "Numrerad lista",
+ "bulletList": "Punktlista",
+ "checkList": "Checklista",
+ "inlineCode": "Infogad kod",
+ "quote": "Citatblock",
+ "header": "Rubrik",
+ "highlight": "Färgmarkera"
+ },
+ "tooltip": {
+ "lightMode": "Växla till ljust läge",
+ "darkMode": "Växla till mörkt läge",
+ "openAsPage": "Öppna som sida",
+ "addNewRow": "Lägg till ny rad",
+ "openMenu": "Klicka för att öppna meny"
+ },
+ "sideBar": {
+ "closeSidebar": "Stäng sidofältet",
+ "openSidebar": "Öppna sidofältet"
+ },
+ "notifications": {
+ "export": {
+ "markdown": "Exporterade anteckning till Markdown",
+ "path": "Dokument/flowy"
+ }
+ },
+ "contactsPage": {
+ "title": "Kontakter",
+ "whatsHappening": "Vad händer denna vecka?",
+ "addContact": "Lägg till kontakt",
+ "editContact": "Redigera kontakt"
+ },
+ "button": {
+ "OK": "OK",
+ "Cancel": "Avbryt",
+ "signIn": "Logga in",
+ "signOut": "Logga ut",
+ "complete": "Slutfört",
+ "save": "Spara"
+ },
+ "label": {
+ "welcome": "Välkommen!",
+ "firstName": "Förnamn",
+ "middleName": "Mellannamn",
+ "lastName": "Efternamn",
+ "stepX": "Steg {X}"
+ },
+ "oAuth": {
+ "err": {
+ "failedTitle": "Kan inte ansluta till ditt konto.",
+ "failedMsg": "Tillse att du har slutfört registreringsprocessen i din webbläsare."
+ },
+ "google": {
+ "title": "GOOGLE-inloggning",
+ "instruction1": "För att kunna importera dina Google-kontakter, måste du auktorisera detta program med hjälp av din webbläsare.",
+ "instruction2": "Kopiera den här koden till urklipp genom att klicka på ikonen eller genom att markera texten:",
+ "instruction3": "Gå till följande länk i din webbläsare, och ange ovanstående kod:",
+ "instruction4": "Tryck på nedanstående knapp när du slutfört registreringen:"
+ }
+ },
+ "settings": {
+ "title": "Inställningar",
+ "menu": {
+ "appearance": "Utseende",
+ "language": "Språk",
+ "user": "Användare",
+ "open": "Öppna inställningarna"
+ },
+ "appearance": {
+ "lightLabel": "Ljust läge",
+ "darkLabel": "Mörkt läge"
+ }
+ },
+ "grid": {
+ "settings": {
+ "filter": "Filter",
+ "sortBy": "Sortera efter",
+ "Properties": "Egenskaper",
+ "group": "Grupp"
+ },
+ "field": {
+ "hide": "Dölj",
+ "insertLeft": "Infoga till vänster",
+ "insertRight": "Infoga till höger",
+ "duplicate": "Klona",
+ "delete": "Ta bort",
+ "textFieldName": "Text",
+ "checkboxFieldName": "Checkruta",
+ "dateFieldName": "Datum",
+ "numberFieldName": "Siffror",
+ "singleSelectFieldName": "Välj",
+ "multiSelectFieldName": "Välj flera",
+ "urlFieldName": "URL",
+ "numberFormat": " Sifferformat",
+ "dateFormat": " Datumformat",
+ "includeTime": " Inkludera tid",
+ "dateFormatFriendly": "Månad Dag,År",
+ "dateFormatISO": "År-Månad-Dag",
+ "dateFormatLocal": "Månad/Dag/År",
+ "dateFormatUS": "År/Månad/Dag",
+ "timeFormat": " Tidsformat",
+ "invalidTimeFormat": "Ogiltigt format",
+ "timeFormatTwelveHour": "12-timmars",
+ "timeFormatTwentyFourHour": "24-timmars",
+ "addSelectOption": "Lägg till ett alternativ",
+ "optionTitle": "Alternativ",
+ "addOption": "Lägg till alternativ",
+ "editProperty": "Redigera egenskap",
+ "newColumn": "Ny kolumn",
+ "deleteFieldPromptMessage": "Är du säker? Denna egenskap kommer att raderas."
+ },
+ "row": {
+ "duplicate": "Klona",
+ "delete": "Ta bort",
+ "textPlaceholder": "Tom",
+ "copyProperty": "Kopierade egenskap till urklipp",
+ "count": "Antal",
+ "newRow": "Ny rad"
+ },
+ "selectOption": {
+ "create": "Skapa",
+ "purpleColor": "Purpur",
+ "pinkColor": "Rosa",
+ "lightPinkColor": "Ljusrosa",
+ "orangeColor": "Orange",
+ "yellowColor": "Gul",
+ "limeColor": "Lime",
+ "greenColor": "Grön",
+ "aquaColor": "Vatten",
+ "blueColor": "Blå",
+ "deleteTag": "Ta bort tagg",
+ "colorPanelTitle": "Färger",
+ "panelTitle": "Välj ett alternativ eller skapa ett",
+ "searchOption": "Sök efter ett alternativ"
+ },
+ "menuName": "Tabell"
+ },
+ "document": {
+ "menuName": "Dokument",
+ "date": {
+ "timeHintTextInTwelveHour": "01:00 PM",
+ "timeHintTextInTwentyFourHour": "13:00"
+ }
+ },
+ "board": {
+ "column": {
+ "create_new_card": "Nytt"
+ }
+ }
+}
diff --git a/frontend/app_flowy/lib/core/grid_notification.dart b/frontend/app_flowy/lib/core/grid_notification.dart
index 9a2429a417..7b177d4a65 100644
--- a/frontend/app_flowy/lib/core/grid_notification.dart
+++ b/frontend/app_flowy/lib/core/grid_notification.dart
@@ -9,31 +9,38 @@ import 'package:flowy_sdk/rust_stream.dart';
import 'notification_helper.dart';
// GridPB
-typedef GridNotificationCallback = void Function(GridNotification, Either);
+typedef GridNotificationCallback = void Function(
+ GridDartNotification, Either);
-class GridNotificationParser extends NotificationParser {
- GridNotificationParser({String? id, required GridNotificationCallback callback})
+class GridNotificationParser
+ extends NotificationParser {
+ GridNotificationParser(
+ {String? id, required GridNotificationCallback callback})
: super(
id: id,
callback: callback,
- tyParser: (ty) => GridNotification.valueOf(ty),
+ tyParser: (ty) => GridDartNotification.valueOf(ty),
errorParser: (bytes) => FlowyError.fromBuffer(bytes),
);
}
-typedef GridNotificationHandler = Function(GridNotification ty, Either result);
+typedef GridNotificationHandler = Function(
+ GridDartNotification ty, Either result);
class GridNotificationListener {
StreamSubscription? _subscription;
GridNotificationParser? _parser;
- GridNotificationListener({required String objectId, required GridNotificationHandler handler})
+ GridNotificationListener(
+ {required String objectId, required GridNotificationHandler handler})
: _parser = GridNotificationParser(id: objectId, callback: handler) {
- _subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
+ _subscription =
+ RustStreamReceiver.listen((observable) => _parser?.parse(observable));
}
Future stop() async {
_parser = null;
await _subscription?.cancel();
+ _subscription = null;
}
}
diff --git a/frontend/app_flowy/lib/core/network_monitor.dart b/frontend/app_flowy/lib/core/network_monitor.dart
index ba7806873d..b1398e87fd 100644
--- a/frontend/app_flowy/lib/core/network_monitor.dart
+++ b/frontend/app_flowy/lib/core/network_monitor.dart
@@ -11,7 +11,8 @@ class NetworkListener {
late StreamSubscription _connectivitySubscription;
NetworkListener() {
- _connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
+ _connectivitySubscription =
+ _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
}
Future start() async {
@@ -39,9 +40,11 @@ class NetworkListener {
return NetworkType.Ethernet;
case ConnectivityResult.mobile:
return NetworkType.Cell;
- case ConnectivityResult.none:
- return NetworkType.UnknownNetworkType;
case ConnectivityResult.bluetooth:
+ return NetworkType.Bluetooth;
+ case ConnectivityResult.vpn:
+ return NetworkType.VPN;
+ case ConnectivityResult.none:
return NetworkType.UnknownNetworkType;
}
}();
diff --git a/frontend/app_flowy/lib/plugins/blank/blank.dart b/frontend/app_flowy/lib/plugins/blank/blank.dart
index 7595adefd5..65c3215131 100644
--- a/frontend/app_flowy/lib/plugins/blank/blank.dart
+++ b/frontend/app_flowy/lib/plugins/blank/blank.dart
@@ -15,6 +15,9 @@ class BlankPluginBuilder extends PluginBuilder {
@override
String get menuName => "Blank";
+ @override
+ String get menuIcon => "";
+
@override
PluginType get pluginType => PluginType.blank;
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
index ce72413425..027fa94316 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
@@ -24,7 +24,8 @@ class BoardBloc extends Bloc {
final BoardDataController _gridDataController;
late final AppFlowyBoardController boardController;
final MoveRowFFIService _rowService;
- LinkedHashMap groupControllers = LinkedHashMap();
+ final LinkedHashMap groupControllers =
+ LinkedHashMap();
GridFieldController get fieldController =>
_gridDataController.fieldController;
@@ -69,7 +70,7 @@ class BoardBloc extends Bloc {
await event.when(
initial: () async {
_startListening();
- await _loadGrid(emit);
+ await _openGrid(emit);
},
createBottomRow: (groupId) async {
final startRowId = groupControllers[groupId]?.lastRow()?.id;
@@ -284,8 +285,8 @@ class BoardBloc extends Bloc {
return [...items];
}
- Future _loadGrid(Emitter emit) async {
- final result = await _gridDataController.loadData();
+ Future _openGrid(Emitter emit) async {
+ final result = await _gridDataController.openGrid();
result.fold(
(grid) => emit(
state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
diff --git a/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart b/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart
index 641239e767..7ca035d375 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart
@@ -34,7 +34,8 @@ class BoardDataController {
// key: the block id
final LinkedHashMap _blocks;
- LinkedHashMap get blocks => _blocks;
+ UnmodifiableMapView get blocks =>
+ UnmodifiableMapView(_blocks);
OnFieldsChanged? _onFieldsChanged;
OnGridChanged? _onGridChanged;
@@ -107,21 +108,22 @@ class BoardDataController {
);
}
- Future> loadData() async {
- final result = await _gridFFIService.loadGrid();
+ Future> openGrid() async {
+ final result = await _gridFFIService.openGrid();
return Future(
() => result.fold(
(grid) async {
_onGridChanged?.call(grid);
- return await fieldController.loadFields(fieldIds: grid.fields).then(
- (result) => result.fold(
- (l) {
- _loadGroups(grid.blocks);
- return left(l);
- },
- (err) => right(err),
- ),
- );
+ final result = await fieldController.loadFields(
+ fieldIds: grid.fields,
+ );
+ return result.fold(
+ (l) {
+ _loadGroups(grid.blocks);
+ return left(l);
+ },
+ (err) => right(err),
+ );
},
(err) => right(err),
),
diff --git a/frontend/app_flowy/lib/plugins/board/application/board_listener.dart b/frontend/app_flowy/lib/plugins/board/application/board_listener.dart
index 9f8662fc5b..f8889ade86 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_listener.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_listener.dart
@@ -32,18 +32,18 @@ class BoardListener {
}
void _handler(
- GridNotification ty,
+ GridDartNotification ty,
Either result,
) {
switch (ty) {
- case GridNotification.DidUpdateGroupView:
+ case GridDartNotification.DidUpdateGroupView:
result.fold(
(payload) => _groupUpdateNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload)),
(error) => _groupUpdateNotifier?.value = right(error),
);
break;
- case GridNotification.DidGroupByNewField:
+ case GridDartNotification.DidGroupByNewField:
result.fold(
(payload) => _groupByNewFieldNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload).newGroups),
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_checkbox_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_checkbox_cell_bloc.dart
index c8a0d87f9c..8229fd1588 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_checkbox_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_checkbox_cell_bloc.dart
@@ -35,7 +35,7 @@ class BoardCheckboxCellBloc
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
- cellController.dispose();
+ await cellController.dispose();
return super.close();
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart
index a19d7b64a8..0512fb8bb9 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart
@@ -31,7 +31,7 @@ class BoardDateCellBloc extends Bloc {
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
- cellController.dispose();
+ await cellController.dispose();
return super.close();
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_number_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_number_cell_bloc.dart
index 2cc4882357..4cf0930591 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_number_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_number_cell_bloc.dart
@@ -32,7 +32,7 @@ class BoardNumberCellBloc
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
- cellController.dispose();
+ await cellController.dispose();
return super.close();
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_select_option_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_select_option_cell_bloc.dart
index daa4dcc383..e1c7195117 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_select_option_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_select_option_cell_bloc.dart
@@ -34,7 +34,7 @@ class BoardSelectOptionCellBloc
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
- cellController.dispose();
+ await cellController.dispose();
return super.close();
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart
index 9d1b14c605..7af1757329 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart
@@ -41,7 +41,7 @@ class BoardTextCellBloc extends Bloc {
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
- cellController.dispose();
+ await cellController.dispose();
return super.close();
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_url_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_url_cell_bloc.dart
index 045a1633fa..9494e7ae68 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_url_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_url_cell_bloc.dart
@@ -38,7 +38,7 @@ class BoardURLCellBloc extends Bloc {
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
- cellController.dispose();
+ await cellController.dispose();
return super.close();
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart
index 82372896d1..92461772e2 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart
@@ -66,6 +66,7 @@ class BoardCardBloc extends Bloc {
state.cells.map((cell) => cell.identifier.fieldContext).toList(),
),
rowPB: state.rowPB,
+ visible: true,
);
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/group_controller.dart b/frontend/app_flowy/lib/plugins/board/application/group_controller.dart
index 6a148c0312..8db9fad4fd 100644
--- a/frontend/app_flowy/lib/plugins/board/application/group_controller.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/group_controller.dart
@@ -39,7 +39,7 @@ class GroupController {
void startListening() {
_listener.start(onGroupChanged: (result) {
result.fold(
- (GroupChangesetPB changeset) {
+ (GroupRowsNotificationPB changeset) {
for (final deletedRow in changeset.deletedRows) {
group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
delegate.removeRow(group, deletedRow);
diff --git a/frontend/app_flowy/lib/plugins/board/application/group_listener.dart b/frontend/app_flowy/lib/plugins/board/application/group_listener.dart
index e3b626af07..536cd35f88 100644
--- a/frontend/app_flowy/lib/plugins/board/application/group_listener.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/group_listener.dart
@@ -8,7 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart';
-typedef UpdateGroupNotifiedValue = Either;
+typedef UpdateGroupNotifiedValue = Either;
class GroupListener {
final GroupPB group;
@@ -27,14 +27,14 @@ class GroupListener {
}
void _handler(
- GridNotification ty,
+ GridDartNotification ty,
Either result,
) {
switch (ty) {
- case GridNotification.DidUpdateGroup:
+ case GridDartNotification.DidUpdateGroup:
result.fold(
(payload) => _groupNotifier?.value =
- left(GroupChangesetPB.fromBuffer(payload)),
+ left(GroupRowsNotificationPB.fromBuffer(payload)),
(error) => _groupNotifier?.value = right(error),
);
break;
diff --git a/frontend/app_flowy/lib/plugins/board/board.dart b/frontend/app_flowy/lib/plugins/board/board.dart
index e22677b9eb..2a709023cf 100644
--- a/frontend/app_flowy/lib/plugins/board/board.dart
+++ b/frontend/app_flowy/lib/plugins/board/board.dart
@@ -20,11 +20,14 @@ class BoardPluginBuilder implements PluginBuilder {
@override
String get menuName => "Board";
+ @override
+ String get menuIcon => "editor/board";
+
@override
PluginType get pluginType => PluginType.board;
@override
- ViewDataTypePB get dataType => ViewDataTypePB.Database;
+ ViewDataFormatPB get dataFormatType => ViewDataFormatPB.DatabaseFormat;
@override
ViewLayoutTypePB? get layoutType => ViewLayoutTypePB.Board;
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
index a7f0d90557..ac82d7de29 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
@@ -9,11 +9,9 @@ import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
import 'package:app_flowy/plugins/grid/application/row/row_data_controller.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_detail.dart';
-import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
@@ -22,7 +20,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:provider/provider.dart';
import '../../grid/application/row/row_cache.dart';
import '../application/board_bloc.dart';
import 'card/card.dart';
@@ -102,27 +99,21 @@ class _BoardContentState extends State {
}
Widget _buildBoard(BuildContext context) {
- return ChangeNotifierProvider.value(
- value: Provider.of(context, listen: true),
- child: Selector(
- selector: (ctx, notifier) => notifier.theme,
- builder: (ctx, theme, child) => Expanded(
- child: AppFlowyBoard(
- boardScrollController: scrollManager,
- scrollController: ScrollController(),
- controller: context.read().boardController,
- headerBuilder: _buildHeader,
- footerBuilder: _buildFooter,
- cardBuilder: (_, column, columnItem) => _buildCard(
- context,
- column,
- columnItem,
- ),
- groupConstraints: const BoxConstraints.tightFor(width: 300),
- config: AppFlowyBoardConfig(
- groupBackgroundColor: theme.bg1,
- ),
- ),
+ return Expanded(
+ child: AppFlowyBoard(
+ boardScrollController: scrollManager,
+ scrollController: ScrollController(),
+ controller: context.read().boardController,
+ headerBuilder: _buildHeader,
+ footerBuilder: _buildFooter,
+ cardBuilder: (_, column, columnItem) => _buildCard(
+ context,
+ column,
+ columnItem,
+ ),
+ groupConstraints: const BoxConstraints.tightFor(width: 300),
+ config: AppFlowyBoardConfig(
+ groupBackgroundColor: Theme.of(context).colorScheme.surfaceVariant,
),
),
);
@@ -159,7 +150,6 @@ class _BoardContentState extends State {
groupData.headerData.groupName,
fontSize: 14,
overflow: TextOverflow.clip,
- color: context.read().textColor,
),
),
icon: _buildHeaderIcon(boardCustomData),
@@ -168,7 +158,7 @@ class _BoardContentState extends State {
width: 20,
child: svgWidget(
"home/add",
- color: context.read().iconColor,
+ color: Theme.of(context).colorScheme.onSurface,
),
),
onAddButtonClick: () {
@@ -191,13 +181,12 @@ class _BoardContentState extends State {
width: 20,
child: svgWidget(
"home/add",
- color: context.read().iconColor,
+ color: Theme.of(context).colorScheme.onSurface,
),
),
title: FlowyText.medium(
LocaleKeys.board_column_create_new_card.tr(),
fontSize: 14,
- color: context.read().textColor,
),
height: 50,
margin: config.footerPadding,
@@ -276,10 +265,12 @@ class _BoardContentState extends State {
}
BoxDecoration _makeBoxDecoration(BuildContext context) {
- final theme = context.read();
- final borderSide = BorderSide(color: theme.shader6, width: 1.0);
+ final borderSide = BorderSide(
+ color: Theme.of(context).dividerColor,
+ width: 1.0,
+ );
return BoxDecoration(
- color: theme.surface,
+ color: Theme.of(context).colorScheme.surface,
border: Border.fromBorderSide(borderSide),
borderRadius: const BorderRadius.all(Radius.circular(6)),
);
@@ -296,6 +287,7 @@ class _BoardContentState extends State {
gridId: gridId,
fields: UnmodifiableListView(fieldController.fieldContexts),
rowPB: rowPB,
+ visible: true,
);
final dataController = GridRowDataController(
@@ -329,15 +321,7 @@ class _ToolbarBlocAdaptor extends StatelessWidget {
fieldController: bloc.fieldController,
);
- return ChangeNotifierProvider.value(
- value: Provider.of(context, listen: true),
- child: Selector(
- selector: (ctx, notifier) => notifier.theme,
- builder: (ctx, theme, child) {
- return BoardToolbar(toolbarContext: toolbarContext);
- },
- ),
- );
+ return BoardToolbar(toolbarContext: toolbarContext);
},
);
}
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_date_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_date_cell.dart
index 18c0a84f47..4d62608c45 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_date_cell.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_date_cell.dart
@@ -1,6 +1,5 @@
import 'package:app_flowy/plugins/board/application/card/board_date_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -53,7 +52,7 @@ class _BoardDateCellState extends State {
child: FlowyText.regular(
state.dateStr,
fontSize: 13,
- color: context.read().shader3,
+ color: Theme.of(context).hintColor,
),
),
);
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart
index 3237316c13..f5252a178a 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart
@@ -1,9 +1,11 @@
import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.dart';
+import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'board_cell.dart';
import 'define.dart';
@@ -150,11 +152,7 @@ class _BoardTextCellState extends State {
onChanged: (value) => focusChanged(),
onEditingComplete: () => focusNode.unfocus(),
maxLines: null,
- style: const TextStyle(
- fontSize: 14,
- fontWeight: FontWeight.w500,
- fontFamily: 'Mulish',
- ),
+ style: Theme.of(context).textTheme.bodyMedium!.size(FontSizes.s14),
decoration: InputDecoration(
// Magic number 4 makes the textField take up the same space as FlowyText
contentPadding: EdgeInsets.symmetric(
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_url_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_url_cell.dart
index f5d7dabf79..ab7ce3e84d 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_url_cell.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_url_cell.dart
@@ -1,8 +1,9 @@
import 'package:app_flowy/plugins/board/application/card/board_url_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
-import 'package:flowy_infra/theme.dart';
+import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'define.dart';
@@ -34,7 +35,6 @@ class _BoardUrlCellState extends State {
@override
Widget build(BuildContext context) {
- final theme = context.watch();
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder(
@@ -53,11 +53,12 @@ class _BoardUrlCellState extends State {
textAlign: TextAlign.left,
text: TextSpan(
text: state.content,
- style: TextStyle(
- color: theme.main2,
- fontSize: 14,
- decoration: TextDecoration.underline,
- ),
+ style: Theme.of(context)
+ .textTheme
+ .bodyMedium!
+ .size(FontSizes.s14)
+ .textColor(Theme.of(context).colorScheme.primary)
+ .underline,
),
),
),
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart
index bf1143523a..6dab2af136 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart
@@ -3,7 +3,6 @@ import 'package:app_flowy/plugins/board/application/card/card_data_controller.da
import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_action_sheet.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -221,8 +220,10 @@ class _CardMoreOption extends StatelessWidget with CardAccessory {
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(3.0),
- child:
- svgWidget('grid/details', color: context.read().iconColor),
+ child: svgWidget(
+ 'grid/details',
+ color: Theme.of(context).colorScheme.onSurface,
+ ),
);
}
@@ -243,7 +244,7 @@ class _CardEditOption extends StatelessWidget with CardAccessory {
padding: const EdgeInsets.all(3.0),
child: svgWidget(
'editor/edit',
- color: context.read().iconColor,
+ color: Theme.of(context).colorScheme.onSurface,
),
);
}
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/container/accessory.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/container/accessory.dart
index 0052e0e29c..9b7ce2c63b 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/card/container/accessory.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/card/container/accessory.dart
@@ -1,7 +1,5 @@
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
enum AccessoryType {
edit,
@@ -28,7 +26,6 @@ class CardAccessoryContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final theme = context.read();
final children = accessories.map((accessory) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
@@ -36,17 +33,16 @@ class CardAccessoryContainer extends StatelessWidget {
accessory.onTap(context);
onTapAccessory(accessory.type);
},
- child: _wrapHover(theme, accessory),
+ child: _wrapHover(context, accessory),
);
}).toList();
return _wrapDecoration(context, Row(children: children));
}
- FlowyHover _wrapHover(AppTheme theme, CardAccessory accessory) {
+ FlowyHover _wrapHover(BuildContext context, CardAccessory accessory) {
return FlowyHover(
style: HoverStyle(
- hoverColor: theme.hover,
- backgroundColor: theme.surface,
+ backgroundColor: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.zero,
),
builder: (_, onHover) => SizedBox(
@@ -58,8 +54,10 @@ class CardAccessoryContainer extends StatelessWidget {
}
Widget _wrapDecoration(BuildContext context, Widget child) {
- final theme = context.read();
- final borderSide = BorderSide(color: theme.shader6, width: 1.0);
+ final borderSide = BorderSide(
+ color: Theme.of(context).dividerColor,
+ width: 1.0,
+ );
final decoration = BoxDecoration(
color: Colors.transparent,
border: Border.fromBorderSide(borderSide),
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_setting.dart b/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_setting.dart
index b02cd0fc95..e583986edf 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_setting.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_setting.dart
@@ -7,7 +7,7 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_propert
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.dart';
+import 'package:flowy_infra/size.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';
@@ -95,7 +95,6 @@ class _SettingItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final theme = context.read();
final isSelected = context
.read()
.state
@@ -108,16 +107,17 @@ class _SettingItem extends StatelessWidget {
isSelected: isSelected,
text: FlowyText.medium(
action.title(),
- fontSize: 12,
- color: theme.textColor,
+ fontSize: FontSizes.s12,
),
- hoverColor: theme.hover,
onTap: () {
context
.read()
.add(BoardSettingEvent.performAction(action));
},
- leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
+ leftIcon: svgWidget(
+ action.iconName(),
+ color: Theme.of(context).colorScheme.onSurface,
+ ),
),
);
}
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_toolbar.dart b/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_toolbar.dart
index f20dcd6aa0..fd00193f19 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_toolbar.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_toolbar.dart
@@ -1,11 +1,9 @@
import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
-import 'package:flutter/widgets.dart';
-import 'package:provider/provider.dart';
+import 'package:flutter/material.dart';
import 'board_setting.dart';
@@ -61,16 +59,17 @@ class _SettingButtonState extends State<_SettingButton> {
@override
Widget build(BuildContext context) {
- final theme = context.read();
return AppFlowyPopover(
controller: popoverController,
constraints: BoxConstraints.loose(const Size(260, 400)),
child: FlowyIconButton(
- hoverColor: theme.hover,
width: 22,
icon: Padding(
padding: const EdgeInsets.symmetric(vertical: 3.0, horizontal: 3.0),
- child: svgWidget("grid/setting/setting", color: theme.iconColor),
+ child: svgWidget(
+ "grid/setting/setting",
+ color: Theme.of(context).colorScheme.onSurface,
+ ),
),
),
popupBuilder: (BuildContext popoverContext) {
diff --git a/frontend/app_flowy/lib/plugins/doc/application/share_service.dart b/frontend/app_flowy/lib/plugins/doc/application/share_service.dart
deleted file mode 100644
index 75d045199b..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/application/share_service.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'dart:async';
-import 'package:dartz/dartz.dart';
-import 'package:flowy_sdk/dispatch/dispatch.dart';
-import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-document/protobuf.dart';
-
-class ShareService {
- Future> export(
- String docId, ExportType type) {
- final request = ExportPayloadPB.create()
- ..viewId = docId
- ..exportType = type;
-
- return DocumentEventExportDocument(request).send();
- }
-
- Future> exportText(String docId) {
- return export(docId, ExportType.Text);
- }
-
- Future> exportMarkdown(String docId) {
- return export(docId, ExportType.Markdown);
- }
-
- Future> exportURL(String docId) {
- return export(docId, ExportType.Link);
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/style_widgets.dart b/frontend/app_flowy/lib/plugins/doc/presentation/style_widgets.dart
deleted file mode 100644
index 8bbd5bc0d0..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/style_widgets.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-import 'package:flowy_infra/image.dart';
-import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/style_widget/icon_button.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_quill/flutter_quill.dart';
-
-class StyleWidgetBuilder {
- static QuillCheckboxBuilder checkbox(AppTheme theme) {
- return EditorCheckboxBuilder(theme);
- }
-}
-
-class EditorCheckboxBuilder extends QuillCheckboxBuilder {
- final AppTheme theme;
-
- EditorCheckboxBuilder(this.theme);
-
- @override
- Widget build(
- {required BuildContext context,
- required bool isChecked,
- required ValueChanged onChanged}) {
- return FlowyEditorCheckbox(
- theme: theme,
- isChecked: isChecked,
- onChanged: onChanged,
- );
- }
-}
-
-class FlowyEditorCheckbox extends StatefulWidget {
- final bool isChecked;
- final ValueChanged onChanged;
- final AppTheme theme;
- const FlowyEditorCheckbox({
- required this.theme,
- required this.isChecked,
- required this.onChanged,
- Key? key,
- }) : super(key: key);
-
- @override
- FlowyEditorCheckboxState createState() => FlowyEditorCheckboxState();
-}
-
-class FlowyEditorCheckboxState extends State {
- late bool isChecked;
-
- @override
- void initState() {
- isChecked = widget.isChecked;
- super.initState();
- }
-
- @override
- Widget build(BuildContext context) {
- final icon = isChecked
- ? svgWidget('editor/editor_check')
- : svgWidget('editor/editor_uncheck');
- return Align(
- alignment: Alignment.centerLeft,
- child: FlowyIconButton(
- onPressed: () {
- isChecked = !isChecked;
- widget.onChanged(isChecked);
- setState(() {});
- },
- iconPadding: EdgeInsets.zero,
- icon: icon,
- width: 23,
- ),
- );
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/check_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/check_button.dart
deleted file mode 100644
index 280209c64a..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/check_button.dart
+++ /dev/null
@@ -1,97 +0,0 @@
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter_quill/models/documents/style.dart';
-import 'package:flutter/material.dart';
-
-import 'toolbar_icon_button.dart';
-
-class FlowyCheckListButton extends StatefulWidget {
- const FlowyCheckListButton({
- required this.controller,
- required this.attribute,
- required this.tooltipText,
- this.iconSize = defaultIconSize,
- this.fillColor,
- this.childBuilder = defaultToggleStyleButtonBuilder,
- Key? key,
- }) : super(key: key);
-
- final double iconSize;
-
- final Color? fillColor;
-
- final QuillController controller;
-
- final ToggleStyleButtonBuilder childBuilder;
-
- final Attribute attribute;
-
- final String tooltipText;
-
- @override
- FlowyCheckListButtonState createState() => FlowyCheckListButtonState();
-}
-
-class FlowyCheckListButtonState extends State {
- bool? _isToggled;
-
- Style get _selectionStyle => widget.controller.getSelectionStyle();
-
- void _didChangeEditingValue() {
- setState(() {
- _isToggled =
- _getIsToggled(widget.controller.getSelectionStyle().attributes);
- });
- }
-
- @override
- void initState() {
- super.initState();
- _isToggled = _getIsToggled(_selectionStyle.attributes);
- widget.controller.addListener(_didChangeEditingValue);
- }
-
- bool _getIsToggled(Map attrs) {
- if (widget.attribute.key == Attribute.list.key) {
- final attribute = attrs[widget.attribute.key];
- if (attribute == null) {
- return false;
- }
- return attribute.value == widget.attribute.value ||
- attribute.value == Attribute.checked.value;
- }
- return attrs.containsKey(widget.attribute.key);
- }
-
- @override
- void didUpdateWidget(covariant FlowyCheckListButton oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.controller != widget.controller) {
- oldWidget.controller.removeListener(_didChangeEditingValue);
- widget.controller.addListener(_didChangeEditingValue);
- _isToggled = _getIsToggled(_selectionStyle.attributes);
- }
- }
-
- @override
- void dispose() {
- widget.controller.removeListener(_didChangeEditingValue);
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- return ToolbarIconButton(
- onPressed: _toggleAttribute,
- width: widget.iconSize * kIconButtonFactor,
- iconName: 'editor/checkbox',
- isToggled: _isToggled ?? false,
- tooltipText: widget.tooltipText,
- );
- }
-
- void _toggleAttribute() {
- widget.controller.formatSelection(_isToggled!
- ? Attribute.clone(Attribute.unchecked, null)
- : Attribute.unchecked);
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/color_picker.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/color_picker.dart
deleted file mode 100644
index 1f262483a8..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/color_picker.dart
+++ /dev/null
@@ -1,280 +0,0 @@
-import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter_quill/models/documents/style.dart';
-import 'package:flutter_quill/utils/color.dart';
-import 'package:app_flowy/generated/locale_keys.g.dart';
-import 'package:easy_localization/easy_localization.dart';
-import 'toolbar_icon_button.dart';
-
-class FlowyColorButton extends StatefulWidget {
- const FlowyColorButton({
- required this.icon,
- required this.controller,
- required this.background,
- this.iconSize = defaultIconSize,
- this.iconTheme,
- Key? key,
- }) : super(key: key);
-
- final IconData icon;
- final double iconSize;
- final bool background;
- final QuillController controller;
- final QuillIconTheme? iconTheme;
-
- @override
- FlowyColorButtonState createState() => FlowyColorButtonState();
-}
-
-class FlowyColorButtonState extends State {
- late bool _isToggledColor;
- late bool _isToggledBackground;
- late bool _isWhite;
- late bool _isWhitebackground;
-
- Style get _selectionStyle => widget.controller.getSelectionStyle();
-
- void _didChangeEditingValue() {
- setState(() {
- _isToggledColor =
- _getIsToggledColor(widget.controller.getSelectionStyle().attributes);
- _isToggledBackground = _getIsToggledBackground(
- widget.controller.getSelectionStyle().attributes);
- _isWhite = _isToggledColor &&
- _selectionStyle.attributes['color']!.value == '#ffffff';
- _isWhitebackground = _isToggledBackground &&
- _selectionStyle.attributes['background']!.value == '#ffffff';
- });
- }
-
- @override
- void initState() {
- super.initState();
- _isToggledColor = _getIsToggledColor(_selectionStyle.attributes);
- _isToggledBackground = _getIsToggledBackground(_selectionStyle.attributes);
- _isWhite = _isToggledColor &&
- _selectionStyle.attributes['color']!.value == '#ffffff';
- _isWhitebackground = _isToggledBackground &&
- _selectionStyle.attributes['background']!.value == '#ffffff';
- widget.controller.addListener(_didChangeEditingValue);
- }
-
- bool _getIsToggledColor(Map attrs) {
- return attrs.containsKey(Attribute.color.key);
- }
-
- bool _getIsToggledBackground(Map attrs) {
- return attrs.containsKey(Attribute.background.key);
- }
-
- @override
- void didUpdateWidget(covariant FlowyColorButton oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.controller != widget.controller) {
- oldWidget.controller.removeListener(_didChangeEditingValue);
- widget.controller.addListener(_didChangeEditingValue);
- _isToggledColor = _getIsToggledColor(_selectionStyle.attributes);
- _isToggledBackground =
- _getIsToggledBackground(_selectionStyle.attributes);
- _isWhite = _isToggledColor &&
- _selectionStyle.attributes['color']!.value == '#ffffff';
- _isWhitebackground = _isToggledBackground &&
- _selectionStyle.attributes['background']!.value == '#ffffff';
- }
- }
-
- @override
- void dispose() {
- widget.controller.removeListener(_didChangeEditingValue);
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
-
- final fillColor = _isToggledColor && !widget.background && _isWhite
- ? stringToColor('#ffffff')
- : (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor);
- final fillColorBackground =
- _isToggledBackground && widget.background && _isWhitebackground
- ? stringToColor('#ffffff')
- : (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor);
-
- return Tooltip(
- message: LocaleKeys.toolbar_highlight.tr(),
- showDuration: Duration.zero,
- child: QuillIconButton(
- highlightElevation: 0,
- hoverElevation: 0,
- size: widget.iconSize * kIconButtonFactor,
- icon: Icon(widget.icon,
- size: widget.iconSize, color: theme.iconTheme.color),
- fillColor: widget.background ? fillColorBackground : fillColor,
- onPressed: _showColorPicker,
- ),
- );
- }
-
- void _changeColor(BuildContext context, Color color) {
- var hex = color.value.toRadixString(16);
- if (hex.startsWith('ff')) {
- hex = hex.substring(2);
- }
- hex = '#$hex';
- widget.controller.formatSelection(
- widget.background ? BackgroundAttribute(hex) : ColorAttribute(hex));
- Navigator.of(context).pop();
- }
-
- void _showColorPicker() {
- final style = widget.controller.getSelectionStyle();
- final values = style.values
- .where((v) => v.key == Attribute.background.key)
- .map((v) => v.value);
- int initialColor = 0;
- if (values.isNotEmpty) {
- assert(values.length == 1);
- initialColor = stringToHex(values.first);
- }
-
- StyledDialog(
- child: SingleChildScrollView(
- child: FlowyColorPicker(
- onColorChanged: (color) {
- if (color == null) {
- widget.controller.formatSelection(BackgroundAttribute(null));
- Navigator.of(context).pop();
- } else {
- _changeColor(context, color);
- }
- },
- initialColor: initialColor,
- ),
- ),
- ).show(context);
- }
-}
-
-int stringToHex(String code) {
- return int.parse(code.substring(1, 7), radix: 16) + 0xFF000000;
-}
-
-class FlowyColorPicker extends StatefulWidget {
- final List colors = [
- 0xffe8e0ff,
- 0xffffe7fd,
- 0xffffe7ee,
- 0xffffefe3,
- 0xfffff2cd,
- 0xfff5ffdc,
- 0xffddffd6,
- 0xffdefff1,
- ];
- final Function(Color?) onColorChanged;
- final int initialColor;
- FlowyColorPicker(
- {Key? key, required this.onColorChanged, this.initialColor = 0})
- : super(key: key);
-
- @override
- State createState() => _FlowyColorPickerState();
-}
-
-// if (shrinkWrap) {
-// innerContent = IntrinsicWidth(child: IntrinsicHeight(child: innerContent));
-// }
-class _FlowyColorPickerState extends State {
- @override
- Widget build(BuildContext context) {
- const double width = 480;
- const int crossAxisCount = 6;
- const double mainAxisSpacing = 10;
- const double crossAxisSpacing = 10;
- final numberOfRows = (widget.colors.length / crossAxisCount).ceil();
-
- const perRowHeight =
- ((width - ((crossAxisCount - 1) * mainAxisSpacing)) / crossAxisCount);
- final totalHeight =
- numberOfRows * perRowHeight + numberOfRows * crossAxisSpacing;
-
- return Container(
- constraints: BoxConstraints.tightFor(width: width, height: totalHeight),
- child: CustomScrollView(
- scrollDirection: Axis.vertical,
- controller: ScrollController(),
- physics: const ClampingScrollPhysics(),
- slivers: [
- SliverGrid(
- gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: crossAxisCount,
- mainAxisSpacing: mainAxisSpacing,
- crossAxisSpacing: crossAxisSpacing,
- childAspectRatio: 1.0,
- ),
- delegate: SliverChildBuilderDelegate(
- (BuildContext context, int index) {
- if (widget.colors.length > index) {
- final isSelected =
- widget.colors[index] == widget.initialColor;
- return ColorItem(
- color: Color(widget.colors[index]),
- onPressed: widget.onColorChanged,
- isSelected: isSelected,
- );
- } else {
- return null;
- }
- },
- childCount: widget.colors.length,
- ),
- ),
- ],
- ),
- );
- }
-}
-
-class ColorItem extends StatelessWidget {
- final Function(Color?) onPressed;
- final bool isSelected;
- final Color color;
- const ColorItem({
- Key? key,
- required this.color,
- required this.onPressed,
- this.isSelected = false,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- if (!isSelected) {
- return RawMaterialButton(
- onPressed: () {
- onPressed(color);
- },
- elevation: 0,
- hoverElevation: 0.6,
- fillColor: color,
- shape: const CircleBorder(),
- );
- } else {
- return RawMaterialButton(
- shape: const CircleBorder(
- side: BorderSide(color: Colors.white, width: 8)) +
- CircleBorder(side: BorderSide(color: color, width: 4)),
- onPressed: () {
- if (isSelected) {
- onPressed(null);
- } else {
- onPressed(color);
- }
- },
- elevation: 1.0,
- hoverElevation: 0.6,
- fillColor: color,
- );
- }
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/header_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/header_button.dart
deleted file mode 100644
index 2db98b5af0..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/header_button.dart
+++ /dev/null
@@ -1,101 +0,0 @@
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter_quill/models/documents/style.dart';
-import 'package:flutter/material.dart';
-import 'package:app_flowy/generated/locale_keys.g.dart';
-import 'package:easy_localization/easy_localization.dart';
-import 'toolbar_icon_button.dart';
-
-class FlowyHeaderStyleButton extends StatefulWidget {
- const FlowyHeaderStyleButton({
- required this.controller,
- this.iconSize = defaultIconSize,
- Key? key,
- }) : super(key: key);
-
- final QuillController controller;
- final double iconSize;
-
- @override
- FlowyHeaderStyleButtonState createState() => FlowyHeaderStyleButtonState();
-}
-
-class FlowyHeaderStyleButtonState extends State {
- Attribute? _value;
-
- Style get _selectionStyle => widget.controller.getSelectionStyle();
-
- @override
- void initState() {
- super.initState();
- setState(() {
- _value =
- _selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
- });
- widget.controller.addListener(_didChangeEditingValue);
- }
-
- @override
- Widget build(BuildContext context) {
- final valueToText = {
- Attribute.h1: 'H1',
- Attribute.h2: 'H2',
- Attribute.h3: 'H3',
- };
-
- final valueAttribute = [
- Attribute.h1,
- Attribute.h2,
- Attribute.h3
- ];
- final valueString = ['H1', 'H2', 'H3'];
- final attributeImageName = ['editor/H1', 'editor/H2', 'editor/H3'];
-
- return Row(
- mainAxisSize: MainAxisSize.min,
- children: List.generate(3, (index) {
- // final child =
- // _valueToText[_value] == _valueString[index] ? svg('editor/H1', color: Colors.white) : svg('editor/H1');
-
- final headerTitle = "${LocaleKeys.toolbar_header.tr()} ${index + 1}";
- final isToggled = valueToText[_value] == valueString[index];
- return ToolbarIconButton(
- onPressed: () {
- if (isToggled) {
- widget.controller.formatSelection(Attribute.header);
- } else {
- widget.controller.formatSelection(valueAttribute[index]);
- }
- },
- width: widget.iconSize * kIconButtonFactor,
- iconName: attributeImageName[index],
- isToggled: isToggled,
- tooltipText: headerTitle,
- );
- }),
- );
- }
-
- void _didChangeEditingValue() {
- setState(() {
- _value =
- _selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
- });
- }
-
- @override
- void didUpdateWidget(covariant FlowyHeaderStyleButton oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.controller != widget.controller) {
- oldWidget.controller.removeListener(_didChangeEditingValue);
- widget.controller.addListener(_didChangeEditingValue);
- _value =
- _selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
- }
- }
-
- @override
- void dispose() {
- widget.controller.removeListener(_didChangeEditingValue);
- super.dispose();
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/history_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/history_button.dart
deleted file mode 100644
index fbe85f40dd..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/history_button.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_quill/flutter_quill.dart';
-
-class FlowyHistoryButton extends StatelessWidget {
- final IconData icon;
- final double iconSize;
- final bool undo;
- final QuillController controller;
- final String tooltipText;
-
- const FlowyHistoryButton({
- required this.icon,
- required this.controller,
- required this.undo,
- required this.tooltipText,
- required this.iconSize,
- Key? key,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return Tooltip(
- message: tooltipText,
- showDuration: Duration.zero,
- child: HistoryButton(
- icon: icon,
- iconSize: iconSize,
- controller: controller,
- undo: undo,
- ),
- );
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/image_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/image_button.dart
deleted file mode 100644
index 1a18ef10f1..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/image_button.dart
+++ /dev/null
@@ -1,85 +0,0 @@
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter/material.dart';
-import 'toolbar_icon_button.dart';
-
-class FlowyImageButton extends StatelessWidget {
- const FlowyImageButton({
- required this.controller,
- required this.tooltipText,
- this.iconSize = defaultIconSize,
- this.onImagePickCallback,
- this.fillColor,
- this.filePickImpl,
- this.webImagePickImpl,
- this.mediaPickSettingSelector,
- Key? key,
- }) : super(key: key);
-
- final double iconSize;
-
- final Color? fillColor;
-
- final QuillController controller;
-
- final OnImagePickCallback? onImagePickCallback;
-
- final WebImagePickImpl? webImagePickImpl;
-
- final FilePickImpl? filePickImpl;
-
- final MediaPickSettingSelector? mediaPickSettingSelector;
-
- final String tooltipText;
-
- @override
- Widget build(BuildContext context) {
- return ToolbarIconButton(
- iconName: 'editor/image',
- width: iconSize * 1.77,
- onPressed: () => _onPressedHandler(context),
- isToggled: false,
- tooltipText: tooltipText,
- );
- }
-
- Future _onPressedHandler(BuildContext context) async {
- // if (onImagePickCallback != null) {
- // final selector = mediaPickSettingSelector ?? ImageVideoUtils.selectMediaPickSetting;
- // final source = await selector(context);
- // if (source != null) {
- // if (source == MediaPickSetting.Gallery) {
- // _pickImage(context);
- // } else {
- // _typeLink(context);
- // }
- // }
- // } else {
- // _typeLink(context);
- // }
- }
-
- // void _pickImage(BuildContext context) => ImageVideoUtils.handleImageButtonTap(
- // context,
- // controller,
- // ImageSource.gallery,
- // onImagePickCallback!,
- // filePickImpl: filePickImpl,
- // webImagePickImpl: webImagePickImpl,
- // );
-
- // void _typeLink(BuildContext context) {
- // TextFieldDialog(
- // title: 'URL',
- // value: "",
- // confirm: (newValue) {
- // if (newValue.isEmpty) {
- // return;
- // }
- // final index = controller.selection.baseOffset;
- // final length = controller.selection.extentOffset - index;
-
- // controller.replaceText(index, length, BlockEmbed.image(newValue), null);
- // },
- // ).show(context);
- // }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/link_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/link_button.dart
deleted file mode 100644
index 22c9f108ec..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/link_button.dart
+++ /dev/null
@@ -1,98 +0,0 @@
-import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flowy_infra/image.dart';
-import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/style_widget/icon_button.dart';
-import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-
-import 'toolbar_icon_button.dart';
-
-class FlowyLinkStyleButton extends StatefulWidget {
- const FlowyLinkStyleButton({
- required this.controller,
- this.iconSize = defaultIconSize,
- Key? key,
- }) : super(key: key);
-
- final QuillController controller;
- final double iconSize;
-
- @override
- FlowyLinkStyleButtonState createState() => FlowyLinkStyleButtonState();
-}
-
-class FlowyLinkStyleButtonState extends State {
- void _didChangeSelection() {
- setState(() {});
- }
-
- @override
- void initState() {
- super.initState();
- widget.controller.addListener(_didChangeSelection);
- }
-
- @override
- void didUpdateWidget(covariant FlowyLinkStyleButton oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.controller != widget.controller) {
- oldWidget.controller.removeListener(_didChangeSelection);
- widget.controller.addListener(_didChangeSelection);
- }
- }
-
- @override
- void dispose() {
- super.dispose();
- widget.controller.removeListener(_didChangeSelection);
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = context.watch();
- final isEnabled = !widget.controller.selection.isCollapsed;
- final pressedHandler = isEnabled ? () => _openLinkDialog(context) : null;
- final icon = isEnabled
- ? svgWidget(
- 'editor/share',
- color: theme.iconColor,
- )
- : svgWidget(
- 'editor/share',
- color: theme.disableIconColor,
- );
-
- return FlowyIconButton(
- onPressed: pressedHandler,
- iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
- icon: icon,
- fillColor: theme.shader6,
- hoverColor: theme.shader5,
- width: widget.iconSize * kIconButtonFactor,
- );
- }
-
- void _openLinkDialog(BuildContext context) {
- final style = widget.controller.getSelectionStyle();
- final values = style.values
- .where((v) => v.key == Attribute.link.key)
- .map((v) => v.value);
- String value = "";
- if (values.isNotEmpty) {
- assert(values.length == 1);
- value = values.first;
- }
-
- NavigatorTextFieldDialog(
- title: 'URL',
- value: value,
- confirm: (newValue) {
- if (newValue.isEmpty) {
- return;
- }
- widget.controller.formatSelection(LinkAttribute(newValue));
- },
- ).show(context);
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/toggle_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/toggle_button.dart
deleted file mode 100644
index 2ecb98c3ea..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/toggle_button.dart
+++ /dev/null
@@ -1,84 +0,0 @@
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter_quill/models/documents/style.dart';
-import 'package:flutter/material.dart';
-
-import 'toolbar_icon_button.dart';
-
-class FlowyToggleStyleButton extends StatefulWidget {
- final Attribute attribute;
- final String normalIcon;
- final double iconSize;
- final QuillController controller;
- final String tooltipText;
-
- const FlowyToggleStyleButton({
- required this.attribute,
- required this.normalIcon,
- required this.controller,
- required this.tooltipText,
- this.iconSize = defaultIconSize,
- Key? key,
- }) : super(key: key);
-
- @override
- ToggleStyleButtonState createState() => ToggleStyleButtonState();
-}
-
-class ToggleStyleButtonState extends State {
- bool? _isToggled;
- Style get _selectionStyle => widget.controller.getSelectionStyle();
- @override
- void initState() {
- super.initState();
- _isToggled = _getIsToggled(_selectionStyle.attributes);
- widget.controller.addListener(_didChangeEditingValue);
- }
-
- @override
- Widget build(BuildContext context) {
- return ToolbarIconButton(
- onPressed: _toggleAttribute,
- width: widget.iconSize * kIconButtonFactor,
- isToggled: _isToggled ?? false,
- iconName: widget.normalIcon,
- tooltipText: widget.tooltipText,
- );
- }
-
- @override
- void didUpdateWidget(covariant FlowyToggleStyleButton oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.controller != widget.controller) {
- oldWidget.controller.removeListener(_didChangeEditingValue);
- widget.controller.addListener(_didChangeEditingValue);
- _isToggled = _getIsToggled(_selectionStyle.attributes);
- }
- }
-
- @override
- void dispose() {
- widget.controller.removeListener(_didChangeEditingValue);
- super.dispose();
- }
-
- void _didChangeEditingValue() {
- setState(() => _isToggled = _getIsToggled(_selectionStyle.attributes));
- }
-
- bool _getIsToggled(Map attrs) {
- if (widget.attribute.key == Attribute.list.key) {
- final attribute = attrs[widget.attribute.key];
- if (attribute == null) {
- return false;
- }
- return attribute.value == widget.attribute.value;
- }
- return attrs.containsKey(widget.attribute.key);
- }
-
- void _toggleAttribute() {
- widget.controller.formatSelection(_isToggled!
- ? Attribute.clone(widget.attribute, null)
- : widget.attribute);
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/tool_bar.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/tool_bar.dart
deleted file mode 100644
index d649340066..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/tool_bar.dart
+++ /dev/null
@@ -1,308 +0,0 @@
-import 'dart:async';
-import 'dart:math';
-
-import 'package:app_flowy/workspace/presentation/widgets/emoji_picker/emoji_picker.dart';
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter/material.dart';
-import 'package:styled_widget/styled_widget.dart';
-import 'check_button.dart';
-import 'color_picker.dart';
-import 'header_button.dart';
-import 'history_button.dart';
-import 'link_button.dart';
-import 'toggle_button.dart';
-import 'toolbar_icon_button.dart';
-import 'package:app_flowy/generated/locale_keys.g.dart';
-
-class EditorToolbar extends StatelessWidget implements PreferredSizeWidget {
- final List children;
- final double toolBarHeight;
- final Color? color;
-
- const EditorToolbar({
- required this.children,
- this.toolBarHeight = 46,
- this.color,
- Key? key,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return Container(
- color: Theme.of(context).canvasColor,
- constraints: BoxConstraints.tightFor(height: preferredSize.height),
- child: ToolbarButtonList(buttons: children)
- .padding(horizontal: 4, vertical: 4),
- );
- }
-
- @override
- Size get preferredSize => Size.fromHeight(toolBarHeight);
-
- factory EditorToolbar.basic({
- required QuillController controller,
- double toolbarIconSize = defaultIconSize,
- OnImagePickCallback? onImagePickCallback,
- OnVideoPickCallback? onVideoPickCallback,
- MediaPickSettingSelector? mediaPickSettingSelector,
- FilePickImpl? filePickImpl,
- WebImagePickImpl? webImagePickImpl,
- WebVideoPickImpl? webVideoPickImpl,
- Key? key,
- }) {
- return EditorToolbar(
- key: key,
- toolBarHeight: toolbarIconSize * 2,
- children: [
- FlowyHistoryButton(
- icon: Icons.undo_outlined,
- iconSize: toolbarIconSize,
- controller: controller,
- undo: true,
- tooltipText: LocaleKeys.toolbar_undo.tr(),
- ),
- FlowyHistoryButton(
- icon: Icons.redo_outlined,
- iconSize: toolbarIconSize,
- controller: controller,
- undo: false,
- tooltipText: LocaleKeys.toolbar_redo.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.bold,
- normalIcon: 'editor/bold',
- iconSize: toolbarIconSize,
- controller: controller,
- tooltipText: LocaleKeys.toolbar_bold.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.italic,
- normalIcon: 'editor/italic',
- iconSize: toolbarIconSize,
- controller: controller,
- tooltipText: LocaleKeys.toolbar_italic.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.underline,
- normalIcon: 'editor/underline',
- iconSize: toolbarIconSize,
- controller: controller,
- tooltipText: LocaleKeys.toolbar_underline.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.strikeThrough,
- normalIcon: 'editor/strikethrough',
- iconSize: toolbarIconSize,
- controller: controller,
- tooltipText: LocaleKeys.toolbar_strike.tr(),
- ),
- FlowyColorButton(
- icon: Icons.format_color_fill,
- iconSize: toolbarIconSize,
- controller: controller,
- background: true,
- ),
- // FlowyImageButton(
- // iconSize: toolbarIconSize,
- // controller: controller,
- // onImagePickCallback: onImagePickCallback,
- // filePickImpl: filePickImpl,
- // webImagePickImpl: webImagePickImpl,
- // mediaPickSettingSelector: mediaPickSettingSelector,
- // ),
- FlowyHeaderStyleButton(
- controller: controller,
- iconSize: toolbarIconSize,
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.ol,
- controller: controller,
- normalIcon: 'editor/numbers',
- iconSize: toolbarIconSize,
- tooltipText: LocaleKeys.toolbar_numList.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.ul,
- controller: controller,
- normalIcon: 'editor/bullet_list',
- iconSize: toolbarIconSize,
- tooltipText: LocaleKeys.toolbar_bulletList.tr(),
- ),
- FlowyCheckListButton(
- attribute: Attribute.unchecked,
- controller: controller,
- iconSize: toolbarIconSize,
- tooltipText: LocaleKeys.toolbar_checkList.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.inlineCode,
- controller: controller,
- normalIcon: 'editor/inline_block',
- iconSize: toolbarIconSize,
- tooltipText: LocaleKeys.toolbar_inlineCode.tr(),
- ),
- FlowyToggleStyleButton(
- attribute: Attribute.blockQuote,
- controller: controller,
- normalIcon: 'editor/quote',
- iconSize: toolbarIconSize,
- tooltipText: LocaleKeys.toolbar_quote.tr(),
- ),
- FlowyLinkStyleButton(
- controller: controller,
- iconSize: toolbarIconSize,
- ),
- FlowyEmojiStyleButton(
- normalIcon: 'editor/insert_emoticon',
- controller: controller,
- tooltipText: "Emoji Picker",
- ),
- ],
- );
- }
-}
-
-class ToolbarButtonList extends StatefulWidget {
- const ToolbarButtonList({required this.buttons, Key? key}) : super(key: key);
-
- final List buttons;
-
- @override
- ToolbarButtonListState createState() => ToolbarButtonListState();
-}
-
-class ToolbarButtonListState extends State
- with WidgetsBindingObserver {
- final ScrollController _controller = ScrollController();
- bool _showLeftArrow = false;
- bool _showRightArrow = false;
-
- @override
- void initState() {
- super.initState();
- _controller.addListener(_handleScroll);
-
- // Listening to the WidgetsBinding instance is necessary so that we can
- // hide the arrows when the window gets a new size and thus the toolbar
- // becomes scrollable/unscrollable.
- WidgetsBinding.instance.addObserver(this);
-
- // Workaround to allow the scroll controller attach to our ListView so that
- // we can detect if overflow arrows need to be shown on init.
- Timer.run(_handleScroll);
- }
-
- @override
- Widget build(BuildContext context) {
- return LayoutBuilder(
- builder: (BuildContext context, BoxConstraints constraints) {
- List children = [];
- double width =
- (widget.buttons.length + 2) * defaultIconSize * kIconButtonFactor;
- final isFit = constraints.maxWidth > width;
- if (!isFit) {
- children.add(_buildLeftArrow());
- width = width + 18;
- }
-
- children.add(_buildScrollableList(constraints, isFit));
-
- if (!isFit) {
- children.add(_buildRightArrow());
- width = width + 18;
- }
-
- return SizedBox(
- width: min(constraints.maxWidth, width),
- child: Row(
- children: children,
- ),
- );
- },
- );
- }
-
- @override
- void didChangeMetrics() => _handleScroll();
-
- @override
- void dispose() {
- _controller.dispose();
- WidgetsBinding.instance.removeObserver(this);
- super.dispose();
- }
-
- void _handleScroll() {
- if (!mounted) return;
- setState(() {
- _showLeftArrow =
- _controller.position.minScrollExtent != _controller.position.pixels;
- _showRightArrow =
- _controller.position.maxScrollExtent != _controller.position.pixels;
- });
- }
-
- Widget _buildLeftArrow() {
- return SizedBox(
- width: 8,
- child: Transform.translate(
- // Move the icon a few pixels to center it
- offset: const Offset(-5, 0),
- child: _showLeftArrow ? const Icon(Icons.arrow_left, size: 18) : null,
- ),
- );
- }
-
- // [[sliver: https://medium.com/flutter/slivers-demystified-6ff68ab0296f]]
- Widget _buildScrollableList(BoxConstraints constraints, bool isFit) {
- Widget child = Expanded(
- child: CustomScrollView(
- scrollDirection: Axis.horizontal,
- controller: _controller,
- physics: const ClampingScrollPhysics(),
- slivers: [
- SliverList(
- delegate: SliverChildBuilderDelegate(
- (BuildContext context, int index) {
- return widget.buttons[index];
- },
- childCount: widget.buttons.length,
- addAutomaticKeepAlives: false,
- ),
- )
- ],
- ),
- );
-
- if (!isFit) {
- child = ScrollConfiguration(
- // Remove the glowing effect, as we already have the arrow indicators
- behavior: _NoGlowBehavior(),
- // The CustomScrollView is necessary so that the children are not
- // stretched to the height of the toolbar, https://bit.ly/3uC3bjI
- child: child,
- );
- }
-
- return child;
- }
-
- Widget _buildRightArrow() {
- return SizedBox(
- width: 8,
- child: Transform.translate(
- // Move the icon a few pixels to center it
- offset: const Offset(-5, 0),
- child: _showRightArrow ? const Icon(Icons.arrow_right, size: 18) : null,
- ),
- );
- }
-}
-
-class _NoGlowBehavior extends ScrollBehavior {
- @override
- Widget buildViewportChrome(BuildContext _, Widget child, AxisDirection __) {
- return child;
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/toolbar_icon_button.dart b/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/toolbar_icon_button.dart
deleted file mode 100644
index aac5b5a4b1..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/presentation/toolbar/toolbar_icon_button.dart
+++ /dev/null
@@ -1,38 +0,0 @@
-import 'package:flowy_infra/image.dart';
-import 'package:flowy_infra_ui/style_widget/icon_button.dart';
-import 'package:flutter/material.dart';
-import 'package:flowy_infra/theme.dart';
-import 'package:provider/provider.dart';
-
-const double defaultIconSize = 18;
-
-class ToolbarIconButton extends StatelessWidget {
- final double width;
- final VoidCallback? onPressed;
- final bool isToggled;
- final String iconName;
- final String tooltipText;
-
- const ToolbarIconButton({
- Key? key,
- required this.onPressed,
- required this.isToggled,
- required this.width,
- required this.iconName,
- required this.tooltipText,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- final theme = context.watch();
- return FlowyIconButton(
- iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
- onPressed: onPressed,
- width: width,
- icon: isToggled == true ? svgWidget(iconName, color: Colors.white) : svgWidget(iconName, color: theme.iconColor),
- fillColor: isToggled == true ? theme.main1 : theme.shader6,
- hoverColor: isToggled == true ? theme.main1 : theme.hover,
- tooltipText: tooltipText,
- );
- }
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/styles.dart b/frontend/app_flowy/lib/plugins/doc/styles.dart
deleted file mode 100644
index d3dee3f97a..0000000000
--- a/frontend/app_flowy/lib/plugins/doc/styles.dart
+++ /dev/null
@@ -1,133 +0,0 @@
-import 'package:app_flowy/plugins/doc/presentation/style_widgets.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_quill/flutter_quill.dart';
-import 'package:provider/provider.dart';
-import 'package:tuple/tuple.dart';
-import 'package:flowy_infra/theme.dart';
-
-DefaultStyles customStyles(BuildContext context) {
- const baseSpacing = Tuple2(6, 0);
-
- final theme = context.watch();
- final themeData = theme.themeData;
- final fontFamily = makeFontFamily(themeData);
-
- final defaultTextStyle = DefaultTextStyle.of(context);
- final baseStyle = defaultTextStyle.style.copyWith(
- fontSize: 18,
- height: 1.3,
- fontWeight: FontWeight.w300,
- letterSpacing: 0.6,
- fontFamily: fontFamily,
- );
-
- return DefaultStyles(
- h1: DefaultTextBlockStyle(
- defaultTextStyle.style.copyWith(
- fontSize: 34,
- color: defaultTextStyle.style.color!.withOpacity(0.70),
- height: 1.15,
- fontWeight: FontWeight.w300,
- ),
- const Tuple2(16, 0),
- const Tuple2(0, 0),
- null),
- h2: DefaultTextBlockStyle(
- defaultTextStyle.style.copyWith(
- fontSize: 24,
- color: defaultTextStyle.style.color!.withOpacity(0.70),
- height: 1.15,
- fontWeight: FontWeight.normal,
- ),
- const Tuple2(8, 0),
- const Tuple2(0, 0),
- null),
- h3: DefaultTextBlockStyle(
- defaultTextStyle.style.copyWith(
- fontSize: 20,
- color: defaultTextStyle.style.color!.withOpacity(0.70),
- height: 1.25,
- fontWeight: FontWeight.w500,
- ),
- const Tuple2(8, 0),
- const Tuple2(0, 0),
- null),
- paragraph: DefaultTextBlockStyle(
- baseStyle, const Tuple2(10, 0), const Tuple2(0, 0), null),
- bold: const TextStyle(fontWeight: FontWeight.bold),
- italic: const TextStyle(fontStyle: FontStyle.italic),
- small: const TextStyle(fontSize: 12, color: Colors.black45),
- underline: const TextStyle(decoration: TextDecoration.underline),
- strikeThrough: const TextStyle(decoration: TextDecoration.lineThrough),
- inlineCode: TextStyle(
- color: Colors.blue.shade900.withOpacity(0.9),
- fontFamily: fontFamily,
- fontSize: 13,
- ),
- link: TextStyle(
- color: themeData.colorScheme.secondary,
- decoration: TextDecoration.underline,
- ),
- color: theme.textColor,
- placeHolder: DefaultTextBlockStyle(
- defaultTextStyle.style.copyWith(
- fontSize: 20,
- height: 1.5,
- color: Colors.grey.withOpacity(0.6),
- ),
- const Tuple2(0, 0),
- const Tuple2(0, 0),
- null),
- lists: DefaultListBlockStyle(baseStyle, baseSpacing, const Tuple2(0, 6),
- null, StyleWidgetBuilder.checkbox(theme)),
- quote: DefaultTextBlockStyle(
- TextStyle(color: baseStyle.color!.withOpacity(0.6)),
- baseSpacing,
- const Tuple2(6, 2),
- BoxDecoration(
- border: Border(
- left: BorderSide(width: 4, color: theme.shader5),
- ),
- )),
- code: DefaultTextBlockStyle(
- TextStyle(
- color: Colors.blue.shade900.withOpacity(0.9),
- fontFamily: fontFamily,
- fontSize: 13,
- height: 1.15,
- ),
- baseSpacing,
- const Tuple2(0, 0),
- BoxDecoration(
- color: Colors.grey.shade50,
- borderRadius: BorderRadius.circular(2),
- )),
- indent: DefaultTextBlockStyle(
- baseStyle, baseSpacing, const Tuple2(0, 6), null),
- align: DefaultTextBlockStyle(
- baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null),
- leading: DefaultTextBlockStyle(
- baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null),
- sizeSmall: const TextStyle(fontSize: 10),
- sizeLarge: const TextStyle(fontSize: 18),
- sizeHuge: const TextStyle(fontSize: 22));
-}
-
-String makeFontFamily(ThemeData themeData) {
- String fontFamily;
- switch (themeData.platform) {
- case TargetPlatform.iOS:
- case TargetPlatform.macOS:
- fontFamily = 'Mulish';
- break;
- case TargetPlatform.android:
- case TargetPlatform.fuchsia:
- case TargetPlatform.windows:
- case TargetPlatform.linux:
- fontFamily = 'Roboto Mono';
- break;
- default:
- throw UnimplementedError();
- }
- return fontFamily;
-}
diff --git a/frontend/app_flowy/lib/plugins/doc/application/doc_bloc.dart b/frontend/app_flowy/lib/plugins/document/application/doc_bloc.dart
similarity index 52%
rename from frontend/app_flowy/lib/plugins/doc/application/doc_bloc.dart
rename to frontend/app_flowy/lib/plugins/document/application/doc_bloc.dart
index 89c87db455..322f253447 100644
--- a/frontend/app_flowy/lib/plugins/doc/application/doc_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/document/application/doc_bloc.dart
@@ -1,11 +1,12 @@
import 'dart:convert';
import 'package:app_flowy/plugins/trash/application/trash_service.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart';
-import 'package:app_flowy/plugins/doc/application/doc_service.dart';
+import 'package:app_flowy/plugins/document/application/doc_service.dart';
+import 'package:appflowy_editor/appflowy_editor.dart'
+ show EditorState, Document, Transaction;
import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
-import 'package:flutter_quill/flutter_quill.dart' show Document, Delta;
import 'package:flowy_sdk/log.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@@ -14,27 +15,26 @@ import 'dart:async';
part 'doc_bloc.freezed.dart';
-typedef FlutterQuillDocument = Document;
-
class DocumentBloc extends Bloc {
final ViewPB view;
- final DocumentService service;
+ final DocumentService _documentService;
- final ViewListener listener;
- final TrashService trashService;
- late FlutterQuillDocument document;
+ final ViewListener _listener;
+ final TrashService _trashService;
+ late EditorState editorState;
StreamSubscription? _subscription;
DocumentBloc({
required this.view,
- required this.service,
- required this.listener,
- required this.trashService,
- }) : super(DocumentState.initial()) {
+ }) : _documentService = DocumentService(),
+ _listener = ViewListener(view: view),
+ _trashService = TrashService(),
+ super(DocumentState.initial()) {
on((event, emit) async {
await event.map(
initial: (Initial value) async {
await _initial(value, emit);
+ _listenOnViewChange();
},
deleted: (Deleted value) async {
emit(state.copyWith(isDeleted: true));
@@ -43,7 +43,7 @@ class DocumentBloc extends Bloc {
emit(state.copyWith(isDeleted: false));
},
deletePermanently: (DeletePermanently value) async {
- final result = await trashService
+ final result = await _trashService
.deleteViews([Tuple2(view.id, TrashType.TrashView)]);
final newState = result.fold(
@@ -51,7 +51,7 @@ class DocumentBloc extends Bloc {
emit(newState);
},
restorePage: (RestorePage value) async {
- final result = await trashService.putback(view.id);
+ final result = await _trashService.putback(view.id);
final newState = result.fold(
(l) => state.copyWith(isDeleted: false), (r) => state);
emit(newState);
@@ -62,18 +62,41 @@ class DocumentBloc extends Bloc {
@override
Future close() async {
- await listener.stop();
+ await _listener.stop();
if (_subscription != null) {
await _subscription?.cancel();
}
- await service.closeDocument(docId: view.id);
+ await _documentService.closeDocument(docId: view.id);
return super.close();
}
Future _initial(Initial value, Emitter emit) async {
- listener.start(
+ final result = await _documentService.openDocument(view: view);
+ result.fold(
+ (block) {
+ final document = Document.fromJson(jsonDecode(block.snapshot));
+ editorState = EditorState(document: document);
+ _listenOnDocumentChange();
+ emit(
+ state.copyWith(
+ loadingState: DocumentLoadingState.finish(left(unit)),
+ ),
+ );
+ },
+ (err) {
+ emit(
+ state.copyWith(
+ loadingState: DocumentLoadingState.finish(right(err)),
+ ),
+ );
+ },
+ );
+ }
+
+ void _listenOnViewChange() {
+ _listener.start(
onViewDeleted: (result) {
result.fold(
(view) => add(const DocumentEvent.deleted()),
@@ -87,46 +110,20 @@ class DocumentBloc extends Bloc {
);
},
);
- final result = await service.openDocument(docId: view.id);
- result.fold(
- (block) {
- document = _decodeJsonToDocument(block.snapshot);
- _subscription = document.changes.listen((event) {
- final delta = event.item2;
- final documentDelta = document.toDelta();
- _composeDelta(delta, documentDelta);
- });
- emit(state.copyWith(
- loadingState: DocumentLoadingState.finish(left(unit))));
- },
- (err) {
- emit(state.copyWith(
- loadingState: DocumentLoadingState.finish(right(err))));
- },
- );
}
- // Document _decodeListToDocument(Uint8List data) {
- // final json = jsonDecode(utf8.decode(data));
- // final document = Document.fromJson(json);
- // return document;
- // }
-
- void _composeDelta(Delta composedDelta, Delta documentDelta) async {
- final json = jsonEncode(composedDelta.toJson());
- Log.debug("doc_id: $view.id - Send json: $json");
- final result = await service.applyEdit(docId: view.id, data: json);
-
- result.fold(
- (_) {},
- (r) => Log.error(r),
- );
- }
-
- Document _decodeJsonToDocument(String data) {
- final json = jsonDecode(data);
- final document = Document.fromJson(json);
- return document;
+ void _listenOnDocumentChange() {
+ _subscription = editorState.transactionStream.listen((transaction) {
+ final json = jsonEncode(TransactionAdaptor(transaction).toJson());
+ _documentService
+ .applyEdit(docId: view.id, operations: json)
+ .then((result) {
+ result.fold(
+ (l) => null,
+ (err) => Log.error(err),
+ );
+ });
+ });
}
}
@@ -160,3 +157,44 @@ class DocumentLoadingState with _$DocumentLoadingState {
const factory DocumentLoadingState.finish(
Either successOrFail) = _Finish;
}
+
+/// Uses to erase the different between appflowy editor and the backend
+class TransactionAdaptor {
+ final Transaction transaction;
+ TransactionAdaptor(this.transaction);
+
+ Map toJson() {
+ final json = {};
+ if (transaction.operations.isNotEmpty) {
+ // The backend uses [0,0] as the beginning path, but the editor uses [0].
+ // So it needs to extend the path by inserting `0` at the head for all
+ // operations before passing to the backend.
+ json['operations'] = transaction.operations
+ .map((e) => e.copyWith(path: [0, ...e.path]).toJson())
+ .toList();
+ }
+ if (transaction.afterSelection != null) {
+ final selection = transaction.afterSelection!;
+ final start = selection.start;
+ final end = selection.end;
+ json['after_selection'] = selection
+ .copyWith(
+ start: start.copyWith(path: [0, ...start.path]),
+ end: end.copyWith(path: [0, ...end.path]),
+ )
+ .toJson();
+ }
+ if (transaction.beforeSelection != null) {
+ final selection = transaction.beforeSelection!;
+ final start = selection.start;
+ final end = selection.end;
+ json['before_selection'] = selection
+ .copyWith(
+ start: start.copyWith(path: [0, ...start.path]),
+ end: end.copyWith(path: [0, ...end.path]),
+ )
+ .toJson();
+ }
+ return json;
+ }
+}
diff --git a/frontend/app_flowy/lib/plugins/doc/application/doc_service.dart b/frontend/app_flowy/lib/plugins/document/application/doc_service.dart
similarity index 63%
rename from frontend/app_flowy/lib/plugins/doc/application/doc_service.dart
rename to frontend/app_flowy/lib/plugins/document/application/doc_service.dart
index 3a6797837f..c967221c9c 100644
--- a/frontend/app_flowy/lib/plugins/doc/application/doc_service.dart
+++ b/frontend/app_flowy/lib/plugins/document/application/doc_service.dart
@@ -3,28 +3,35 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-sync/document.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart';
class DocumentService {
Future> openDocument({
- required String docId,
+ required ViewPB view,
}) async {
- await FolderEventSetLatestView(ViewIdPB(value: docId)).send();
+ await FolderEventSetLatestView(ViewIdPB(value: view.id)).send();
+
+ final payload = OpenDocumentContextPB()
+ ..documentId = view.id
+ ..documentVersion = DocumentVersionPB.V1;
+ // switch (view.dataFormat) {
+ // case ViewDataFormatPB.DeltaFormat:
+ // payload.documentVersion = DocumentVersionPB.V0;
+ // break;
+ // default:
+ // break;
+ // }
- final payload = DocumentIdPB(value: docId);
return DocumentEventGetDocument(payload).send();
}
Future> applyEdit({
required String docId,
- required String data,
- String operations = "",
+ required String operations,
}) {
final payload = EditPayloadPB.create()
..docId = docId
- ..operations = operations
- ..operationsStr = data;
+ ..operations = operations;
return DocumentEventApplyEdit(payload).send();
}
diff --git a/frontend/app_flowy/lib/plugins/doc/application/prelude.dart b/frontend/app_flowy/lib/plugins/document/application/prelude.dart
similarity index 100%
rename from frontend/app_flowy/lib/plugins/doc/application/prelude.dart
rename to frontend/app_flowy/lib/plugins/document/application/prelude.dart
diff --git a/frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart b/frontend/app_flowy/lib/plugins/document/application/share_bloc.dart
similarity index 56%
rename from frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart
rename to frontend/app_flowy/lib/plugins/document/application/share_bloc.dart
index fa7dbb761a..c74cdb8471 100644
--- a/frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/document/application/share_bloc.dart
@@ -1,14 +1,14 @@
-import 'dart:async';
+import 'dart:convert';
import 'dart:io';
-import 'package:app_flowy/startup/tasks/rust_sdk.dart';
-import 'package:app_flowy/workspace/application/markdown/delta_markdown.dart';
-import 'package:app_flowy/plugins/doc/application/share_service.dart';
+import 'package:app_flowy/plugins/document/application/share_service.dart';
import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart';
+import 'package:appflowy_editor/appflowy_editor.dart'
+ show Document, documentToMarkdown;
part 'share_bloc.freezed.dart';
class DocShareBloc extends Bloc {
@@ -18,11 +18,14 @@ class DocShareBloc extends Bloc {
: super(const DocShareState.initial()) {
on((event, emit) async {
await event.map(
- shareMarkdown: (ShareMarkdown value) async {
- await service.exportMarkdown(view.id).then((result) {
+ shareMarkdown: (ShareMarkdown shareMarkdown) async {
+ await service.exportMarkdown(view).then((result) {
result.fold(
(value) => emit(
- DocShareState.finish(left(_convertDeltaToMarkdown(value)))),
+ DocShareState.finish(
+ left(_saveMarkdown(value, shareMarkdown.path)),
+ ),
+ ),
(error) => emit(DocShareState.finish(right(error))),
);
});
@@ -35,38 +38,23 @@ class DocShareBloc extends Bloc {
});
}
- ExportDataPB _convertDeltaToMarkdown(ExportDataPB value) {
- final result = deltaToMarkdown(value.data);
- value.data = result;
- writeFile(result);
+ ExportDataPB _saveMarkdown(ExportDataPB value, String path) {
+ final markdown = _convertDocumentToMarkdown(value);
+ value.data = markdown;
+ File(path).writeAsStringSync(markdown);
return value;
}
- Future get _exportDir async {
- Directory documentsDir = await appFlowyDocumentDirectory();
-
- return documentsDir;
- }
-
- Future get _localPath async {
- final dir = await _exportDir;
- return dir.path;
- }
-
- Future get _localFile async {
- final path = await _localPath;
- return File('$path/${view.name}.md');
- }
-
- Future writeFile(String md) async {
- final file = await _localFile;
- return file.writeAsString(md);
+ String _convertDocumentToMarkdown(ExportDataPB value) {
+ final json = jsonDecode(value.data);
+ final document = Document.fromJson(json);
+ return documentToMarkdown(document);
}
}
@freezed
class DocShareEvent with _$DocShareEvent {
- const factory DocShareEvent.shareMarkdown() = ShareMarkdown;
+ const factory DocShareEvent.shareMarkdown(String path) = ShareMarkdown;
const factory DocShareEvent.shareText() = ShareText;
const factory DocShareEvent.shareLink() = ShareLink;
}
diff --git a/frontend/app_flowy/lib/plugins/document/application/share_service.dart b/frontend/app_flowy/lib/plugins/document/application/share_service.dart
new file mode 100644
index 0000000000..5bb0ef0d4d
--- /dev/null
+++ b/frontend/app_flowy/lib/plugins/document/application/share_service.dart
@@ -0,0 +1,30 @@
+import 'dart:async';
+import 'package:dartz/dartz.dart';
+import 'package:flowy_sdk/dispatch/dispatch.dart';
+import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-document/protobuf.dart';
+import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
+
+class ShareService {
+ Future> export(
+ ViewPB view, ExportType type) {
+ var payload = ExportPayloadPB.create()
+ ..viewId = view.id
+ ..exportType = type
+ ..documentVersion = DocumentVersionPB.V1;
+
+ return DocumentEventExportDocument(payload).send();
+ }
+
+ Future> exportText(ViewPB view) {
+ return export(view, ExportType.Text);
+ }
+
+ Future> exportMarkdown(ViewPB view) {
+ return export(view, ExportType.Markdown);
+ }
+
+ Future> exportURL(ViewPB view) {
+ return export(view, ExportType.Link);
+ }
+}
diff --git a/frontend/app_flowy/lib/plugins/doc/document.dart b/frontend/app_flowy/lib/plugins/document/document.dart
similarity index 81%
rename from frontend/app_flowy/lib/plugins/doc/document.dart
rename to frontend/app_flowy/lib/plugins/document/document.dart
index 55296f7831..9ad6107dcf 100644
--- a/frontend/app_flowy/lib/plugins/doc/document.dart
+++ b/frontend/app_flowy/lib/plugins/document/document.dart
@@ -4,8 +4,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugins/util.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart';
-import 'package:app_flowy/workspace/application/appearance.dart';
-import 'package:app_flowy/plugins/doc/application/share_bloc.dart';
+import 'package:app_flowy/plugins/document/application/share_bloc.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart';
import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
@@ -14,8 +13,8 @@ import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:clipboard/clipboard.dart';
import 'package:easy_localization/easy_localization.dart';
+import 'package:file_picker/file_picker.dart';
import 'package:flowy_infra/size.dart';
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@@ -23,7 +22,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:provider/provider.dart';
import 'document_page.dart';
@@ -40,11 +38,14 @@ class DocumentPluginBuilder extends PluginBuilder {
@override
String get menuName => LocaleKeys.document_menuName.tr();
+ @override
+ String get menuIcon => "editor/documents";
+
@override
PluginType get pluginType => PluginType.editor;
@override
- ViewDataTypePB get dataType => ViewDataTypePB.Text;
+ ViewDataFormatPB get dataFormatType => ViewDataFormatPB.TreeFormat;
}
class DocumentPlugin extends Plugin {
@@ -128,21 +129,13 @@ class DocumentShareButton extends StatelessWidget {
);
},
child: BlocBuilder(
- builder: (context, state) {
- return ChangeNotifierProvider.value(
- value: Provider.of(context, listen: true),
- child: Selector(
- selector: (ctx, notifier) => notifier.locale,
- builder: (ctx, _, child) => ConstrainedBox(
- constraints: const BoxConstraints.expand(
- height: 30,
- width: 100,
- ),
- child: const ShareActionList(),
- ),
- ),
- );
- },
+ builder: (context, state) => ConstrainedBox(
+ constraints: const BoxConstraints.expand(
+ height: 30,
+ width: 100,
+ ),
+ child: ShareActionList(view: view),
+ ),
),
),
);
@@ -165,11 +158,16 @@ class DocumentShareButton extends StatelessWidget {
}
class ShareActionList extends StatelessWidget {
- const ShareActionList({Key? key}) : super(key: key);
+ const ShareActionList({
+ Key? key,
+ required this.view,
+ }) : super(key: key);
+
+ final ViewPB view;
@override
Widget build(BuildContext context) {
- final theme = context.watch();
+ final docShareBloc = context.read();
return PopoverActionList(
direction: PopoverDirection.bottomWithCenterAligned,
actions: ShareAction.values
@@ -178,20 +176,23 @@ class ShareActionList extends StatelessWidget {
buildChild: (controller) {
return RoundedTextButton(
title: LocaleKeys.shareAction_buttonText.tr(),
- fontSize: 12,
+ fontSize: FontSizes.s12,
borderRadius: Corners.s6Border,
- color: theme.main1,
+ color: Theme.of(context).colorScheme.primary,
onPressed: () => controller.show(),
);
},
- onSelected: (action, controller) {
+ onSelected: (action, controller) async {
switch (action.inner) {
case ShareAction.markdown:
- context
- .read()
- .add(const DocShareEvent.shareMarkdown());
- showMessageToast(
- 'Exported to: ${LocaleKeys.notifications_export_path.tr()}');
+ final exportPath = await FilePicker.platform.saveFile(
+ dialogTitle: '',
+ fileName: '${view.name}.md',
+ );
+ if (exportPath != null) {
+ docShareBloc.add(DocShareEvent.shareMarkdown(exportPath));
+ showMessageToast('Exported to: $exportPath');
+ }
break;
case ShareAction.copyLink:
NavigatorAlertDialog(
diff --git a/frontend/app_flowy/lib/plugins/doc/document_page.dart b/frontend/app_flowy/lib/plugins/document/document_page.dart
similarity index 52%
rename from frontend/app_flowy/lib/plugins/doc/document_page.dart
rename to frontend/app_flowy/lib/plugins/document/document_page.dart
index 8593766087..cc4b31f582 100644
--- a/frontend/app_flowy/lib/plugins/doc/document_page.dart
+++ b/frontend/app_flowy/lib/plugins/document/document_page.dart
@@ -1,17 +1,14 @@
+import 'package:app_flowy/plugins/document/editor_styles.dart';
+import 'package:app_flowy/plugins/document/presentation/plugins/horizontal_rule_node_widget.dart';
import 'package:app_flowy/startup/startup.dart';
-import 'package:app_flowy/workspace/application/appearance.dart';
-import 'package:app_flowy/plugins/doc/presentation/banner.dart';
-import 'package:app_flowy/plugins/doc/presentation/toolbar/tool_bar.dart';
-import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
-import 'package:flowy_infra_ui/widget/spacing.dart';
-import 'package:flutter_quill/flutter_quill.dart' as quill;
+import 'package:app_flowy/plugins/document/presentation/banner.dart';
+import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:provider/provider.dart';
+import 'package:intl/intl.dart';
import 'application/doc_bloc.dart';
-import 'styles.dart';
class DocumentPage extends StatefulWidget {
final VoidCallback onDeleted;
@@ -29,11 +26,12 @@ class DocumentPage extends StatefulWidget {
class _DocumentPageState extends State {
late DocumentBloc documentBloc;
- final scrollController = ScrollController();
final FocusNode _focusNode = FocusNode();
@override
void initState() {
+ // The appflowy editor use Intl as localization, set the default language as fallback.
+ Intl.defaultLocale = 'en_US';
documentBloc = getIt(param1: super.widget.view)
..add(const DocumentEvent.initial());
super.initState();
@@ -48,9 +46,9 @@ class _DocumentPageState extends State {
child:
BlocBuilder(builder: (context, state) {
return state.loadingState.map(
- // loading: (_) => const FlowyProgressIndicator(),
- loading: (_) =>
- SizedBox.expand(child: Container(color: Colors.transparent)),
+ loading: (_) => SizedBox.expand(
+ child: Container(color: Colors.transparent),
+ ),
finish: (result) => result.successOrFail.fold(
(_) {
if (state.forceClose) {
@@ -75,23 +73,12 @@ class _DocumentPageState extends State {
}
Widget _renderDocument(BuildContext context, DocumentState state) {
- quill.QuillController controller = quill.QuillController(
- document: context.read().document,
- selection: const TextSelection.collapsed(offset: 0),
- );
return Column(
children: [
if (state.isDeleted) _renderBanner(context),
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- _renderEditor(controller),
- const VSpace(10),
- _renderToolbar(controller),
- const VSpace(10),
- ],
- ),
+ // AppFlowy Editor
+ _renderAppFlowyEditor(
+ context.read().editorState,
),
],
);
@@ -107,36 +94,26 @@ class _DocumentPageState extends State {
);
}
- Widget _renderEditor(quill.QuillController controller) {
- final editor = quill.QuillEditor(
- controller: controller,
- focusNode: _focusNode,
- scrollable: true,
- paintCursorAboveText: true,
- autoFocus: controller.document.isEmpty(),
- expands: false,
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
- readOnly: false,
- scrollBottomInset: 0,
- scrollController: scrollController,
- customStyles: customStyles(context),
+ Widget _renderAppFlowyEditor(EditorState editorState) {
+ final theme = Theme.of(context);
+ final editor = AppFlowyEditor(
+ editorState: editorState,
+ autoFocus: editorState.document.isEmpty,
+ customBuilders: {
+ 'horizontal_rule': HorizontalRuleWidgetBuilder(),
+ },
+ shortcutEvents: [
+ insertHorizontalRule,
+ ],
+ themeData: theme.copyWith(extensions: [
+ ...theme.extensions.values,
+ customEditorTheme(context),
+ ...customPluginTheme(context),
+ ]),
);
-
return Expanded(
- child: ScrollbarListStack(
- axis: Axis.vertical,
- controller: scrollController,
- barSize: 6.0,
- child: SizedBox.expand(child: editor),
- ),
- );
- }
-
- Widget _renderToolbar(quill.QuillController controller) {
- return ChangeNotifierProvider.value(
- value: Provider.of(context, listen: true),
- child: EditorToolbar.basic(
- controller: controller,
+ child: SizedBox.expand(
+ child: editor,
),
);
}
diff --git a/frontend/app_flowy/lib/plugins/document/editor_styles.dart b/frontend/app_flowy/lib/plugins/document/editor_styles.dart
new file mode 100644
index 0000000000..00cbcb473e
--- /dev/null
+++ b/frontend/app_flowy/lib/plugins/document/editor_styles.dart
@@ -0,0 +1,65 @@
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:flutter/material.dart';
+
+const _baseFontSize = 14.0;
+
+EditorStyle customEditorTheme(BuildContext context) {
+ var editorStyle = Theme.of(context).brightness == Brightness.dark
+ ? EditorStyle.dark
+ : EditorStyle.light;
+ editorStyle = editorStyle.copyWith(
+ textStyle: editorStyle.textStyle?.copyWith(
+ fontFamily: 'poppins',
+ fontSize: _baseFontSize,
+ ),
+ placeholderTextStyle: editorStyle.placeholderTextStyle?.copyWith(
+ fontFamily: 'poppins',
+ fontSize: _baseFontSize,
+ ),
+ bold: editorStyle.bold?.copyWith(
+ fontWeight: FontWeight.w500,
+ ),
+ backgroundColor: Theme.of(context).colorScheme.surface,
+ );
+ return editorStyle;
+}
+
+Iterable> customPluginTheme(BuildContext context) {
+ const basePadding = 12.0;
+ var headingPluginStyle = Theme.of(context).brightness == Brightness.dark
+ ? HeadingPluginStyle.dark
+ : HeadingPluginStyle.light;
+ headingPluginStyle = headingPluginStyle.copyWith(
+ textStyle: (EditorState editorState, Node node) {
+ final headingToFontSize = {
+ 'h1': _baseFontSize + 12,
+ 'h2': _baseFontSize + 8,
+ 'h3': _baseFontSize + 4,
+ 'h4': _baseFontSize,
+ 'h5': _baseFontSize,
+ 'h6': _baseFontSize,
+ };
+ final fontSize =
+ headingToFontSize[node.attributes.heading] ?? _baseFontSize;
+ return TextStyle(fontSize: fontSize, fontWeight: FontWeight.w600);
+ },
+ padding: (EditorState editorState, Node node) {
+ final headingToPadding = {
+ 'h1': basePadding + 6,
+ 'h2': basePadding + 4,
+ 'h3': basePadding + 2,
+ 'h4': basePadding,
+ 'h5': basePadding,
+ 'h6': basePadding,
+ };
+ final padding = headingToPadding[node.attributes.heading] ?? basePadding;
+ return EdgeInsets.only(bottom: padding);
+ },
+ );
+ final pluginTheme = Theme.of(context).brightness == Brightness.dark
+ ? darkPlguinStyleExtension
+ : lightPlguinStyleExtension;
+ return pluginTheme.toList()
+ ..removeWhere((element) => element is HeadingPluginStyle)
+ ..add(headingPluginStyle);
+}
diff --git a/frontend/app_flowy/lib/plugins/doc/presentation/banner.dart b/frontend/app_flowy/lib/plugins/document/presentation/banner.dart
similarity index 72%
rename from frontend/app_flowy/lib/plugins/doc/presentation/banner.dart
rename to frontend/app_flowy/lib/plugins/document/presentation/banner.dart
index 66c1f6dfba..bfa5130f21 100644
--- a/frontend/app_flowy/lib/plugins/doc/presentation/banner.dart
+++ b/frontend/app_flowy/lib/plugins/document/presentation/banner.dart
@@ -1,11 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
-import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/buttons/base_styled_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
class DocumentBanner extends StatelessWidget {
@@ -17,12 +15,11 @@ class DocumentBanner extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final theme = context.watch();
return ConstrainedBox(
constraints: const BoxConstraints(minHeight: 60),
child: Container(
width: double.infinity,
- color: theme.main1,
+ color: Theme.of(context).colorScheme.primary,
child: FittedBox(
alignment: Alignment.center,
fit: BoxFit.scaleDown,
@@ -36,30 +33,32 @@ class DocumentBanner extends StatelessWidget {
minHeight: 40,
contentPadding: EdgeInsets.zero,
bgColor: Colors.transparent,
- hoverColor: theme.main2,
- downColor: theme.main1,
+ hoverColor: Theme.of(context).colorScheme.primary,
+ downColor: Theme.of(context).colorScheme.primaryContainer,
outlineColor: Colors.white,
borderRadius: Corners.s8Border,
onPressed: onRestore,
child: FlowyText.medium(
- LocaleKeys.deletePagePrompt_restore.tr(),
- color: Colors.white,
- fontSize: 14)),
+ LocaleKeys.deletePagePrompt_restore.tr(),
+ color: Theme.of(context).colorScheme.onPrimary,
+ fontSize: 14,
+ )),
const HSpace(20),
BaseStyledButton(
minWidth: 220,
minHeight: 40,
contentPadding: EdgeInsets.zero,
bgColor: Colors.transparent,
- hoverColor: theme.main2,
- downColor: theme.main1,
+ hoverColor: Theme.of(context).colorScheme.primaryContainer,
+ downColor: Theme.of(context).colorScheme.primary,
outlineColor: Colors.white,
borderRadius: Corners.s8Border,
onPressed: onDelete,
child: FlowyText.medium(
- LocaleKeys.deletePagePrompt_deletePermanent.tr(),
- color: Colors.white,
- fontSize: 14)),
+ LocaleKeys.deletePagePrompt_deletePermanent.tr(),
+ color: Theme.of(context).colorScheme.onPrimary,
+ fontSize: 14,
+ )),
],
),
),
diff --git a/frontend/app_flowy/lib/plugins/document/presentation/plugins/horizontal_rule_node_widget.dart b/frontend/app_flowy/lib/plugins/document/presentation/plugins/horizontal_rule_node_widget.dart
new file mode 100644
index 0000000000..c3d4cbeb35
--- /dev/null
+++ b/frontend/app_flowy/lib/plugins/document/presentation/plugins/horizontal_rule_node_widget.dart
@@ -0,0 +1,168 @@
+import 'dart:collection';
+
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:flutter/material.dart';
+
+ShortcutEvent insertHorizontalRule = ShortcutEvent(
+ key: 'Horizontal rule',
+ command: 'Minus',
+ handler: _insertHorzaontalRule,
+);
+
+ShortcutEventHandler _insertHorzaontalRule = (editorState, event) {
+ final selection = editorState.service.selectionService.currentSelection.value;
+ final textNodes = editorState.service.selectionService.currentSelectedNodes
+ .whereType();
+ if (textNodes.length != 1 || selection == null) {
+ return KeyEventResult.ignored;
+ }
+ final textNode = textNodes.first;
+ if (textNode.toPlainText() == '--') {
+ final transaction = editorState.transaction
+ ..deleteText(textNode, 0, 2)
+ ..insertNode(
+ textNode.path,
+ Node(
+ type: 'horizontal_rule',
+ children: LinkedList(),
+ attributes: {},
+ ),
+ )
+ ..afterSelection =
+ Selection.single(path: textNode.path.next, startOffset: 0);
+ editorState.apply(transaction);
+ return KeyEventResult.handled;
+ }
+ return KeyEventResult.ignored;
+};
+
+SelectionMenuItem horizontalRuleMenuItem = SelectionMenuItem(
+ name: () => 'Horizontal rule',
+ icon: (editorState, onSelected) => Icon(
+ Icons.horizontal_rule,
+ color: onSelected
+ ? editorState.editorStyle.selectionMenuItemSelectedIconColor
+ : editorState.editorStyle.selectionMenuItemIconColor,
+ size: 18.0,
+ ),
+ keywords: ['horizontal rule'],
+ handler: (editorState, _, __) {
+ final selection =
+ editorState.service.selectionService.currentSelection.value;
+ final textNodes = editorState.service.selectionService.currentSelectedNodes
+ .whereType();
+ if (selection == null || textNodes.isEmpty) {
+ return;
+ }
+ final textNode = textNodes.first;
+ if (textNode.toPlainText().isEmpty) {
+ final transaction = editorState.transaction
+ ..insertNode(
+ textNode.path,
+ Node(
+ type: 'horizontal_rule',
+ children: LinkedList(),
+ attributes: {},
+ ),
+ )
+ ..afterSelection =
+ Selection.single(path: textNode.path.next, startOffset: 0);
+ editorState.apply(transaction);
+ } else {
+ final transaction = editorState.transaction
+ ..insertNode(
+ selection.end.path.next,
+ TextNode(
+ children: LinkedList(),
+ attributes: {
+ 'subtype': 'horizontal_rule',
+ },
+ delta: Delta()..insert('---'),
+ ),
+ )
+ ..afterSelection = selection;
+ editorState.apply(transaction);
+ }
+ },
+);
+
+class HorizontalRuleWidgetBuilder extends NodeWidgetBuilder {
+ @override
+ Widget build(NodeWidgetContext context) {
+ return _HorizontalRuleWidget(
+ key: context.node.key,
+ node: context.node,
+ editorState: context.editorState,
+ );
+ }
+
+ @override
+ NodeValidator get nodeValidator => (node) {
+ return true;
+ };
+}
+
+class _HorizontalRuleWidget extends StatefulWidget {
+ const _HorizontalRuleWidget({
+ Key? key,
+ required this.node,
+ required this.editorState,
+ }) : super(key: key);
+
+ final Node node;
+ final EditorState editorState;
+
+ @override
+ State<_HorizontalRuleWidget> createState() => __HorizontalRuleWidgetState();
+}
+
+class __HorizontalRuleWidgetState extends State<_HorizontalRuleWidget>
+ with SelectableMixin {
+ RenderBox get _renderBox => context.findRenderObject() as RenderBox;
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.symmetric(vertical: 10),
+ child: Container(
+ height: 1,
+ color: Colors.grey,
+ ),
+ );
+ }
+
+ @override
+ Position start() => Position(path: widget.node.path, offset: 0);
+
+ @override
+ Position end() => Position(path: widget.node.path, offset: 1);
+
+ @override
+ Position getPositionInOffset(Offset start) => end();
+
+ @override
+ bool get shouldCursorBlink => false;
+
+ @override
+ CursorStyle get cursorStyle => CursorStyle.borderLine;
+
+ @override
+ Rect? getCursorRectInPosition(Position position) {
+ final size = _renderBox.size;
+ return Rect.fromLTWH(-size.width / 2.0, 0, size.width, size.height);
+ }
+
+ @override
+ List getRectsInSelection(Selection selection) =>
+ [Offset.zero & _renderBox.size];
+
+ @override
+ Selection getSelectionInRange(Offset start, Offset end) => Selection.single(
+ path: widget.node.path,
+ startOffset: 0,
+ endOffset: 1,
+ );
+
+ @override
+ Offset localToGlobal(Offset offset) => _renderBox.localToGlobal(offset);
+}
diff --git a/frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart b/frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart
index b39226f0be..34bd1ba3dd 100644
--- a/frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart
+++ b/frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart
@@ -13,7 +13,7 @@ class GridBlockCache {
late GridRowCache _rowCache;
late GridBlockListener _listener;
- List get rows => _rowCache.rows;
+ List get rows => _rowCache.visibleRows;
GridRowCache get rowCache => _rowCache;
GridBlockCache({
@@ -30,7 +30,7 @@ class GridBlockCache {
_listener = GridBlockListener(blockId: block.id);
_listener.start((result) {
result.fold(
- (changesets) => _rowCache.applyChangesets(changesets),
+ (changeset) => _rowCache.applyChangesets(changeset),
(err) => Log.error(err),
);
});
diff --git a/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart
index 91f93c61fe..c4770462b3 100644
--- a/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart
+++ b/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart
@@ -7,11 +7,12 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
-typedef GridBlockUpdateNotifierValue = Either, FlowyError>;
+typedef GridBlockUpdateNotifierValue = Either;
class GridBlockListener {
final String blockId;
- PublishNotifier? _rowsUpdateNotifier = PublishNotifier();
+ PublishNotifier? _rowsUpdateNotifier =
+ PublishNotifier();
GridNotificationListener? _listener;
GridBlockListener({required this.blockId});
@@ -29,11 +30,12 @@ class GridBlockListener {
_rowsUpdateNotifier?.addPublishListener(onBlockChanged);
}
- void _handler(GridNotification ty, Either result) {
+ void _handler(GridDartNotification ty, Either result) {
switch (ty) {
- case GridNotification.DidUpdateGridBlock:
+ case GridDartNotification.DidUpdateGridBlock:
result.fold(
- (payload) => _rowsUpdateNotifier?.value = left([GridBlockChangesetPB.fromBuffer(payload)]),
+ (payload) => _rowsUpdateNotifier?.value =
+ left(GridBlockChangesetPB.fromBuffer(payload)),
(error) => _rowsUpdateNotifier?.value = right(error),
);
break;
diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart
index 4805ad8b7a..9d22177933 100644
--- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart
+++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart
@@ -22,9 +22,9 @@ class CellListener {
objectId: "$rowId:$fieldId", handler: _handler);
}
- void _handler(GridNotification ty, Either result) {
+ void _handler(GridDartNotification ty, Either result) {
switch (ty) {
- case GridNotification.DidUpdateCell:
+ case GridDartNotification.DidUpdateCell:
result.fold(
(payload) => _updateCellNotifier?.value = left(unit),
(error) => _updateCellNotifier?.value = right(error),
diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_controller.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_controller.dart
index 7a43378eb8..cdf695dc7f 100644
--- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_controller.dart
+++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_controller.dart
@@ -234,7 +234,7 @@ class IGridCellController extends Equatable {
return data;
}
- /// Return the FieldTypeOptionDataPB that can be parsed into corresponding class using the [parser].
+ /// Return the TypeOptionPB that can be parsed into corresponding class using the [parser].
/// [PD] is the type that the parser return.
Future>
getFieldTypeOption(P parser) {
@@ -290,20 +290,20 @@ class IGridCellController extends Equatable {
});
}
- void dispose() {
+ Future dispose() async {
if (_isDispose) {
Log.error("$this should only dispose once");
return;
}
_isDispose = true;
- _cellListener?.stop();
+ await _cellListener?.stop();
_loadDataOperation?.cancel();
_saveDataOperation?.cancel();
_cellDataNotifier = null;
if (_onFieldChangedFn != null) {
_fieldNotifier.unregister(_cacheKey, _onFieldChangedFn!);
- _fieldNotifier.dispose();
+ await _fieldNotifier.dispose();
_onFieldChangedFn = null;
}
}
@@ -329,7 +329,7 @@ class GridCellFieldNotifierImpl extends IGridCellFieldNotifier {
@override
void onCellFieldChanged(void Function(FieldPB p1) callback) {
- _onChangesetFn = (FieldChangesetPB changeset) {
+ _onChangesetFn = (GridFieldChangesetPB changeset) {
for (final updatedField in changeset.updatedFields) {
callback(updatedField);
}
diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_loader.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_loader.dart
index a6a1ba43a9..daf404d497 100644
--- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_loader.dart
+++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_loader.dart
@@ -25,7 +25,7 @@ class GridCellDataLoader {
final fut = service.getCell(cellId: cellId);
return fut.then(
(result) => result.fold(
- (GridCellPB cell) {
+ (CellPB cell) {
try {
return parser.parserData(cell.data);
} catch (e, s) {
diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_persistence.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_persistence.dart
index 71927bae14..253744a28a 100644
--- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_persistence.dart
+++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_persistence.dart
@@ -29,10 +29,12 @@ class CellDataPersistence implements IGridCellDataPersistence {
@freezed
class CalendarData with _$CalendarData {
- const factory CalendarData({required DateTime date, String? time}) = _CalendarData;
+ const factory CalendarData({required DateTime date, String? time}) =
+ _CalendarData;
}
-class DateCellDataPersistence implements IGridCellDataPersistence {
+class DateCellDataPersistence
+ implements IGridCellDataPersistence {
final GridCellIdentifier cellId;
DateCellDataPersistence({
required this.cellId,
@@ -40,10 +42,11 @@ class DateCellDataPersistence implements IGridCellDataPersistence
@override
Future