Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02b7149514 | ||
|
|
37547a6485 | ||
|
|
6e27d551d9 | ||
|
|
d02b8c609b | ||
|
|
f86a98cd51 | ||
|
|
3e3bdb59ae | ||
|
|
95d620931f | ||
|
|
cb7bb390e6 | ||
|
|
ce8cee5637 | ||
|
|
1b56538a2f | ||
|
|
b1729ab3eb | ||
|
|
bfe6c8074a | ||
|
|
381d2e6c71 | ||
|
|
e3eee76609 | ||
|
|
e96bea0de5 | ||
|
|
bf121623ae | ||
|
|
f2dd58a4f1 | ||
|
|
e24a8aabeb | ||
|
|
5b59800449 | ||
|
|
6a43dd871d | ||
|
|
4f2585baed | ||
|
|
80a273edae | ||
|
|
2bd90ba7ab | ||
|
|
a50c940282 | ||
|
|
bec8122178 | ||
|
|
edd58ede45 | ||
|
|
561d0f0808 | ||
|
|
ee52bf4b0e | ||
|
|
4fa39f298c | ||
|
|
5994cc135f | ||
|
|
265177e444 | ||
|
|
82dcd4b99e | ||
|
|
8cee792b94 | ||
|
|
33e0f8d26d | ||
|
|
2ef72f3203 | ||
|
|
012b6c0066 | ||
|
|
09d61c79c9 | ||
|
|
80f08d4bec | ||
|
|
188b36cae6 | ||
|
|
2247fa8edb | ||
|
|
acc1d779c5 | ||
|
|
dac4bd88e0 | ||
|
|
65a910291b | ||
|
|
f0c440dcad | ||
|
|
107662dceb | ||
|
|
dc73df4203 | ||
|
|
57389d1fdd | ||
|
|
6bbdc7ceff | ||
|
|
75d40b79d0 | ||
|
|
cdfb634aa6 | ||
|
|
45d0d41830 | ||
|
|
6935653e15 | ||
|
|
9a213fa562 | ||
|
|
a85cc62a58 | ||
|
|
386182e295 | ||
|
|
70bb7f2ad6 | ||
|
|
2746666123 | ||
|
|
65cc2040e5 | ||
|
|
056e2d49d0 | ||
|
|
51a7954af7 | ||
|
|
74ff6772db | ||
|
|
ffff628359 | ||
|
|
f8d09e4894 | ||
|
|
b41b212b0d | ||
|
|
ca7777e891 | ||
|
|
d842f228e8 | ||
|
|
5cc8340e05 | ||
|
|
eaa1dcdeb9 | ||
|
|
6c31cf9555 | ||
|
|
bb681bdd1e | ||
|
|
f23c6098a7 | ||
|
|
f04d64a191 | ||
|
|
d01afab96e | ||
|
|
19ee0ea44d | ||
|
|
623f182bba | ||
|
|
bc66f43f47 | ||
|
|
2202326278 | ||
|
|
99c48f7100 | ||
|
|
f9862c501c | ||
|
|
6dcf69f151 | ||
|
|
a978b29748 | ||
|
|
17a0a79379 | ||
|
|
37345578c1 | ||
|
|
a2b592a59b | ||
|
|
2a35787dd1 | ||
|
|
bc723f8d0f | ||
|
|
dad0419da0 | ||
|
|
0b343f7ee1 | ||
|
|
a9c06632ad | ||
|
|
376f2d887d | ||
|
|
ba8cbe170c | ||
|
|
96c058db9b | ||
|
|
12151d1f3b | ||
|
|
e2ced6524f | ||
|
|
ad99998d33 | ||
|
|
cf97c8ba9c | ||
|
|
1f187a3917 | ||
|
|
76b94e363e | ||
|
|
7db36e3f1e | ||
|
|
93d787a9ae | ||
|
|
f5b23e5fc1 | ||
|
|
55cb7acc7f | ||
|
|
2838cd5e0c | ||
|
|
070ac051b1 | ||
|
|
32bd0ffca2 | ||
|
|
243f062d4f | ||
|
|
a0efd206a9 | ||
|
|
9717dfa3c4 | ||
|
|
eb78f9d36a | ||
|
|
1ad2f6cef5 | ||
|
|
973cd9194d | ||
|
|
0068c7e731 | ||
|
|
c009347735 | ||
|
|
07947db98b | ||
|
|
3b1152615a | ||
|
|
0e5a03a282 | ||
|
|
4582413e89 | ||
|
|
9ed5bfa51e | ||
|
|
ec89e9517b | ||
|
|
c7eb490db4 | ||
|
|
125eaf49a9 | ||
|
|
73c4a33191 | ||
|
|
68bfa0b9cd | ||
|
|
d42084f242 | ||
|
|
886766c887 | ||
|
|
37a6b54e82 | ||
|
|
341dce67d4 | ||
|
|
43cafdd524 | ||
|
|
2d85afe168 | ||
|
|
44585079b6 | ||
|
|
a33fc3dd60 | ||
|
|
e3b7864a91 | ||
|
|
6bbf6873d6 | ||
|
|
bc9b1a5c33 | ||
|
|
8b68b1390c | ||
|
|
915494761a | ||
|
|
e467481b75 | ||
|
|
c3a7f94cb3 | ||
|
|
033a231b67 | ||
|
|
d2b0f7e6b0 | ||
|
|
0c211188f0 | ||
|
|
4f08654fc3 | ||
|
|
db1184ff0d | ||
|
|
764ec73e94 | ||
|
|
4d5a3ee13d | ||
|
|
034d4d9bf4 | ||
|
|
ed977868cf | ||
|
|
8ccc2414c8 | ||
|
|
6977e5e65c | ||
|
|
e38398e235 | ||
|
|
b8ade5af12 | ||
|
|
da45531801 | ||
|
|
ddd3fbb178 | ||
|
|
e1c8135f5d | ||
|
|
2f2736df20 | ||
|
|
2c13cccb4f | ||
|
|
7970e7fae3 | ||
|
|
75f7b9765d | ||
|
|
ac2a0c5b91 | ||
|
|
c7acf9a594 | ||
|
|
d1d667c497 | ||
|
|
b21ed2488b | ||
|
|
03eaf0b4cb | ||
|
|
b9e49f109d | ||
|
|
b03b2705f0 | ||
|
|
521fe13cfb | ||
|
|
09445411a3 | ||
|
|
f86254c8ef | ||
|
|
35c21c0d84 | ||
|
|
c50c23bc3a | ||
|
|
a8a35dcbec | ||
|
|
f390658ee0 | ||
|
|
994e204097 | ||
|
|
5825195b8e | ||
|
|
df66521f13 | ||
|
|
8323614583 | ||
|
|
5762419aae | ||
|
|
bd8d816862 | ||
|
|
5ddb5100ad | ||
|
|
27a8eea6e2 | ||
|
|
6e24af9c68 | ||
|
|
da19987f4b | ||
|
|
6f4b11f468 | ||
|
|
98e9ba19d6 | ||
|
|
4545410703 | ||
|
|
c453d734ab | ||
|
|
0719f54dec | ||
|
|
7781b912f0 | ||
|
|
c6c97f7c83 | ||
|
|
a38c213744 | ||
|
|
073adf6268 | ||
|
|
d05cc4005b | ||
|
|
da1ee430b0 | ||
|
|
13e9b29eef | ||
|
|
c0c302bdfd | ||
|
|
5da5d92b8a | ||
|
|
47429e2fd2 | ||
|
|
07b183aef2 | ||
|
|
dc97912dba | ||
|
|
2825e19465 | ||
|
|
baa67e2aed | ||
|
|
d60c39d483 | ||
|
|
745ee264c8 | ||
|
|
4b1f45a4be | ||
|
|
fa427fe650 | ||
|
|
ab5b40fa51 | ||
|
|
60676fdc41 | ||
|
|
96be3c6ebe | ||
|
|
1d6f74180f | ||
|
|
6e028c4f64 | ||
|
|
d92c0bffd6 | ||
|
|
a66d457f10 | ||
|
|
88e0f6a32c | ||
|
|
34cb2b2a09 | ||
|
|
5fb86c4002 | ||
|
|
25707edbdd | ||
|
|
85f36ad877 | ||
|
|
c80e77ab16 | ||
|
|
a9c8bad599 | ||
|
|
268b6ce926 | ||
|
|
da8c39d0b6 | ||
|
|
7e3273c708 | ||
|
|
67e396aadf | ||
|
|
6304c7d95b | ||
|
|
ad0a6d01d2 | ||
|
|
f556e50be4 | ||
|
|
593446bffe | ||
|
|
91e5219627 | ||
|
|
2d8182c503 | ||
|
|
8e63f97f77 | ||
|
|
3f3d30856d | ||
|
|
0a3231cd9a | ||
|
|
aab62f4048 | ||
|
|
79c1568295 | ||
|
|
c8569d3c62 | ||
|
|
3635b6b63e | ||
|
|
7ca4da0966 | ||
|
|
557a524648 | ||
|
|
88eeb6bd36 | ||
|
|
d1c29ec3e7 | ||
|
|
fb8a81eca5 | ||
|
|
e297769ac2 | ||
|
|
543846c241 | ||
|
|
84f41cec76 | ||
|
|
3afca2b482 | ||
|
|
b417fb5fdf | ||
|
|
0b2dc415af | ||
|
|
d0558e4da1 | ||
|
|
7839ad26c4 | ||
|
|
075bf8f2fc | ||
|
|
11649ef16d | ||
|
|
24340f3091 | ||
|
|
a2bdb08a84 | ||
|
|
47ccfbf4ed | ||
|
|
24bf1c1893 | ||
|
|
9b0fccbdda | ||
|
|
dcf8fd538d | ||
|
|
c35db5c2a2 | ||
|
|
08bb4e4116 | ||
|
|
2e4df44c29 | ||
|
|
f58c91fb3f | ||
|
|
fd135fb664 | ||
|
|
c74308999d | ||
|
|
e5a1bd2c52 | ||
|
|
a3f4dfacba | ||
|
|
3619fadf57 |
No files matched your search
@@ -4,21 +4,25 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "develop"
|
||||
- "release/*"
|
||||
paths:
|
||||
- ".github/workflows/flutter_ci.yaml"
|
||||
- "frontend/**"
|
||||
- "!frontend/appflowy_tauri/**"
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
- "develop"
|
||||
- "release/*"
|
||||
paths:
|
||||
- ".github/workflows/flutter_ci.yaml"
|
||||
- "frontend/**"
|
||||
- "!frontend/appflowy_tauri/**"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.7.5"
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
RUST_TOOLCHAIN: "1.65"
|
||||
|
||||
jobs:
|
||||
@@ -62,12 +66,17 @@ jobs:
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
prefix-key: ${{ matrix.os }}
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
|
||||
- uses: davidB/rust-cargo-make@v1
|
||||
with:
|
||||
version: '0.36.6'
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo install --force cargo-make
|
||||
cargo install --force duckscript_cli
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
|
||||
@@ -90,6 +99,7 @@ jobs:
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
git config --system core.longpaths true
|
||||
flutter config --enable-windows-desktop
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: "3.7.5"
|
||||
flutter-version: "3.10.1"
|
||||
cache: true
|
||||
|
||||
- name: Cache Cargo
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- "*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.7.5"
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
RUST_TOOLCHAIN: "1.65"
|
||||
|
||||
jobs:
|
||||
@@ -136,11 +136,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
target: x86_64-apple-darwin,
|
||||
os: macos-10.15,
|
||||
extra-build-args: "",
|
||||
}
|
||||
- { target: x86_64-apple-darwin, os: macos-11, extra-build-args: "" }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "develop"
|
||||
- "release/*"
|
||||
paths:
|
||||
- "frontend/rust-lib/**"
|
||||
@@ -12,6 +13,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
- "develop"
|
||||
- "release/*"
|
||||
paths:
|
||||
- "frontend/rust-lib/**"
|
||||
@@ -20,7 +22,7 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUST_TOOLCHAIN: "1.65"
|
||||
FLUTTER_VERSION: "3.7.5"
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
|
||||
jobs:
|
||||
test-on-ubuntu:
|
||||
@@ -54,13 +56,19 @@ jobs:
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
prefix-key: 'ubuntu-latest'
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
|
||||
- name: Build FlowySDK
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make --profile development-linux-x86_64 appflowy-core-dev
|
||||
|
||||
- name: Run rust-lib tests
|
||||
working-directory: frontend/rust-lib
|
||||
run: RUST_LOG=info RUST_BACKTRACE=1 cargo test --no-default-features --features="rev-sqlite"
|
||||
|
||||
- name: rustfmt rust-lib
|
||||
run: cargo fmt --all -- --check
|
||||
working-directory: frontend/rust-lib/
|
||||
@@ -69,16 +77,12 @@ jobs:
|
||||
run: cargo clippy --features="rev-sqlite"
|
||||
working-directory: frontend/rust-lib
|
||||
|
||||
- name: Run rust-lib tests
|
||||
working-directory: frontend/rust-lib
|
||||
run: RUST_LOG=info cargo test --no-default-features --features="sync,rev-sqlite"
|
||||
|
||||
- name: rustfmt shared-lib
|
||||
run: cargo fmt --all -- --check
|
||||
working-directory: shared-lib
|
||||
|
||||
- name: clippy shared-lib
|
||||
run: cargo clippy -- -D warnings
|
||||
run: cargo clippy -- -D warnings
|
||||
working-directory: shared-lib
|
||||
|
||||
- name: Run shared-lib tests
|
||||
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
FLUTTER_VERSION: "3.7.5"
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
RUST_TOOLCHAIN: "1.65"
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -6,7 +6,8 @@ on:
|
||||
- "frontend/appflowy_tauri/**"
|
||||
|
||||
env:
|
||||
NODE_VERSION: "16"
|
||||
NODE_VERSION: "18.16.0"
|
||||
PNPM_VERSION: "8.5.0"
|
||||
RUST_TOOLCHAIN: "1.65"
|
||||
|
||||
jobs:
|
||||
@@ -14,8 +15,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# platform: [macos-latest, ubuntu-20.04, windows-latest]
|
||||
platform: [macos-latest]
|
||||
# platform: [macos-latest, ubuntu-latest, windows-latest]
|
||||
platform: [ubuntu-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
@@ -35,7 +36,10 @@ jobs:
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.platform }}
|
||||
prefix-key: 'ubuntu-latest-tauri'
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
frontend/appflowy_tauri/src-tauri
|
||||
|
||||
- name: install dependencies (windows only)
|
||||
if: matrix.platform == 'windows-latest'
|
||||
@@ -45,15 +49,17 @@ jobs:
|
||||
cargo install --force duckscript_cli
|
||||
vcpkg integrate install
|
||||
cargo make appflowy-tauri-deps-tools
|
||||
npm install -g pnpm@${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: install dependencies (ubuntu only)
|
||||
if: matrix.platform == 'ubuntu-20.04'
|
||||
if: matrix.platform == 'ubuntu-latest'
|
||||
working-directory: frontend
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
cargo install --force cargo-make
|
||||
cargo make appflowy-tauri-deps-tools
|
||||
npm install -g pnpm@${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: install dependencies (macOS only)
|
||||
if: matrix.platform == 'macos-latest'
|
||||
@@ -61,21 +67,16 @@ jobs:
|
||||
run: |
|
||||
cargo install --force cargo-make
|
||||
cargo make appflowy-tauri-deps-tools
|
||||
npm install -g pnpm@${{ env.PNPM_VERSION }}
|
||||
|
||||
# - name: lint
|
||||
# working-directory: frontend/appflowy_tauri
|
||||
# run: |
|
||||
# yarn --frozen-lockfile
|
||||
# yarn test:prettier
|
||||
# yarn test:code
|
||||
|
||||
- name: build
|
||||
working-directory: frontend/appflowy_tauri
|
||||
run: |
|
||||
mkdir dist
|
||||
npm install
|
||||
cargo make --cwd .. tauri_build
|
||||
yarn && yarn build
|
||||
pnpm install
|
||||
cargo make --cwd .. tauri_build
|
||||
pnpm test:errors
|
||||
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
|
||||
@@ -35,3 +35,5 @@ pubspec.lock
|
||||
.githooks/gitlint
|
||||
.githooks/gitlint.exe
|
||||
.fvm/
|
||||
|
||||
**/AppFlowy-Collab/
|
||||
@@ -1,5 +1,11 @@
|
||||
# Release Notes
|
||||
|
||||
## Version 0.1.5 - 11/05/2023
|
||||
|
||||
### Bug Fixes
|
||||
- Fix: calendar dates don't match with weekdays.
|
||||
- Fix: sort numbers in Grid.
|
||||
|
||||
## Version 0.1.4 - 04/05/2023
|
||||
|
||||
### New features
|
||||
|
||||
@@ -23,9 +23,11 @@ You are in charge of your data and customizations.
|
||||
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/200787830-96be260b-d0a0-4152-864e-6730b19095cd.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/174753177-98e4c899-2356-4137-bb42-374bba2b127b.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/190650183-a940f1e0-a2c5-4797-ab3a-56758f6f696c.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664610-fc209a97-815e-4716-af07-d94a859d1907.png" alt="AppFlowy Docs & Notes & Wikis" width="1000px" /></p>
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664628-5def2450-914a-4b2d-b907-92b7476b9863.png" alt="AppFlowy Databases for Tasks and Projects" width="1000px" /></p>
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664642-22e26c1b-5eae-4635-9aa6-b12ecf1c3c46.png" alt="AppFlowy Kanban Board for To-Dos" width="1000px" /></p>
|
||||
<p align="center"><img src="https://github.com/AppFlowy-IO/AppFlowy/assets/12026239/6be93d2b-a5c5-48a9-b7cf-c599d5f5140c" alt="AppFlowy Calendars for Plan and Manage Content" width="1000px" /></p>
|
||||
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664657-dc5291f3-67b0-4a43-a818-640e92735deb.png" alt="AppFlowy OpenAI GPT Writers" width="1000px" /></p>
|
||||
|
||||
## User Installation
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"preLaunchTask": "AF: Build Appflowy Core",
|
||||
"env": {
|
||||
"RUST_LOG": "trace",
|
||||
// "RUST_LOG": "debug"
|
||||
"RUST_BACKTRACE": 1
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
@@ -24,7 +24,7 @@
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"env": {
|
||||
"RUST_LOG": "debug"
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
{
|
||||
"label": "AF: Generate Freezed Files",
|
||||
"type": "shell",
|
||||
"command": "flutter pub run build_runner build --delete-conflicting-outputs",
|
||||
"command": "dart run build_runner build -d",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/appflowy_flutter"
|
||||
}
|
||||
@@ -180,7 +180,7 @@
|
||||
{
|
||||
"label": "AF: Tauri UI Build",
|
||||
"type": "shell",
|
||||
"command": "npm run build",
|
||||
"command": "pnpm run build",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/appflowy_tauri"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,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.1.4"
|
||||
CURRENT_APP_VERSION = "0.2.0"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
|
||||
PRODUCT_NAME = "AppFlowy"
|
||||
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
|
||||
@@ -59,6 +59,7 @@ BUILD_FLAG = "debug"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
PRODUCT_EXT = "app"
|
||||
BUILD_ARCHS = "arm64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.development-mac-x86_64]
|
||||
RUST_LOG = "info"
|
||||
@@ -68,6 +69,7 @@ BUILD_FLAG = "debug"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
PRODUCT_EXT = "app"
|
||||
BUILD_ARCHS = "x86_64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.production-mac-arm64]
|
||||
BUILD_FLAG = "release"
|
||||
@@ -77,6 +79,7 @@ FLUTTER_OUTPUT_DIR = "Release"
|
||||
PRODUCT_EXT = "app"
|
||||
APP_ENVIRONMENT = "production"
|
||||
BUILD_ARCHS = "arm64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.production-mac-x86_64]
|
||||
BUILD_FLAG = "release"
|
||||
@@ -86,6 +89,7 @@ FLUTTER_OUTPUT_DIR = "Release"
|
||||
PRODUCT_EXT = "app"
|
||||
APP_ENVIRONMENT = "production"
|
||||
BUILD_ARCHS = "x86_64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.development-windows-x86]
|
||||
TARGET_OS = "windows"
|
||||
|
||||
@@ -68,3 +68,5 @@ windows/flutter/dart_ffi/
|
||||
**/**/Brewfile.lock.json
|
||||
**/.sandbox
|
||||
**/.vscode/
|
||||
|
||||
*.env
|
||||
@@ -1,7 +1,7 @@
|
||||
.PHONY: freeze_build, free_watch
|
||||
|
||||
freeze_build:
|
||||
flutter pub run build_runner build --delete-conflicting-outputs
|
||||
dart run build_runner build -d
|
||||
|
||||
watch:
|
||||
flutter pub run build_runner watch
|
||||
dart run build_runner watch
|
||||
@@ -1,6 +1,6 @@
|
||||
<h1 align="center" style="margin:0"> AppFlowy_Flutter</h1>
|
||||
<div align="center">
|
||||
<img src="https://img.shields.io/badge/Flutter-v3.7.5-blue"/>
|
||||
<img src="https://img.shields.io/badge/Flutter-v3.10.1-blue"/>
|
||||
<img src="https://img.shields.io/badge/Rust-v1.65-orange"/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ linter:
|
||||
rules:
|
||||
- require_trailing_commas
|
||||
|
||||
- prefer_final_fields
|
||||
- prefer_final_in_for_each
|
||||
- prefer_final_locals
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_10_2941)">
|
||||
<path d="M17.9706 5.70199L17.9706 5.702L17.9712 5.70405L20.4218 13.6624C20.4393 13.7435 20.4508 13.8258 20.4561 13.9086V19.3106C20.4561 19.7769 20.078 20.1549 19.6117 20.1548H3.40062C2.93431 20.1549 2.55625 19.7769 2.55625 19.3106V13.9086C2.56155 13.8257 2.57301 13.7433 2.59054 13.6622L4.97263 5.70366C5.26597 4.72587 6.16595 4.05625 7.1868 4.05625L15.8285 4.05625C16.8329 4.05625 17.7119 4.7315 17.9706 5.70199ZM4.55716 12.99L4.53544 13.0624H4.61104H8.80431C9.02825 13.0624 9.24302 13.1514 9.40137 13.3097C9.55971 13.4681 9.64867 13.6828 9.64867 13.9068V14.8074V14.8636H9.70492H13.3074H13.3636V14.8074V13.9068C13.3636 13.6828 13.4526 13.4681 13.6109 13.3097C13.7693 13.1514 13.9841 13.0624 14.208 13.0624H18.4013H18.4769L18.4551 12.99L16.5342 6.5868C16.3843 6.08715 15.9244 5.74498 15.4028 5.74498H7.60955C7.0879 5.74498 6.62802 6.08715 6.47812 6.5868L4.55716 12.99ZM15.1086 14.7511H15.0524V14.8074V15.708C15.0524 15.8189 15.0305 15.9287 14.9881 16.0311C14.9457 16.1336 14.8835 16.2267 14.8051 16.3051C14.7267 16.3835 14.6336 16.4457 14.5311 16.4881C14.4287 16.5305 14.3189 16.5524 14.208 16.5524H8.80431C8.69343 16.5524 8.58363 16.5305 8.48118 16.4881C8.37874 16.4457 8.28566 16.3835 8.20725 16.3051C8.12885 16.2267 8.06665 16.1336 8.02422 16.0311C7.98178 15.9287 7.95994 15.8189 7.95994 15.708V14.8074V14.7511H7.90369H4.52623C4.3709 14.7511 4.24498 14.8771 4.24498 15.0324V18.1849C4.24498 18.3402 4.3709 18.4661 4.52623 18.4661H18.4861C18.6414 18.4661 18.7673 18.3402 18.7673 18.1849V15.0324C18.7673 14.8771 18.6414 14.7511 18.4861 14.7511H15.1086ZM8.80435 10.2481C8.58041 10.2481 8.36564 10.1591 8.20729 10.0007C8.04895 9.8424 7.95999 9.62763 7.95999 9.40369C7.95999 9.17975 8.04895 8.96498 8.20729 8.80663C8.36564 8.64829 8.58041 8.55933 8.80435 8.55933H14.208C14.432 8.55933 14.6468 8.64829 14.8051 8.80663C14.9635 8.96498 15.0524 9.17975 15.0524 9.40369C15.0524 9.62763 14.9635 9.8424 14.8051 10.0007C14.6468 10.1591 14.432 10.2481 14.208 10.2481H8.80435Z" fill="#333333" stroke="white" stroke-width="0.1125"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_10_2941">
|
||||
<rect width="18" height="16.2111" fill="white" transform="translate(2.5 4)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.7" d="M14.1579 9L14.6673 8.57546C14.5413 8.42426 14.3547 8.33684 14.1579 8.33684V9ZM16 11.2105L15.4905 11.6351C15.6165 11.7863 15.8032 11.8737 16 11.8737V11.2105ZM9.66316 12.6843C9.66316 12.318 9.36625 12.0211 9 12.0211C8.63375 12.0211 8.33684 12.318 8.33684 12.6843H9.66316ZM8.33684 17.1053C8.33684 17.4716 8.63375 17.7685 9 17.7685C9.36625 17.7685 9.66316 17.4716 9.66316 17.1053H8.33684ZM23.6632 12.6843C23.6632 12.318 23.3663 12.0211 23 12.0211C22.6337 12.0211 22.3368 12.318 22.3368 12.6843H23.6632ZM22.3368 17.1053C22.3368 17.4716 22.6337 17.7685 23 17.7685C23.3663 17.7685 23.6632 17.4716 23.6632 17.1053H22.3368ZM9.66316 9.73684C9.66316 9.69614 9.69614 9.66316 9.73684 9.66316V8.33684C8.96364 8.33684 8.33684 8.96364 8.33684 9.73684H9.66316ZM9.73684 9.66316H14.1579V8.33684H9.73684V9.66316ZM13.6484 9.42454L15.4905 11.6351L16.5094 10.786L14.6673 8.57546L13.6484 9.42454ZM16 11.8737H22.2631V10.5474H16V11.8737ZM22.2631 11.8737C22.3038 11.8737 22.3368 11.9067 22.3368 11.9474H23.6631C23.6631 11.1742 23.0363 10.5474 22.2631 10.5474V11.8737ZM22.3368 11.9474V21.5263H23.6631V11.9474H22.3368ZM22.3368 21.5263C22.3368 21.567 22.3038 21.6 22.2631 21.6V22.9263C23.0363 22.9263 23.6631 22.2995 23.6631 21.5263H22.3368ZM22.2631 21.6H9.73684V22.9263H22.2631V21.6ZM9.73684 21.6C9.69614 21.6 9.66316 21.567 9.66316 21.5263H8.33684C8.33684 22.2995 8.96365 22.9263 9.73684 22.9263V21.6ZM9.66316 21.5263V9.73684H8.33684V21.5263H9.66316ZM22.9999 14.2317H9V15.558H22.9999V14.2317ZM8.33684 12.6843V17.1053H9.66316V12.6843H8.33684ZM22.3368 12.6843V17.1053H23.6632V12.6843H22.3368Z" fill="#333333"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.7874 10.1975C22.48 10.8859 23.0235 11.6885 23.4041 12.5811C23.7967 13.5077 24 14.4863 24 15.499C24 16.5117 23.7987 17.4943 23.4061 18.4189C23.0256 19.3115 22.482 20.1141 21.7894 20.8025C21.0968 21.491 20.2895 22.0314 19.3915 22.4096C18.4614 22.8019 17.4729 23 16.4541 23C15.4354 23 14.4469 22.7999 13.5167 22.4096C12.6188 22.0314 11.8114 21.491 11.1189 20.8025C10.8833 20.5684 10.8833 20.1881 11.1189 19.954C11.3544 19.7198 11.7369 19.7198 11.9725 19.954C13.1684 21.1448 14.7589 21.7992 16.4521 21.7992C18.1453 21.7992 19.7338 21.1428 20.9317 19.954C22.1296 18.7652 22.792 17.1801 22.792 15.499C22.792 13.8179 22.1316 12.2368 20.9357 11.046C19.7398 9.85524 18.1493 9.2008 16.4561 9.2008C15.6971 9.2008 14.9562 9.33089 14.2516 9.59106C13.5711 9.84323 12.9429 10.2055 12.3852 10.6718C11.6041 11.3242 10.996 12.1508 10.6075 13.0734L11.2618 12.7231C11.5557 12.565 11.9222 12.6751 12.0792 12.9673C12.2383 13.2595 12.1275 13.6237 11.8336 13.7799L9.92094 14.8005C9.92094 14.8025 9.91892 14.8025 9.91892 14.8025C9.82832 14.8506 9.72967 14.8746 9.63303 14.8746C9.44378 14.8746 9.26258 14.7885 9.14581 14.6304C9.14455 14.6267 9.14249 14.6237 9.14064 14.621C9.13954 14.6194 9.13851 14.6179 9.13776 14.6164C9.13575 14.6124 9.13323 14.6089 9.13071 14.6054C9.1282 14.6019 9.12568 14.5984 9.12367 14.5944C9.11561 14.5824 9.10756 14.5704 9.10152 14.5584L8.07272 12.6551C7.91367 12.3629 8.0244 11.9987 8.31834 11.8426C8.61228 11.6845 8.97871 11.7945 9.13575 12.0867L9.45989 12.6871C9.91892 11.5584 10.6558 10.5457 11.6061 9.75317C12.2705 9.1988 13.0174 8.76451 13.8288 8.46631C14.6663 8.1561 15.5501 8 16.4521 8C17.4708 8 18.4594 8.20013 19.3895 8.59039C20.2875 8.96865 21.0948 9.50901 21.7874 10.1975ZM15.52 12.1206C15.52 11.7884 15.7898 11.5202 16.124 11.5202C16.4582 11.5202 16.728 11.7884 16.728 12.1206V15.2747H19.8244C20.1587 15.2747 20.4284 15.5429 20.4284 15.8751C20.4284 16.2073 20.1587 16.4755 19.8244 16.4755H16.1481C15.8441 16.4755 15.5925 16.2514 15.5502 15.9612C15.5301 15.9031 15.52 15.8411 15.52 15.7751V12.1206Z" fill="#333333" fill-opacity="0.7"/>
|
||||
<path d="M23.4041 12.5811L23.4435 12.5643L23.4435 12.5642L23.4041 12.5811ZM21.7874 10.1975L21.7572 10.2279L21.7874 10.1975ZM23.4061 18.4189L23.4455 18.4358L23.4455 18.4357L23.4061 18.4189ZM19.3915 22.4096L19.3749 22.3701L19.3749 22.3701L19.3915 22.4096ZM13.5167 22.4096L13.5001 22.4491L13.5001 22.4491L13.5167 22.4096ZM11.1189 20.8025L11.1491 20.7721L11.1189 20.8025ZM11.1189 19.954L11.1491 19.9844L11.1189 19.954ZM11.9725 19.954L12.0027 19.9236L12.0027 19.9236L11.9725 19.954ZM20.9317 19.954L20.9619 19.9844L20.9317 19.954ZM20.9357 11.046L20.9055 11.0764L20.9357 11.046ZM14.2516 9.59106L14.2367 9.55086L14.2367 9.55087L14.2516 9.59106ZM12.3852 10.6718L12.4127 10.7047L12.4127 10.7047L12.3852 10.6718ZM10.6075 13.0734L10.568 13.0567L10.521 13.1683L10.6277 13.1112L10.6075 13.0734ZM11.2618 12.7231L11.282 12.7609L11.2821 12.7609L11.2618 12.7231ZM12.0792 12.9673L12.0415 12.9876L12.0416 12.9878L12.0792 12.9673ZM11.8336 13.7799L11.8135 13.742L11.8134 13.742L11.8336 13.7799ZM9.92094 14.8005L9.90076 14.7627L9.87808 14.7748V14.8005H9.92094ZM9.91892 14.8025L9.9189 14.7597L9.90825 14.7597L9.89885 14.7647L9.91892 14.8025ZM9.14581 14.6304L9.10311 14.6447L9.11134 14.6559L9.14581 14.6304ZM9.14064 14.621L9.10537 14.6453L9.10537 14.6453L9.14064 14.621ZM9.13776 14.6164L9.17605 14.5972L9.17604 14.5972L9.13776 14.6164ZM9.13071 14.6054L9.09591 14.6304L9.09591 14.6304L9.13071 14.6054ZM9.12367 14.5944L9.16225 14.575L9.15926 14.5705L9.12367 14.5944ZM9.10152 14.5584L9.13982 14.5391L9.13922 14.538L9.10152 14.5584ZM8.07272 12.6551L8.11042 12.6347L8.11036 12.6346L8.07272 12.6551ZM8.31834 11.8426L8.33844 11.8804L8.33864 11.8803L8.31834 11.8426ZM9.13575 12.0867L9.09799 12.107L9.09803 12.1071L9.13575 12.0867ZM9.45989 12.6871L9.42218 12.7075L9.46535 12.7875L9.49959 12.7033L9.45989 12.6871ZM11.6061 9.75317L11.6335 9.78608L11.6335 9.78608L11.6061 9.75317ZM13.8288 8.46631L13.8436 8.50654L13.8437 8.5065L13.8288 8.46631ZM19.3895 8.59039L19.4062 8.5509L19.4061 8.55087L19.3895 8.59039ZM16.728 15.2747H16.6851V15.3176H16.728V15.2747ZM15.5502 15.9612L15.5934 15.9549L15.5907 15.9471L15.5502 15.9612ZM23.4435 12.5642C23.0608 11.6666 22.5141 10.8594 21.8176 10.1671L21.7572 10.2279C22.4458 10.9124 22.9863 11.7104 23.3646 12.5979L23.4435 12.5642ZM24.0429 15.499C24.0429 14.4805 23.8383 13.4961 23.4435 12.5643L23.3646 12.5978C23.755 13.5192 23.9571 14.4922 23.9571 15.499H24.0429ZM23.4455 18.4357C23.8404 17.5058 24.0429 16.5174 24.0429 15.499H23.9571C23.9571 16.5059 23.757 17.4829 23.3666 18.4022L23.4455 18.4357ZM21.8196 20.8329C22.5161 20.1406 23.0628 19.3334 23.4455 18.4358L23.3667 18.4021C22.9883 19.2896 22.4478 20.0876 21.7592 20.7721L21.8196 20.8329ZM19.4082 22.4491C20.3112 22.0687 21.1231 21.5253 21.8196 20.8329L21.7592 20.7721C21.0705 21.4567 20.2678 21.994 19.3749 22.3701L19.4082 22.4491ZM16.4541 23.0429C17.4785 23.0429 18.4727 22.8436 19.4082 22.4491L19.3749 22.3701C18.4501 22.7601 17.4672 22.9571 16.4541 22.9571V23.0429ZM13.5001 22.4491C14.4355 22.8416 15.4297 23.0429 16.4541 23.0429V22.9571C15.4411 22.9571 14.4582 22.7581 13.5333 22.3701L13.5001 22.4491ZM11.0886 20.8329C11.7851 21.5253 12.5971 22.0687 13.5001 22.4491L13.5333 22.3701C12.6405 21.994 11.8377 21.4567 11.1491 20.7721L11.0886 20.8329ZM11.0886 19.9236C10.8362 20.1745 10.8362 20.582 11.0886 20.8329L11.1491 20.7721C10.9304 20.5547 10.9304 20.2018 11.1491 19.9844L11.0886 19.9236ZM12.0027 19.9236C11.7504 19.6728 11.3409 19.6728 11.0886 19.9236L11.1491 19.9844C11.3679 19.7668 11.7234 19.7668 11.9423 19.9844L12.0027 19.9236ZM16.4521 21.7563C14.7702 21.7563 13.1906 21.1064 12.0027 19.9236L11.9423 19.9843C13.1462 21.1832 14.7476 21.8421 16.4521 21.8421V21.7563ZM20.9015 19.9235C19.7116 21.1044 18.134 21.7563 16.4521 21.7563V21.8421C18.1566 21.8421 19.756 21.1811 20.9619 19.9844L20.9015 19.9235ZM22.7492 15.499C22.7492 17.1686 22.0914 18.7428 20.9015 19.9235L20.9619 19.9844C22.1679 18.7876 22.8349 17.1916 22.8349 15.499H22.7492ZM20.9055 11.0764C22.0934 12.2592 22.7492 13.8294 22.7492 15.499H22.8349C22.8349 13.8064 22.1699 12.2144 20.966 11.0157L20.9055 11.0764ZM16.4561 9.24366C18.1381 9.24366 19.7177 9.89365 20.9055 11.0764L20.966 11.0157C19.762 9.81683 18.1606 9.15794 16.4561 9.15794V9.24366ZM14.2664 9.63127C14.9662 9.37289 15.7021 9.24366 16.4561 9.24366V9.15794C15.6922 9.15794 14.9462 9.28889 14.2367 9.55086L14.2664 9.63127ZM12.4127 10.7047C12.9666 10.2415 13.5905 9.88174 14.2665 9.63125L14.2367 9.55087C13.5517 9.80472 12.9192 10.1694 12.3577 10.6389L12.4127 10.7047ZM10.647 13.09C11.0329 12.1737 11.6368 11.3527 12.4127 10.7047L12.3578 10.6389C11.5713 11.2957 10.9592 12.1278 10.568 13.0567L10.647 13.09ZM11.2416 12.6854L10.5872 13.0356L10.6277 13.1112L11.282 12.7609L11.2416 12.6854ZM12.117 12.947C11.9487 12.6339 11.5562 12.5161 11.2415 12.6854L11.2821 12.7609C11.5553 12.614 11.8957 12.7164 12.0415 12.9876L12.117 12.947ZM11.8537 13.8177C12.1685 13.6505 12.2874 13.2601 12.1168 12.9468L12.0416 12.9878C12.1891 13.2589 12.0865 13.597 11.8135 13.742L11.8537 13.8177ZM9.94111 14.8383L11.8538 13.8177L11.8134 13.74Line truncated
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2990 5100 c-19 -10 -382 -366 -806 -792 l-771 -773 -42 -85 c-125
|
||||
-256 -84 -501 120 -714 47 -50 91 -101 98 -113 14 -27 14 -116 0 -168 -57
|
||||
-207 -310 -495 -535 -606 -73 -37 -92 -42 -190 -50 -60 -4 -145 -18 -189 -29
|
||||
-312 -80 -560 -328 -646 -645 -32 -116 -32 -336 -1 -450 88 -318 330 -560 647
|
||||
-646 115 -32 335 -32 450 0 263 71 474 247 591 494 45 95 71 203 83 337 7 90
|
||||
15 122 40 176 149 318 583 627 777 554 15 -6 68 -50 119 -98 214 -205 459
|
||||
-246 715 -121 85 42 85 42 849 803 420 418 776 781 792 805 34 53 37 97 10
|
||||
149 -24 46 -1934 1954 -1978 1976 -42 21 -90 20 -133 -4z m920 -1195 l845
|
||||
-845 -318 -317 -317 -318 -847 847 -848 848 315 315 c173 173 317 315 320 315
|
||||
3 0 385 -380 850 -845z m-282 -1972 c-320 -320 -330 -327 -458 -328 -100 0
|
||||
-145 23 -264 135 -52 49 -114 99 -137 111 -242 123 -589 11 -902 -291 -135
|
||||
-130 -224 -245 -287 -375 -54 -110 -80 -200 -80 -285 -2 -277 -206 -528 -475
|
||||
-585 -203 -43 -395 15 -545 164 -190 188 -233 466 -108 704 42 81 164 203 245
|
||||
245 77 41 198 72 277 72 326 1 780 374 949 780 74 178 76 355 5 494 -11 21
|
||||
-59 80 -108 132 -110 117 -135 164 -135 259 0 131 3 136 324 458 l286 287 847
|
||||
-847 848 -848 -282 -282z"/>
|
||||
<path d="M828 1029 c-43 -22 -78 -81 -78 -129 0 -76 74 -150 150 -150 17 0 49
|
||||
9 70 20 45 23 80 80 80 130 0 50 -35 107 -80 130 -49 25 -94 25 -142 -1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,6 +1,6 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 4.3999H4.11111H13" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.77775 4.4V3.2C5.77775 2.88174 5.89481 2.57652 6.10319 2.35147C6.31156 2.12643 6.59418 2 6.88886 2H9.11108C9.40577 2 9.68838 2.12643 9.89676 2.35147C10.1051 2.57652 10.2222 2.88174 10.2222 3.2V4.4M11.8889 4.4V12.8C11.8889 13.1183 11.7718 13.4235 11.5634 13.6485C11.3551 13.8736 11.0724 14 10.7778 14H5.2222C4.92751 14 4.64489 13.8736 4.43652 13.6485C4.22815 13.4235 4.11108 13.1183 4.11108 12.8V4.4H11.8889Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.88892 7.3999V10.9999" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.11108 7.3999V10.9999" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 4.40039H4.11111H13" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.77799 4.4V3.2C5.77799 2.88174 5.89506 2.57652 6.10343 2.35147C6.31181 2.12643 6.59442 2 6.88911 2H9.11133C9.40601 2 9.68863 2.12643 9.897 2.35147C10.1054 2.57652 10.2224 2.88174 10.2224 3.2V4.4M11.8891 4.4V12.8C11.8891 13.1183 11.772 13.4235 11.5637 13.6485C11.3553 13.8736 11.0727 14 10.778 14H5.22244C4.92775 14 4.64514 13.8736 4.43676 13.6485C4.22839 13.4235 4.11133 13.1183 4.11133 12.8V4.4H11.8891Z" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.88867 7.40039V11.0004" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.11133 7.40039V11.0004" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 886 B After Width: | Height: | Size: 886 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.974 6.33301H7.35865C6.7922 6.33301 6.33301 6.7922 6.33301 7.35865V11.974C6.33301 12.5405 6.7922 12.9997 7.35865 12.9997H11.974C12.5405 12.9997 12.9997 12.5405 12.9997 11.974V7.35865C12.9997 6.7922 12.5405 6.33301 11.974 6.33301Z" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4.53846 9.66667H4.02564C3.75362 9.66667 3.49275 9.55861 3.3004 9.36626C3.10806 9.17392 3 8.91304 3 8.64103V4.02564C3 3.75362 3.10806 3.49275 3.3004 3.3004C3.49275 3.10806 3.75362 3 4.02564 3H8.64103C8.91304 3 9.17392 3.10806 9.36626 3.3004C9.55861 3.49275 9.66667 3.75362 9.66667 4.02564V4.53846" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 785 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 8.91521C7.21574 9.22582 7.49099 9.48283 7.80707 9.66881C8.12315 9.85479 8.47268 9.96538 8.83194 9.99309C9.1912 10.0208 9.5518 9.96497 9.88926 9.8294C10.2267 9.69383 10.5332 9.48169 10.7878 9.20736L12.2949 7.58431C12.7525 7.07413 13.0056 6.39083 12.9999 5.68156C12.9942 4.9723 12.73 4.29384 12.2643 3.7923C11.7986 3.29075 11.1686 3.00627 10.51 3.0001C9.85142 2.99394 9.21693 3.26659 8.7432 3.75935L7.87913 4.68448" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 7.08479C8.78426 6.77418 8.50901 6.51717 8.19293 6.33119C7.87685 6.14521 7.52732 6.03462 7.16806 6.00691C6.8088 5.9792 6.4482 6.03503 6.11074 6.1706C5.77327 6.30617 5.46683 6.51831 5.21218 6.79264L3.7051 8.41569C3.24755 8.92587 2.99437 9.60918 3.00009 10.3184C3.00582 11.0277 3.26998 11.7062 3.73569 12.2077C4.2014 12.7092 4.8314 12.9937 5.48999 12.9999C6.14858 13.0061 6.78307 12.7334 7.2568 12.2407L8.11584 11.3155" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="9" y="3" width="2" height="2" rx="0.5" fill="#333333"/>
|
||||
<rect x="5" y="3" width="2" height="2" rx="0.5" fill="#333333"/>
|
||||
<rect x="9" y="7" width="2" height="2" rx="0.5" fill="#333333"/>
|
||||
<rect x="5" y="7" width="2" height="2" rx="0.5" fill="#333333"/>
|
||||
<rect x="9" y="11" width="2" height="2" rx="0.5" fill="#333333"/>
|
||||
<rect x="5" y="11" width="2" height="2" rx="0.5" fill="#333333"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 495 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 6C3 3.79086 4.79086 2 7 2H17C19.2091 2 21 3.79086 21 6C21 8.20914 19.2091 10 17 10H7C4.79086 10 3 8.20914 3 6Z" stroke="#000000" stroke-width="2"/>
|
||||
<path d="M3 16C3 14.8954 3.89543 14 5 14H8C9.10457 14 10 14.8954 10 16V19C10 20.1046 9.10457 21 8 21H5C3.89543 21 3 20.1046 3 19V16Z" stroke="#000000" stroke-width="2"/>
|
||||
<path d="M14 17.5C14 15.567 15.567 14 17.5 14C19.433 14 21 15.567 21 17.5C21 19.433 19.433 21 17.5 21C15.567 21 14 19.433 14 17.5Z" stroke="#000000" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 725 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="127px" height="96px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:0.982" fill="#5864f2" d="M 40.5,-0.5 C 42.5,-0.5 44.5,-0.5 46.5,-0.5C 46.7534,3.03777 48.5868,5.03777 52,5.5C 59.3333,4.16667 66.6667,4.16667 74,5.5C 77.4132,5.03777 79.2466,3.03777 79.5,-0.5C 81.8333,-0.5 84.1667,-0.5 86.5,-0.5C 93.6784,1.84095 100.845,4.50762 108,7.5C 117.556,21.9281 123.723,37.5947 126.5,54.5C 126.5,63.1667 126.5,71.8333 126.5,80.5C 117.234,86.2996 107.567,91.2996 97.5,95.5C 95.8333,95.5 94.1667,95.5 92.5,95.5C 90.2583,92.0205 88.2583,88.3538 86.5,84.5C 89.9621,82.9349 93.2954,81.1016 96.5,79C 95.8333,78.8333 95.1667,78.6667 94.5,78.5C 80.6757,84.0674 66.3424,85.9007 51.5,84C 44.0284,82.4993 36.6951,80.8327 29.5,79C 32.7046,81.1016 36.0379,82.9349 39.5,84.5C 37.7417,88.3538 35.7417,92.0205 33.5,95.5C 31.8333,95.5 30.1667,95.5 28.5,95.5C 18.4329,91.2996 8.76625,86.2996 -0.5,80.5C -0.5,71.8333 -0.5,63.1667 -0.5,54.5C 2.27734,37.5947 8.44401,21.9281 18,7.5C 25.419,4.30685 32.919,1.64019 40.5,-0.5 Z M 38.5,40.5 C 51.8373,41.4956 55.6706,48.1623 50,60.5C 42.3899,66.5776 36.3899,65.2442 32,56.5C 30.062,49.3891 32.2287,44.0558 38.5,40.5 Z M 80.5,40.5 C 93.8373,41.4956 97.6706,48.1623 92,60.5C 84.3899,66.5776 78.3899,65.2442 74,56.5C 72.062,49.3891 74.2287,44.0558 80.5,40.5 Z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 960 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" data-e2e="" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" width="1" height="1" ><path fill-rule="evenodd" clip-rule="evenodd" d="M43 24.4313C43 23.084 42.8767 21.7885 42.6475 20.5449H24.3877V27.8945H34.8219C34.3724 30.2695 33.0065 32.2818 30.9532 33.6291V38.3964H37.2189C40.885 35.0886 43 30.2177 43 24.4313Z" fill="#4285F4"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M24.3872 43.001C29.6219 43.001 34.0107 41.2996 37.2184 38.3978L30.9527 33.6305C29.2165 34.7705 26.9958 35.4441 24.3872 35.4441C19.3375 35.4441 15.0633 32.1018 13.5388 27.6108H7.06152V32.5337C10.2517 38.7433 16.8082 43.001 24.3872 43.001Z" fill="#34A853"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M13.5395 27.6094C13.1516 26.4695 12.9313 25.2517 12.9313 23.9994C12.9313 22.7472 13.1516 21.5295 13.5395 20.3894V15.4668H7.06217C5.74911 18.0318 5 20.9336 5 23.9994C5 27.0654 5.74911 29.9673 7.06217 32.5323L13.5395 27.6094Z" fill="#FBBC04"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M24.3872 12.5568C27.2336 12.5568 29.7894 13.5155 31.7987 15.3982L37.3595 9.94866C34.0018 6.88281 29.6131 5 24.3872 5C16.8082 5 10.2517 9.25777 7.06152 15.4674L13.5388 20.39C15.0633 15.8991 19.3375 12.5568 24.3872 12.5568Z" fill="#EA4335"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,254 @@
|
||||
{
|
||||
"document": {
|
||||
"type": "editor",
|
||||
"children": [
|
||||
{ "type": "cover" },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "heading", "heading": "h1" },
|
||||
"delta": [{ "insert": "Welcome to AppFlowy!" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "heading", "heading": "h2" },
|
||||
"delta": [{ "insert": "Here are the basics" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [{ "insert": "Click anywhere and just start typing." }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": false },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "Highlight ",
|
||||
"attributes": { "backgroundColor": "0x4dffeb3b" }
|
||||
},
|
||||
{ "insert": "any text, and use the editing menu to " },
|
||||
{ "insert": "style", "attributes": { "italic": true } },
|
||||
{ "insert": " " },
|
||||
{ "insert": "your", "attributes": { "bold": true } },
|
||||
{ "insert": " " },
|
||||
{ "insert": "writing", "attributes": { "underline": true } },
|
||||
{ "insert": " " },
|
||||
{ "insert": "however", "attributes": { "code": true } },
|
||||
{ "insert": " you " },
|
||||
{ "insert": "like.", "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [
|
||||
{ "insert": "As soon as you type " },
|
||||
{
|
||||
"insert": "/",
|
||||
"attributes": { "code": true, "color": "0xff00b5ff" }
|
||||
},
|
||||
{ "insert": " a menu will pop up. Select " },
|
||||
{
|
||||
"insert": "different types",
|
||||
"attributes": { "backgroundColor": "0x4d9c27b0" }
|
||||
},
|
||||
{ "insert": " of content blocks you can add." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [
|
||||
{ "insert": "Type " },
|
||||
{ "insert": "/", "attributes": { "code": true } },
|
||||
{ "insert": " followed by " },
|
||||
{ "insert": "/bullet", "attributes": { "code": true } },
|
||||
{ "insert": " or " },
|
||||
{ "insert": "/num", "attributes": { "code": true } },
|
||||
{ "insert": " to create a list.", "attributes": { "code": false } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": true },
|
||||
"delta": [
|
||||
{ "insert": "Click " },
|
||||
{ "insert": "+ New Page ", "attributes": { "code": true } },
|
||||
{
|
||||
"insert": "button at the bottom of your sidebar to add a new page."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [
|
||||
{ "insert": "Click " },
|
||||
{ "insert": "+", "attributes": { "code": true } },
|
||||
{ "insert": " next to any page title in the sidebar to " },
|
||||
{ "insert": "quickly", "attributes": { "color": "0xff8427e0" } },
|
||||
{ "insert": " add a new subpage, " },
|
||||
{ "insert": "Document", "attributes": { "code": true } },
|
||||
{ "insert": ", ", "attributes": { "code": false } },
|
||||
{ "insert": "Grid", "attributes": { "code": true } },
|
||||
{ "insert": ", or ", "attributes": { "code": false } },
|
||||
{ "insert": "Kanban Board", "attributes": { "code": true } },
|
||||
{ "insert": ".", "attributes": { "code": false } }
|
||||
]
|
||||
},
|
||||
{ "type": "text", "delta": [] },
|
||||
{ "type": "divider" },
|
||||
{ "type": "text", "attributes": { "checkbox": null }, "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "heading",
|
||||
"checkbox": null,
|
||||
"heading": "h2"
|
||||
},
|
||||
"delta": [{ "insert": "Keyboard shortcuts, markdown, and code block" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "number-list",
|
||||
"number": 1,
|
||||
"heading": null
|
||||
},
|
||||
"delta": [
|
||||
{ "insert": "Keyboard shortcuts " },
|
||||
{
|
||||
"insert": "guide",
|
||||
"attributes": {
|
||||
"href": "https://appflowy.gitbook.io/docs/essential-documentation/shortcuts"
|
||||
}
|
||||
},
|
||||
{ "retain": 1, "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "number-list",
|
||||
"number": 2,
|
||||
"heading": null
|
||||
},
|
||||
"delta": [
|
||||
{ "insert": "Markdown " },
|
||||
{
|
||||
"insert": "reference",
|
||||
"attributes": {
|
||||
"href": "https://appflowy.gitbook.io/docs/essential-documentation/markdown"
|
||||
}
|
||||
},
|
||||
{ "retain": 1, "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "number": 3, "subtype": "number-list" },
|
||||
"delta": [
|
||||
{ "insert": "Type " },
|
||||
{ "insert": "/code", "attributes": { "code": true } },
|
||||
{
|
||||
"insert": " to insert a code block",
|
||||
"attributes": { "code": false }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "code_block",
|
||||
"number": 3,
|
||||
"heading": null,
|
||||
"number-list": null,
|
||||
"theme": "vs",
|
||||
"language": "rust"
|
||||
},
|
||||
"delta": [
|
||||
{
|
||||
"insert": "// This is the main function.\nfn main() {\n // Print text to the console.\n println!(\"Hello World!\");\n}"
|
||||
},
|
||||
{ "retain": 1, "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{ "type": "text", "attributes": { "checkbox": null }, "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "heading",
|
||||
"checkbox": null,
|
||||
"heading": "h2"
|
||||
},
|
||||
"delta": [{ "insert": "Have a question❓" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "quote" },
|
||||
"delta": [
|
||||
{ "insert": "Click " },
|
||||
{ "insert": "?", "attributes": { "code": true } },
|
||||
{ "insert": " at the bottom right for help and support." }
|
||||
]
|
||||
},
|
||||
{ "type": "text", "delta": [] },
|
||||
{
|
||||
"type": "callout",
|
||||
"children": [
|
||||
{ "type": "text", "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "heading", "heading": "h2" },
|
||||
"delta": [{ "insert": "Like AppFlowy? Follow us:" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "bulleted-list" },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "GitHub",
|
||||
"attributes": {
|
||||
"href": "https://github.com/AppFlowy-IO/AppFlowy"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "bulleted-list" },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "Twitter",
|
||||
"attributes": { "href": "https://twitter.com/appflowy" }
|
||||
},
|
||||
{ "insert": ": @appflowy" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "bulleted-list" },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "Newsletter",
|
||||
"attributes": { "href": "https://blog-appflowy.ghost.io/" }
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"attributes": { "emoji": "😀" }
|
||||
},
|
||||
{ "type": "text", "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": null, "heading": null },
|
||||
"delta": []
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": null, "heading": null },
|
||||
"delta": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
{
|
||||
"document": {
|
||||
"type": "editor",
|
||||
"children": [
|
||||
{ "type": "cover" },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "heading", "heading": "h1" },
|
||||
"delta": [{ "insert": "Welcome to AppFlowy!" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "heading", "heading": "h2" },
|
||||
"delta": [{ "insert": "Here are the basics" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [{ "insert": "Click anywhere and just start typing." }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": false },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "Highlight ",
|
||||
"attributes": { "backgroundColor": "0x4dffeb3b" }
|
||||
},
|
||||
{ "insert": "any text, and use the editing menu to " },
|
||||
{ "insert": "style", "attributes": { "italic": true } },
|
||||
{ "insert": " " },
|
||||
{ "insert": "your", "attributes": { "bold": true } },
|
||||
{ "insert": " " },
|
||||
{ "insert": "writing", "attributes": { "underline": true } },
|
||||
{ "insert": " " },
|
||||
{ "insert": "however", "attributes": { "code": true } },
|
||||
{ "insert": " you " },
|
||||
{ "insert": "like.", "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [
|
||||
{ "insert": "As soon as you type " },
|
||||
{
|
||||
"insert": "/",
|
||||
"attributes": { "code": true, "color": "0xff00b5ff" }
|
||||
},
|
||||
{ "insert": " a menu will pop up. Select " },
|
||||
{
|
||||
"insert": "different types",
|
||||
"attributes": { "backgroundColor": "0x4d9c27b0" }
|
||||
},
|
||||
{ "insert": " of content blocks you can add." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [
|
||||
{ "insert": "Type " },
|
||||
{ "insert": "/", "attributes": { "code": true } },
|
||||
{ "insert": " followed by " },
|
||||
{ "insert": "/bullet", "attributes": { "code": true } },
|
||||
{ "insert": " or " },
|
||||
{ "insert": "/num", "attributes": { "code": true } },
|
||||
{ "insert": " to create a list.", "attributes": { "code": false } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": true },
|
||||
"delta": [
|
||||
{ "insert": "Click " },
|
||||
{ "insert": "+ New Page ", "attributes": { "code": true } },
|
||||
{
|
||||
"insert": "button at the bottom of your sidebar to add a new page."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "checkbox", "checkbox": null },
|
||||
"delta": [
|
||||
{ "insert": "Click " },
|
||||
{ "insert": "+", "attributes": { "code": true } },
|
||||
{ "insert": " next to any page title in the sidebar to " },
|
||||
{ "insert": "quickly", "attributes": { "color": "0xff8427e0" } },
|
||||
{ "insert": " add a new subpage, " },
|
||||
{ "insert": "Document", "attributes": { "code": true } },
|
||||
{ "insert": ", ", "attributes": { "code": false } },
|
||||
{ "insert": "Grid", "attributes": { "code": true } },
|
||||
{ "insert": ", or ", "attributes": { "code": false } },
|
||||
{ "insert": "Kanban Board", "attributes": { "code": true } },
|
||||
{ "insert": ".", "attributes": { "code": false } }
|
||||
]
|
||||
},
|
||||
{ "type": "text", "delta": [] },
|
||||
{ "type": "divider" },
|
||||
{ "type": "text", "attributes": { "checkbox": null }, "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "heading",
|
||||
"checkbox": null,
|
||||
"heading": "h2"
|
||||
},
|
||||
"delta": [{ "insert": "Keyboard shortcuts, markdown, and code block" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "number-list",
|
||||
"number": 1,
|
||||
"heading": null
|
||||
},
|
||||
"delta": [
|
||||
{ "insert": "Keyboard shortcuts " },
|
||||
{
|
||||
"insert": "guide",
|
||||
"attributes": {
|
||||
"href": "https://appflowy.gitbook.io/docs/essential-documentation/shortcuts"
|
||||
}
|
||||
},
|
||||
{ "retain": 1, "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "number-list",
|
||||
"number": 2,
|
||||
"heading": null
|
||||
},
|
||||
"delta": [
|
||||
{ "insert": "Markdown " },
|
||||
{
|
||||
"insert": "reference",
|
||||
"attributes": {
|
||||
"href": "https://appflowy.gitbook.io/docs/essential-documentation/markdown"
|
||||
}
|
||||
},
|
||||
{ "retain": 1, "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "number": 3, "subtype": "number-list" },
|
||||
"delta": [
|
||||
{ "insert": "Type " },
|
||||
{ "insert": "/code", "attributes": { "code": true } },
|
||||
{
|
||||
"insert": " to insert a code block",
|
||||
"attributes": { "code": false }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "code_block",
|
||||
"number": 3,
|
||||
"heading": null,
|
||||
"number-list": null,
|
||||
"theme": "vs",
|
||||
"language": "rust"
|
||||
},
|
||||
"delta": [
|
||||
{
|
||||
"insert": "// This is the main function.\nfn main() {\n // Print text to the console.\n println!(\"Hello World!\");\n}"
|
||||
},
|
||||
{ "retain": 1, "attributes": { "strikethrough": true } }
|
||||
]
|
||||
},
|
||||
{ "type": "text", "attributes": { "checkbox": null }, "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": {
|
||||
"subtype": "heading",
|
||||
"checkbox": null,
|
||||
"heading": "h2"
|
||||
},
|
||||
"delta": [{ "insert": "Have a question❓" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "quote" },
|
||||
"delta": [
|
||||
{ "insert": "Click " },
|
||||
{ "insert": "?", "attributes": { "code": true } },
|
||||
{ "insert": " at the bottom right for help and support." }
|
||||
]
|
||||
},
|
||||
{ "type": "text", "delta": [] },
|
||||
{
|
||||
"type": "callout",
|
||||
"children": [
|
||||
{ "type": "text", "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "heading", "heading": "h2" },
|
||||
"delta": [{ "insert": "Like AppFlowy? Follow us:" }]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "bulleted-list" },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "GitHub",
|
||||
"attributes": {
|
||||
"href": "https://github.com/AppFlowy-IO/AppFlowy"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "bulleted-list" },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "Twitter",
|
||||
"attributes": { "href": "https://twitter.com/appflowy" }
|
||||
},
|
||||
{ "insert": ": @appflowy" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": "bulleted-list" },
|
||||
"delta": [
|
||||
{
|
||||
"insert": "Newsletter",
|
||||
"attributes": { "href": "https://blog-appflowy.ghost.io/" }
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"attributes": { "emoji": "😀" }
|
||||
},
|
||||
{ "type": "text", "delta": [] },
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": null, "heading": null },
|
||||
"delta": []
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"attributes": { "subtype": null, "heading": null },
|
||||
"delta": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
"subscribeNewsletterText": "Subscribe to Newsletter",
|
||||
"letsGoButtonText": "Quick Start",
|
||||
"title": "Title",
|
||||
"youCanAlso": "You can also",
|
||||
"and": "and",
|
||||
"signUp": {
|
||||
"buttonText": "Sign Up",
|
||||
"title": "Sign Up to @:appName",
|
||||
@@ -21,6 +23,7 @@
|
||||
"signIn": {
|
||||
"loginTitle": "Login to @:appName",
|
||||
"loginButtonText": "Login",
|
||||
"loginAsGuestButtonText": "Get Started",
|
||||
"buttonText": "Sign In",
|
||||
"forgotPassword": "Forgot Password?",
|
||||
"emailHint": "Email",
|
||||
@@ -45,7 +48,8 @@
|
||||
"medium": "medium",
|
||||
"large": "large",
|
||||
"fontSize": "Font Size",
|
||||
"import": "Import"
|
||||
"import": "Import",
|
||||
"moreOptions": "More options"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Rename",
|
||||
@@ -108,6 +112,7 @@
|
||||
"openAsPage": "Open as a Page",
|
||||
"addNewRow": "Add a new row",
|
||||
"openMenu": "Click to open menu",
|
||||
"dragRow": "Long press to reorder the row",
|
||||
"viewDataBase": "View database",
|
||||
"referencePage": "This {name} is referenced"
|
||||
},
|
||||
@@ -182,15 +187,20 @@
|
||||
"theme": "Theme"
|
||||
},
|
||||
"files": {
|
||||
"defaultLocation": "Where your data is stored now",
|
||||
"copy": "Copy",
|
||||
"defaultLocation": "Read files and data storage location",
|
||||
"exportData": "Export your data",
|
||||
"doubleTapToCopy": "Double tap to copy the path",
|
||||
"restoreLocation": "Restore to AppFlowy default path",
|
||||
"customizeLocation": "Open another folder",
|
||||
"restartApp": "Please restart app for the changes to take effect.",
|
||||
"exportDatabase": "Export database",
|
||||
"selectFiles": "Select the files that need to be export",
|
||||
"selectAll": "Select all",
|
||||
"deselectAll": "Deselect all",
|
||||
"createNewFolder": "Create a new folder",
|
||||
"createNewFolderDesc": "Tell us where you want to store your data",
|
||||
"defineWhereYourDataIsStored": "Define where your data is stored",
|
||||
"open": "Open",
|
||||
"openFolder": "Open an existing folder",
|
||||
"openFolderDesc": "Read and write it to your existing AppFlowy folder",
|
||||
@@ -199,9 +209,17 @@
|
||||
"locationDesc": "Pick a name for your AppFlowy data folder",
|
||||
"browser": "Browse",
|
||||
"create": "Create",
|
||||
"set": "Set",
|
||||
"folderPath": "Path to store your folder",
|
||||
"locationCannotBeEmpty": "Path cannot be empty",
|
||||
"pathCopiedSnackbar": "File storage path copied to clipboard!"
|
||||
"pathCopiedSnackbar": "File storage path copied to clipboard!",
|
||||
"changeLocationTooltips": "Change the data directory",
|
||||
"change": "Change",
|
||||
"openLocationTooltips": "Open another data directory",
|
||||
"recoverLocationTooltips": "Reset to AppFlowy's default data directory",
|
||||
"exportFileSuccess": "Export file successfully!",
|
||||
"exportFileFail": "Export file failed!",
|
||||
"export": "Export"
|
||||
},
|
||||
"user": {
|
||||
"name": "Name",
|
||||
@@ -221,7 +239,8 @@
|
||||
"deleteFilter": "Delete filter",
|
||||
"filterBy": "Filter by...",
|
||||
"typeAValue": "Type a value...",
|
||||
"layout": "Layout"
|
||||
"layout": "Layout",
|
||||
"databaseLayout": "Layout"
|
||||
},
|
||||
"textFilter": {
|
||||
"contains": "Contains",
|
||||
@@ -272,6 +291,8 @@
|
||||
"textFieldName": "Text",
|
||||
"checkboxFieldName": "Checkbox",
|
||||
"dateFieldName": "Date",
|
||||
"updatedAtFieldName": "Last modified time",
|
||||
"createdAtFieldName": "Created time",
|
||||
"numberFieldName": "Numbers",
|
||||
"singleSelectFieldName": "Select",
|
||||
"multiSelectFieldName": "Multiselect",
|
||||
@@ -358,12 +379,14 @@
|
||||
"autoGeneratorGenerate": "Generate",
|
||||
"autoGeneratorHintText": "Ask OpenAI ...",
|
||||
"autoGeneratorCantGetOpenAIKey": "Can't get OpenAI key",
|
||||
"autoGeneratorRewrite": "Rewrite",
|
||||
"smartEdit": "AI Assistants",
|
||||
"openAI": "OpenAI",
|
||||
"smartEditFixSpelling": "Fix spelling",
|
||||
"warning": "⚠️ AI responses can be inaccurate or misleading.",
|
||||
"smartEditSummarize": "Summarize",
|
||||
"smartEditImproveWriting": "Improve Writing",
|
||||
"smartEditImproveWriting": "Improve writing",
|
||||
"smartEditMakeLonger": "Make longer",
|
||||
"smartEditCouldNotFetchResult": "Could not fetch result from OpenAI",
|
||||
"smartEditCouldNotFetchKey": "Could not fetch OpenAI key",
|
||||
"smartEditDisabled": "Connect OpenAI in Settings",
|
||||
@@ -395,6 +418,21 @@
|
||||
"mathEquation": {
|
||||
"addMathEquation": "Add Math Equation",
|
||||
"editMathEquation": "Edit Math Equation"
|
||||
},
|
||||
"optionAction": {
|
||||
"click": "Click",
|
||||
"toOpenMenu": " to open menu",
|
||||
"delete": "Delete",
|
||||
"duplicate": "Duplicate",
|
||||
"turnInto": "Turn into",
|
||||
"moveUp": "Move up",
|
||||
"moveDown": "Move down",
|
||||
"color": "Color",
|
||||
"align": "Align",
|
||||
"left": "Left",
|
||||
"center": "Center",
|
||||
"right": "Right",
|
||||
"defaultColor": "Default"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -420,7 +458,8 @@
|
||||
"firstDayOfWeek": "Start week on",
|
||||
"layoutDateField": "Layout calendar by",
|
||||
"noDateTitle": "No Date",
|
||||
"emptyNoDate": "No unscheduled events"
|
||||
"noDateHint": "Unscheduled events will show up here",
|
||||
"clickToAdd": "Click to add to the calendar"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ void main() {
|
||||
|
||||
final TestPointer pointer = TestPointer(1, PointerDeviceKind.mouse);
|
||||
final imageFinder = find.byType(Image);
|
||||
Offset offset = tester.getCenter(imageFinder);
|
||||
final Offset offset = tester.getCenter(imageFinder);
|
||||
|
||||
pointer.hover(offset);
|
||||
expect(find.byType(RoundedTextButton), findsOneWidget);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'util/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('document', () {
|
||||
const location = 'appflowy';
|
||||
|
||||
setUp(() async {
|
||||
await TestFolder.cleanTestLocation(location);
|
||||
await TestFolder.setTestLocation(location);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await TestFolder.cleanTestLocation(location);
|
||||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
await TestFolder.cleanTestLocation(null);
|
||||
});
|
||||
|
||||
testWidgets('create a new document when launching app in first time',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create a new document
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateDocumentButton();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// expect to see a new document
|
||||
tester.expectToSeePageName(
|
||||
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
);
|
||||
// and with one paragraph block
|
||||
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('delete the readme page and restore it', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
await tester.tapGoButton();
|
||||
|
||||
// delete the readme page
|
||||
await tester.hoverOnPageName(readme);
|
||||
await tester.tapDeletePageButton();
|
||||
|
||||
// the banner should show up and the readme page should be gone
|
||||
tester.expectToSeeDocumentBanner();
|
||||
tester.expectNotToSeePageName(readme);
|
||||
|
||||
// restore the readme page
|
||||
await tester.tapRestoreButton();
|
||||
|
||||
// the banner should be gone and the readme page should be back
|
||||
tester.expectNotToSeeDocumentBanner();
|
||||
tester.expectToSeePageName(readme);
|
||||
});
|
||||
|
||||
testWidgets('delete the readme page and delete it permanently',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
await tester.tapGoButton();
|
||||
|
||||
// delete the readme page
|
||||
await tester.hoverOnPageName(readme);
|
||||
await tester.tapDeletePageButton();
|
||||
|
||||
// the banner should show up and the readme page should be gone
|
||||
tester.expectToSeeDocumentBanner();
|
||||
tester.expectNotToSeePageName(readme);
|
||||
|
||||
// delete the page permanently
|
||||
await tester.tapDeletePermanentlyButton();
|
||||
|
||||
// the banner should be gone and the readme page should be gone
|
||||
tester.expectNotToSeeDocumentBanner();
|
||||
tester.expectNotToSeePageName(readme);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/base/built_in_page_widget.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/built_in_page_widget.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/openai/service/openai_client.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'board_test.dart' as board_test;
|
||||
import 'switch_folder_test.dart' as switch_folder_test;
|
||||
import 'empty_document_test.dart' as empty_document_test;
|
||||
import 'open_ai_smart_menu_test.dart' as smart_menu_test;
|
||||
import 'document_test.dart' as document_test;
|
||||
|
||||
/// The main task runner for all integration tests in AppFlowy.
|
||||
///
|
||||
@@ -18,4 +19,5 @@ void main() {
|
||||
board_test.main();
|
||||
empty_document_test.main();
|
||||
smart_menu_test.main();
|
||||
document_test.main();
|
||||
}
|
||||
@@ -51,7 +51,7 @@ void main() {
|
||||
// Click create button again
|
||||
await tester.tapCreateButton();
|
||||
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
|
||||
await TestFolder.cleanTestLocation(folderName);
|
||||
});
|
||||
@@ -69,7 +69,7 @@ void main() {
|
||||
await tester.tapOpenFolderButton();
|
||||
|
||||
await tester.wait(1000);
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
|
||||
await TestFolder.cleanTestLocation(folderName);
|
||||
});
|
||||
@@ -84,7 +84,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
await tester.tapGoButton();
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
|
||||
// switch to user B
|
||||
{
|
||||
@@ -99,7 +99,7 @@ void main() {
|
||||
await mockGetDirectoryPath(userB);
|
||||
await tester.tapCustomLocationButton();
|
||||
await tester.pumpAndSettle();
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
}
|
||||
|
||||
// switch to the userA
|
||||
@@ -116,7 +116,7 @@ void main() {
|
||||
await tester.tapCustomLocationButton();
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
expect(find.textContaining(userA), findsOneWidget);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ void main() {
|
||||
await tester.tapCustomLocationButton();
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
expect(find.textContaining(userB), findsOneWidget);
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// home and readme document
|
||||
await tester.expectToSeeWelcomePage();
|
||||
tester.expectToSeeWelcomePage();
|
||||
|
||||
// open settings and restore the location
|
||||
await tester.openSettings();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:appflowy/main.dart' as app;
|
||||
import 'package:appflowy/startup/tasks/prelude.dart';
|
||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@@ -21,7 +21,7 @@ class TestFolder {
|
||||
static Future<void> setTestLocation(String? name) async {
|
||||
final location = await testLocation(name);
|
||||
SharedPreferences.setMockInitialValues({
|
||||
kSettingsLocationDefaultLocation: location.path,
|
||||
KVKeys.pathLocation: location.path,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class TestFolder {
|
||||
/// Get current using location.
|
||||
static Future<String> currentLocation() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(kSettingsLocationDefaultLocation)!;
|
||||
return prefs.getString(KVKeys.pathLocation)!;
|
||||
}
|
||||
|
||||
/// Get default location under development environment.
|
||||
@@ -58,17 +58,21 @@ class TestFolder {
|
||||
|
||||
extension AppFlowyTestBase on WidgetTester {
|
||||
Future<void> initializeAppFlowy() async {
|
||||
const MethodChannel('hotkey_manager')
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
if (methodCall.method == 'unregisterAll') {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(
|
||||
const MethodChannel('hotkey_manager'),
|
||||
(MethodCall methodCall) async {
|
||||
if (methodCall.method == 'unregisterAll') {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
);
|
||||
|
||||
await app.main();
|
||||
await wait(3000);
|
||||
await pumpAndSettle(const Duration(seconds: 2));
|
||||
return;
|
||||
}
|
||||
|
||||
Future<void> tapButton(
|
||||
@@ -87,7 +91,7 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
String tr, {
|
||||
int milliseconds = 500,
|
||||
}) async {
|
||||
final button = find.text(tr);
|
||||
final button = find.text(tr, findRichText: true);
|
||||
await tapButton(
|
||||
button,
|
||||
milliseconds: milliseconds,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
@@ -51,8 +51,7 @@ class TestWorkspaceService {
|
||||
Future<void> setUpAll() async {
|
||||
SharedPreferences.setMockInitialValues(
|
||||
{
|
||||
kSettingsLocationDefaultLocation:
|
||||
await workspace.root.then((value) => value.path),
|
||||
KVKeys.pathLocation: await workspace.root.then((value) => value.path),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,100 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/banner.dart';
|
||||
import 'package:appflowy/user/presentation/skip_log_in_screen.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/home_stack.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/app/header/add_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/app/section/item.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'base.dart';
|
||||
|
||||
const String readme = 'Read me';
|
||||
|
||||
extension AppFlowyLaunch on WidgetTester {
|
||||
Future<void> tapGoButton() async {
|
||||
await tapButtonWithName(LocaleKeys.letsGoButtonText.tr());
|
||||
return;
|
||||
final goButton = find.byType(GoButton);
|
||||
await tapButton(goButton);
|
||||
}
|
||||
|
||||
Future<void> tapCreateButton() async {
|
||||
await tapButtonWithName(LocaleKeys.settings_files_create.tr());
|
||||
return;
|
||||
}
|
||||
|
||||
Future<void> expectToSeeWelcomePage() async {
|
||||
void expectToSeeWelcomePage() {
|
||||
expect(find.byType(HomeStack), findsOneWidget);
|
||||
expect(find.textContaining('Read me'), findsNWidgets(2));
|
||||
}
|
||||
|
||||
Future<void> tapAddButton() async {
|
||||
final addButton = find.byType(AddButton);
|
||||
await tapButton(addButton);
|
||||
}
|
||||
|
||||
Future<void> tapCreateDocumentButton() async {
|
||||
await tapButtonWithName(LocaleKeys.document_menuName.tr());
|
||||
}
|
||||
|
||||
Finder findPageName(String name) {
|
||||
return find.byWidgetPredicate(
|
||||
(widget) => widget is ViewSectionItem && widget.view.name == name,
|
||||
);
|
||||
}
|
||||
|
||||
void expectToSeePageName(String name) {
|
||||
final pageName = findPageName(name);
|
||||
expect(pageName, findsOneWidget);
|
||||
}
|
||||
|
||||
void expectNotToSeePageName(String name) {
|
||||
final pageName = findPageName(name);
|
||||
expect(pageName, findsNothing);
|
||||
}
|
||||
|
||||
Future<void> hoverOnPageName(String name) async {
|
||||
final pageName = find.byWidgetPredicate(
|
||||
(widget) => widget is ViewSectionItem && widget.view.name == name,
|
||||
);
|
||||
|
||||
final gesture = await createGesture(kind: PointerDeviceKind.mouse);
|
||||
await gesture.addPointer(location: Offset.zero);
|
||||
addTearDown(gesture.removePointer);
|
||||
await pump();
|
||||
await gesture.moveTo(getCenter(pageName));
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> tapPageOptionButton() async {
|
||||
final optionButton = find.byType(ViewDisclosureButton);
|
||||
await tapButton(optionButton);
|
||||
}
|
||||
|
||||
Future<void> tapDeletePageButton() async {
|
||||
await tapPageOptionButton();
|
||||
await tapButtonWithName(ViewDisclosureAction.delete.name);
|
||||
}
|
||||
|
||||
void expectToSeeDocumentBanner() {
|
||||
expect(find.byType(DocumentBanner), findsOneWidget);
|
||||
}
|
||||
|
||||
void expectNotToSeeDocumentBanner() {
|
||||
expect(find.byType(DocumentBanner), findsNothing);
|
||||
}
|
||||
|
||||
Future<void> tapRestoreButton() async {
|
||||
final restoreButton = find.textContaining(
|
||||
LocaleKeys.deletePagePrompt_restore.tr(),
|
||||
);
|
||||
await tapButton(restoreButton);
|
||||
}
|
||||
|
||||
Future<void> tapDeletePermanentlyButton() async {
|
||||
final restoreButton = find.textContaining(
|
||||
LocaleKeys.deletePagePrompt_deletePermanent.tr(),
|
||||
);
|
||||
await tapButton(restoreButton);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/openai/service/openai_client.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/openai/service/text_completion.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/openai/service/error.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/text_completion.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/error.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:async';
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-config/entities.pb.dart';
|
||||
|
||||
class Config {
|
||||
static Future<void> setSupabaseConfig({
|
||||
required String url,
|
||||
required String anonKey,
|
||||
required String key,
|
||||
required String secret,
|
||||
}) async {
|
||||
await ConfigEventSetSupabaseConfig(
|
||||
SupabaseConfigPB.create()
|
||||
..supabaseUrl = url
|
||||
..key = key
|
||||
..anonKey = anonKey
|
||||
..jwtSecret = secret,
|
||||
).send();
|
||||
}
|
||||
|
||||
static Future<void> setSupabaseCollabPluginConfig({
|
||||
required String url,
|
||||
required String key,
|
||||
required String jwtSecret,
|
||||
required String collabTable,
|
||||
}) async {
|
||||
final payload = CollabPluginConfigPB.create();
|
||||
final collabTableConfig = CollabTableConfigPB.create()
|
||||
..tableName = collabTable;
|
||||
|
||||
payload.supabaseConfig = SupabaseDBConfigPB.create()
|
||||
..supabaseUrl = url
|
||||
..key = key
|
||||
..jwtSecret = jwtSecret
|
||||
..collabTableConfig = collabTableConfig;
|
||||
|
||||
await ConfigEventSetCollabPluginConfig(payload).send();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-config/entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
abstract class KeyValueStorage {
|
||||
Future<void> set(String key, String value);
|
||||
Future<Either<FlowyError, String>> get(String key);
|
||||
Future<void> remove(String key);
|
||||
Future<void> clear();
|
||||
}
|
||||
|
||||
class DartKeyValue implements KeyValueStorage {
|
||||
SharedPreferences? _sharedPreferences;
|
||||
SharedPreferences get sharedPreferences => _sharedPreferences!;
|
||||
|
||||
@override
|
||||
Future<Either<FlowyError, String>> get(String key) async {
|
||||
await _initSharedPreferencesIfNeeded();
|
||||
|
||||
final value = sharedPreferences.getString(key);
|
||||
if (value != null) {
|
||||
return Right(value);
|
||||
}
|
||||
return Left(FlowyError());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> remove(String key) async {
|
||||
await _initSharedPreferencesIfNeeded();
|
||||
|
||||
await sharedPreferences.remove(key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> set(String key, String value) async {
|
||||
await _initSharedPreferencesIfNeeded();
|
||||
|
||||
await sharedPreferences.setString(key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clear() async {
|
||||
await _initSharedPreferencesIfNeeded();
|
||||
|
||||
await sharedPreferences.clear();
|
||||
}
|
||||
|
||||
Future<void> _initSharedPreferencesIfNeeded() async {
|
||||
_sharedPreferences ??= await SharedPreferences.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/// Key-value store
|
||||
/// The data is stored in the local storage of the device.
|
||||
class RustKeyValue implements KeyValueStorage {
|
||||
@override
|
||||
Future<void> set(String key, String value) async {
|
||||
await ConfigEventSetKeyValue(
|
||||
KeyValuePB.create()
|
||||
..key = key
|
||||
..value = value,
|
||||
).send();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<FlowyError, String>> get(String key) async {
|
||||
final payload = KeyPB.create()..key = key;
|
||||
final response = await ConfigEventGetKeyValue(payload).send();
|
||||
return response.swap().map((r) => r.value);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> remove(String key) async {
|
||||
await ConfigEventRemoveKeyValue(
|
||||
KeyPB.create()..key = key,
|
||||
).send();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clear() async {
|
||||
// TODO(Lucas): implement clear
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
class KVKeys {
|
||||
const KVKeys._();
|
||||
|
||||
static const String prefix = 'io.appflowy.appflowy_flutter';
|
||||
|
||||
/// The key for the path location of the local data for the whole app.
|
||||
static const String pathLocation = '$prefix.path_location';
|
||||
|
||||
/// The key for the last time login type.
|
||||
///
|
||||
/// The value is one of the following:
|
||||
/// - local
|
||||
/// - supabase
|
||||
static const String loginType = '$prefix.login_type';
|
||||
|
||||
/// The key for saving the window size
|
||||
///
|
||||
/// The value is a json string with the following format:
|
||||
/// {'height': 600.0, 'width': 800.0}
|
||||
static const String windowSize = 'windowSize';
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/notification/notification_helper.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document2/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef DocumentNotificationCallback = void Function(
|
||||
DocumentNotification,
|
||||
Either<Uint8List, FlowyError>,
|
||||
);
|
||||
|
||||
class DocumentNotificationParser
|
||||
extends NotificationParser<DocumentNotification, FlowyError> {
|
||||
DocumentNotificationParser({
|
||||
String? id,
|
||||
required DocumentNotificationCallback callback,
|
||||
}) : super(
|
||||
id: id,
|
||||
callback: callback,
|
||||
tyParser: (ty) => DocumentNotification.valueOf(ty),
|
||||
errorParser: (bytes) => FlowyError.fromBuffer(bytes),
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'dart:typed_data';
|
||||
import 'package:appflowy_backend/protobuf/flowy-notification/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/notification.pb.dart';
|
||||
import 'package:appflowy_backend/rust_stream.dart';
|
||||
|
||||
import 'notification_helper.dart';
|
||||
@@ -3,7 +3,7 @@ import 'dart:typed_data';
|
||||
import 'package:appflowy_backend/protobuf/flowy-notification/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/notification.pb.dart';
|
||||
import 'package:appflowy_backend/rust_stream.dart';
|
||||
|
||||
import 'notification_helper.dart';
|
||||
@@ -0,0 +1,45 @@
|
||||
// lib/env/env.dart
|
||||
import 'package:envied/envied.dart';
|
||||
|
||||
part 'env.g.dart';
|
||||
|
||||
@Envied(path: '.env')
|
||||
abstract class Env {
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_URL',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseUrl = _Env.supabaseUrl;
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_ANON_KEY',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseAnonKey = _Env.supabaseAnonKey;
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_KEY',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseKey = _Env.supabaseKey;
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_JWT_SECRET',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseJwtSecret = _Env.supabaseJwtSecret;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_COLLAB_TABLE',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseCollabTable = _Env.supabaseCollabTable;
|
||||
}
|
||||
|
||||
bool get isSupabaseEnable =>
|
||||
Env.supabaseUrl.isNotEmpty &&
|
||||
Env.supabaseAnonKey.isNotEmpty &&
|
||||
Env.supabaseKey.isNotEmpty &&
|
||||
Env.supabaseJwtSecret.isNotEmpty;
|
||||
@@ -1,37 +1,10 @@
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:appflowy/startup/entry_point.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||
|
||||
import 'startup/launch_configuration.dart';
|
||||
import 'startup/startup.dart';
|
||||
import 'user/presentation/splash_screen.dart';
|
||||
import 'window/window.dart';
|
||||
|
||||
class FlowyApp implements EntryPoint {
|
||||
@override
|
||||
Widget create(LaunchConfiguration config) {
|
||||
return SplashScreen(
|
||||
autoRegister: config.autoRegistrationSupported,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Handle platform errors not caught by Flutter.
|
||||
// Reduces the likelihood of the app crashing, and logs the error.
|
||||
PlatformDispatcher.instance.onError = (error, stack) {
|
||||
Log.error('Uncaught platform error', error, stack);
|
||||
return true;
|
||||
};
|
||||
|
||||
await EasyLocalization.ensureInitialized();
|
||||
await hotKeyManager.unregisterAll();
|
||||
|
||||
await AppWindow.initialize();
|
||||
|
||||
await FlowyRunner.run(FlowyApp());
|
||||
}
|
||||
@@ -28,16 +28,17 @@ class BlankPluginConfig implements PluginConfig {
|
||||
|
||||
class BlankPagePlugin extends Plugin {
|
||||
@override
|
||||
PluginDisplay get display => BlankPagePluginDisplay();
|
||||
PluginWidgetBuilder get widgetBuilder => BlankPagePluginWidgetBuilder();
|
||||
|
||||
@override
|
||||
PluginId get id => "BlankStack";
|
||||
|
||||
@override
|
||||
PluginType get ty => PluginType.blank;
|
||||
PluginType get pluginType => PluginType.blank;
|
||||
}
|
||||
|
||||
class BlankPagePluginDisplay extends PluginDisplay with NavigationItem {
|
||||
class BlankPagePluginWidgetBuilder extends PluginWidgetBuilder
|
||||
with NavigationItem {
|
||||
@override
|
||||
Widget get leftBarItem => FlowyText.medium(LocaleKeys.blankPageTitle.tr());
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
part of 'cell_service.dart';
|
||||
|
||||
typedef CellByFieldId = LinkedHashMap<String, CellIdentifier>;
|
||||
typedef CellContextByFieldId = LinkedHashMap<String, DatabaseCellContext>;
|
||||
|
||||
class DatabaseCell {
|
||||
dynamic object;
|
||||
@@ -13,7 +13,7 @@ class DatabaseCell {
|
||||
/// We use [fieldId + rowId] to identify the cell.
|
||||
class CellCacheKey {
|
||||
final String fieldId;
|
||||
final String rowId;
|
||||
final RowId rowId;
|
||||
CellCacheKey({
|
||||
required this.fieldId,
|
||||
required this.rowId,
|
||||
@@ -28,7 +28,7 @@ class CellCache {
|
||||
final String viewId;
|
||||
|
||||
/// fieldId: {cacheKey: GridCell}
|
||||
final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
|
||||
final Map<String, Map<RowId, dynamic>> _cellDataByFieldId = {};
|
||||
CellCache({
|
||||
required this.viewId,
|
||||
});
|
||||
@@ -38,7 +38,7 @@ class CellCache {
|
||||
}
|
||||
|
||||
void remove(CellCacheKey key) {
|
||||
var map = _cellDataByFieldId[key.fieldId];
|
||||
final map = _cellDataByFieldId[key.fieldId];
|
||||
if (map != null) {
|
||||
map.remove(key.rowId);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_listener.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
@@ -21,7 +22,7 @@ import 'cell_service.dart';
|
||||
///
|
||||
// ignore: must_be_immutable
|
||||
class CellController<T, D> extends Equatable {
|
||||
final CellIdentifier cellId;
|
||||
final DatabaseCellContext cellContext;
|
||||
final CellCache _cellCache;
|
||||
final CellCacheKey _cacheKey;
|
||||
final FieldBackendService _fieldBackendSvc;
|
||||
@@ -36,37 +37,37 @@ class CellController<T, D> extends Equatable {
|
||||
Timer? _loadDataOperation;
|
||||
Timer? _saveDataOperation;
|
||||
|
||||
String get viewId => cellId.viewId;
|
||||
String get viewId => cellContext.viewId;
|
||||
|
||||
String get rowId => cellId.rowId;
|
||||
RowId get rowId => cellContext.rowId;
|
||||
|
||||
String get fieldId => cellId.fieldInfo.id;
|
||||
String get fieldId => cellContext.fieldInfo.id;
|
||||
|
||||
FieldInfo get fieldInfo => cellId.fieldInfo;
|
||||
FieldInfo get fieldInfo => cellContext.fieldInfo;
|
||||
|
||||
FieldType get fieldType => cellId.fieldInfo.fieldType;
|
||||
FieldType get fieldType => cellContext.fieldInfo.fieldType;
|
||||
|
||||
CellController({
|
||||
required this.cellId,
|
||||
required this.cellContext,
|
||||
required CellCache cellCache,
|
||||
required CellDataLoader<T> cellDataLoader,
|
||||
required CellDataPersistence<D> cellDataPersistence,
|
||||
}) : _cellCache = cellCache,
|
||||
_cellDataLoader = cellDataLoader,
|
||||
_cellDataPersistence = cellDataPersistence,
|
||||
_fieldListener = SingleFieldListener(fieldId: cellId.fieldId),
|
||||
_fieldListener = SingleFieldListener(fieldId: cellContext.fieldId),
|
||||
_fieldBackendSvc = FieldBackendService(
|
||||
viewId: cellId.viewId,
|
||||
fieldId: cellId.fieldInfo.id,
|
||||
viewId: cellContext.viewId,
|
||||
fieldId: cellContext.fieldInfo.id,
|
||||
),
|
||||
_cacheKey = CellCacheKey(
|
||||
rowId: cellId.rowId,
|
||||
fieldId: cellId.fieldInfo.id,
|
||||
rowId: cellContext.rowId,
|
||||
fieldId: cellContext.fieldInfo.id,
|
||||
) {
|
||||
_cellDataNotifier = CellDataNotifier(value: _cellCache.get(_cacheKey));
|
||||
_cellListener = CellListener(
|
||||
rowId: cellId.rowId,
|
||||
fieldId: cellId.fieldInfo.id,
|
||||
rowId: cellContext.rowId,
|
||||
fieldId: cellContext.fieldInfo.id,
|
||||
);
|
||||
|
||||
/// 1.Listen on user edit event and load the new cell data if needed.
|
||||
@@ -194,8 +195,10 @@ class CellController<T, D> extends Equatable {
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props =>
|
||||
[_cellCache.get(_cacheKey) ?? "", cellId.rowId + cellId.fieldInfo.id];
|
||||
List<Object> get props => [
|
||||
_cellCache.get(_cacheKey) ?? "",
|
||||
cellContext.rowId + cellContext.fieldInfo.id
|
||||
];
|
||||
}
|
||||
|
||||
class CellDataNotifier<T> extends ChangeNotifier {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/url_type_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/url_entities.pb.dart';
|
||||
|
||||
import 'cell_controller.dart';
|
||||
import 'cell_service.dart';
|
||||
@@ -11,96 +12,116 @@ typedef CheckboxCellController = CellController<String, String>;
|
||||
typedef NumberCellController = CellController<String, String>;
|
||||
typedef SelectOptionCellController
|
||||
= CellController<SelectOptionCellDataPB, String>;
|
||||
typedef ChecklistCellController
|
||||
= CellController<SelectOptionCellDataPB, String>;
|
||||
typedef ChecklistCellController = CellController<ChecklistCellDataPB, String>;
|
||||
typedef DateCellController = CellController<DateCellDataPB, DateCellData>;
|
||||
typedef URLCellController = CellController<URLCellDataPB, String>;
|
||||
|
||||
class CellControllerBuilder {
|
||||
final CellIdentifier _cellId;
|
||||
final DatabaseCellContext _cellContext;
|
||||
final CellCache _cellCache;
|
||||
|
||||
CellControllerBuilder({
|
||||
required CellIdentifier cellId,
|
||||
required DatabaseCellContext cellContext,
|
||||
required CellCache cellCache,
|
||||
}) : _cellCache = cellCache,
|
||||
_cellId = cellId;
|
||||
_cellContext = cellContext;
|
||||
|
||||
CellController build() {
|
||||
switch (_cellId.fieldType) {
|
||||
switch (_cellContext.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
parser: StringCellDataParser(),
|
||||
);
|
||||
return TextCellController(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||
cellDataPersistence:
|
||||
TextCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.LastEditedTime:
|
||||
case FieldType.CreatedTime:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
parser: DateCellDataParser(),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
|
||||
return DateCellController(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
|
||||
cellDataPersistence:
|
||||
DateCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
case FieldType.Number:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
parser: NumberCellDataParser(),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
return NumberCellController(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||
cellDataPersistence:
|
||||
TextCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
case FieldType.RichText:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
parser: StringCellDataParser(),
|
||||
);
|
||||
return TextCellController(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||
cellDataPersistence:
|
||||
TextCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.SingleSelect:
|
||||
case FieldType.Checklist:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
parser: SelectOptionCellDataParser(),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
|
||||
return SelectOptionCellController(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||
cellDataPersistence:
|
||||
TextCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
|
||||
case FieldType.Checklist:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellContext: _cellContext,
|
||||
parser: ChecklistCellDataParser(),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
|
||||
return ChecklistCellController(
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence:
|
||||
TextCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
case FieldType.URL:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
parser: URLCellDataParser(),
|
||||
);
|
||||
return URLCellController(
|
||||
cellId: _cellId,
|
||||
cellContext: _cellContext,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||
cellDataPersistence:
|
||||
TextCellDataPersistence(cellContext: _cellContext),
|
||||
);
|
||||
}
|
||||
throw UnimplementedError;
|
||||
|
||||
@@ -11,18 +11,18 @@ abstract class CellDataParser<T> {
|
||||
|
||||
class CellDataLoader<T> {
|
||||
final CellBackendService service = CellBackendService();
|
||||
final CellIdentifier cellId;
|
||||
final DatabaseCellContext cellContext;
|
||||
final CellDataParser<T> parser;
|
||||
final bool reloadOnFieldChanged;
|
||||
|
||||
CellDataLoader({
|
||||
required this.cellId,
|
||||
required this.cellContext,
|
||||
required this.parser,
|
||||
this.reloadOnFieldChanged = false,
|
||||
});
|
||||
|
||||
Future<T?> loadData() {
|
||||
final fut = service.getCell(cellId: cellId);
|
||||
final fut = service.getCell(cellContext: cellContext);
|
||||
return fut.then(
|
||||
(result) => result.fold(
|
||||
(CellPB cell) {
|
||||
@@ -84,6 +84,16 @@ class SelectOptionCellDataParser
|
||||
}
|
||||
}
|
||||
|
||||
class ChecklistCellDataParser implements CellDataParser<ChecklistCellDataPB> {
|
||||
@override
|
||||
ChecklistCellDataPB? parserData(List<int> data) {
|
||||
if (data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return ChecklistCellDataPB.fromBuffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
class URLCellDataParser implements CellDataParser<URLCellDataPB> {
|
||||
@override
|
||||
URLCellDataPB? parserData(List<int> data) {
|
||||
|
||||
@@ -7,16 +7,19 @@ abstract class CellDataPersistence<D> {
|
||||
}
|
||||
|
||||
class TextCellDataPersistence implements CellDataPersistence<String> {
|
||||
final CellIdentifier cellId;
|
||||
final DatabaseCellContext cellContext;
|
||||
final _cellBackendSvc = CellBackendService();
|
||||
|
||||
TextCellDataPersistence({
|
||||
required this.cellId,
|
||||
required this.cellContext,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Option<FlowyError>> save(String data) async {
|
||||
final fut = _cellBackendSvc.updateCell(cellId: cellId, data: data);
|
||||
final fut = _cellBackendSvc.updateCell(
|
||||
cellContext: cellContext,
|
||||
data: data,
|
||||
);
|
||||
return fut.then((result) {
|
||||
return result.fold(
|
||||
(l) => none(),
|
||||
@@ -29,30 +32,30 @@ class TextCellDataPersistence implements CellDataPersistence<String> {
|
||||
@freezed
|
||||
class DateCellData with _$DateCellData {
|
||||
const factory DateCellData({
|
||||
required DateTime date,
|
||||
DateTime? dateTime,
|
||||
String? time,
|
||||
required bool includeTime,
|
||||
}) = _DateCellData;
|
||||
}
|
||||
|
||||
class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
||||
final CellIdentifier cellId;
|
||||
final DatabaseCellContext cellContext;
|
||||
DateCellDataPersistence({
|
||||
required this.cellId,
|
||||
required this.cellContext,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Option<FlowyError>> save(DateCellData data) {
|
||||
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
|
||||
|
||||
final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
|
||||
payload.date = date;
|
||||
payload.isUtc = data.date.isUtc;
|
||||
payload.includeTime = data.includeTime;
|
||||
|
||||
final payload = DateChangesetPB.create()
|
||||
..cellPath = _makeCellPath(cellContext);
|
||||
if (data.dateTime != null) {
|
||||
final date = (data.dateTime!.millisecondsSinceEpoch ~/ 1000).toString();
|
||||
payload.date = date;
|
||||
}
|
||||
if (data.time != null) {
|
||||
payload.time = data.time!;
|
||||
}
|
||||
payload.includeTime = data.includeTime;
|
||||
|
||||
return DatabaseEventUpdateDateCell(payload).send().then((result) {
|
||||
return result.fold(
|
||||
@@ -63,7 +66,7 @@ class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
||||
}
|
||||
}
|
||||
|
||||
CellIdPB _makeCellPath(CellIdentifier cellId) {
|
||||
CellIdPB _makeCellPath(DatabaseCellContext cellId) {
|
||||
return CellIdPB.create()
|
||||
..viewId = cellId.viewId
|
||||
..fieldId = cellId.fieldId
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import 'package:appflowy/core/grid_notification.dart';
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import '../row/row_service.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<Unit, FlowyError>;
|
||||
|
||||
class CellListener {
|
||||
final String rowId;
|
||||
final RowId rowId;
|
||||
final String fieldId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue>? _updateCellNotifier =
|
||||
PublishNotifier();
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/url_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/cell_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/url_type_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:convert' show utf8;
|
||||
|
||||
import '../field/field_controller.dart';
|
||||
import '../row/row_service.dart';
|
||||
part 'cell_service.freezed.dart';
|
||||
part 'cell_data_loader.dart';
|
||||
part 'cell_cache.dart';
|
||||
@@ -23,40 +25,39 @@ class CellBackendService {
|
||||
CellBackendService();
|
||||
|
||||
Future<Either<void, FlowyError>> updateCell({
|
||||
required CellIdentifier cellId,
|
||||
required DatabaseCellContext cellContext,
|
||||
required String data,
|
||||
}) {
|
||||
final payload = CellChangesetPB.create()
|
||||
..viewId = cellId.viewId
|
||||
..fieldId = cellId.fieldId
|
||||
..rowId = cellId.rowId
|
||||
..typeCellData = data;
|
||||
..viewId = cellContext.viewId
|
||||
..fieldId = cellContext.fieldId
|
||||
..rowId = cellContext.rowId
|
||||
..cellChangeset = data;
|
||||
return DatabaseEventUpdateCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<CellPB, FlowyError>> getCell({
|
||||
required CellIdentifier cellId,
|
||||
required DatabaseCellContext cellContext,
|
||||
}) {
|
||||
final payload = CellIdPB.create()
|
||||
..viewId = cellId.viewId
|
||||
..fieldId = cellId.fieldId
|
||||
..rowId = cellId.rowId;
|
||||
..viewId = cellContext.viewId
|
||||
..fieldId = cellContext.fieldId
|
||||
..rowId = cellContext.rowId;
|
||||
return DatabaseEventGetCell(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
/// Id of the cell
|
||||
/// We can locate the cell by using database + rowId + field.id.
|
||||
@freezed
|
||||
class CellIdentifier with _$CellIdentifier {
|
||||
const factory CellIdentifier({
|
||||
class DatabaseCellContext with _$DatabaseCellContext {
|
||||
const factory DatabaseCellContext({
|
||||
required String viewId,
|
||||
required String rowId,
|
||||
required RowId rowId,
|
||||
required FieldInfo fieldInfo,
|
||||
}) = _CellIdentifier;
|
||||
}) = _DatabaseCellContext;
|
||||
|
||||
// ignore: unused_element
|
||||
const CellIdentifier._();
|
||||
const DatabaseCellContext._();
|
||||
|
||||
String get fieldId => fieldInfo.id;
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
class ChecklistCellBackendService {
|
||||
final DatabaseCellContext cellContext;
|
||||
|
||||
ChecklistCellBackendService({required this.cellContext});
|
||||
|
||||
Future<Either<Unit, FlowyError>> create({
|
||||
required String name,
|
||||
}) {
|
||||
final payload = ChecklistCellDataChangesetPB.create()
|
||||
..viewId = cellContext.viewId
|
||||
..fieldId = cellContext.fieldInfo.id
|
||||
..rowId = cellContext.rowId
|
||||
..insertOptions.add(name);
|
||||
|
||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> delete({
|
||||
required List<String> optionIds,
|
||||
}) {
|
||||
final payload = ChecklistCellDataChangesetPB.create()
|
||||
..viewId = cellContext.viewId
|
||||
..fieldId = cellContext.fieldInfo.id
|
||||
..rowId = cellContext.rowId
|
||||
..deleteOptionIds.addAll(optionIds);
|
||||
|
||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> select({
|
||||
required String optionId,
|
||||
}) {
|
||||
final payload = ChecklistCellDataChangesetPB.create()
|
||||
..viewId = cellContext.viewId
|
||||
..fieldId = cellContext.fieldInfo.id
|
||||
..rowId = cellContext.rowId
|
||||
..selectedOptionIds.add(optionId);
|
||||
|
||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> update({
|
||||
required SelectOptionPB option,
|
||||
}) {
|
||||
final payload = ChecklistCellDataChangesetPB.create()
|
||||
..viewId = cellContext.viewId
|
||||
..fieldId = cellContext.fieldInfo.id
|
||||
..rowId = cellContext.rowId
|
||||
..updateOptions.add(option);
|
||||
|
||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<ChecklistCellDataPB, FlowyError>> getCellData() {
|
||||
final payload = CellIdPB.create()
|
||||
..fieldId = cellContext.fieldInfo.id
|
||||
..viewId = cellContext.viewId
|
||||
..rowId = cellContext.rowId
|
||||
..rowId = cellContext.rowId;
|
||||
|
||||
return DatabaseEventGetChecklistCellData(payload).send();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/cell_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
|
||||
|
||||
class SelectOptionBackendService {
|
||||
final CellIdentifier cellId;
|
||||
SelectOptionBackendService({required this.cellId});
|
||||
class SelectOptionCellBackendService {
|
||||
final DatabaseCellContext cellContext;
|
||||
SelectOptionCellBackendService({required this.cellContext});
|
||||
|
||||
String get viewId => cellId.viewId;
|
||||
String get fieldId => cellId.fieldInfo.id;
|
||||
String get rowId => cellId.rowId;
|
||||
String get viewId => cellContext.viewId;
|
||||
String get fieldId => cellContext.fieldInfo.id;
|
||||
RowId get rowId => cellContext.rowId;
|
||||
|
||||
Future<Either<Unit, FlowyError>> create({
|
||||
required String name,
|
||||
@@ -24,19 +25,17 @@ class SelectOptionBackendService {
|
||||
(result) {
|
||||
return result.fold(
|
||||
(option) {
|
||||
final cellIdentifier = CellIdPB.create()
|
||||
final payload = RepeatedSelectOptionPayload.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
final payload = SelectOptionChangesetPB.create()
|
||||
..cellIdentifier = cellIdentifier;
|
||||
|
||||
if (isSelected) {
|
||||
payload.insertOptions.add(option);
|
||||
payload.items.add(option);
|
||||
} else {
|
||||
payload.updateOptions.add(option);
|
||||
payload.items.add(option);
|
||||
}
|
||||
return DatabaseEventUpdateSelectOption(payload).send();
|
||||
return DatabaseEventInsertOrUpdateSelectOption(payload).send();
|
||||
},
|
||||
(r) => right(r),
|
||||
);
|
||||
@@ -47,20 +46,24 @@ class SelectOptionBackendService {
|
||||
Future<Either<Unit, FlowyError>> update({
|
||||
required SelectOptionPB option,
|
||||
}) {
|
||||
final payload = SelectOptionChangesetPB.create()
|
||||
..updateOptions.add(option)
|
||||
..cellIdentifier = _cellIdentifier();
|
||||
return DatabaseEventUpdateSelectOption(payload).send();
|
||||
final payload = RepeatedSelectOptionPayload.create()
|
||||
..items.add(option)
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
return DatabaseEventInsertOrUpdateSelectOption(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> delete({
|
||||
required Iterable<SelectOptionPB> options,
|
||||
}) {
|
||||
final payload = SelectOptionChangesetPB.create()
|
||||
..deleteOptions.addAll(options)
|
||||
..cellIdentifier = _cellIdentifier();
|
||||
final payload = RepeatedSelectOptionPayload.create()
|
||||
..items.addAll(options)
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
|
||||
return DatabaseEventUpdateSelectOption(payload).send();
|
||||
return DatabaseEventDeleteSelectOption(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<SelectOptionCellDataPB, FlowyError>> getCellData() {
|
||||
@@ -2,14 +2,14 @@ import 'package:appflowy/plugins/database_view/application/field/field_controlle
|
||||
import 'package:appflowy/plugins/database_view/application/layout/calendar_setting_listener.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/view/view_cache.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
@@ -18,6 +18,7 @@ import 'defines.dart';
|
||||
import 'layout/layout_setting_listener.dart';
|
||||
import 'row/row_cache.dart';
|
||||
import 'group/group_listener.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
||||
typedef OnGroupByField = void Function(List<GroupPB>);
|
||||
typedef OnUpdateGroup = void Function(List<GroupPB>);
|
||||
@@ -38,18 +39,18 @@ class GroupCallbacks {
|
||||
});
|
||||
}
|
||||
|
||||
class LayoutCallbacks {
|
||||
final void Function(LayoutSettingPB) onLayoutChanged;
|
||||
final void Function(LayoutSettingPB) onLoadLayout;
|
||||
class DatabaseLayoutSettingCallbacks {
|
||||
final void Function(DatabaseLayoutSettingPB) onLayoutChanged;
|
||||
final void Function(DatabaseLayoutSettingPB) onLoadLayout;
|
||||
|
||||
LayoutCallbacks({
|
||||
DatabaseLayoutSettingCallbacks({
|
||||
required this.onLayoutChanged,
|
||||
required this.onLoadLayout,
|
||||
});
|
||||
}
|
||||
|
||||
class CalendarLayoutCallbacks {
|
||||
final void Function(LayoutSettingPB) onCalendarLayoutChanged;
|
||||
final void Function(DatabaseLayoutSettingPB) onCalendarLayoutChanged;
|
||||
|
||||
CalendarLayoutCallbacks({required this.onCalendarLayoutChanged});
|
||||
}
|
||||
@@ -58,14 +59,14 @@ class DatabaseCallbacks {
|
||||
OnDatabaseChanged? onDatabaseChanged;
|
||||
OnFieldsChanged? onFieldsChanged;
|
||||
OnFiltersChanged? onFiltersChanged;
|
||||
OnRowsChanged? onRowsChanged;
|
||||
OnNumOfRowsChanged? onNumOfRowsChanged;
|
||||
OnRowsDeleted? onRowsDeleted;
|
||||
OnRowsUpdated? onRowsUpdated;
|
||||
OnRowsCreated? onRowsCreated;
|
||||
|
||||
DatabaseCallbacks({
|
||||
this.onDatabaseChanged,
|
||||
this.onRowsChanged,
|
||||
this.onNumOfRowsChanged,
|
||||
this.onFieldsChanged,
|
||||
this.onFiltersChanged,
|
||||
this.onRowsUpdated,
|
||||
@@ -78,13 +79,13 @@ class DatabaseController {
|
||||
final String viewId;
|
||||
final DatabaseViewBackendService _databaseViewBackendSvc;
|
||||
final FieldController fieldController;
|
||||
DatabaseLayoutPB? databaseLayout;
|
||||
late DatabaseViewCache _viewCache;
|
||||
final LayoutTypePB layoutType;
|
||||
|
||||
// Callbacks
|
||||
DatabaseCallbacks? _databaseCallbacks;
|
||||
GroupCallbacks? _groupCallbacks;
|
||||
LayoutCallbacks? _layoutCallbacks;
|
||||
DatabaseLayoutSettingCallbacks? _layoutCallbacks;
|
||||
CalendarLayoutCallbacks? _calendarLayoutCallbacks;
|
||||
|
||||
// Getters
|
||||
@@ -92,15 +93,15 @@ class DatabaseController {
|
||||
|
||||
// Listener
|
||||
final DatabaseGroupListener groupListener;
|
||||
final DatabaseLayoutListener layoutListener;
|
||||
final DatabaseLayoutSettingListener layoutListener;
|
||||
final DatabaseCalendarLayoutListener calendarLayoutListener;
|
||||
|
||||
DatabaseController({required ViewPB view, required this.layoutType})
|
||||
DatabaseController({required ViewPB view})
|
||||
: viewId = view.id,
|
||||
_databaseViewBackendSvc = DatabaseViewBackendService(viewId: view.id),
|
||||
fieldController = FieldController(viewId: view.id),
|
||||
groupListener = DatabaseGroupListener(view.id),
|
||||
layoutListener = DatabaseLayoutListener(view.id),
|
||||
layoutListener = DatabaseLayoutSettingListener(view.id),
|
||||
calendarLayoutListener = DatabaseCalendarLayoutListener(view.id) {
|
||||
_viewCache = DatabaseViewCache(
|
||||
viewId: viewId,
|
||||
@@ -110,14 +111,11 @@ class DatabaseController {
|
||||
_listenOnFieldsChanged();
|
||||
_listenOnGroupChanged();
|
||||
_listenOnLayoutChanged();
|
||||
if (layoutType == LayoutTypePB.Calendar) {
|
||||
_listenOnCalendarLayoutChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void setListener({
|
||||
DatabaseCallbacks? onDatabaseChanged,
|
||||
LayoutCallbacks? onLayoutChanged,
|
||||
DatabaseLayoutSettingCallbacks? onLayoutChanged,
|
||||
GroupCallbacks? onGroupChanged,
|
||||
CalendarLayoutCallbacks? onCalendarLayoutChanged,
|
||||
}) {
|
||||
@@ -131,6 +129,12 @@ class DatabaseController {
|
||||
return _databaseViewBackendSvc.openGrid().then((result) {
|
||||
return result.fold(
|
||||
(database) async {
|
||||
databaseLayout = database.layoutType;
|
||||
|
||||
if (databaseLayout == DatabaseLayoutPB.Calendar) {
|
||||
_listenOnCalendarLayoutChanged();
|
||||
}
|
||||
|
||||
_databaseCallbacks?.onDatabaseChanged?.call(database);
|
||||
_viewCache.rowCache.setInitialRows(database.rows);
|
||||
return await fieldController
|
||||
@@ -156,7 +160,7 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
Future<Either<RowPB, FlowyError>> createRow({
|
||||
String? startRowId,
|
||||
RowId? startRowId,
|
||||
String? groupId,
|
||||
void Function(RowDataBuilder builder)? withCells,
|
||||
}) {
|
||||
@@ -175,18 +179,28 @@ class DatabaseController {
|
||||
);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveRow({
|
||||
Future<Either<Unit, FlowyError>> moveGroupRow({
|
||||
required RowPB fromRow,
|
||||
required String groupId,
|
||||
RowPB? toRow,
|
||||
}) {
|
||||
return _databaseViewBackendSvc.moveRow(
|
||||
return _databaseViewBackendSvc.moveGroupRow(
|
||||
fromRowId: fromRow.id,
|
||||
toGroupId: groupId,
|
||||
toRowId: toRow?.id,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveRow({
|
||||
required RowPB fromRow,
|
||||
required RowPB toRow,
|
||||
}) {
|
||||
return _databaseViewBackendSvc.moveRow(
|
||||
fromRowId: fromRow.id,
|
||||
toRowId: toRow.id,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveGroup({
|
||||
required String fromGroupId,
|
||||
required String toGroupId,
|
||||
@@ -198,7 +212,7 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
Future<void> updateCalenderLayoutSetting(
|
||||
CalendarLayoutSettingsPB layoutSetting,
|
||||
CalendarLayoutSettingPB layoutSetting,
|
||||
) async {
|
||||
await _databaseViewBackendSvc
|
||||
.updateLayoutSetting(calendarLayoutSetting: layoutSetting)
|
||||
@@ -231,20 +245,20 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
Future<void> _loadLayoutSetting() async {
|
||||
_databaseViewBackendSvc.getLayoutSetting(layoutType).then((result) {
|
||||
result.fold(
|
||||
(l) {
|
||||
_layoutCallbacks?.onLoadLayout(l);
|
||||
},
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
});
|
||||
if (databaseLayout != null) {
|
||||
_databaseViewBackendSvc.getLayoutSetting(databaseLayout!).then((result) {
|
||||
result.fold(
|
||||
(l) => _layoutCallbacks?.onLoadLayout(l),
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _listenOnRowsChanged() {
|
||||
final callbacks = DatabaseViewCallbacks(
|
||||
onRowsChanged: (rows, rowByRowId, reason) {
|
||||
_databaseCallbacks?.onRowsChanged?.call(rows, rowByRowId, reason);
|
||||
onNumOfRowsChanged: (rows, rowByRowId, reason) {
|
||||
_databaseCallbacks?.onNumOfRowsChanged?.call(rows, rowByRowId, reason);
|
||||
},
|
||||
onRowsDeleted: (ids) {
|
||||
_databaseCallbacks?.onRowsDeleted?.call(ids);
|
||||
@@ -341,10 +355,15 @@ class RowDataBuilder {
|
||||
_cellDataByFieldId[fieldInfo.field.id] = num.toString();
|
||||
}
|
||||
|
||||
/// The date should use the UTC timezone. Becuase the backend uses UTC timezone to format the time string.
|
||||
void insertDate(FieldInfo fieldInfo, DateTime date) {
|
||||
assert(fieldInfo.fieldType == FieldType.DateTime);
|
||||
final timestamp = (date.toUtc().millisecondsSinceEpoch ~/ 1000);
|
||||
assert(
|
||||
[
|
||||
FieldType.DateTime,
|
||||
FieldType.LastEditedTime,
|
||||
FieldType.CreatedTime,
|
||||
].contains(fieldInfo.fieldType),
|
||||
);
|
||||
final timestamp = date.millisecondsSinceEpoch ~/ 1000;
|
||||
_cellDataByFieldId[fieldInfo.field.id] = timestamp.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pb.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
|
||||
class DatabaseViewBackendService {
|
||||
final String viewId;
|
||||
@@ -16,22 +17,26 @@ class DatabaseViewBackendService {
|
||||
required this.viewId,
|
||||
});
|
||||
|
||||
Future<Either<DatabasePB, FlowyError>> openGrid() async {
|
||||
await FolderEventSetLatestView(ViewIdPB(value: viewId)).send();
|
||||
/// Returns the datbaase id associated with the view.
|
||||
Future<Either<String, FlowyError>> getDatabaseId() async {
|
||||
final payload = DatabaseViewIdPB(value: viewId);
|
||||
return DatabaseEventGetDatabaseId(payload)
|
||||
.send()
|
||||
.then((value) => value.leftMap((l) => l.value));
|
||||
}
|
||||
|
||||
Future<Either<DatabasePB, FlowyError>> openGrid() async {
|
||||
final payload = DatabaseViewIdPB(value: viewId);
|
||||
return DatabaseEventGetDatabase(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<RowPB, FlowyError>> createRow({
|
||||
String? startRowId,
|
||||
RowId? startRowId,
|
||||
String? groupId,
|
||||
Map<String, String>? cellDataByFieldId,
|
||||
}) {
|
||||
var payload = CreateRowPayloadPB.create()..viewId = viewId;
|
||||
if (startRowId != null) {
|
||||
payload.startRowId = startRowId;
|
||||
}
|
||||
final payload = CreateRowPayloadPB.create()..viewId = viewId;
|
||||
payload.startRowId = startRowId ?? "";
|
||||
|
||||
if (groupId != null) {
|
||||
payload.groupId = groupId;
|
||||
@@ -44,12 +49,12 @@ class DatabaseViewBackendService {
|
||||
return DatabaseEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveRow({
|
||||
required String fromRowId,
|
||||
Future<Either<Unit, FlowyError>> moveGroupRow({
|
||||
required RowId fromRowId,
|
||||
required String toGroupId,
|
||||
String? toRowId,
|
||||
RowId? toRowId,
|
||||
}) {
|
||||
var payload = MoveGroupRowPayloadPB.create()
|
||||
final payload = MoveGroupRowPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fromRowId = fromRowId
|
||||
..toGroupId = toGroupId;
|
||||
@@ -61,6 +66,18 @@ class DatabaseViewBackendService {
|
||||
return DatabaseEventMoveGroupRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveRow({
|
||||
required String fromRowId,
|
||||
required String toRowId,
|
||||
}) {
|
||||
final payload = MoveRowPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fromRowId = fromRowId
|
||||
..toRowId = toRowId;
|
||||
|
||||
return DatabaseEventMoveRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveGroup({
|
||||
required String fromGroupId,
|
||||
required String toGroupId,
|
||||
@@ -76,7 +93,7 @@ class DatabaseViewBackendService {
|
||||
Future<Either<List<FieldPB>, FlowyError>> getFields({
|
||||
List<FieldIdPB>? fieldIds,
|
||||
}) {
|
||||
var payload = GetFieldPayloadPB.create()..viewId = viewId;
|
||||
final payload = GetFieldPayloadPB.create()..viewId = viewId;
|
||||
|
||||
if (fieldIds != null) {
|
||||
payload.fieldIds = RepeatedFieldIdPB(items: fieldIds);
|
||||
@@ -86,27 +103,23 @@ class DatabaseViewBackendService {
|
||||
});
|
||||
}
|
||||
|
||||
Future<Either<LayoutSettingPB, FlowyError>> getLayoutSetting(
|
||||
LayoutTypePB layoutType,
|
||||
Future<Either<DatabaseLayoutSettingPB, FlowyError>> getLayoutSetting(
|
||||
DatabaseLayoutPB layoutType,
|
||||
) {
|
||||
final payload = DatabaseLayoutIdPB.create()
|
||||
final payload = DatabaseLayoutMetaPB.create()
|
||||
..viewId = viewId
|
||||
..layout = layoutType;
|
||||
return DatabaseEventGetLayoutSetting(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> updateLayoutSetting({
|
||||
CalendarLayoutSettingsPB? calendarLayoutSetting,
|
||||
CalendarLayoutSettingPB? calendarLayoutSetting,
|
||||
}) {
|
||||
final layoutSetting = LayoutSettingPB.create();
|
||||
final payload = LayoutSettingChangesetPB.create()..viewId = viewId;
|
||||
if (calendarLayoutSetting != null) {
|
||||
layoutSetting.calendar = calendarLayoutSetting;
|
||||
payload.calendar = calendarLayoutSetting;
|
||||
}
|
||||
|
||||
final payload = UpdateLayoutSettingPB.create()
|
||||
..viewId = viewId
|
||||
..layoutSetting = layoutSetting;
|
||||
|
||||
return DatabaseEventSetLayoutSetting(payload).send();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
|
||||
import '../grid/presentation/widgets/filter/filter_info.dart';
|
||||
import 'field/field_controller.dart';
|
||||
import 'row/row_cache.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
||||
typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldInfo>);
|
||||
typedef OnFiltersChanged = void Function(List<FilterInfo>);
|
||||
typedef OnDatabaseChanged = void Function(DatabasePB);
|
||||
|
||||
typedef OnRowsCreated = void Function(List<String> ids);
|
||||
typedef OnRowsUpdated = void Function(List<String> ids);
|
||||
typedef OnRowsDeleted = void Function(List<String> ids);
|
||||
typedef OnRowsChanged = void Function(
|
||||
typedef OnRowsCreated = void Function(List<RowId> ids);
|
||||
typedef OnRowsUpdated = void Function(List<RowId> ids);
|
||||
typedef OnRowsDeleted = void Function(List<RowId> ids);
|
||||
typedef OnNumOfRowsChanged = void Function(
|
||||
UnmodifiableListView<RowInfo> rows,
|
||||
UnmodifiableMapView<String, RowInfo> rowByRowId,
|
||||
UnmodifiableMapView<RowId, RowInfo> rowByRowId,
|
||||
RowsChangedReason reason,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'field_service.dart';
|
||||
@@ -10,7 +10,7 @@ class FieldActionSheetBloc
|
||||
extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
|
||||
final FieldBackendService fieldService;
|
||||
|
||||
FieldActionSheetBloc({required FieldCellContext fieldCellContext})
|
||||
FieldActionSheetBloc({required FieldContext fieldCellContext})
|
||||
: fieldService = FieldBackendService(
|
||||
viewId: fieldCellContext.viewId,
|
||||
fieldId: fieldCellContext.field.id,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@@ -14,7 +14,7 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||
final FieldBackendService _fieldBackendSvc;
|
||||
|
||||
FieldCellBloc({
|
||||
required FieldCellContext cellContext,
|
||||
required FieldContext cellContext,
|
||||
}) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
|
||||
_fieldBackendSvc = FieldBackendService(
|
||||
viewId: cellContext.viewId,
|
||||
@@ -83,8 +83,7 @@ class FieldCellState with _$FieldCellState {
|
||||
required double width,
|
||||
}) = _FieldCellState;
|
||||
|
||||
factory FieldCellState.initial(FieldCellContext cellContext) =>
|
||||
FieldCellState(
|
||||
factory FieldCellState.initial(FieldContext cellContext) => FieldCellState(
|
||||
viewId: cellContext.viewId,
|
||||
field: cellContext.field,
|
||||
width: cellContext.field.width.toDouble(),
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'dart:collection';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/filter_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/sort_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/filter_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/util.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/util.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../../grid/presentation/widgets/filter/filter_info.dart';
|
||||
import '../../grid/presentation/widgets/sort/sort_info.dart';
|
||||
@@ -94,7 +94,7 @@ class FieldController {
|
||||
_updatedFieldCallbacks = {};
|
||||
|
||||
// Group callbacks
|
||||
final Map<String, GroupConfigurationPB> _groupConfigurationByFieldId = {};
|
||||
final Map<String, GroupSettingPB> _groupConfigurationByFieldId = {};
|
||||
|
||||
// Filter callbacks
|
||||
final Map<OnReceiveFilters, VoidCallback> _filterCallbacks = {};
|
||||
@@ -401,7 +401,7 @@ class FieldController {
|
||||
|
||||
void _updateSetting(DatabaseViewSettingPB setting) {
|
||||
_groupConfigurationByFieldId.clear();
|
||||
for (final configuration in setting.groupConfigurations.items) {
|
||||
for (final configuration in setting.groupSettings.items) {
|
||||
_groupConfigurationByFieldId[configuration.fieldId] = configuration;
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ class FieldController {
|
||||
|
||||
void _updateFieldInfos() {
|
||||
if (_fieldNotifier != null) {
|
||||
for (var field in _fieldNotifier!.fieldInfos) {
|
||||
for (final field in _fieldNotifier!.fieldInfos) {
|
||||
field._isGroupField = _groupConfigurationByFieldId[field.id] != null;
|
||||
field._hasFilter = _filterPBByFieldId[field.id] != null;
|
||||
field._hasSort = _sortPBByFieldId[field.id] != null;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'field_service.dart';
|
||||
@@ -12,12 +12,20 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
final TypeOptionController dataController;
|
||||
|
||||
FieldEditorBloc({
|
||||
required String viewId,
|
||||
required String fieldName,
|
||||
required bool isGroupField,
|
||||
required IFieldTypeOptionLoader loader,
|
||||
}) : dataController = TypeOptionController(viewId: viewId, loader: loader),
|
||||
super(FieldEditorState.initial(viewId, fieldName, isGroupField)) {
|
||||
required FieldPB field,
|
||||
required FieldTypeOptionLoader loader,
|
||||
}) : dataController = TypeOptionController(
|
||||
field: field,
|
||||
loader: loader,
|
||||
),
|
||||
super(
|
||||
FieldEditorState.initial(
|
||||
loader.viewId,
|
||||
loader.field.name,
|
||||
isGroupField,
|
||||
),
|
||||
) {
|
||||
on<FieldEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
@@ -27,7 +35,8 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
add(FieldEditorEvent.didReceiveFieldChanged(field));
|
||||
}
|
||||
});
|
||||
await dataController.loadTypeOptionData();
|
||||
await dataController.reloadTypeOption();
|
||||
add(FieldEditorEvent.didReceiveFieldChanged(dataController.field));
|
||||
},
|
||||
updateName: (name) {
|
||||
if (state.name != name) {
|
||||
@@ -49,7 +58,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
() => null,
|
||||
(field) {
|
||||
final fieldService = FieldBackendService(
|
||||
viewId: viewId,
|
||||
viewId: loader.viewId,
|
||||
fieldId: field.id,
|
||||
);
|
||||
fieldService.deleteField();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:appflowy/core/grid_notification.dart';
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<FieldPB, FlowyError>;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'field_service.freezed.dart';
|
||||
@@ -29,12 +29,11 @@ class FieldBackendService {
|
||||
|
||||
Future<Either<Unit, FlowyError>> updateField({
|
||||
String? name,
|
||||
FieldType? fieldType,
|
||||
bool? frozen,
|
||||
bool? visibility,
|
||||
double? width,
|
||||
}) {
|
||||
var payload = FieldChangesetPB.create()
|
||||
final payload = FieldChangesetPB.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId;
|
||||
|
||||
@@ -42,10 +41,6 @@ class FieldBackendService {
|
||||
payload.name = name;
|
||||
}
|
||||
|
||||
if (fieldType != null) {
|
||||
payload.fieldType = fieldType;
|
||||
}
|
||||
|
||||
if (frozen != null) {
|
||||
payload.frozen = frozen;
|
||||
}
|
||||
@@ -66,7 +61,7 @@ class FieldBackendService {
|
||||
required String fieldId,
|
||||
required List<int> typeOptionData,
|
||||
}) {
|
||||
var payload = TypeOptionChangesetPB.create()
|
||||
final payload = TypeOptionChangesetPB.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
..typeOptionData = typeOptionData;
|
||||
@@ -107,8 +102,8 @@ class FieldBackendService {
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldCellContext with _$FieldCellContext {
|
||||
const factory FieldCellContext({
|
||||
class FieldContext with _$FieldContext {
|
||||
const factory FieldContext({
|
||||
required String viewId,
|
||||
required FieldPB field,
|
||||
}) = _FieldCellContext;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
@@ -41,8 +40,8 @@ class DateTypeOptionBloc
|
||||
}
|
||||
|
||||
DateTypeOptionPB _updateTypeOption({
|
||||
DateFormat? dateFormat,
|
||||
TimeFormat? timeFormat,
|
||||
DateFormatPB? dateFormat,
|
||||
TimeFormatPB? timeFormat,
|
||||
bool? includeTime,
|
||||
}) {
|
||||
state.typeOption.freeze();
|
||||
@@ -54,19 +53,15 @@ class DateTypeOptionBloc
|
||||
if (timeFormat != null) {
|
||||
typeOption.timeFormat = timeFormat;
|
||||
}
|
||||
|
||||
if (includeTime != null) {
|
||||
typeOption.includeTime = includeTime;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DateTypeOptionEvent with _$DateTypeOptionEvent {
|
||||
const factory DateTypeOptionEvent.didSelectDateFormat(DateFormat format) =
|
||||
const factory DateTypeOptionEvent.didSelectDateFormat(DateFormatPB format) =
|
||||
_DidSelectDateFormat;
|
||||
const factory DateTypeOptionEvent.didSelectTimeFormat(TimeFormat format) =
|
||||
const factory DateTypeOptionEvent.didSelectTimeFormat(TimeFormatPB format) =
|
||||
_DidSelectTimeFormat;
|
||||
const factory DateTypeOptionEvent.includeTime(bool includeTime) =
|
||||
_IncludeTime;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/multi_select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'dart:async';
|
||||
import 'select_option_type_option_bloc.dart';
|
||||
import 'type_option_context.dart';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/format.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/number_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/number_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
@@ -22,7 +21,7 @@ class NumberTypeOptionBloc
|
||||
);
|
||||
}
|
||||
|
||||
NumberTypeOptionPB _updateNumberFormat(NumberFormat format) {
|
||||
NumberTypeOptionPB _updateNumberFormat(NumberFormatPB format) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.format = format;
|
||||
@@ -32,7 +31,7 @@ class NumberTypeOptionBloc
|
||||
|
||||
@freezed
|
||||
class NumberTypeOptionEvent with _$NumberTypeOptionEvent {
|
||||
const factory NumberTypeOptionEvent.didSelectFormat(NumberFormat format) =
|
||||
const factory NumberTypeOptionEvent.didSelectFormat(NumberFormatPB format) =
|
||||
_DidSelectFormat;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/format.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/number_entities.pbenum.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'number_format_bloc.freezed.dart';
|
||||
@@ -9,7 +9,8 @@ class NumberFormatBloc extends Bloc<NumberFormatEvent, NumberFormatState> {
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
setFilter: (_SetFilter value) {
|
||||
final List<NumberFormat> formats = List.from(NumberFormat.values);
|
||||
final List<NumberFormatPB> formats =
|
||||
List.from(NumberFormatPB.values);
|
||||
if (value.filter.isNotEmpty) {
|
||||
formats.retainWhere(
|
||||
(element) => element
|
||||
@@ -34,92 +35,92 @@ class NumberFormatEvent with _$NumberFormatEvent {
|
||||
@freezed
|
||||
class NumberFormatState with _$NumberFormatState {
|
||||
const factory NumberFormatState({
|
||||
required List<NumberFormat> formats,
|
||||
required List<NumberFormatPB> formats,
|
||||
required String filter,
|
||||
}) = _NumberFormatState;
|
||||
|
||||
factory NumberFormatState.initial() {
|
||||
return const NumberFormatState(
|
||||
formats: NumberFormat.values,
|
||||
formats: NumberFormatPB.values,
|
||||
filter: "",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension NumberFormatExtension on NumberFormat {
|
||||
extension NumberFormatExtension on NumberFormatPB {
|
||||
String title() {
|
||||
switch (this) {
|
||||
case NumberFormat.ArgentinePeso:
|
||||
case NumberFormatPB.ArgentinePeso:
|
||||
return "Argentine peso";
|
||||
case NumberFormat.Baht:
|
||||
case NumberFormatPB.Baht:
|
||||
return "Baht";
|
||||
case NumberFormat.CanadianDollar:
|
||||
case NumberFormatPB.CanadianDollar:
|
||||
return "Canadian dollar";
|
||||
case NumberFormat.ChileanPeso:
|
||||
case NumberFormatPB.ChileanPeso:
|
||||
return "Chilean peso";
|
||||
case NumberFormat.ColombianPeso:
|
||||
case NumberFormatPB.ColombianPeso:
|
||||
return "Colombian peso";
|
||||
case NumberFormat.DanishKrone:
|
||||
case NumberFormatPB.DanishKrone:
|
||||
return "Danish krone";
|
||||
case NumberFormat.Dirham:
|
||||
case NumberFormatPB.Dirham:
|
||||
return "Dirham";
|
||||
case NumberFormat.EUR:
|
||||
case NumberFormatPB.EUR:
|
||||
return "Euro";
|
||||
case NumberFormat.Forint:
|
||||
case NumberFormatPB.Forint:
|
||||
return "Forint";
|
||||
case NumberFormat.Franc:
|
||||
case NumberFormatPB.Franc:
|
||||
return "Franc";
|
||||
case NumberFormat.HongKongDollar:
|
||||
case NumberFormatPB.HongKongDollar:
|
||||
return "Hone Kong dollar";
|
||||
case NumberFormat.Koruna:
|
||||
case NumberFormatPB.Koruna:
|
||||
return "Koruna";
|
||||
case NumberFormat.Krona:
|
||||
case NumberFormatPB.Krona:
|
||||
return "Krona";
|
||||
case NumberFormat.Leu:
|
||||
case NumberFormatPB.Leu:
|
||||
return "Leu";
|
||||
case NumberFormat.Lira:
|
||||
case NumberFormatPB.Lira:
|
||||
return "Lira";
|
||||
case NumberFormat.MexicanPeso:
|
||||
case NumberFormatPB.MexicanPeso:
|
||||
return "Mexican peso";
|
||||
case NumberFormat.NewTaiwanDollar:
|
||||
case NumberFormatPB.NewTaiwanDollar:
|
||||
return "New Taiwan dollar";
|
||||
case NumberFormat.NewZealandDollar:
|
||||
case NumberFormatPB.NewZealandDollar:
|
||||
return "New Zealand dollar";
|
||||
case NumberFormat.NorwegianKrone:
|
||||
case NumberFormatPB.NorwegianKrone:
|
||||
return "Norwegian krone";
|
||||
case NumberFormat.Num:
|
||||
case NumberFormatPB.Num:
|
||||
return "Number";
|
||||
case NumberFormat.Percent:
|
||||
case NumberFormatPB.Percent:
|
||||
return "Percent";
|
||||
case NumberFormat.PhilippinePeso:
|
||||
case NumberFormatPB.PhilippinePeso:
|
||||
return "Philippine peso";
|
||||
case NumberFormat.Pound:
|
||||
case NumberFormatPB.Pound:
|
||||
return "Pound";
|
||||
case NumberFormat.Rand:
|
||||
case NumberFormatPB.Rand:
|
||||
return "Rand";
|
||||
case NumberFormat.Real:
|
||||
case NumberFormatPB.Real:
|
||||
return "Real";
|
||||
case NumberFormat.Ringgit:
|
||||
case NumberFormatPB.Ringgit:
|
||||
return "Ringgit";
|
||||
case NumberFormat.Riyal:
|
||||
case NumberFormatPB.Riyal:
|
||||
return "Riyal";
|
||||
case NumberFormat.Ruble:
|
||||
case NumberFormatPB.Ruble:
|
||||
return "Ruble";
|
||||
case NumberFormat.Rupee:
|
||||
case NumberFormatPB.Rupee:
|
||||
return "Rupee";
|
||||
case NumberFormat.Rupiah:
|
||||
case NumberFormatPB.Rupiah:
|
||||
return "Rupiah";
|
||||
case NumberFormat.Shekel:
|
||||
case NumberFormatPB.Shekel:
|
||||
return "Skekel";
|
||||
case NumberFormat.USD:
|
||||
case NumberFormatPB.USD:
|
||||
return "US dollar";
|
||||
case NumberFormat.UruguayanPeso:
|
||||
case NumberFormatPB.UruguayanPeso:
|
||||
return "Uruguayan peso";
|
||||
case NumberFormat.Won:
|
||||
case NumberFormatPB.Won:
|
||||
return "Won";
|
||||
case NumberFormat.Yen:
|
||||
case NumberFormatPB.Yen:
|
||||
return "Yen";
|
||||
case NumberFormat.Yuan:
|
||||
case NumberFormatPB.Yuan:
|
||||
return "Yuan";
|
||||
default:
|
||||
throw UnimplementedError;
|
||||
@@ -128,13 +129,13 @@ extension NumberFormatExtension on NumberFormat {
|
||||
|
||||
// String iconName() {
|
||||
// switch (this) {
|
||||
// case NumberFormat.CNY:
|
||||
// case NumberFormatPB.CNY:
|
||||
// return "grid/field/yen";
|
||||
// case NumberFormat.EUR:
|
||||
// case NumberFormatPB.EUR:
|
||||
// return "grid/field/euro";
|
||||
// case NumberFormat.Number:
|
||||
// case NumberFormatPB.Number:
|
||||
// return "grid/field/numbers";
|
||||
// case NumberFormat.USD:
|
||||
// case NumberFormatPB.USD:
|
||||
// return "grid/field/us_dollar";
|
||||
// default:
|
||||
// throw UnimplementedError;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
part 'select_option_type_option_bloc.freezed.dart';
|
||||
|
||||
abstract class ISelectOptionAction {
|
||||
abstract mixin class ISelectOptionAction {
|
||||
Future<List<SelectOptionPB>> Function(String) get insertOption;
|
||||
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get deleteOption;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/single_select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'dart:async';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
import 'select_option_type_option_bloc.dart';
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/number_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/text_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/url_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/checkbox_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/checklist_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/multi_select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/number_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/single_select_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/text_type_option.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/url_type_option.pb.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
|
||||
import 'type_option_data_controller.dart';
|
||||
|
||||
abstract class TypeOptionParser<T> {
|
||||
@@ -116,7 +113,7 @@ class TypeOptionContext<T extends GeneratedMessage> {
|
||||
required TypeOptionController dataController,
|
||||
}) : _dataController = dataController;
|
||||
|
||||
String get viewId => _dataController.viewId;
|
||||
String get viewId => _dataController.loader.viewId;
|
||||
|
||||
String get fieldId => _dataController.field.id;
|
||||
|
||||
@@ -124,7 +121,7 @@ class TypeOptionContext<T extends GeneratedMessage> {
|
||||
void Function(T)? onCompleted,
|
||||
required void Function(FlowyError) onError,
|
||||
}) async {
|
||||
await _dataController.loadTypeOptionData().then((result) {
|
||||
await _dataController.reloadTypeOption().then((result) {
|
||||
result.fold((l) => null, (err) => onError(err));
|
||||
});
|
||||
|
||||
@@ -153,65 +150,15 @@ abstract class TypeOptionFieldDelegate {
|
||||
void dispose();
|
||||
}
|
||||
|
||||
abstract class IFieldTypeOptionLoader {
|
||||
abstract class ITypeOptionLoader {
|
||||
String get viewId;
|
||||
Future<Either<TypeOptionPB, FlowyError>> load();
|
||||
String get fieldName;
|
||||
|
||||
Future<Either<Unit, FlowyError>> switchToField(
|
||||
String fieldId,
|
||||
FieldType fieldType,
|
||||
) {
|
||||
final payload = UpdateFieldTypePayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
..fieldType = fieldType;
|
||||
|
||||
return DatabaseEventUpdateFieldType(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses when creating a new field
|
||||
class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
|
||||
TypeOptionPB? fieldTypeOption;
|
||||
|
||||
@override
|
||||
final String viewId;
|
||||
NewFieldTypeOptionLoader({
|
||||
required this.viewId,
|
||||
});
|
||||
|
||||
/// Creates the field type option if the fieldTypeOption is null.
|
||||
/// Otherwise, it loads the type option data from the backend.
|
||||
@override
|
||||
Future<Either<TypeOptionPB, FlowyError>> load() {
|
||||
if (fieldTypeOption != null) {
|
||||
final payload = TypeOptionPathPB.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldTypeOption!.field_2.id
|
||||
..fieldType = fieldTypeOption!.field_2.fieldType;
|
||||
|
||||
return DatabaseEventGetTypeOption(payload).send();
|
||||
} else {
|
||||
final payload = CreateFieldPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fieldType = FieldType.RichText;
|
||||
|
||||
return DatabaseEventCreateTypeOption(payload).send().then((result) {
|
||||
return result.fold(
|
||||
(newFieldTypeOption) {
|
||||
fieldTypeOption = newFieldTypeOption;
|
||||
return left(newFieldTypeOption);
|
||||
},
|
||||
(err) => right(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Future<Either<TypeOptionPB, FlowyError>> initialize();
|
||||
}
|
||||
|
||||
/// Uses when editing a existing field
|
||||
class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
|
||||
@override
|
||||
class FieldTypeOptionLoader {
|
||||
final String viewId;
|
||||
final FieldPB field;
|
||||
|
||||
@@ -220,7 +167,6 @@ class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
|
||||
required this.field,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<TypeOptionPB, FlowyError>> load() {
|
||||
final payload = TypeOptionPathPB.create()
|
||||
..viewId = viewId
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:protobuf/protobuf.dart' hide FieldInfo;
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
@@ -10,30 +11,26 @@ import '../field_service.dart';
|
||||
import 'type_option_context.dart';
|
||||
|
||||
class TypeOptionController {
|
||||
final String viewId;
|
||||
late TypeOptionPB _typeOption;
|
||||
final IFieldTypeOptionLoader loader;
|
||||
final FieldTypeOptionLoader loader;
|
||||
final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
|
||||
|
||||
/// Returns a [TypeOptionController] used to modify the specified
|
||||
/// [FieldPB]'s data
|
||||
///
|
||||
/// Should call [loadTypeOptionData] if the passed-in [FieldInfo]
|
||||
/// Should call [reloadTypeOption] if the passed-in [FieldInfo]
|
||||
/// is null
|
||||
///
|
||||
TypeOptionController({
|
||||
required this.viewId,
|
||||
required this.loader,
|
||||
FieldInfo? fieldInfo,
|
||||
required FieldPB field,
|
||||
}) {
|
||||
if (fieldInfo != null) {
|
||||
_typeOption = TypeOptionPB.create()
|
||||
..viewId = viewId
|
||||
..field_2 = fieldInfo.field;
|
||||
}
|
||||
_typeOption = TypeOptionPB.create()
|
||||
..viewId = loader.viewId
|
||||
..field_2 = field;
|
||||
}
|
||||
|
||||
Future<Either<TypeOptionPB, FlowyError>> loadTypeOptionData() async {
|
||||
Future<Either<TypeOptionPB, FlowyError>> reloadTypeOption() async {
|
||||
final result = await loader.load();
|
||||
return result.fold(
|
||||
(data) {
|
||||
@@ -66,7 +63,7 @@ class TypeOptionController {
|
||||
|
||||
_fieldNotifier.value = _typeOption.field_2;
|
||||
|
||||
FieldBackendService(viewId: viewId, fieldId: field.id)
|
||||
FieldBackendService(viewId: loader.viewId, fieldId: field.id)
|
||||
.updateField(name: name);
|
||||
}
|
||||
|
||||
@@ -78,20 +75,25 @@ class TypeOptionController {
|
||||
});
|
||||
|
||||
FieldBackendService.updateFieldTypeOption(
|
||||
viewId: viewId,
|
||||
viewId: loader.viewId,
|
||||
fieldId: field.id,
|
||||
typeOptionData: typeOptionData,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> switchToField(FieldType newFieldType) async {
|
||||
final result = await loader.switchToField(field.id, newFieldType);
|
||||
final payload = UpdateFieldTypePayloadPB.create()
|
||||
..viewId = loader.viewId
|
||||
..fieldId = field.id
|
||||
..fieldType = newFieldType;
|
||||
|
||||
final result = await DatabaseEventUpdateFieldType(payload).send();
|
||||
await result.fold(
|
||||
(_) {
|
||||
// Should load the type-option data after switching to a new field.
|
||||
// After loading the type-option data, the editor widget that uses
|
||||
// the type-option data will be rebuild.
|
||||
loadTypeOptionData();
|
||||
reloadTypeOption();
|
||||
},
|
||||
(err) => Future(() => Log.error(err)),
|
||||
);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/cell_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
|
||||
|
||||
class TypeOptionBackendService {
|
||||
final String viewId;
|
||||
@@ -23,4 +22,15 @@ class TypeOptionBackendService {
|
||||
|
||||
return DatabaseEventCreateSelectOption(payload).send();
|
||||
}
|
||||
|
||||
static Future<Either<TypeOptionPB, FlowyError>> createFieldTypeOption({
|
||||
required String viewId,
|
||||
FieldType fieldType = FieldType.RichText,
|
||||
}) {
|
||||
final payload = CreateFieldPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fieldType = FieldType.RichText;
|
||||
|
||||
return DatabaseEventCreateTypeOption(payload).send();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/grid_notification.dart';
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/filter_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/filter_changeset.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/util.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/util.pb.dart';
|
||||
|
||||
typedef UpdateFilterNotifiedValue
|
||||
= Either<FilterChangesetNotificationPB, FlowyError>;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/checkbox_filter.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/checklist_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/date_filter.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/number_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/select_option_filter.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/text_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/util.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_filter.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_filter.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/number_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_filter.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/text_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/util.pb.dart';
|
||||
import 'package:fixnum/fixnum.dart' as $fixnum;
|
||||
|
||||
class FilterBackendService {
|
||||
@@ -84,11 +84,20 @@ class FilterBackendService {
|
||||
required String fieldId,
|
||||
String? filterId,
|
||||
required DateFilterConditionPB condition,
|
||||
required FieldType fieldType,
|
||||
int? start,
|
||||
int? end,
|
||||
int? timestamp,
|
||||
}) {
|
||||
var filter = DateFilterPB();
|
||||
assert(
|
||||
[
|
||||
FieldType.DateTime,
|
||||
FieldType.LastEditedTime,
|
||||
FieldType.CreatedTime,
|
||||
].contains(fieldType),
|
||||
);
|
||||
|
||||
final filter = DateFilterPB();
|
||||
if (timestamp != null) {
|
||||
filter.timestamp = $fixnum.Int64(timestamp);
|
||||
} else {
|
||||
@@ -105,7 +114,7 @@ class FilterBackendService {
|
||||
return insertFilter(
|
||||
fieldId: fieldId,
|
||||
filterId: filterId,
|
||||
fieldType: FieldType.DateTime,
|
||||
fieldType: fieldType,
|
||||
data: filter.writeToBuffer(),
|
||||
);
|
||||
}
|
||||
@@ -169,7 +178,7 @@ class FilterBackendService {
|
||||
required FieldType fieldType,
|
||||
required List<int> data,
|
||||
}) {
|
||||
var insertFilterPayload = AlterFilterPayloadPB.create()
|
||||
final insertFilterPayload = UpdateFilterPayloadPB.create()
|
||||
..fieldId = fieldId
|
||||
..fieldType = fieldType
|
||||
..viewId = viewId
|
||||
@@ -181,7 +190,7 @@ class FilterBackendService {
|
||||
|
||||
final payload = DatabaseSettingChangesetPB.create()
|
||||
..viewId = viewId
|
||||
..alterFilter = insertFilterPayload;
|
||||
..updateFilter = insertFilterPayload;
|
||||
return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) {
|
||||
return result.fold(
|
||||
(l) => left(l),
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/grid_notification.dart';
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/notification.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group_changeset.pb.dart';
|
||||
|
||||
typedef GroupUpdateValue = Either<GroupChangesetPB, FlowyError>;
|
||||
typedef GroupUpdateValue = Either<GroupChangesPB, FlowyError>;
|
||||
typedef GroupByNewFieldValue = Either<List<GroupPB>, FlowyError>;
|
||||
|
||||
class DatabaseGroupListener {
|
||||
@@ -36,17 +36,17 @@ class DatabaseGroupListener {
|
||||
Either<Uint8List, FlowyError> result,
|
||||
) {
|
||||
switch (ty) {
|
||||
case DatabaseNotification.DidUpdateGroups:
|
||||
case DatabaseNotification.DidUpdateNumOfGroups:
|
||||
result.fold(
|
||||
(payload) => _numOfGroupsNotifier?.value =
|
||||
left(GroupChangesetPB.fromBuffer(payload)),
|
||||
left(GroupChangesPB.fromBuffer(payload)),
|
||||
(error) => _numOfGroupsNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
case DatabaseNotification.DidGroupByField:
|
||||
result.fold(
|
||||
(payload) => _groupByFieldNotifier?.value =
|
||||
left(GroupChangesetPB.fromBuffer(payload).initialGroups),
|
||||
left(GroupChangesPB.fromBuffer(payload).initialGroups),
|
||||
(error) => _groupByFieldNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
class GroupBackendService {
|
||||
final String viewId;
|
||||
GroupBackendService(this.viewId);
|
||||
|
||||
Future<Either<Unit, FlowyError>> groupByField({
|
||||
required String fieldId,
|
||||
required FieldType fieldType,
|
||||
}) {
|
||||
final payload = GroupByFieldPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
..fieldType = fieldType;
|
||||
|
||||
return DatabaseEventSetGroupByField(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> updateGroup({
|
||||
required String groupId,
|
||||
String? name,
|
||||
bool? visible,
|
||||
}) {
|
||||
final payload = UpdateGroupPB.create()..groupId = groupId;
|
||||
if (name != null) {
|
||||
payload.name = name;
|
||||
}
|
||||
if (visible != null) {
|
||||
payload.visible = visible;
|
||||
}
|
||||
return DatabaseEventUpdateGroup(payload).send();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/grid_notification.dart';
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef NewLayoutFieldValue = Either<LayoutSettingPB, FlowyError>;
|
||||
typedef NewLayoutFieldValue = Either<DatabaseLayoutSettingPB, FlowyError>;
|
||||
|
||||
class DatabaseCalendarLayoutListener {
|
||||
final String viewId;
|
||||
@@ -33,7 +33,7 @@ class DatabaseCalendarLayoutListener {
|
||||
case DatabaseNotification.DidSetNewLayoutField:
|
||||
result.fold(
|
||||
(payload) => _newLayoutFieldNotifier?.value =
|
||||
left(LayoutSettingPB.fromBuffer(payload)),
|
||||
left(DatabaseLayoutSettingPB.fromBuffer(payload)),
|
||||
(error) => _newLayoutFieldNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import 'layout_service.dart';
|
||||
part 'layout_bloc.freezed.dart';
|
||||
|
||||
class DatabaseLayoutBloc
|
||||
extends Bloc<DatabaseLayoutEvent, DatabaseLayoutState> {
|
||||
final DatabaseLayoutBackendService layoutService;
|
||||
|
||||
DatabaseLayoutBloc({
|
||||
required String viewId,
|
||||
required DatabaseLayoutPB databaseLayout,
|
||||
}) : layoutService = DatabaseLayoutBackendService(viewId),
|
||||
super(DatabaseLayoutState.initial(viewId, databaseLayout)) {
|
||||
on<DatabaseLayoutEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
initial: () {},
|
||||
updateLayout: (DatabaseLayoutPB layout) {
|
||||
layoutService.updateLayout(
|
||||
fieldId: viewId,
|
||||
layout: layout,
|
||||
);
|
||||
emit(state.copyWith(databaseLayout: layout));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DatabaseLayoutEvent with _$DatabaseLayoutEvent {
|
||||
const factory DatabaseLayoutEvent.initial() = _Initial;
|
||||
const factory DatabaseLayoutEvent.updateLayout(DatabaseLayoutPB layout) =
|
||||
_UpdateLayout;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DatabaseLayoutState with _$DatabaseLayoutState {
|
||||
const factory DatabaseLayoutState({
|
||||
required String viewId,
|
||||
required DatabaseLayoutPB databaseLayout,
|
||||
}) = _DatabaseLayoutState;
|
||||
|
||||
factory DatabaseLayoutState.initial(
|
||||
String viewId,
|
||||
DatabaseLayoutPB databaseLayout,
|
||||
) =>
|
||||
DatabaseLayoutState(
|
||||
viewId: viewId,
|
||||
databaseLayout: databaseLayout,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
/// Listener for database layout changes.
|
||||
class DatabaseLayoutListener {
|
||||
final String viewId;
|
||||
PublishNotifier<Either<DatabaseLayoutPB, FlowyError>>? _layoutNotifier =
|
||||
PublishNotifier();
|
||||
DatabaseNotificationListener? _listener;
|
||||
DatabaseLayoutListener(this.viewId);
|
||||
|
||||
void start({
|
||||
required void Function(Either<DatabaseLayoutPB, FlowyError>)
|
||||
onLayoutChanged,
|
||||
}) {
|
||||
_layoutNotifier?.addPublishListener(onLayoutChanged);
|
||||
_listener = DatabaseNotificationListener(
|
||||
objectId: viewId,
|
||||
handler: _handler,
|
||||
);
|
||||
}
|
||||
|
||||
void _handler(
|
||||
DatabaseNotification ty,
|
||||
Either<Uint8List, FlowyError> result,
|
||||
) {
|
||||
switch (ty) {
|
||||
case DatabaseNotification.DidUpdateDatabaseLayout:
|
||||
result.fold(
|
||||
(payload) => _layoutNotifier?.value =
|
||||
left(DatabaseLayoutMetaPB.fromBuffer(payload).layout),
|
||||
(error) => _layoutNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
_layoutNotifier?.dispose();
|
||||
_layoutNotifier = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
class DatabaseLayoutBackendService {
|
||||
final String viewId;
|
||||
|
||||
DatabaseLayoutBackendService(this.viewId);
|
||||
|
||||
Future<Either<ViewPB, FlowyError>> updateLayout({
|
||||
required String fieldId,
|
||||
required DatabaseLayoutPB layout,
|
||||
}) {
|
||||
final payload = UpdateViewPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..layout = _viewLayoutFromDatabaseLayout(layout);
|
||||
|
||||
return FolderEventUpdateView(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
ViewLayoutPB _viewLayoutFromDatabaseLayout(DatabaseLayoutPB databaseLayout) {
|
||||
switch (databaseLayout) {
|
||||
case DatabaseLayoutPB.Board:
|
||||
return ViewLayoutPB.Board;
|
||||
case DatabaseLayoutPB.Calendar:
|
||||
return ViewLayoutPB.Calendar;
|
||||
case DatabaseLayoutPB.Grid:
|
||||
return ViewLayoutPB.Grid;
|
||||
default:
|
||||
throw UnimplementedError;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/grid_notification.dart';
|
||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef LayoutSettingsValue<T> = Either<T, FlowyError>;
|
||||
|
||||
class DatabaseLayoutListener {
|
||||
class DatabaseLayoutSettingListener {
|
||||
final String viewId;
|
||||
PublishNotifier<LayoutSettingsValue<LayoutSettingPB>>? _settingNotifier =
|
||||
PublishNotifier();
|
||||
PublishNotifier<LayoutSettingsValue<DatabaseLayoutSettingPB>>?
|
||||
_settingNotifier = PublishNotifier();
|
||||
DatabaseNotificationListener? _listener;
|
||||
DatabaseLayoutListener(this.viewId);
|
||||
DatabaseLayoutSettingListener(this.viewId);
|
||||
|
||||
void start({
|
||||
required void Function(LayoutSettingsValue<LayoutSettingPB>)
|
||||
required void Function(LayoutSettingsValue<DatabaseLayoutSettingPB>)
|
||||
onLayoutChanged,
|
||||
}) {
|
||||
_settingNotifier?.addPublishListener(onLayoutChanged);
|
||||
@@ -34,7 +34,7 @@ class DatabaseLayoutListener {
|
||||
case DatabaseNotification.DidUpdateLayoutSettings:
|
||||
result.fold(
|
||||
(payload) => _settingNotifier?.value =
|
||||
left(LayoutSettingPB.fromBuffer(payload)),
|
||||
left(DatabaseLayoutSettingPB.fromBuffer(payload)),
|
||||
(error) => _settingNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import 'dart:collection';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../cell/cell_service.dart';
|
||||
import '../field/field_controller.dart';
|
||||
import 'row_list.dart';
|
||||
import 'row_service.dart';
|
||||
part 'row_cache.freezed.dart';
|
||||
|
||||
typedef RowUpdateCallback = void Function();
|
||||
@@ -16,7 +17,7 @@ abstract class RowFieldsDelegate {
|
||||
void onFieldsChanged(void Function(List<FieldInfo>) callback);
|
||||
}
|
||||
|
||||
abstract class RowCacheDelegate {
|
||||
abstract mixin class RowCacheDelegate {
|
||||
UnmodifiableListView<FieldInfo> get fields;
|
||||
void onRowDispose();
|
||||
}
|
||||
@@ -29,7 +30,7 @@ abstract class RowCacheDelegate {
|
||||
class RowCache {
|
||||
final String viewId;
|
||||
|
||||
/// _rows containers the current block's rows
|
||||
/// _rows contains the current block's rows
|
||||
/// Use List to reverse the order of the GridRow.
|
||||
final RowList _rowList = RowList();
|
||||
|
||||
@@ -38,11 +39,11 @@ class RowCache {
|
||||
final RowChangesetNotifier _rowChangeReasonNotifier;
|
||||
|
||||
UnmodifiableListView<RowInfo> get rowInfos {
|
||||
var visibleRows = [..._rowList.rows];
|
||||
final visibleRows = [..._rowList.rows];
|
||||
return UnmodifiableListView(visibleRows);
|
||||
}
|
||||
|
||||
UnmodifiableMapView<String, RowInfo> get rowByRowId {
|
||||
UnmodifiableMapView<RowId, RowInfo> get rowByRowId {
|
||||
return UnmodifiableMapView(_rowList.rowInfoByRowId);
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ class RowCache {
|
||||
});
|
||||
}
|
||||
|
||||
RowInfo? getRow(String rowId) {
|
||||
RowInfo? getRow(RowId rowId) {
|
||||
return _rowList.get(rowId);
|
||||
}
|
||||
|
||||
@@ -82,13 +83,13 @@ class RowCache {
|
||||
await _cellCache.dispose();
|
||||
}
|
||||
|
||||
void applyRowsChanged(RowsChangesetPB changeset) {
|
||||
void applyRowsChanged(RowsChangePB changeset) {
|
||||
_deleteRows(changeset.deletedRows);
|
||||
_insertRows(changeset.insertedRows);
|
||||
_updateRows(changeset.updatedRows);
|
||||
}
|
||||
|
||||
void applyRowsVisibility(RowsVisibilityChangesetPB changeset) {
|
||||
void applyRowsVisibility(RowsVisibilityChangePB changeset) {
|
||||
_hideRows(changeset.invisibleRows);
|
||||
_showRows(changeset.visibleRows);
|
||||
}
|
||||
@@ -115,7 +116,7 @@ class RowCache {
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteRows(List<String> deletedRowIds) {
|
||||
void _deleteRows(List<RowId> deletedRowIds) {
|
||||
for (final rowId in deletedRowIds) {
|
||||
final deletedRow = _rowList.remove(rowId);
|
||||
if (deletedRow != null) {
|
||||
@@ -137,7 +138,7 @@ class RowCache {
|
||||
|
||||
void _updateRows(List<UpdatedRowPB> updatedRows) {
|
||||
if (updatedRows.isEmpty) return;
|
||||
List<RowPB> rowPBs = [];
|
||||
final List<RowPB> rowPBs = [];
|
||||
for (final updatedRow in updatedRows) {
|
||||
for (final fieldId in updatedRow.fieldIds) {
|
||||
final key = CellCacheKey(
|
||||
@@ -156,7 +157,7 @@ class RowCache {
|
||||
}
|
||||
}
|
||||
|
||||
void _hideRows(List<String> invisibleRows) {
|
||||
void _hideRows(List<RowId> invisibleRows) {
|
||||
for (final rowId in invisibleRows) {
|
||||
final deletedRow = _rowList.remove(rowId);
|
||||
if (deletedRow != null) {
|
||||
@@ -183,8 +184,8 @@ class RowCache {
|
||||
}
|
||||
|
||||
RowUpdateCallback addListener({
|
||||
required String rowId,
|
||||
void Function(CellByFieldId, RowsChangedReason)? onCellUpdated,
|
||||
required RowId rowId,
|
||||
void Function(CellContextByFieldId, RowsChangedReason)? onCellUpdated,
|
||||
bool Function()? listenWhen,
|
||||
}) {
|
||||
listenerHandler() async {
|
||||
@@ -196,7 +197,7 @@ class RowCache {
|
||||
if (onCellUpdated != null) {
|
||||
final rowInfo = _rowList.get(rowId);
|
||||
if (rowInfo != null) {
|
||||
final CellByFieldId cellDataMap =
|
||||
final CellContextByFieldId cellDataMap =
|
||||
_makeGridCells(rowId, rowInfo.rowPB);
|
||||
onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason);
|
||||
}
|
||||
@@ -219,7 +220,7 @@ class RowCache {
|
||||
_rowChangeReasonNotifier.removeListener(callback);
|
||||
}
|
||||
|
||||
CellByFieldId loadGridCells(String rowId) {
|
||||
CellContextByFieldId loadGridCells(RowId rowId) {
|
||||
final RowPB? data = _rowList.get(rowId)?.rowPB;
|
||||
if (data == null) {
|
||||
_loadRow(rowId);
|
||||
@@ -227,7 +228,7 @@ class RowCache {
|
||||
return _makeGridCells(rowId, data);
|
||||
}
|
||||
|
||||
Future<void> _loadRow(String rowId) async {
|
||||
Future<void> _loadRow(RowId rowId) async {
|
||||
final payload = RowIdPB.create()
|
||||
..viewId = viewId
|
||||
..rowId = rowId;
|
||||
@@ -239,12 +240,12 @@ class RowCache {
|
||||
);
|
||||
}
|
||||
|
||||
CellByFieldId _makeGridCells(String rowId, RowPB? row) {
|
||||
CellContextByFieldId _makeGridCells(RowId rowId, RowPB? row) {
|
||||
// ignore: prefer_collection_literals
|
||||
var cellDataMap = CellByFieldId();
|
||||
final cellDataMap = CellContextByFieldId();
|
||||
for (final field in _delegate.fields) {
|
||||
if (field.visibility) {
|
||||
cellDataMap[field.id] = CellIdentifier(
|
||||
cellDataMap[field.id] = DatabaseCellContext(
|
||||
rowId: rowId,
|
||||
viewId: viewId,
|
||||
fieldInfo: field,
|
||||
@@ -319,7 +320,7 @@ typedef InsertedIndexs = List<InsertedIndex>;
|
||||
typedef DeletedIndexs = List<DeletedIndex>;
|
||||
// key: id of the row
|
||||
// value: UpdatedIndex
|
||||
typedef UpdatedIndexMap = LinkedHashMap<String, UpdatedIndex>;
|
||||
typedef UpdatedIndexMap = LinkedHashMap<RowId, UpdatedIndex>;
|
||||
|
||||
@freezed
|
||||
class RowsChangedReason with _$RowsChangedReason {
|
||||
@@ -337,7 +338,7 @@ class RowsChangedReason with _$RowsChangedReason {
|
||||
|
||||
class InsertedIndex {
|
||||
final int index;
|
||||
final String rowId;
|
||||
final RowId rowId;
|
||||
InsertedIndex({
|
||||
required this.index,
|
||||
required this.rowId,
|
||||
@@ -355,7 +356,7 @@ class DeletedIndex {
|
||||
|
||||
class UpdatedIndex {
|
||||
final int index;
|
||||
final String rowId;
|
||||
final RowId rowId;
|
||||
UpdatedIndex({
|
||||
required this.index,
|
||||
required this.rowId,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../cell/cell_service.dart';
|
||||
import 'row_cache.dart';
|
||||
import 'row_service.dart';
|
||||
|
||||
typedef OnRowChanged = void Function(CellByFieldId, RowsChangedReason);
|
||||
typedef OnRowChanged = void Function(CellContextByFieldId, RowsChangedReason);
|
||||
|
||||
class RowController {
|
||||
final String rowId;
|
||||
final RowId rowId;
|
||||
final String? groupId;
|
||||
final String viewId;
|
||||
final List<VoidCallback> _onRowChangedListeners = [];
|
||||
final RowCache _rowCache;
|
||||
@@ -16,9 +18,10 @@ class RowController {
|
||||
required this.rowId,
|
||||
required this.viewId,
|
||||
required RowCache rowCache,
|
||||
this.groupId,
|
||||
}) : _rowCache = rowCache;
|
||||
|
||||
CellByFieldId loadData() {
|
||||
CellContextByFieldId loadData() {
|
||||
return _rowCache.loadGridCells(rowId);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:collection';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
import 'row_cache.dart';
|
||||
import 'row_service.dart';
|
||||
|
||||
class RowList {
|
||||
/// Use List to reverse the order of the row.
|
||||
@@ -9,13 +10,13 @@ class RowList {
|
||||
List<RowInfo> get rows => List.from(_rowInfos);
|
||||
|
||||
/// Use Map for faster access the raw row data.
|
||||
final HashMap<String, RowInfo> rowInfoByRowId = HashMap();
|
||||
final HashMap<RowId, RowInfo> rowInfoByRowId = HashMap();
|
||||
|
||||
RowInfo? get(String rowId) {
|
||||
RowInfo? get(RowId rowId) {
|
||||
return rowInfoByRowId[rowId];
|
||||
}
|
||||
|
||||
int? indexOfRow(String rowId) {
|
||||
int? indexOfRow(RowId rowId) {
|
||||
final rowInfo = rowInfoByRowId[rowId];
|
||||
if (rowInfo != null) {
|
||||
return _rowInfos.indexOf(rowInfo);
|
||||
@@ -56,7 +57,7 @@ class RowList {
|
||||
}
|
||||
}
|
||||
|
||||
DeletedIndex? remove(String rowId) {
|
||||
DeletedIndex? remove(RowId rowId) {
|
||||
final rowInfo = rowInfoByRowId[rowId];
|
||||
if (rowInfo != null) {
|
||||
final index = _rowInfos.indexOf(rowInfo);
|
||||
@@ -74,7 +75,7 @@ class RowList {
|
||||
List<InsertedRowPB> insertedRows,
|
||||
RowInfo Function(RowPB) builder,
|
||||
) {
|
||||
InsertedIndexs insertIndexs = [];
|
||||
final InsertedIndexs insertIndexs = [];
|
||||
for (final insertRow in insertedRows) {
|
||||
final isContains = contains(insertRow.row.id);
|
||||
|
||||
@@ -145,18 +146,17 @@ class RowList {
|
||||
}
|
||||
}
|
||||
|
||||
void moveRow(String rowId, int oldIndex, int newIndex) {
|
||||
void moveRow(RowId rowId, int oldIndex, int newIndex) {
|
||||
final index = _rowInfos.indexWhere(
|
||||
(rowInfo) => rowInfo.rowPB.id == rowId,
|
||||
);
|
||||
if (index != -1) {
|
||||
assert(index == oldIndex);
|
||||
final rowInfo = remove(rowId)!.rowInfo;
|
||||
insert(newIndex, rowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(String rowId) {
|
||||
bool contains(RowId rowId) {
|
||||
return rowInfoByRowId[rowId] != null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
|
||||
typedef RowId = String;
|
||||
|
||||
class RowBackendService {
|
||||
final String viewId;
|
||||
@@ -10,7 +12,7 @@ class RowBackendService {
|
||||
required this.viewId,
|
||||
});
|
||||
|
||||
Future<Either<RowPB, FlowyError>> createRow(String rowId) {
|
||||
Future<Either<RowPB, FlowyError>> createRow(RowId rowId) {
|
||||
final payload = CreateRowPayloadPB.create()
|
||||
..viewId = viewId
|
||||
..startRowId = rowId;
|
||||
@@ -18,7 +20,7 @@ class RowBackendService {
|
||||
return DatabaseEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<OptionalRowPB, FlowyError>> getRow(String rowId) {
|
||||
Future<Either<OptionalRowPB, FlowyError>> getRow(RowId rowId) {
|
||||
final payload = RowIdPB.create()
|
||||
..viewId = viewId
|
||||
..rowId = rowId;
|
||||
@@ -26,7 +28,7 @@ class RowBackendService {
|
||||
return DatabaseEventGetRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> deleteRow(String rowId) {
|
||||
Future<Either<Unit, FlowyError>> deleteRow(RowId rowId) {
|
||||
final payload = RowIdPB.create()
|
||||
..viewId = viewId
|
||||
..rowId = rowId;
|
||||
@@ -34,10 +36,16 @@ class RowBackendService {
|
||||
return DatabaseEventDeleteRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> duplicateRow(String rowId) {
|
||||
Future<Either<Unit, FlowyError>> duplicateRow({
|
||||
required RowId rowId,
|
||||
String? groupId,
|
||||
}) {
|
||||
final payload = RowIdPB.create()
|
||||
..viewId = viewId
|
||||
..rowId = rowId;
|
||||
if (groupId != null) {
|
||||
payload.groupId = groupId;
|
||||
}
|
||||
|
||||
return DatabaseEventDuplicateRow(payload).send();
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/setting/setting_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import '../group/group_service.dart';
|
||||
|
||||
part 'group_bloc.freezed.dart';
|
||||
|
||||
class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> {
|
||||
final FieldController _fieldController;
|
||||
final SettingBackendService _settingBackendSvc;
|
||||
final GroupBackendService _groupBackendSvc;
|
||||
Function(List<FieldInfo>)? _onFieldsFn;
|
||||
|
||||
DatabaseGroupBloc({
|
||||
required String viewId,
|
||||
required FieldController fieldController,
|
||||
}) : _fieldController = fieldController,
|
||||
_settingBackendSvc = SettingBackendService(viewId: viewId),
|
||||
_groupBackendSvc = GroupBackendService(viewId),
|
||||
super(DatabaseGroupState.initial(viewId, fieldController.fieldInfos)) {
|
||||
on<DatabaseGroupEvent>(
|
||||
(event, emit) async {
|
||||
@@ -29,7 +30,7 @@ class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> {
|
||||
emit(state.copyWith(fieldContexts: fieldContexts));
|
||||
},
|
||||
setGroupByField: (String fieldId, FieldType fieldType) async {
|
||||
final result = await _settingBackendSvc.groupByField(
|
||||
final result = await _groupBackendSvc.groupByField(
|
||||
fieldId: fieldId,
|
||||
fieldType: fieldType,
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
@@ -40,7 +42,31 @@ class DatabaseSettingState with _$DatabaseSettingState {
|
||||
}
|
||||
|
||||
enum DatabaseSettingAction {
|
||||
showFilters,
|
||||
sortBy,
|
||||
showProperties,
|
||||
showLayout,
|
||||
showGroup,
|
||||
}
|
||||
|
||||
extension DatabaseSettingActionExtension on DatabaseSettingAction {
|
||||
String iconName() {
|
||||
switch (this) {
|
||||
case DatabaseSettingAction.showProperties:
|
||||
return 'grid/setting/properties';
|
||||
case DatabaseSettingAction.showLayout:
|
||||
return 'grid/setting/database_layout';
|
||||
case DatabaseSettingAction.showGroup:
|
||||
return 'grid/setting/group';
|
||||
}
|
||||
}
|
||||
|
||||
String title() {
|
||||
switch (this) {
|
||||
case DatabaseSettingAction.showProperties:
|
||||
return LocaleKeys.grid_settings_Properties.tr();
|
||||
case DatabaseSettingAction.showLayout:
|
||||
return LocaleKeys.grid_settings_databaseLayout.tr();
|
||||
case DatabaseSettingAction.showGroup:
|
||||
return LocaleKeys.grid_settings_group.tr();
|
||||
}
|
||||
}
|
||||
}
|
||||