Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
764b4db166 | ||
|
|
7701533ed2 | ||
|
|
29c89013f0 | ||
|
|
1fad5aa804 | ||
|
|
675e23e971 | ||
|
|
c9ee82ec75 | ||
|
|
0c9935ccf2 | ||
|
|
d28846bbaa | ||
|
|
58ecf62240 | ||
|
|
a5eaf15548 | ||
|
|
4589d86d81 | ||
|
|
9330df4ce1 | ||
|
|
7cdd47757b | ||
|
|
9d18e9de40 | ||
|
|
e2dd179001 | ||
|
|
35a47bfe5d | ||
|
|
9dc209bda7 | ||
|
|
104851d330 | ||
|
|
a1db5bff5c | ||
|
|
453346e69c | ||
|
|
923285bfcf | ||
|
|
0de8b92db6 | ||
|
|
125bcbc9db | ||
|
|
ef9596f4ab | ||
|
|
3c04b72932 | ||
|
|
a3bea472bf | ||
|
|
5ac7b8e165 | ||
|
|
95a938657b | ||
|
|
fbb1753350 | ||
|
|
c6401da0b5 | ||
|
|
f724185f1c | ||
|
|
63a12a1d2b | ||
|
|
890f7573f3 | ||
|
|
6f159e741b | ||
|
|
9a72f31d60 | ||
|
|
ab7acbd5de | ||
|
|
b7dfc85208 | ||
|
|
16a01e11ed | ||
|
|
70914e6228 | ||
|
|
45cbd70bf4 | ||
|
|
fb9bc359b8 | ||
|
|
135d8a811e | ||
|
|
03518c951c | ||
|
|
03b8f2ccb2 | ||
|
|
a40c639a96 | ||
|
|
ea0c4e96d2 | ||
|
|
a1143e24f3 | ||
|
|
ff79635b2b | ||
|
|
f0d2cf7da3 | ||
|
|
5e2ed56f5b | ||
|
|
70963a55f1 | ||
|
|
62be81395d | ||
|
|
7c21f61d2e | ||
|
|
ad4c68a353 | ||
|
|
355061d415 | ||
|
|
3039944c74 | ||
|
|
338e342410 | ||
|
|
8c544bc8c4 | ||
|
|
266209caeb | ||
|
|
eb77346e5a | ||
|
|
f28c5d849c | ||
|
|
ea37f46f88 | ||
|
|
e68d3f1c71 | ||
|
|
5741feb7cc | ||
|
|
2cd88594e8 | ||
|
|
a885170869 | ||
|
|
915ce02157 | ||
|
|
6e9a5a16a6 | ||
|
|
13c72a31b7 | ||
|
|
96410b2d32 | ||
|
|
d32c2082b6 | ||
|
|
c368d855c7 | ||
|
|
b1378b4545 | ||
|
|
5ab64f8835 |
No files matched your search
@@ -134,6 +134,7 @@ jobs:
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
os: ${{ matrix.os }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
||||
|
||||
@@ -136,5 +136,6 @@ jobs:
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
os: ${{ matrix.os }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
working-directory: frontend
|
||||
run: |
|
||||
flutter config --enable-windows-desktop
|
||||
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-windows-x86 appflowy
|
||||
dart ./scripts/flutter_release_build/build_flowy.dart . ${{ github.ref_name }}
|
||||
|
||||
- name: Archive Asset
|
||||
uses: vimtor/action-zip@v1
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
asset_name: ${{ env.WINDOWS_INSTALLER_NAME }}.exe
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
build-for-macOS:
|
||||
build-for-macOS-x86_64:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
needs: create-release
|
||||
@@ -212,6 +212,96 @@ jobs:
|
||||
asset_name: ${{ env.MACOS_DMG_NAME }}.dmg
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
build-for-macOS-universal:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
needs: create-release
|
||||
env:
|
||||
MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/macos/Release
|
||||
MACOS_AARCH64_ZIP_NAME: AppFlowy_${{ github.ref_name }}_macos-universal.zip
|
||||
MACOS_DMG_NAME: AppFlowy_${{ github.ref_name }}_macos-universal
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
targets: "aarch64-apple-darwin,x86_64-apple-darwin",
|
||||
os: macos-11,
|
||||
extra-build-args: "",
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
targets: ${{ matrix.job.targets }}
|
||||
components: rustfmt
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: appflowy-lib-cache
|
||||
key: ${{ matrix.job.os }}-${{ matrix.job.target }}
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo install --force cargo-make
|
||||
cargo install --force duckscript_cli
|
||||
|
||||
- name: Build AppFlowy
|
||||
working-directory: frontend
|
||||
run: |
|
||||
flutter config --enable-macos-desktop
|
||||
sh scripts/flutter_release_build/build_universal_package_for_macos.sh
|
||||
|
||||
- name: Create macOS dmg
|
||||
run: |
|
||||
brew install create-dmg
|
||||
create-dmg \
|
||||
--volname ${{ env.MACOS_DMG_NAME }} \
|
||||
--hide-extension "AppFlowy.app" \
|
||||
--background frontend/scripts/dmg_assets/AppFlowyInstallerBackground.jpg \
|
||||
--window-size 600 450 \
|
||||
--icon-size 94 \
|
||||
--icon "AppFlowy.app" 141 249 \
|
||||
--app-drop-link 458 249 \
|
||||
"${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \
|
||||
"${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app"
|
||||
|
||||
- name: Archive Asset
|
||||
working-directory: ${{ env.MACOS_APP_RELEASE_PATH }}
|
||||
run: zip --symlinks -qr ${{ env.MACOS_AARCH64_ZIP_NAME }} AppFlowy.app
|
||||
|
||||
- name: Upload Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_AARCH64_ZIP_NAME }}
|
||||
asset_name: ${{ env.MACOS_AARCH64_ZIP_NAME }}
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload DMG Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg
|
||||
asset_name: ${{ env.MACOS_DMG_NAME }}.dmg
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
build-for-linux:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
@@ -360,7 +450,13 @@ jobs:
|
||||
|
||||
notify-discord:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-for-linux, build-for-windows, build-for-macOS]
|
||||
needs:
|
||||
[
|
||||
build-for-linux,
|
||||
build-for-windows,
|
||||
build-for-macOS-x86_64,
|
||||
build-for-macOS-universal,
|
||||
]
|
||||
steps:
|
||||
- name: Notify Discord
|
||||
run: |
|
||||
|
||||
@@ -22,7 +22,6 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUST_TOOLCHAIN: "1.70"
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
|
||||
jobs:
|
||||
test-on-ubuntu:
|
||||
@@ -40,14 +39,6 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
profile: minimal
|
||||
|
||||
- name: Install flutter
|
||||
id: flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
@@ -60,11 +51,6 @@ jobs:
|
||||
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"
|
||||
@@ -75,16 +61,4 @@ jobs:
|
||||
|
||||
- name: clippy rust-lib
|
||||
run: cargo clippy --features="rev-sqlite"
|
||||
working-directory: frontend/rust-lib
|
||||
|
||||
- name: rustfmt shared-lib
|
||||
run: cargo fmt --all -- --check
|
||||
working-directory: shared-lib
|
||||
|
||||
- name: clippy shared-lib
|
||||
run: cargo clippy -- -D warnings
|
||||
working-directory: shared-lib
|
||||
|
||||
- name: Run shared-lib tests
|
||||
working-directory: shared-lib
|
||||
run: RUST_LOG=info cargo test --no-default-features
|
||||
working-directory: frontend/rust-lib
|
||||
+37
-2
@@ -1,11 +1,46 @@
|
||||
# Release Notes
|
||||
|
||||
## Version 0.2.9 - 08/08/2023
|
||||
|
||||
### New Features
|
||||
|
||||
- Improve tab and shortcut, click with alt/option to open a page in new tab.
|
||||
- Improve database tab bar UI.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Add button and more action button of the favorite section doesn't work.
|
||||
- Fix euro currency number format.
|
||||
- Some UI issues
|
||||
|
||||
## Version 0.2.8 - 08/03/2023
|
||||
|
||||
### New Features
|
||||
|
||||
- Nestable personal folder that supports drag and drop
|
||||
- Support for favorite folders.
|
||||
- Support for sorting by date in Grid view.
|
||||
- Add a duplicate button in the Board context menu.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Improve readability in Callout
|
||||
- Some UI issues
|
||||
|
||||
## Version 0.2.7 - 07/18/2023
|
||||
|
||||
### New Features
|
||||
|
||||
- Dynamic load themes
|
||||
- Inline math equation
|
||||
<img width="1147" src="https://github.com/AppFlowy-IO/AppFlowy/assets/11863087/ac464740-c685-4a85-ae99-1074c1c607e5">
|
||||
|
||||
- Open page in new tab
|
||||
- Create toggle lists to keep things tidy in your pages
|
||||
- Alt/Option + click to add a text block above
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Pasting into a Grid property crashed on Windows
|
||||
- Double-click a link to open
|
||||
|
||||
## Version 0.2.6 - 07/11/2023
|
||||
|
||||
|
||||
@@ -68,6 +68,14 @@ Contributions make the open-source community a fantastic place to learn, inspire
|
||||
If your Pull Request is accepted as it fixes a bug, adds functionality, or makes AppFlowy's codebase significantly easier to use or understand, **Congratulations!** If your administrative and managerial work behind the scenes sustains the community, **Congratulations!** You are now an official contributor to AppFlowy. Get in touch with us ([link](https://tally.so/r/mKP5z3)) to receive the very special Contributor T-shirt!
|
||||
Proudly wear your T-shirt and show it to us by tagging [@appflowy](https://twitter.com/appflowy) on Twitter.
|
||||
|
||||
|
||||
## Translations 🌎🗺
|
||||
|
||||
[](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy?ref=badge)
|
||||
|
||||
To add translations, you can manually edit the JSON translation files in `/frontend/appflowy_flutter/assets/translations`, use the [inlang online editor](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy), or run `npx inlang machine translate` to add missing translations.
|
||||
|
||||
|
||||
## Join the community to build AppFlowy together
|
||||
|
||||
<a href="https://github.com/AppFlowy-IO/AppFlowy/graphs/contributors">
|
||||
|
||||
Vendored
+22
-45
@@ -43,47 +43,34 @@
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
"name": "AF-iOS: Clean + Rebuild All",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"preLaunchTask": "AF: Clean + Rebuild All (iOS)",
|
||||
"env": {
|
||||
"RUST_LOG": "trace"
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
"name": "AF-iOS-Simulator: Clean + Rebuild All",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"preLaunchTask": "AF: Clean + Rebuild All (iOS Simulator)",
|
||||
"env": {
|
||||
"RUST_LOG": "trace"
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
"name": "AF-desktop: Debug Rust",
|
||||
"request": "attach",
|
||||
"type": "lldb",
|
||||
"pid": "${command:pickMyProcess}"
|
||||
},
|
||||
// {
|
||||
// "name": "AF-desktop: profile mode",
|
||||
// "request": "launch",
|
||||
// "program": "./lib/main.dart",
|
||||
// "type": "dart",
|
||||
// "flutterMode": "profile",
|
||||
// "cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
// },
|
||||
{
|
||||
// This task builds the Rust and Dart code of AppFlowy for android.
|
||||
"name": "AF-android: Build All",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"preLaunchTask": "AF: build_mobile_sdk",
|
||||
"env": {
|
||||
"RUST_LOG": "info"
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
// This task builds will:
|
||||
// - call the clean task,
|
||||
// - rebuild all the generated Files (including freeze and language files)
|
||||
// - rebuild the the Rust and Dart code of AppFlowy.
|
||||
"name": "AF-android: Clean + Rebuild All",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"preLaunchTask": "AF: Clean + Rebuild All (Android)",
|
||||
"env": {
|
||||
"RUST_LOG": "info"
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
// https://tauri.app/v1/guides/debugging/vs-code
|
||||
"type": "lldb",
|
||||
@@ -99,15 +86,5 @@
|
||||
"preLaunchTask": "AF: Tauri UI Dev",
|
||||
"cwd": "${workspaceRoot}/appflowy_tauri/"
|
||||
},
|
||||
// {
|
||||
// "type": "lldb",
|
||||
// "request": "launch",
|
||||
// "name": "AF-tauri: Production Debug",
|
||||
// "cargo": {
|
||||
// "args": ["build", "--release", "--manifest-path=./appflowy_tauri/src-tauri/Cargo.toml"]
|
||||
// },
|
||||
// "preLaunchTask": "AF: Tauri UI Build",
|
||||
// "cwd": "${workspaceRoot}/appflowy_tauri/"
|
||||
// },
|
||||
]
|
||||
}
|
||||
Vendored
+31
-4
@@ -28,13 +28,13 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Clean + Rebuild All (Android)",
|
||||
"label": "AF: Clean + Rebuild All (iOS)",
|
||||
"type": "shell",
|
||||
"dependsOrder": "sequence",
|
||||
"dependsOn": [
|
||||
"AF: Dart Clean",
|
||||
"AF: Flutter Clean",
|
||||
"AF: Build Appflowy Core_for_android",
|
||||
"AF: Build Appflowy Core For iOS",
|
||||
"AF: Flutter Pub Get",
|
||||
"AF: Flutter Package Get",
|
||||
"AF: Generate Language Files",
|
||||
@@ -46,9 +46,36 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Build Appflowy Core_for_android",
|
||||
"label": "AF: Clean + Rebuild All (iOS Simulator)",
|
||||
"type": "shell",
|
||||
"command": "cargo make --profile development-android appflowy-core-dev-android",
|
||||
"dependsOrder": "sequence",
|
||||
"dependsOn": [
|
||||
"AF: Dart Clean",
|
||||
"AF: Flutter Clean",
|
||||
"AF: Build Appflowy Core For iOS Simulator",
|
||||
"AF: Flutter Pub Get",
|
||||
"AF: Flutter Package Get",
|
||||
"AF: Generate Language Files",
|
||||
"AF: Generate Freezed Files"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Build Appflowy Core For iOS",
|
||||
"type": "shell",
|
||||
"command": "cargo make --profile development-ios-arm64 appflowy-core-dev-ios",
|
||||
"group": "build",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Build Appflowy Core For iOS Simulator",
|
||||
"type": "shell",
|
||||
"command": "cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios",
|
||||
"group": "build",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
|
||||
+30
-7
@@ -2,6 +2,7 @@
|
||||
|
||||
extend = [
|
||||
{ path = "scripts/makefile/desktop.toml" },
|
||||
{ path = "scripts/makefile/mobile.toml" },
|
||||
{ path = "scripts/makefile/protobuf.toml" },
|
||||
{ path = "scripts/makefile/tests.toml" },
|
||||
{ path = "scripts/makefile/docker.toml" },
|
||||
@@ -23,7 +24,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.2.7"
|
||||
CURRENT_APP_VERSION = "0.2.9"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
|
||||
PRODUCT_NAME = "AppFlowy"
|
||||
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
|
||||
@@ -59,6 +60,7 @@ BUILD_FLAG = "debug"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
PRODUCT_EXT = "app"
|
||||
BUILD_ARCHS = "arm64"
|
||||
BUILD_ACTIVE_ARCHS_ONLY = true
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.development-mac-x86_64]
|
||||
@@ -69,6 +71,7 @@ BUILD_FLAG = "debug"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
PRODUCT_EXT = "app"
|
||||
BUILD_ARCHS = "x86_64"
|
||||
BUILD_ACTIVE_ARCHS_ONLY = true
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.production-mac-arm64]
|
||||
@@ -79,6 +82,7 @@ FLUTTER_OUTPUT_DIR = "Release"
|
||||
PRODUCT_EXT = "app"
|
||||
APP_ENVIRONMENT = "production"
|
||||
BUILD_ARCHS = "arm64"
|
||||
BUILD_ACTIVE_ARCHS_ONLY = false
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.production-mac-x86_64]
|
||||
@@ -89,8 +93,17 @@ FLUTTER_OUTPUT_DIR = "Release"
|
||||
PRODUCT_EXT = "app"
|
||||
APP_ENVIRONMENT = "production"
|
||||
BUILD_ARCHS = "x86_64"
|
||||
BUILD_ACTIVE_ARCHS_ONLY = false
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.production-mac-universal]
|
||||
BUILD_FLAG = "release"
|
||||
TARGET_OS = "macos"
|
||||
FLUTTER_OUTPUT_DIR = "Release"
|
||||
PRODUCT_EXT = "app"
|
||||
BUILD_ACTIVE_ARCHS_ONLY = false
|
||||
APP_ENVIRONMENT = "production"
|
||||
|
||||
[env.development-windows-x86]
|
||||
TARGET_OS = "windows"
|
||||
RUST_COMPILE_TARGET = "x86_64-pc-windows-msvc"
|
||||
@@ -150,6 +163,22 @@ LINUX_ARCH = "arm64"
|
||||
APP_ENVIRONMENT = "production"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
|
||||
|
||||
[env.development-ios-arm64-sim]
|
||||
BUILD_FLAG = "debug"
|
||||
TARGET_OS = "ios"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
RUST_COMPILE_TARGET = "aarch64-apple-ios-sim"
|
||||
BUILD_ARCHS = "arm64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.development-ios-arm64]
|
||||
BUILD_FLAG = "debug"
|
||||
TARGET_OS = "ios"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
RUST_COMPILE_TARGET = "aarch64-apple-ios"
|
||||
BUILD_ARCHS = "arm64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[tasks.echo_env]
|
||||
script = ['''
|
||||
echo "-------- Env Parameters --------"
|
||||
@@ -165,12 +194,6 @@ script = ['''
|
||||
''']
|
||||
script_runner = "@shell"
|
||||
|
||||
[env.production-ios]
|
||||
BUILD_FLAG = "release"
|
||||
TARGET_OS = "ios"
|
||||
FLUTTER_OUTPUT_DIR = "Release"
|
||||
PRODUCT_EXT = "ipa"
|
||||
|
||||
[env.development-android]
|
||||
BUILD_FLAG = "debug"
|
||||
TARGET_OS = "android"
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 6L18.781 11.9243L25 12.8801L20.5 17.489L21.562 24L16 20.9243L10.438 24L11.5 17.489L7 12.8801L13.219 11.9243L16 6Z" fill="#FFD667" stroke="#FFD667" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 329 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 6L18.781 11.9243L25 12.8801L20.5 17.489L21.562 24L16 20.9243L10.438 24L11.5 17.489L7 12.8801L13.219 11.9243L16 6Z" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 314 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 4.5L14.0858 8.94322L18.75 9.66009L15.375 13.1167L16.1715 18L12 15.6932L7.8285 18L8.625 13.1167L5.25 9.66009L9.91425 8.94322L12 4.5Z" stroke="#333333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3L9.3905 5.96215L12.5 6.44006L10.25 8.74448L10.781 12L8 10.4621L5.219 12L5.75 8.74448L3.5 6.44006L6.6095 5.96215L8 3Z" fill="#FFD667" stroke="#FFD667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 315 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3L9.3905 5.96215L12.5 6.44006L10.25 8.74448L10.781 12L8 10.4621L5.219 12L5.75 8.74448L3.5 6.44006L6.6095 5.96215L8 3Z" fill="#none" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 313 B |
@@ -0,0 +1,50 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/card/card.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.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('board row test', () {
|
||||
testWidgets('delete item in ToDo card', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
const name = 'Card 1';
|
||||
final card1 = find.findTextInFlowyText(name);
|
||||
await tester.hoverOnWidget(
|
||||
card1,
|
||||
onHover: () async {
|
||||
final moreOption = find.byType(CardMoreOption);
|
||||
await tester.tapButton(moreOption);
|
||||
},
|
||||
);
|
||||
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
|
||||
expect(find.findTextInFlowyText(name), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('duplicate item in ToDo card', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
const name = 'Card 1';
|
||||
final card1 = find.findTextInFlowyText(name);
|
||||
await tester.hoverOnWidget(
|
||||
card1,
|
||||
onHover: () async {
|
||||
final moreOption = find.byType(CardMoreOption);
|
||||
await tester.tapButton(moreOption);
|
||||
},
|
||||
);
|
||||
await tester.tapButtonWithName(LocaleKeys.button_duplicate.tr());
|
||||
expect(find.textContaining(name, findRichText: true), findsNWidgets(2));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'board_row_test.dart' as board_row_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Board integration tests
|
||||
board_row_test.main();
|
||||
}
|
||||
@@ -14,8 +14,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateCalendarButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
|
||||
|
||||
// open setting
|
||||
await tester.tapDatabaseSettingButton();
|
||||
@@ -36,7 +35,11 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create calendar view
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Calendar, 'calendar');
|
||||
const name = 'calendar';
|
||||
await tester.createNewPageWithName(
|
||||
name: name,
|
||||
layout: ViewLayoutPB.Calendar,
|
||||
);
|
||||
|
||||
// Open setting
|
||||
await tester.tapDatabaseSettingButton();
|
||||
@@ -47,9 +50,9 @@ void main() {
|
||||
await tester.tapFirstDayOfWeekStartFromMonday();
|
||||
|
||||
// Open the other page and open the new calendar page again
|
||||
await tester.openPage(readme);
|
||||
await tester.openPage(gettingStarted);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 300));
|
||||
await tester.openPage('calendar');
|
||||
await tester.openPage(name, layout: ViewLayoutPB.Calendar);
|
||||
|
||||
// Open setting again and check the start from Monday is selected
|
||||
await tester.tapDatabaseSettingButton();
|
||||
@@ -65,8 +68,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create the calendar view
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateCalendarButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
|
||||
|
||||
// Scroll until today's date cell is visible
|
||||
await tester.scrollToToday();
|
||||
@@ -135,8 +137,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create the calendar view
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateCalendarButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
|
||||
|
||||
// Create a new event on the first of this month
|
||||
final today = DateTime.now();
|
||||
|
||||
@@ -15,8 +15,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
await tester.editCell(
|
||||
rowIndex: 0,
|
||||
@@ -38,7 +37,10 @@ void main() {
|
||||
testWidgets('edit multiple text cells', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Grid, 'my grid');
|
||||
await tester.createNewPageWithName(
|
||||
name: 'my grid',
|
||||
layout: ViewLayoutPB.Grid,
|
||||
);
|
||||
await tester.createField(FieldType.RichText, 'description');
|
||||
|
||||
await tester.editCell(
|
||||
@@ -75,8 +77,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
const fieldType = FieldType.Number;
|
||||
|
||||
@@ -134,8 +135,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
await tester.assertCheckboxCell(rowIndex: 0, isSelected: false);
|
||||
await tester.tapCheckboxCellInGrid(rowIndex: 0);
|
||||
@@ -153,8 +153,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
const fieldType = FieldType.CreatedTime;
|
||||
// Create a create time field
|
||||
@@ -172,8 +171,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
const fieldType = FieldType.LastEditedTime;
|
||||
// Create a last time field
|
||||
@@ -191,8 +189,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
const fieldType = FieldType.DateTime;
|
||||
await tester.createField(fieldType, fieldType.name);
|
||||
@@ -268,6 +265,18 @@ void main() {
|
||||
content: DateFormat('dd/MM/y hh:mm a').format(now),
|
||||
);
|
||||
|
||||
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
||||
await tester.findDateEditor(findsOneWidget);
|
||||
|
||||
// Clear the date and time
|
||||
await tester.clearDate();
|
||||
|
||||
await tester.assertDateCellInGrid(
|
||||
rowIndex: 0,
|
||||
fieldType: fieldType,
|
||||
content: '',
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
@@ -276,9 +285,9 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
const fieldType = FieldType.SingleSelect;
|
||||
await tester.tapAddButton();
|
||||
|
||||
// When create a grid, it will create a single select field by default
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Tap the cell to invoke the selection option editor
|
||||
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
||||
@@ -354,8 +363,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
const fieldType = FieldType.MultiSelect;
|
||||
await tester.createField(fieldType, fieldType.name);
|
||||
|
||||
@@ -17,8 +17,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Invoke the field editor
|
||||
await tester.tapGridFieldWithName('Name');
|
||||
@@ -35,8 +34,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Invoke the field editor
|
||||
await tester.tapGridFieldWithName('Type');
|
||||
@@ -58,8 +56,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// create a field
|
||||
await tester.createField(FieldType.Checklist, 'checklist');
|
||||
@@ -73,8 +70,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// create a field
|
||||
await tester.createField(FieldType.Checkbox, 'New field 1');
|
||||
@@ -94,8 +90,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// create a field
|
||||
await tester.scrollToRight(find.byType(GridPage));
|
||||
@@ -115,8 +110,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// create a field
|
||||
await tester.scrollToRight(find.byType(GridPage));
|
||||
@@ -136,8 +130,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
await tester.scrollToRight(find.byType(GridPage));
|
||||
await tester.tapNewPropertyButton();
|
||||
@@ -157,8 +150,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
for (final fieldType in [
|
||||
FieldType.Checklist,
|
||||
@@ -190,7 +182,9 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Grid);
|
||||
await tester.createNewPageWithName(
|
||||
layout: ViewLayoutPB.Grid,
|
||||
);
|
||||
|
||||
// Invoke the field editor
|
||||
await tester.tapGridFieldWithName('Type');
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'util/database_test_op.dart';
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('grid', () {
|
||||
group('database filter', () {
|
||||
testWidgets('add text filter', (tester) async {
|
||||
await tester.openV020database();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -19,8 +20,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -34,8 +34,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -55,8 +54,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -85,8 +83,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -108,8 +105,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -144,8 +140,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -160,8 +155,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -201,8 +195,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -241,8 +234,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
@@ -258,8 +250,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// Create a new grid
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Hover first row and then open the row page
|
||||
await tester.openFirstRowDetailPage();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
@@ -12,8 +13,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
await tester.tapCreateRowButtonInGrid();
|
||||
|
||||
// The initial number of rows is 3
|
||||
@@ -25,8 +25,8 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
await tester.hoverOnFirstRowOfGrid();
|
||||
|
||||
await tester.tapCreateRowButtonInRowMenuOfGrid();
|
||||
@@ -41,8 +41,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
await tester.hoverOnFirstRowOfGrid();
|
||||
|
||||
// Open the row menu and then click the delete
|
||||
@@ -60,8 +59,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
await tester.assertRowCountInGridPage(3);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
@@ -13,8 +14,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// open setting
|
||||
await tester.tapDatabaseSettingButton();
|
||||
@@ -31,8 +31,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// open setting
|
||||
await tester.tapDatabaseSettingButton();
|
||||
|
||||
@@ -10,22 +10,22 @@ void main() {
|
||||
group('grid', () {
|
||||
testWidgets('add text sort', (tester) async {
|
||||
await tester.openV020database();
|
||||
// create a filter
|
||||
// create a sort
|
||||
await tester.tapDatabaseSortButton();
|
||||
await tester.tapCreateSortByFieldType(FieldType.RichText, 'Name');
|
||||
|
||||
// check the text cell order
|
||||
final textCells = <String>[
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
];
|
||||
for (final (index, content) in textCells.indexed) {
|
||||
await tester.assertCellContent(
|
||||
@@ -142,7 +142,6 @@ void main() {
|
||||
|
||||
// check the number cell order
|
||||
for (final (index, content) in <String>[
|
||||
'',
|
||||
'-2',
|
||||
'-1',
|
||||
'0.1',
|
||||
@@ -152,6 +151,7 @@ void main() {
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'',
|
||||
].indexed) {
|
||||
await tester.assertCellContent(
|
||||
rowIndex: index,
|
||||
@@ -186,53 +186,74 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('add number and text sort', (tester) async {
|
||||
testWidgets('add checkbox and number sort', (tester) async {
|
||||
await tester.openV020database();
|
||||
// create a filter
|
||||
await tester.tapDatabaseSortButton();
|
||||
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
|
||||
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
|
||||
|
||||
// open the sort menu and select number order by descending
|
||||
// open the sort menu and sort checkbox by descending
|
||||
await tester.tapSortMenuInSettingBar();
|
||||
await tester.tapSortButtonByName('number');
|
||||
await tester.tapSortButtonByName('Done');
|
||||
await tester.tapSortByDescending();
|
||||
for (final (index, content) in <String>[
|
||||
'12',
|
||||
'11',
|
||||
'10',
|
||||
'2',
|
||||
'1',
|
||||
'0.2',
|
||||
'0.1',
|
||||
'-1',
|
||||
'-2',
|
||||
'',
|
||||
for (final (index, content) in <bool>[
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
].indexed) {
|
||||
await tester.assertCellContent(
|
||||
await tester.assertCheckboxCell(
|
||||
rowIndex: index,
|
||||
fieldType: FieldType.Number,
|
||||
content: content,
|
||||
isSelected: content,
|
||||
);
|
||||
}
|
||||
|
||||
// add another sort, this time by number descending
|
||||
await tester.tapSortMenuInSettingBar();
|
||||
await tester.tapCreateSortByFieldTypeInSortMenu(
|
||||
FieldType.RichText,
|
||||
'Name',
|
||||
FieldType.Number,
|
||||
'number',
|
||||
);
|
||||
await tester.tapSortButtonByName('number');
|
||||
await tester.tapSortByDescending();
|
||||
|
||||
// check checkbox cell order
|
||||
for (final (index, content) in <bool>[
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
].indexed) {
|
||||
await tester.assertCheckboxCell(
|
||||
rowIndex: index,
|
||||
isSelected: content,
|
||||
);
|
||||
}
|
||||
|
||||
// check number cell order
|
||||
for (final (index, content) in <String>[
|
||||
'1',
|
||||
'0.2',
|
||||
'0.1',
|
||||
'-1',
|
||||
'-2',
|
||||
'12',
|
||||
'11',
|
||||
'10',
|
||||
'2',
|
||||
'',
|
||||
'-1',
|
||||
'-2',
|
||||
'0.1',
|
||||
'0.2',
|
||||
'1',
|
||||
].indexed) {
|
||||
await tester.assertCellContent(
|
||||
rowIndex: index,
|
||||
@@ -241,26 +262,6 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
// check text cell order
|
||||
for (final (index, content) in <String>[
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
].indexed) {
|
||||
await tester.assertCellContent(
|
||||
rowIndex: index,
|
||||
fieldType: FieldType.RichText,
|
||||
content: content,
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,8 +15,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Create board view
|
||||
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.board);
|
||||
@@ -37,8 +36,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Create board view
|
||||
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.board);
|
||||
@@ -63,8 +61,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateGridButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
||||
|
||||
// Create board view
|
||||
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.board);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('copy and paste in document', () {
|
||||
testWidgets('paste multiple lines at the first line', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName();
|
||||
|
||||
// mock the clipboard
|
||||
const lines = 3;
|
||||
AppFlowyClipboard.mockSetData(
|
||||
AppFlowyClipboardData(
|
||||
text: List.generate(lines, (index) => 'line $index').join('\n'),
|
||||
),
|
||||
);
|
||||
|
||||
// paste the text
|
||||
await tester.simulateKeyEvent(
|
||||
LogicalKeyboardKey.keyV,
|
||||
isControlPressed: Platform.isLinux || Platform.isWindows,
|
||||
isMetaPressed: Platform.isMacOS,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final editorState = tester.editor.getCurrentEditorState();
|
||||
expect(editorState.document.root.children.length, 4);
|
||||
for (var i = 0; i < lines; i++) {
|
||||
expect(
|
||||
editorState.getNodeAtPath([i])!.delta!.toPlainText(),
|
||||
'line $i',
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
+13
-11
@@ -17,9 +17,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create a new document
|
||||
await tester.tapAddButton();
|
||||
await tester.tapCreateDocumentButton();
|
||||
await tester.pumpAndSettle();
|
||||
await tester.createNewPageWithName();
|
||||
|
||||
// expect to see a new document
|
||||
tester.expectToSeePageName(
|
||||
@@ -35,19 +33,21 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// delete the readme page
|
||||
await tester.hoverOnPageName(readme);
|
||||
await tester.tapDeletePageButton();
|
||||
await tester.hoverOnPageName(
|
||||
gettingStarted,
|
||||
onHover: () async => await tester.tapDeletePageButton(),
|
||||
);
|
||||
|
||||
// the banner should show up and the readme page should be gone
|
||||
tester.expectToSeeDocumentBanner();
|
||||
tester.expectNotToSeePageName(readme);
|
||||
tester.expectNotToSeePageName(gettingStarted);
|
||||
|
||||
// restore the readme page
|
||||
await tester.tapRestoreButton();
|
||||
|
||||
// the banner should be gone and the readme page should be back
|
||||
tester.expectNotToSeeDocumentBanner();
|
||||
tester.expectToSeePageName(readme);
|
||||
tester.expectToSeePageName(gettingStarted);
|
||||
});
|
||||
|
||||
testWidgets('delete the readme page and delete it permanently',
|
||||
@@ -57,19 +57,21 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// delete the readme page
|
||||
await tester.hoverOnPageName(readme);
|
||||
await tester.tapDeletePageButton();
|
||||
await tester.hoverOnPageName(
|
||||
gettingStarted,
|
||||
onHover: () async => await tester.tapDeletePageButton(),
|
||||
);
|
||||
|
||||
// the banner should show up and the readme page should be gone
|
||||
tester.expectToSeeDocumentBanner();
|
||||
tester.expectNotToSeePageName(readme);
|
||||
tester.expectNotToSeePageName(gettingStarted);
|
||||
|
||||
// delete the page permanently
|
||||
await tester.tapDeletePermanentlyButton();
|
||||
|
||||
// the banner should be gone and the readme page should be gone
|
||||
tester.expectNotToSeeDocumentBanner();
|
||||
tester.expectNotToSeePageName(readme);
|
||||
tester.expectNotToSeePageName(gettingStarted);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
|
||||
import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
|
||||
import 'edit_document_test.dart' as document_edit_test;
|
||||
import 'document_with_outline_block_test.dart' as document_with_outline_block;
|
||||
import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -23,4 +24,5 @@ void startTesting() {
|
||||
document_with_cover_image_test.main();
|
||||
document_with_outline_block.main();
|
||||
document_with_toggle_list_test.main();
|
||||
document_copy_and_paste_test.main();
|
||||
}
|
||||
+92
-4
@@ -1,9 +1,12 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/link_to_page_widget.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/uuid.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
@@ -61,6 +64,54 @@ void main() {
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('create a grid inside a document', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await createInlineDatabase(tester, ViewLayoutPB.Grid);
|
||||
|
||||
// validate the referenced grid is inserted
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(AppFlowyEditor),
|
||||
matching: find.byType(GridPage),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('create a board inside a document', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await createInlineDatabase(tester, ViewLayoutPB.Board);
|
||||
|
||||
// validate the referenced grid is inserted
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(AppFlowyEditor),
|
||||
matching: find.byType(BoardPage),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('create a calendar inside a document', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await createInlineDatabase(tester, ViewLayoutPB.Calendar);
|
||||
|
||||
// validate the referenced grid is inserted
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(AppFlowyEditor),
|
||||
matching: find.byType(CalendarPage),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,13 +124,15 @@ Future<void> insertReferenceDatabase(
|
||||
final id = uuid();
|
||||
final name = '${layout.name}_$id';
|
||||
await tester.createNewPageWithName(
|
||||
layout,
|
||||
name,
|
||||
name: name,
|
||||
layout: layout,
|
||||
openAfterCreated: false,
|
||||
);
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
'insert_a_reference_${layout.name}',
|
||||
name: 'insert_a_reference_${layout.name}',
|
||||
layout: ViewLayoutPB.Document,
|
||||
openAfterCreated: true,
|
||||
);
|
||||
// tap the first line of the document
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
@@ -98,3 +151,38 @@ Future<void> insertReferenceDatabase(
|
||||
expect(referencedDatabase, findsOneWidget);
|
||||
await tester.tapButton(referencedDatabase);
|
||||
}
|
||||
|
||||
Future<void> createInlineDatabase(
|
||||
WidgetTester tester,
|
||||
ViewLayoutPB layout,
|
||||
) async {
|
||||
// create a new document
|
||||
final documentName = 'insert_a_inline_${layout.name}';
|
||||
await tester.createNewPageWithName(
|
||||
name: documentName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
openAfterCreated: true,
|
||||
);
|
||||
// tap the first line of the document
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
// insert a referenced view
|
||||
await tester.editor.showSlashMenu();
|
||||
final name = switch (layout) {
|
||||
ViewLayoutPB.Grid => LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
|
||||
ViewLayoutPB.Board =>
|
||||
LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
|
||||
ViewLayoutPB.Calendar =>
|
||||
LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr(),
|
||||
_ => '',
|
||||
};
|
||||
await tester.editor.tapSlashMenuItemWithName(
|
||||
name,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final childViews = tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(documentName))
|
||||
.view
|
||||
.childViews;
|
||||
expect(childViews.length, 1);
|
||||
}
|
||||
+4
-4
@@ -21,8 +21,8 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
name: LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
@@ -67,8 +67,8 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
name: LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
|
||||
+14
-8
@@ -62,9 +62,11 @@ void main() {
|
||||
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Document);
|
||||
|
||||
// rename
|
||||
await tester.hoverOnPageName(pageName);
|
||||
const newName = 'RenameToNewPageName';
|
||||
await tester.renamePage(newName);
|
||||
await tester.hoverOnPageName(
|
||||
pageName,
|
||||
onHover: () async => await tester.renamePage(newName),
|
||||
);
|
||||
final finder = find.descendant(
|
||||
of: find.byType(MentionPageBlock),
|
||||
matching: find.findTextInFlowyText(newName),
|
||||
@@ -79,8 +81,11 @@ void main() {
|
||||
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Grid);
|
||||
|
||||
// rename
|
||||
await tester.hoverOnPageName(pageName);
|
||||
await tester.tapDeletePageButton();
|
||||
await tester.hoverOnPageName(
|
||||
pageName,
|
||||
layout: ViewLayoutPB.Grid,
|
||||
onHover: () async => await tester.tapDeletePageButton(),
|
||||
);
|
||||
final finder = find.descendant(
|
||||
of: find.byType(MentionPageBlock),
|
||||
matching: find.findTextInFlowyText(pageName),
|
||||
@@ -101,13 +106,14 @@ Future<String> insertingInlinePage(
|
||||
final id = uuid();
|
||||
final name = '${layout.name}_$id';
|
||||
await tester.createNewPageWithName(
|
||||
layout,
|
||||
name,
|
||||
name: name,
|
||||
layout: layout,
|
||||
openAfterCreated: false,
|
||||
);
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
'insert_a_inline_page_${layout.name}',
|
||||
name: 'insert_a_inline_page_${layout.name}',
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
// tap the first line of the document
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
|
||||
@@ -25,7 +25,7 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
|
||||
+4
-4
@@ -16,8 +16,8 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
'outline_test',
|
||||
name: 'outline_test',
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
@@ -33,8 +33,8 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
'outline_test',
|
||||
name: 'outline_test',
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
@@ -78,7 +78,7 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
@@ -118,7 +118,7 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
@@ -156,7 +156,7 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
@@ -191,7 +191,7 @@ void main() {
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
|
||||
@@ -18,7 +18,10 @@ void main() {
|
||||
|
||||
// create a new document called Sample
|
||||
const pageName = 'Sample';
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Document, pageName);
|
||||
await tester.createNewPageWithName(
|
||||
name: pageName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// focus on the editor
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
@@ -56,7 +59,7 @@ void main() {
|
||||
);
|
||||
|
||||
// switch to other page and switch back
|
||||
await tester.openPage(readme);
|
||||
await tester.openPage(gettingStarted);
|
||||
await tester.openPage(pageName);
|
||||
|
||||
// the numbered list should be kept
|
||||
@@ -72,7 +75,10 @@ void main() {
|
||||
|
||||
// create a new document called Sample
|
||||
const pageName = 'Sample';
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Document, pageName);
|
||||
await tester.createNewPageWithName(
|
||||
name: pageName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// focus on the editor
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
@@ -85,7 +91,7 @@ void main() {
|
||||
}
|
||||
|
||||
// switch to other page and switch back
|
||||
await tester.openPage(readme);
|
||||
await tester.openPage(gettingStarted);
|
||||
await tester.openPage(pageName);
|
||||
|
||||
// this screenshots are different on different platform, so comment it out temporarily.
|
||||
|
||||
@@ -16,10 +16,10 @@ void main() {
|
||||
final context = await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// expect to see a readme page
|
||||
tester.expectToSeePageName(readme);
|
||||
// expect to see a getting started page
|
||||
tester.expectToSeePageName(gettingStarted);
|
||||
|
||||
await tester.tapAddButton();
|
||||
await tester.tapAddViewButton();
|
||||
await tester.tapImportButton();
|
||||
|
||||
final testFileNames = ['test1.md', 'test2.md'];
|
||||
|
||||
@@ -14,6 +14,9 @@ import 'document/document_test_runner.dart' as document_test_runner;
|
||||
import 'import_files_test.dart' as import_files_test;
|
||||
import 'share_markdown_test.dart' as share_markdown_test;
|
||||
import 'switch_folder_test.dart' as switch_folder_test;
|
||||
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
|
||||
import 'board/board_test_runner.dart' as board_test_runner;
|
||||
import 'tabs_test.dart' as tabs_test;
|
||||
|
||||
/// The main task runner for all integration tests in AppFlowy.
|
||||
///
|
||||
@@ -31,6 +34,12 @@ void main() {
|
||||
// Document integration tests
|
||||
document_test_runner.startTesting();
|
||||
|
||||
// Sidebar integration tests
|
||||
sidebar_test_runner.startTesting();
|
||||
|
||||
// Board integration test
|
||||
board_test_runner.startTesting();
|
||||
|
||||
// Database integration tests
|
||||
database_cell_test.main();
|
||||
database_field_test.main();
|
||||
@@ -43,6 +52,9 @@ void main() {
|
||||
database_view_test.main();
|
||||
database_calendar_test.main();
|
||||
|
||||
// Tabs
|
||||
tabs_test.main();
|
||||
|
||||
// board_test.main();
|
||||
// empty_document_test.main();
|
||||
// smart_menu_test.main();
|
||||
|
||||
@@ -16,7 +16,7 @@ void main() {
|
||||
await tester.tapGoButton();
|
||||
|
||||
// expect to see a readme page
|
||||
tester.expectToSeePageName(readme);
|
||||
tester.expectToSeePageName(gettingStarted);
|
||||
|
||||
// mock the file picker
|
||||
final path = await mockSaveFilePath(
|
||||
@@ -42,12 +42,16 @@ void main() {
|
||||
final context = await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// expect to see a readme page
|
||||
tester.expectToSeePageName(readme);
|
||||
// expect to see a getting started page
|
||||
tester.expectToSeePageName(gettingStarted);
|
||||
|
||||
// rename the document
|
||||
await tester.hoverOnPageName(readme);
|
||||
await tester.renamePage('example');
|
||||
await tester.hoverOnPageName(
|
||||
gettingStarted,
|
||||
onHover: () async {
|
||||
await tester.renamePage('example');
|
||||
},
|
||||
);
|
||||
|
||||
final shareButton = find.byType(ShareActionList);
|
||||
final shareButtonState =
|
||||
@@ -90,6 +94,13 @@ const expectedMarkdown = r'''
|
||||
1. Keyboard shortcuts [guide](https://appflowy.gitbook.io/docs/essential-documentation/shortcuts)
|
||||
1. Markdown [reference](https://appflowy.gitbook.io/docs/essential-documentation/markdown)
|
||||
1. Type `/code` to insert a code block
|
||||
```rust
|
||||
// This is the main function.
|
||||
fn main() {
|
||||
// Print text to the console.
|
||||
println!("Hello World!");
|
||||
}
|
||||
```
|
||||
|
||||
## Have a question❓
|
||||
> Click `?` at the bottom right for help and support.
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.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('sidebar expand test', () {
|
||||
bool isExpanded({required FolderCategoryType type}) {
|
||||
if (type == FolderCategoryType.personal) {
|
||||
return find
|
||||
.descendant(
|
||||
of: find.byType(PersonalFolder),
|
||||
matching: find.byType(ViewItem),
|
||||
)
|
||||
.evaluate()
|
||||
.isNotEmpty;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
testWidgets('first time the personal folder is expanded', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// first time is expanded
|
||||
expect(isExpanded(type: FolderCategoryType.personal), true);
|
||||
|
||||
// collapse the personal folder
|
||||
await tester.tapButton(
|
||||
find.byTooltip(LocaleKeys.sideBar_clickToHidePersonal.tr()),
|
||||
);
|
||||
expect(isExpanded(type: FolderCategoryType.personal), false);
|
||||
|
||||
// expand the personal folder
|
||||
await tester.tapButton(
|
||||
find.byTooltip(LocaleKeys.sideBar_clickToHidePersonal.tr()),
|
||||
);
|
||||
expect(isExpanded(type: FolderCategoryType.personal), true);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/favorite_folder.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/base.dart';
|
||||
import '../util/common_operations.dart';
|
||||
import '../util/expectation.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('Favorites', () {
|
||||
testWidgets(
|
||||
'Toggle favorites for views creates / removes the favorite header along with favorite views',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// no favorite folder
|
||||
expect(find.byType(FavoriteFolder), findsNothing);
|
||||
|
||||
// create the nested views
|
||||
final names = [
|
||||
1,
|
||||
2,
|
||||
].map((e) => 'document_$e').toList();
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
final parentName = i == 0 ? gettingStarted : names[i - 1];
|
||||
await tester.createNewPageWithName(
|
||||
name: names[i],
|
||||
parentName: parentName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
tester.expectToSeePageName(
|
||||
names[i],
|
||||
parentName: parentName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
parentLayout: ViewLayoutPB.Document,
|
||||
);
|
||||
}
|
||||
|
||||
await tester.favoriteViewByName(gettingStarted);
|
||||
expect(
|
||||
tester.findFavoritePageName(gettingStarted),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
await tester.favoriteViewByName(names[1]);
|
||||
expect(
|
||||
tester.findFavoritePageName(names[1]),
|
||||
findsNWidgets(2),
|
||||
);
|
||||
|
||||
await tester.unfavoriteViewByName(gettingStarted);
|
||||
expect(
|
||||
tester.findFavoritePageName(gettingStarted),
|
||||
findsNothing,
|
||||
);
|
||||
expect(
|
||||
tester.findFavoritePageName(
|
||||
names[1],
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
await tester.unfavoriteViewByName(names[1]);
|
||||
expect(
|
||||
tester.findFavoritePageName(
|
||||
names[1],
|
||||
),
|
||||
findsNothing,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'renaming a favorite view updates name under favorite header',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
const name = 'test';
|
||||
await tester.favoriteViewByName(gettingStarted);
|
||||
await tester.hoverOnPageName(
|
||||
gettingStarted,
|
||||
layout: ViewLayoutPB.Document,
|
||||
onHover: () async {
|
||||
await tester.renamePage(name);
|
||||
await tester.pumpAndSettle();
|
||||
},
|
||||
);
|
||||
expect(
|
||||
tester.findPageName(name),
|
||||
findsNWidgets(2),
|
||||
);
|
||||
expect(
|
||||
tester.findFavoritePageName(name),
|
||||
findsNothing,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'deleting first level favorite view removes its instance from favorite header, deleting root level views leads to removal of all favorites that are its children',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final names = [1, 2].map((e) => 'document_$e').toList();
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
final parentName = i == 0 ? gettingStarted : names[i - 1];
|
||||
await tester.createNewPageWithName(
|
||||
name: names[i],
|
||||
parentName: parentName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
tester.expectToSeePageName(names[i], parentName: parentName);
|
||||
}
|
||||
await tester.favoriteViewByName(gettingStarted);
|
||||
await tester.favoriteViewByName(names[0]);
|
||||
await tester.favoriteViewByName(names[1]);
|
||||
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
),
|
||||
findsNWidgets(6),
|
||||
);
|
||||
|
||||
await tester.hoverOnPageName(
|
||||
names[1],
|
||||
layout: ViewLayoutPB.Document,
|
||||
onHover: () async {
|
||||
await tester.tapDeletePageButton();
|
||||
await tester.pumpAndSettle();
|
||||
},
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
),
|
||||
findsNWidgets(3),
|
||||
);
|
||||
|
||||
await tester.hoverOnPageName(
|
||||
gettingStarted,
|
||||
layout: ViewLayoutPB.Document,
|
||||
onHover: () async {
|
||||
await tester.tapDeletePageButton();
|
||||
await tester.pumpAndSettle();
|
||||
},
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
),
|
||||
findsNothing,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'view selection is synced between favorites and personal folder',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName();
|
||||
await tester.favoriteViewByName(gettingStarted);
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is FlowyHover &&
|
||||
widget.isSelected != null &&
|
||||
widget.isSelected!(),
|
||||
),
|
||||
findsNWidgets(2),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'context menu opens up for favorites',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName();
|
||||
await tester.favoriteViewByName(gettingStarted);
|
||||
await tester.hoverOnPageName(
|
||||
gettingStarted,
|
||||
layout: ViewLayoutPB.Document,
|
||||
useLast: false,
|
||||
onHover: () async {
|
||||
await tester.tapPageOptionButton();
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
find.byType(PopoverContainer),
|
||||
findsOneWidget,
|
||||
);
|
||||
},
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('sidebar test', () {
|
||||
testWidgets('create a new page', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create a new page
|
||||
const name = 'Hello AppFlowy';
|
||||
await tester.tapNewPageButton();
|
||||
await tester.enterText(find.byType(TextFormField), name);
|
||||
await tester.tapOKButton();
|
||||
|
||||
// expect to see a new document
|
||||
tester.expectToSeePageName(
|
||||
name,
|
||||
);
|
||||
// and with one paragraph block
|
||||
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('create a new document, grid, board and calendar',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
for (final layout in ViewLayoutPB.values) {
|
||||
// create a new page
|
||||
final name = 'AppFlowy_$layout';
|
||||
await tester.createNewPageWithName(
|
||||
name: name,
|
||||
layout: layout,
|
||||
);
|
||||
|
||||
// expect to see a new page
|
||||
tester.expectToSeePageName(
|
||||
name,
|
||||
layout: layout,
|
||||
);
|
||||
|
||||
switch (layout) {
|
||||
case ViewLayoutPB.Document:
|
||||
// and with one paragraph block
|
||||
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
|
||||
break;
|
||||
case ViewLayoutPB.Grid:
|
||||
expect(find.byType(GridPage), findsOneWidget);
|
||||
break;
|
||||
case ViewLayoutPB.Board:
|
||||
expect(find.byType(BoardPage), findsOneWidget);
|
||||
break;
|
||||
case ViewLayoutPB.Calendar:
|
||||
expect(find.byType(CalendarPage), findsOneWidget);
|
||||
break;
|
||||
}
|
||||
|
||||
await tester.openPage(gettingStarted);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('create some nested pages, and move them', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final names = [1, 2, 3, 4].map((e) => 'document_$e').toList();
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
final parentName = i == 0 ? gettingStarted : names[i - 1];
|
||||
await tester.createNewPageWithName(
|
||||
name: names[i],
|
||||
parentName: parentName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
tester.expectToSeePageName(names[i], parentName: parentName);
|
||||
}
|
||||
|
||||
// move the document_3 to the getting started page
|
||||
await tester.movePageToOtherPage(
|
||||
name: names[3],
|
||||
parentName: gettingStarted,
|
||||
layout: ViewLayoutPB.Document,
|
||||
parentLayout: ViewLayoutPB.Document,
|
||||
);
|
||||
final fromId = tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(names[3]))
|
||||
.view
|
||||
.parentViewId;
|
||||
final toId = tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(gettingStarted))
|
||||
.view
|
||||
.id;
|
||||
expect(fromId, toId);
|
||||
|
||||
// move the document_2 before document_1
|
||||
await tester.movePageToOtherPage(
|
||||
name: names[2],
|
||||
parentName: gettingStarted,
|
||||
layout: ViewLayoutPB.Document,
|
||||
parentLayout: ViewLayoutPB.Document,
|
||||
position: DraggableHoverPosition.bottom,
|
||||
);
|
||||
final childViews = tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(gettingStarted))
|
||||
.view
|
||||
.childViews;
|
||||
expect(
|
||||
childViews[0].id,
|
||||
tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(names[2]))
|
||||
.view
|
||||
.id,
|
||||
);
|
||||
expect(
|
||||
childViews[1].id,
|
||||
tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(names[0]))
|
||||
.view
|
||||
.id,
|
||||
);
|
||||
expect(
|
||||
childViews[2].id,
|
||||
tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(names[3]))
|
||||
.view
|
||||
.id,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('unable to move a document into a database', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
const document = 'document';
|
||||
await tester.createNewPageWithName(
|
||||
name: document,
|
||||
openAfterCreated: false,
|
||||
);
|
||||
tester.expectToSeePageName(document, layout: ViewLayoutPB.Document);
|
||||
|
||||
const grid = 'grid';
|
||||
await tester.createNewPageWithName(
|
||||
name: grid,
|
||||
layout: ViewLayoutPB.Grid,
|
||||
openAfterCreated: false,
|
||||
);
|
||||
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
|
||||
|
||||
// move the document to the grid page
|
||||
await tester.movePageToOtherPage(
|
||||
name: document,
|
||||
parentName: grid,
|
||||
layout: ViewLayoutPB.Document,
|
||||
parentLayout: ViewLayoutPB.Grid,
|
||||
);
|
||||
|
||||
// it should not be moved
|
||||
final childViews = tester
|
||||
.widget<SingleInnerViewItem>(tester.findPageName(gettingStarted))
|
||||
.view
|
||||
.childViews;
|
||||
expect(
|
||||
childViews[0].name,
|
||||
document,
|
||||
);
|
||||
expect(
|
||||
childViews[1].name,
|
||||
grid,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('unable to create a new database inside the existing one',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
const grid = 'grid';
|
||||
await tester.createNewPageWithName(
|
||||
name: grid,
|
||||
layout: ViewLayoutPB.Grid,
|
||||
openAfterCreated: true,
|
||||
);
|
||||
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
|
||||
|
||||
await tester.hoverOnPageName(
|
||||
grid,
|
||||
layout: ViewLayoutPB.Grid,
|
||||
onHover: () async {
|
||||
expect(find.byType(ViewAddButton), findsNothing);
|
||||
expect(find.byType(ViewMoreActionButton), findsOneWidget);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'sidebar_test.dart' as sidebar_test;
|
||||
import 'sidebar_expand_test.dart' as sidebar_expanded_test;
|
||||
import 'sidebar_favorites_test.dart' as sidebar_favorite_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Sidebar integration tests
|
||||
sidebar_test.main();
|
||||
sidebar_expanded_test.main();
|
||||
sidebar_favorite_test.main();
|
||||
}
|
||||
@@ -1,23 +1,26 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/workspace/presentation/home/tabs/flowy_tab.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/tabs/tabs_manager.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'util/base.dart';
|
||||
import 'util/common_operations.dart';
|
||||
import 'util/expectation.dart';
|
||||
import 'util/keyboard.dart';
|
||||
|
||||
const _readmeName = 'Read me';
|
||||
const _documentName = 'Document';
|
||||
const _calendarName = 'Calendar';
|
||||
const _documentName = 'First Doc';
|
||||
const _documentTwoName = 'Second Doc';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('Tabs', () {
|
||||
testWidgets('Open AppFlowy and open/navigate multiple tabs',
|
||||
(tester) async {
|
||||
testWidgets('Open AppFlowy and open/navigate/close tabs', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
@@ -29,25 +32,21 @@ void main() {
|
||||
findsNothing,
|
||||
);
|
||||
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Calendar, _calendarName);
|
||||
await tester.createNewPageWithName(ViewLayoutPB.Document, _documentName);
|
||||
await tester.createNewPageWithName(
|
||||
name: _documentName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// Navigate current view to "Read me" document again
|
||||
await tester.tapButtonWithName(_readmeName);
|
||||
await tester.createNewPageWithName(
|
||||
name: _documentTwoName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
/// Open second menu item in a new tab
|
||||
await tester.openAppInNewTab(_calendarName);
|
||||
await tester.openAppInNewTab(gettingStarted, ViewLayoutPB.Document);
|
||||
|
||||
/// Open third menu item in a new tab
|
||||
await tester.openAppInNewTab(_documentName);
|
||||
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(TabsManager),
|
||||
matching: find.byType(TabBar),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
await tester.openAppInNewTab(_documentName, ViewLayoutPB.Document);
|
||||
|
||||
expect(
|
||||
find.descendant(
|
||||
@@ -57,13 +56,32 @@ void main() {
|
||||
findsNWidgets(3),
|
||||
);
|
||||
|
||||
/// Navigate to the first tab
|
||||
/// Navigate to the second tab
|
||||
await tester.tap(
|
||||
find.descendant(
|
||||
of: find.byType(FlowyTab),
|
||||
matching: find.text(_readmeName),
|
||||
matching: find.text(gettingStarted),
|
||||
),
|
||||
);
|
||||
|
||||
/// Close tab by shortcut
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
Platform.isMacOS
|
||||
? LogicalKeyboardKey.meta
|
||||
: LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.keyW,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(TabBar),
|
||||
matching: find.byType(FlowyTab),
|
||||
),
|
||||
findsNWidgets(2),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -91,7 +91,6 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
warnIfMissed: warnIfMissed,
|
||||
);
|
||||
await pumpAndSettle(Duration(milliseconds: milliseconds));
|
||||
return;
|
||||
}
|
||||
|
||||
Future<void> tapButtonWithName(
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import 'dart:ui';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
|
||||
import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
|
||||
import 'package:appflowy/user/presentation/skip_log_in_screen.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:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@@ -24,35 +27,48 @@ extension CommonOperations on WidgetTester {
|
||||
}
|
||||
|
||||
/// Tap the + button on the home page.
|
||||
Future<void> tapAddButton() async {
|
||||
final addButton = find.byType(AddButton);
|
||||
await tapButton(addButton);
|
||||
Future<void> tapAddViewButton({
|
||||
String name = gettingStarted,
|
||||
}) async {
|
||||
await hoverOnPageName(
|
||||
name,
|
||||
onHover: () async {
|
||||
final addButton = find.byType(ViewAddButton);
|
||||
await tapButton(addButton);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Tap the 'New Page' Button on the sidebar.
|
||||
Future<void> tapNewPageButton() async {
|
||||
final newPageButton = find.byType(SidebarNewPageButton);
|
||||
await tapButton(newPageButton);
|
||||
}
|
||||
|
||||
/// Tap the create document button.
|
||||
///
|
||||
/// Must call [tapAddButton] first.
|
||||
/// Must call [tapAddViewButton] first.
|
||||
Future<void> tapCreateDocumentButton() async {
|
||||
await tapButtonWithName(LocaleKeys.document_menuName.tr());
|
||||
}
|
||||
|
||||
/// Tap the create grid button.
|
||||
///
|
||||
/// Must call [tapAddButton] first.
|
||||
/// Must call [tapAddViewButton] first.
|
||||
Future<void> tapCreateGridButton() async {
|
||||
await tapButtonWithName(LocaleKeys.grid_menuName.tr());
|
||||
}
|
||||
|
||||
/// Tap the create grid button.
|
||||
///
|
||||
/// Must call [tapAddButton] first.
|
||||
/// Must call [tapAddViewButton] first.
|
||||
Future<void> tapCreateCalendarButton() async {
|
||||
await tapButtonWithName(LocaleKeys.calendar_menuName.tr());
|
||||
}
|
||||
|
||||
/// Tap the import button.
|
||||
///
|
||||
/// Must call [tapAddButton] first.
|
||||
/// Must call [tapAddViewButton] first.
|
||||
Future<void> tapImportButton() async {
|
||||
await tapButtonWithName(LocaleKeys.moreAction_import.tr());
|
||||
}
|
||||
@@ -116,6 +132,7 @@ extension CommonOperations on WidgetTester {
|
||||
Finder finder, {
|
||||
Offset? offset,
|
||||
Future<void> Function()? onHover,
|
||||
bool removePointer = true,
|
||||
}) async {
|
||||
try {
|
||||
final gesture = await createGesture(kind: PointerDeviceKind.mouse);
|
||||
@@ -133,19 +150,30 @@ extension CommonOperations on WidgetTester {
|
||||
/// Hover on the page name.
|
||||
Future<void> hoverOnPageName(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
Future<void> Function()? onHover,
|
||||
bool useLast = true,
|
||||
}) async {
|
||||
final pageNames = findPageName(name, layout: layout);
|
||||
if (useLast) {
|
||||
await hoverOnWidget(findPageName(name).last, onHover: onHover);
|
||||
await hoverOnWidget(
|
||||
pageNames.last,
|
||||
onHover: onHover,
|
||||
);
|
||||
} else {
|
||||
await hoverOnWidget(findPageName(name).first, onHover: onHover);
|
||||
await hoverOnWidget(
|
||||
pageNames.first,
|
||||
onHover: onHover,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// open the page with given name.
|
||||
Future<void> openPage(String name) async {
|
||||
final finder = findPageName(name);
|
||||
Future<void> openPage(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
}) async {
|
||||
final finder = findPageName(name, layout: layout);
|
||||
expect(finder, findsOneWidget);
|
||||
await tapButton(finder);
|
||||
}
|
||||
@@ -154,20 +182,38 @@ extension CommonOperations on WidgetTester {
|
||||
///
|
||||
/// Must call [hoverOnPageName] first.
|
||||
Future<void> tapPageOptionButton() async {
|
||||
final optionButton = find.byType(ViewDisclosureButton);
|
||||
final optionButton = find.byType(ViewMoreActionButton);
|
||||
await tapButton(optionButton);
|
||||
}
|
||||
|
||||
/// Tap the delete page button.
|
||||
Future<void> tapDeletePageButton() async {
|
||||
await tapPageOptionButton();
|
||||
await tapButtonWithName(ViewDisclosureAction.delete.name);
|
||||
await tapButtonWithName(ViewMoreActionType.delete.name);
|
||||
}
|
||||
|
||||
/// Tap the rename page button.
|
||||
Future<void> tapRenamePageButton() async {
|
||||
await tapPageOptionButton();
|
||||
await tapButtonWithName(ViewDisclosureAction.rename.name);
|
||||
await tapButtonWithName(ViewMoreActionType.rename.name);
|
||||
}
|
||||
|
||||
/// Tap the favorite page button
|
||||
Future<void> tapFavoritePageButton() async {
|
||||
await tapPageOptionButton();
|
||||
await tapButtonWithName(ViewMoreActionType.favorite.name);
|
||||
}
|
||||
|
||||
/// Tap the unfavorite page button
|
||||
Future<void> tapUnfavoritePageButton() async {
|
||||
await tapPageOptionButton();
|
||||
await tapButtonWithName(ViewMoreActionType.unFavorite.name);
|
||||
}
|
||||
|
||||
/// Tap the Open in a new tab button
|
||||
Future<void> tapOpenInTabButton() async {
|
||||
await tapPageOptionButton();
|
||||
await tapButtonWithName(ViewMoreActionType.openInNewTab.name);
|
||||
}
|
||||
|
||||
/// Rename the page.
|
||||
@@ -224,12 +270,14 @@ extension CommonOperations on WidgetTester {
|
||||
await tapButton(markdownButton);
|
||||
}
|
||||
|
||||
Future<void> createNewPageWithName(
|
||||
ViewLayoutPB layout, [
|
||||
Future<void> createNewPageWithName({
|
||||
String? name,
|
||||
]) async {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
String? parentName,
|
||||
bool openAfterCreated = true,
|
||||
}) async {
|
||||
// create a new page
|
||||
await tapAddButton();
|
||||
await tapAddViewButton(name: parentName ?? gettingStarted);
|
||||
await tapButtonWithName(layout.menuName);
|
||||
await pumpAndSettle();
|
||||
|
||||
@@ -237,6 +285,7 @@ extension CommonOperations on WidgetTester {
|
||||
if (name != null) {
|
||||
await hoverOnPageName(
|
||||
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layout: layout,
|
||||
onHover: () async {
|
||||
await renamePage(name);
|
||||
await pumpAndSettle();
|
||||
@@ -244,6 +293,16 @@ extension CommonOperations on WidgetTester {
|
||||
);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
// open the page after created
|
||||
if (openAfterCreated) {
|
||||
await openPage(
|
||||
// if the name is null, use the default name
|
||||
name ?? LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layout: layout,
|
||||
);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> simulateKeyEvent(
|
||||
@@ -282,11 +341,72 @@ extension CommonOperations on WidgetTester {
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> openAppInNewTab(String name) async {
|
||||
await hoverOnPageName(name);
|
||||
await tap(find.byType(ViewDisclosureButton));
|
||||
Future<void> openAppInNewTab(String name, ViewLayoutPB layout) async {
|
||||
await hoverOnPageName(
|
||||
name,
|
||||
onHover: () async {
|
||||
await tapOpenInTabButton();
|
||||
await pumpAndSettle();
|
||||
},
|
||||
);
|
||||
await pumpAndSettle();
|
||||
await tap(find.text(LocaleKeys.disclosureAction_openNewTab.tr()));
|
||||
}
|
||||
|
||||
Future<void> favoriteViewByName(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
}) async {
|
||||
await hoverOnPageName(
|
||||
name,
|
||||
layout: layout,
|
||||
useLast: true,
|
||||
onHover: () async {
|
||||
await tapFavoritePageButton();
|
||||
await pumpAndSettle();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> unfavoriteViewByName(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
}) async {
|
||||
await hoverOnPageName(
|
||||
name,
|
||||
layout: layout,
|
||||
useLast: true,
|
||||
onHover: () async {
|
||||
await tapUnfavoritePageButton();
|
||||
await pumpAndSettle();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> movePageToOtherPage({
|
||||
required String name,
|
||||
required String parentName,
|
||||
required ViewLayoutPB layout,
|
||||
required ViewLayoutPB parentLayout,
|
||||
DraggableHoverPosition position = DraggableHoverPosition.center,
|
||||
}) async {
|
||||
final from = findPageName(name, layout: layout);
|
||||
final to = findPageName(parentName, layout: parentLayout);
|
||||
final gesture = await startGesture(getCenter(from));
|
||||
Offset offset = Offset.zero;
|
||||
switch (position) {
|
||||
case DraggableHoverPosition.center:
|
||||
offset = getCenter(to);
|
||||
break;
|
||||
case DraggableHoverPosition.top:
|
||||
offset = getTopLeft(to);
|
||||
break;
|
||||
case DraggableHoverPosition.bottom:
|
||||
offset = getBottomLeft(to);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
await gesture.moveTo(offset, timeStamp: const Duration(milliseconds: 400));
|
||||
await gesture.up();
|
||||
await pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:appflowy/plugins/database_view/calendar/application/calendar_blo
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_day.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/option_list.dart';
|
||||
@@ -14,31 +15,42 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/create_filter_list.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/disclosure_button.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/filter_menu_item.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/footer/grid_footer.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell_action_sheet.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_list.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/create_sort_list.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/order_panel.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_menu.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/grid_layout.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart';
|
||||
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.dart';
|
||||
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_header.dart';
|
||||
import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_progress_bar.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/select_option_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/text_field.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_progress_bar.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/setting/database_setting.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:calendar_view/calendar_view.dart';
|
||||
@@ -50,25 +62,12 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/footer/grid_footer.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
|
||||
import 'base.dart';
|
||||
import 'common_operations.dart';
|
||||
import 'expectation.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'mock/mock_file_picker.dart';
|
||||
|
||||
extension AppFlowyDatabaseTest on WidgetTester {
|
||||
@@ -77,9 +76,9 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapGoButton();
|
||||
|
||||
// expect to see a readme page
|
||||
expectToSeePageName(readme);
|
||||
expectToSeePageName(gettingStarted);
|
||||
|
||||
await tapAddButton();
|
||||
await tapAddViewButton();
|
||||
await tapImportButton();
|
||||
|
||||
final testFileNames = ['v020.afdb'];
|
||||
@@ -103,7 +102,8 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
paths: paths,
|
||||
);
|
||||
await tapDatabaseRawDataButton();
|
||||
await openPage('v020');
|
||||
await pumpAndSettle();
|
||||
await openPage('v020', layout: ViewLayoutPB.Grid);
|
||||
}
|
||||
|
||||
Future<void> hoverOnFirstRowOfGrid() async {
|
||||
@@ -358,6 +358,16 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapButton(findNewDateFormat);
|
||||
}
|
||||
|
||||
Future<void> clearDate() async {
|
||||
final findDateEditor = find.byType(DateCellEditor);
|
||||
final findClearButton = find.byType(ClearDateButton);
|
||||
final finder = find.descendant(
|
||||
of: findDateEditor,
|
||||
matching: findClearButton,
|
||||
);
|
||||
await tapButton(finder);
|
||||
}
|
||||
|
||||
Future<void> tapSelectOptionCellInGrid({
|
||||
required int rowIndex,
|
||||
required FieldType fieldType,
|
||||
|
||||
@@ -87,7 +87,7 @@ class EditorOperations {
|
||||
|
||||
Future<void> switchSolidColorBackground() async {
|
||||
final findPurpleButton = find.byWidgetPredicate(
|
||||
(widget) => widget is ColorItem && widget.option.colorHex == "ffe8e0ff",
|
||||
(widget) => widget is ColorItem && widget.option.name == 'Purple',
|
||||
);
|
||||
await tester.tapButton(findPurpleButton);
|
||||
}
|
||||
|
||||
@@ -2,30 +2,53 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/banner.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
|
||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/home_stack.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/app/section/item.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
const String readme = 'Read me';
|
||||
// const String readme = 'Read me';
|
||||
const String gettingStarted = '⭐️ Getting started';
|
||||
|
||||
extension Expectation on WidgetTester {
|
||||
/// Expect to see the home page and with a default read me page.
|
||||
void expectToSeeHomePage() {
|
||||
expect(find.byType(HomeStack), findsOneWidget);
|
||||
expect(find.textContaining(readme), findsWidgets);
|
||||
expect(find.textContaining(gettingStarted), findsWidgets);
|
||||
}
|
||||
|
||||
/// Expect to see the page name on the home page.
|
||||
void expectToSeePageName(String name) {
|
||||
final pageName = findPageName(name);
|
||||
void expectToSeePageName(
|
||||
String name, {
|
||||
String? parentName,
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
|
||||
}) {
|
||||
final pageName = findPageName(
|
||||
name,
|
||||
layout: layout,
|
||||
parentName: parentName,
|
||||
parentLayout: parentLayout,
|
||||
);
|
||||
expect(pageName, findsOneWidget);
|
||||
}
|
||||
|
||||
/// Expect not to see the page name on the home page.
|
||||
void expectNotToSeePageName(String name) {
|
||||
final pageName = findPageName(name);
|
||||
void expectNotToSeePageName(
|
||||
String name, {
|
||||
String? parentName,
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
|
||||
}) {
|
||||
final pageName = findPageName(
|
||||
name,
|
||||
layout: layout,
|
||||
parentName: parentName,
|
||||
parentLayout: parentLayout,
|
||||
);
|
||||
expect(pageName, findsNothing);
|
||||
}
|
||||
|
||||
@@ -125,11 +148,49 @@ extension Expectation on WidgetTester {
|
||||
expect(textWidget, findsOneWidget);
|
||||
}
|
||||
|
||||
/// Find the page name on the home page.
|
||||
Finder findPageName(String name) {
|
||||
/// Find if the page is favorite
|
||||
Finder findFavoritePageName(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
String? parentName,
|
||||
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
|
||||
}) {
|
||||
return find.byWidgetPredicate(
|
||||
(widget) => widget is ViewSectionItem && widget.view.name == name,
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite &&
|
||||
widget.view.name == name &&
|
||||
widget.view.layout == layout,
|
||||
skipOffstage: false,
|
||||
);
|
||||
}
|
||||
|
||||
Finder findPageName(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
String? parentName,
|
||||
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
|
||||
}) {
|
||||
if (parentName == null) {
|
||||
return find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is SingleInnerViewItem &&
|
||||
widget.view.name == name &&
|
||||
widget.view.layout == layout,
|
||||
skipOffstage: false,
|
||||
);
|
||||
}
|
||||
|
||||
return find.descendant(
|
||||
of: find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.name == parentName &&
|
||||
widget.view.layout == parentLayout,
|
||||
skipOffstage: false,
|
||||
),
|
||||
matching: findPageName(name, layout: layout),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -77,13 +77,6 @@ Future<String> mockSaveFilePath(
|
||||
Future<List<String>> mockPickFilePaths({
|
||||
required List<String> paths,
|
||||
}) async {
|
||||
// late final Directory dir;
|
||||
// if (customPath != null) {
|
||||
// dir = Directory(customPath);
|
||||
// } else {
|
||||
// dir = await TestFolder.testLocation(applicationDataPath, name);
|
||||
// }
|
||||
// final paths = fileNames.map((e) => p.join(dir.path, e)).toList();
|
||||
getIt.unregister<FilePickerService>();
|
||||
getIt.registerFactory<FilePickerService>(
|
||||
() => MockFilePicker(
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>9.0</string>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,5 +1,5 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
@@ -1,81 +1,163 @@
|
||||
PODS:
|
||||
- flowy_editor (0.0.1):
|
||||
- Flutter
|
||||
- flowy_infra_ui (0.0.1):
|
||||
- app_links (0.0.1):
|
||||
- Flutter
|
||||
- appflowy_backend (0.0.1):
|
||||
- Flutter
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- ReachabilitySwift
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.4):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.4)
|
||||
- DKImagePickerController/PhotoGallery (4.3.4):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.4)
|
||||
- DKPhotoGallery (0.0.17):
|
||||
- DKPhotoGallery/Core (= 0.0.17)
|
||||
- DKPhotoGallery/Model (= 0.0.17)
|
||||
- DKPhotoGallery/Preview (= 0.0.17)
|
||||
- DKPhotoGallery/Resource (= 0.0.17)
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Core (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Preview
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Model (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Preview (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Resource
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Resource (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- flowy_infra_ui (0.0.1):
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- flutter_inappwebview (0.0.1):
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- flutter_inappwebview/Core (= 0.0.1)
|
||||
- OrderedSet (~> 5.0)
|
||||
- flutter_inappwebview/Core (0.0.1):
|
||||
- Toast
|
||||
- integration_test (0.0.1):
|
||||
- Flutter
|
||||
- OrderedSet (~> 5.0)
|
||||
- flutter_keyboard_visibility (0.0.1):
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- image_picker (0.0.1):
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- OrderedSet (5.0.0)
|
||||
- path_provider (0.0.1):
|
||||
- FlutterMacOS
|
||||
- ReachabilitySwift (5.0.0)
|
||||
- rich_clipboard_ios (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher (0.0.1):
|
||||
- SDWebImage (5.14.2):
|
||||
- SDWebImage/Core (= 5.14.2)
|
||||
- SDWebImage/Core (5.14.2)
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- video_player (0.0.1):
|
||||
- FlutterMacOS
|
||||
- sign_in_with_apple (0.0.1):
|
||||
- Flutter
|
||||
- SwiftyGif (5.4.3)
|
||||
- Toast (4.0.0)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter_wkwebview (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- flowy_editor (from `.symlinks/plugins/flowy_editor/ios`)
|
||||
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
|
||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||
- appflowy_backend (from `.symlinks/plugins/appflowy_backend/ios`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- video_player (from `.symlinks/plugins/video_player/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- rich_clipboard_ios (from `.symlinks/plugins/rich_clipboard_ios/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- OrderedSet
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- ReachabilitySwift
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- Toast
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
flowy_editor:
|
||||
:path: ".symlinks/plugins/flowy_editor/ios"
|
||||
flowy_infra_ui:
|
||||
:path: ".symlinks/plugins/flowy_infra_ui/ios"
|
||||
app_links:
|
||||
:path: ".symlinks/plugins/app_links/ios"
|
||||
appflowy_backend:
|
||||
:path: ".symlinks/plugins/appflowy_backend/ios"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
flowy_infra_ui:
|
||||
:path: ".symlinks/plugins/flowy_infra_ui/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_inappwebview:
|
||||
:path: ".symlinks/plugins/flutter_inappwebview/ios"
|
||||
flutter_keyboard_visibility:
|
||||
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
||||
image_picker:
|
||||
:path: ".symlinks/plugins/image_picker/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
url_launcher:
|
||||
:path: ".symlinks/plugins/url_launcher/ios"
|
||||
video_player:
|
||||
:path: ".symlinks/plugins/video_player/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
integration_test:
|
||||
:path: ".symlinks/plugins/integration_test/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
rich_clipboard_ios:
|
||||
:path: ".symlinks/plugins/rich_clipboard_ios/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sign_in_with_apple:
|
||||
:path: ".symlinks/plugins/sign_in_with_apple/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
webview_flutter_wkwebview:
|
||||
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
flowy_editor: bf8d58894ddb03453bd4d8521c57267ad638b837
|
||||
flowy_infra_ui: 146c88346fd55d2ee6a41ae35059a5bf095cfbb3
|
||||
appflowy_backend: c416222c639e678828776789bf0c1a1d0d59df3c
|
||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
video_player: ecd305f42e9044793efd34846e1ce64c31ea6fcb
|
||||
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
|
||||
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
|
||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
|
||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
|
||||
integration_test: 13825b8a9334a850581300559b8839134b124670
|
||||
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
rich_clipboard_ios: 7588abe18f881a6d0e9ec0b12e51cae2761e8942
|
||||
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
|
||||
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
|
||||
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
|
||||
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
|
||||
|
||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
COCOAPODS: 1.11.3
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -217,10 +217,12 @@
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
@@ -231,6 +233,7 @@
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
@@ -340,7 +343,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -414,7 +417,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -463,7 +466,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
||||
@@ -47,5 +47,7 @@
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -29,4 +29,16 @@ class KVKeys {
|
||||
'kDocumentAppearanceFontSize';
|
||||
static const String kDocumentAppearanceFontFamily =
|
||||
'kDocumentAppearanceFontFamily';
|
||||
|
||||
/// The key for saving the expanded views
|
||||
///
|
||||
/// The value is a json string with the following format:
|
||||
/// {'viewId': true, 'viewId2': false}
|
||||
static const String expandedViews = 'expandedViews';
|
||||
|
||||
/// The key for saving the expanded folder
|
||||
///
|
||||
/// The value is a json string with the following format:
|
||||
/// {'SidebarFolderCategoryType.value': true}
|
||||
static const String expandedFolders = 'expandedFolders';
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-net/network_state.pb.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class NetworkListener {
|
||||
@@ -46,12 +46,12 @@ class NetworkListener {
|
||||
return NetworkTypePB.VPN;
|
||||
case ConnectivityResult.none:
|
||||
case ConnectivityResult.other:
|
||||
return NetworkTypePB.Unknown;
|
||||
return NetworkTypePB.NetworkUnknown;
|
||||
}
|
||||
}();
|
||||
Log.info("Network type: $networkType");
|
||||
final state = NetworkStatePB.create()..ty = networkType;
|
||||
NetworkEventUpdateNetworkType(state).send().then((result) {
|
||||
UserEventUpdateNetworkState(state).send().then((result) {
|
||||
result.fold(
|
||||
(l) {},
|
||||
(e) => Log.error(e),
|
||||
|
||||
@@ -8,4 +8,12 @@ extension RawKeyboardExtension on RawKeyboard {
|
||||
LogicalKeyboardKey.altRight,
|
||||
].contains(key),
|
||||
);
|
||||
|
||||
bool get isControlPressed => keysPressed.any(
|
||||
(key) => [
|
||||
LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.controlLeft,
|
||||
LogicalKeyboardKey.controlRight,
|
||||
].contains(key),
|
||||
);
|
||||
}
|
||||
+12
-50
@@ -1,4 +1,5 @@
|
||||
// lib/env/env.dart
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:envied/envied.dart';
|
||||
|
||||
part 'env.g.dart';
|
||||
@@ -28,61 +29,22 @@ abstract class Env {
|
||||
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_DB',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseDb = _Env.supabaseDb;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB_USER',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseDbUser = _Env.supabaseDbUser;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB_PASSWORD',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseDbPassword = _Env.supabaseDbPassword;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB_PORT',
|
||||
defaultValue: '5432',
|
||||
)
|
||||
static final String supabaseDbPort = _Env.supabaseDbPort;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'ENABLE_SUPABASE_SYNC',
|
||||
defaultValue: true,
|
||||
)
|
||||
static final bool enableSupabaseSync = _Env.enableSupabaseSync;
|
||||
}
|
||||
|
||||
bool get isSupabaseEnable => false;
|
||||
// Env.supabaseUrl.isNotEmpty &&
|
||||
// Env.supabaseAnonKey.isNotEmpty &&
|
||||
// Env.supabaseKey.isNotEmpty &&
|
||||
// Env.supabaseJwtSecret.isNotEmpty &&
|
||||
// Env.supabaseDb.isNotEmpty &&
|
||||
// Env.supabaseDbUser.isNotEmpty &&
|
||||
// Env.supabaseDbPassword.isNotEmpty &&
|
||||
// Env.supabaseDbPort.isNotEmpty;
|
||||
bool get isSupabaseEnabled {
|
||||
// Only enable supabase in release and develop mode.
|
||||
if (integrationEnv().isRelease || integrationEnv().isDevelop) {
|
||||
return Env.supabaseUrl.isNotEmpty &&
|
||||
Env.supabaseAnonKey.isNotEmpty &&
|
||||
Env.supabaseJwtSecret.isNotEmpty;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,8 @@ class BlankPagePluginWidgetBuilder extends PluginWidgetBuilder
|
||||
Widget tabBarItem(String pluginId) => leftBarItem;
|
||||
|
||||
@override
|
||||
Widget buildWidget({PluginContext? context}) => const BlankPage();
|
||||
Widget buildWidget({PluginContext? context, required bool shrinkWrap}) =>
|
||||
const BlankPage();
|
||||
|
||||
@override
|
||||
List<NavigationItem> get navigationItems => [this];
|
||||
|
||||
+2
-2
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_listener.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_meta_listener.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
@@ -8,7 +9,6 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../field/field_controller.dart';
|
||||
import '../field/field_service.dart';
|
||||
import '../field/type_option/type_option_context.dart';
|
||||
import 'cell_listener.dart';
|
||||
@@ -104,7 +104,7 @@ class CellController<T, D> extends Equatable {
|
||||
);
|
||||
|
||||
// Only the primary can listen on the row meta changes.
|
||||
if (_cellContext.fieldInfo.isPrimary) {
|
||||
if (_cellContext.fieldInfo.field.isPrimary) {
|
||||
_rowMetaListener?.start(
|
||||
callback: (newRowMeta) {
|
||||
_cellContext = _cellContext.copyWith(rowMeta: newRowMeta);
|
||||
|
||||
+4
@@ -35,6 +35,7 @@ class DateCellData with _$DateCellData {
|
||||
DateTime? dateTime,
|
||||
String? time,
|
||||
required bool includeTime,
|
||||
bool? clearFlag,
|
||||
}) = _DateCellData;
|
||||
}
|
||||
|
||||
@@ -55,6 +56,9 @@ class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
||||
if (data.time != null) {
|
||||
payload.time = data.time!;
|
||||
}
|
||||
if (data.clearFlag != null) {
|
||||
payload.clearFlag = data.clearFlag!;
|
||||
}
|
||||
payload.includeTime = data.includeTime;
|
||||
|
||||
return DatabaseEventUpdateDateCell(payload).send().then((result) {
|
||||
|
||||
+5
-5
@@ -15,7 +15,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:convert' show utf8;
|
||||
|
||||
import '../field/field_controller.dart';
|
||||
import '../field/field_info.dart';
|
||||
import '../row/row_service.dart';
|
||||
part 'cell_service.freezed.dart';
|
||||
part 'cell_data_loader.dart';
|
||||
@@ -62,14 +62,14 @@ class DatabaseCellContext with _$DatabaseCellContext {
|
||||
|
||||
String get rowId => rowMeta.id;
|
||||
|
||||
String get fieldId => fieldInfo.id;
|
||||
String get fieldId => fieldInfo.field.id;
|
||||
|
||||
FieldType get fieldType => fieldInfo.fieldType;
|
||||
FieldType get fieldType => fieldInfo.field.fieldType;
|
||||
|
||||
ValueKey key() {
|
||||
return ValueKey("${rowMeta.id}$fieldId${fieldInfo.fieldType}");
|
||||
return ValueKey("${rowMeta.id}$fieldId${fieldInfo.field.fieldType}");
|
||||
}
|
||||
|
||||
/// Only the primary field can have an emoji.
|
||||
String? get emoji => fieldInfo.isPrimary ? rowMeta.icon : null;
|
||||
String? get emoji => fieldInfo.field.isPrimary ? rowMeta.icon : null;
|
||||
}
|
||||
+10
@@ -13,8 +13,10 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'database_view_service.dart';
|
||||
import 'defines.dart';
|
||||
import 'field/field_info.dart';
|
||||
import 'layout/layout_service.dart';
|
||||
import 'layout/layout_setting_listener.dart';
|
||||
import 'row/row_cache.dart';
|
||||
@@ -92,6 +94,8 @@ class DatabaseController {
|
||||
final DatabaseGroupListener _groupListener;
|
||||
final DatabaseLayoutSettingListener _layoutListener;
|
||||
|
||||
final ValueNotifier<bool> _isLoading = ValueNotifier(true);
|
||||
|
||||
DatabaseController({required ViewPB view})
|
||||
: viewId = view.id,
|
||||
_databaseViewBackendSvc = DatabaseViewBackendService(viewId: view.id),
|
||||
@@ -109,6 +113,12 @@ class DatabaseController {
|
||||
_listenOnLayoutChanged();
|
||||
}
|
||||
|
||||
void setIsLoading(bool isLoading) {
|
||||
_isLoading.value = isLoading;
|
||||
}
|
||||
|
||||
ValueNotifier<bool> get isLoading => _isLoading;
|
||||
|
||||
void addListener({
|
||||
DatabaseCallbacks? onDatabaseChanged,
|
||||
DatabaseLayoutSettingCallbacks? onLayoutChanged,
|
||||
|
||||
@@ -3,12 +3,16 @@ import 'dart:collection';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_info.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';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../grid/presentation/widgets/filter/filter_info.dart';
|
||||
import 'field/field_controller.dart';
|
||||
import 'field/field_info.dart';
|
||||
import 'row/row_cache.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
||||
part 'defines.freezed.dart';
|
||||
|
||||
typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldInfo>);
|
||||
typedef OnFiltersChanged = void Function(List<FilterInfo>);
|
||||
typedef OnSortsChanged = void Function(List<SortInfo>);
|
||||
@@ -27,3 +31,11 @@ typedef OnNumOfRowsChanged = void Function(
|
||||
);
|
||||
|
||||
typedef OnError = void Function(FlowyError);
|
||||
|
||||
@freezed
|
||||
class LoadingState with _$LoadingState {
|
||||
const factory LoadingState.loading() = _Loading;
|
||||
const factory LoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
+15
-77
@@ -19,6 +19,7 @@ import '../setting/setting_listener.dart';
|
||||
import '../setting/setting_service.dart';
|
||||
import '../sort/sort_listener.dart';
|
||||
import '../sort/sort_service.dart';
|
||||
import 'field_info.dart';
|
||||
import 'field_listener.dart';
|
||||
|
||||
class _GridFieldNotifier extends ChangeNotifier {
|
||||
@@ -438,12 +439,18 @@ class FieldController {
|
||||
}
|
||||
|
||||
void _updateFieldInfos() {
|
||||
final List<FieldInfo> newFieldInfos = [];
|
||||
for (final field in _fieldNotifier.fieldInfos) {
|
||||
field._isGroupField = _groupConfigurationByFieldId[field.id] != null;
|
||||
field._hasFilter = _filterPBByFieldId[field.id] != null;
|
||||
field._hasSort = _sortPBByFieldId[field.id] != null;
|
||||
newFieldInfos.add(
|
||||
field.copyWith(
|
||||
isGroupField: _groupConfigurationByFieldId[field.id] != null,
|
||||
hasFilter: _filterPBByFieldId[field.id] != null,
|
||||
hasSort: _sortPBByFieldId[field.id] != null,
|
||||
),
|
||||
);
|
||||
}
|
||||
_fieldNotifier.notify();
|
||||
|
||||
_fieldNotifier.fieldInfos = newFieldInfos;
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
@@ -488,7 +495,7 @@ class FieldController {
|
||||
}
|
||||
|
||||
_fieldNotifier.fieldInfos =
|
||||
newFields.map((field) => FieldInfo(field: field)).toList();
|
||||
newFields.map((field) => FieldInfo.initial(field)).toList();
|
||||
_loadFilters();
|
||||
_loadSorts();
|
||||
_updateFieldInfos();
|
||||
@@ -652,7 +659,7 @@ class FieldController {
|
||||
}
|
||||
final List<FieldInfo> newFieldInfos = fieldInfos;
|
||||
for (final indexField in insertedFields) {
|
||||
final fieldInfo = FieldInfo(field: indexField.field_1);
|
||||
final fieldInfo = FieldInfo.initial(indexField.field_1);
|
||||
if (newFieldInfos.length > indexField.index) {
|
||||
newFieldInfos.insert(indexField.index, fieldInfo);
|
||||
} else {
|
||||
@@ -674,7 +681,7 @@ class FieldController {
|
||||
newFields.indexWhere((field) => field.id == updatedFieldPB.id);
|
||||
if (index != -1) {
|
||||
newFields.removeAt(index);
|
||||
final fieldInfo = FieldInfo(field: updatedFieldPB);
|
||||
final fieldInfo = FieldInfo.initial(updatedFieldPB);
|
||||
newFields.insert(index, fieldInfo);
|
||||
updatedFields.add(fieldInfo);
|
||||
}
|
||||
@@ -693,7 +700,7 @@ class RowCacheDependenciesImpl extends RowFieldsDelegate with RowLifeCycle {
|
||||
RowCacheDependenciesImpl(FieldController cache) : _fieldController = cache;
|
||||
|
||||
@override
|
||||
UnmodifiableListView<FieldInfo> get fields =>
|
||||
UnmodifiableListView<FieldInfo> get fieldInfos =>
|
||||
UnmodifiableListView(_fieldController.fieldInfos);
|
||||
|
||||
@override
|
||||
@@ -729,72 +736,3 @@ FieldInfo? _findFieldInfo({
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class FieldInfo {
|
||||
final FieldPB _field;
|
||||
bool _isGroupField = false;
|
||||
|
||||
bool _hasFilter = false;
|
||||
|
||||
bool _hasSort = false;
|
||||
|
||||
String get id => _field.id;
|
||||
|
||||
FieldType get fieldType => _field.fieldType;
|
||||
|
||||
bool get visibility => _field.visibility;
|
||||
|
||||
double get width => _field.width.toDouble();
|
||||
|
||||
bool get isPrimary => _field.isPrimary;
|
||||
|
||||
String get name => _field.name;
|
||||
|
||||
FieldPB get field => _field;
|
||||
|
||||
bool get isGroupField => _isGroupField;
|
||||
|
||||
bool get hasFilter => _hasFilter;
|
||||
|
||||
bool get canBeGroup {
|
||||
switch (_field.fieldType) {
|
||||
case FieldType.URL:
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.SingleSelect:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool get canCreateFilter {
|
||||
if (hasFilter) return false;
|
||||
|
||||
switch (_field.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.RichText:
|
||||
case FieldType.SingleSelect:
|
||||
case FieldType.Checklist:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool get canCreateSort {
|
||||
if (_hasSort) return false;
|
||||
|
||||
switch (_field.fieldType) {
|
||||
case FieldType.RichText:
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.Number:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FieldInfo({required FieldPB field}) : _field = field;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'field_info.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class FieldInfo with _$FieldInfo {
|
||||
const FieldInfo._();
|
||||
|
||||
const factory FieldInfo({
|
||||
required FieldPB field,
|
||||
required bool isGroupField,
|
||||
required bool hasFilter,
|
||||
required bool hasSort,
|
||||
}) = _FieldInfo;
|
||||
|
||||
String get id => field.id;
|
||||
|
||||
FieldType get fieldType => field.fieldType;
|
||||
|
||||
String get name => field.name;
|
||||
|
||||
factory FieldInfo.initial(FieldPB field) => FieldInfo(
|
||||
field: field,
|
||||
hasFilter: false,
|
||||
hasSort: false,
|
||||
isGroupField: false,
|
||||
);
|
||||
|
||||
bool get canBeGroup {
|
||||
switch (field.fieldType) {
|
||||
case FieldType.URL:
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.SingleSelect:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool get canCreateFilter {
|
||||
if (hasFilter) return false;
|
||||
|
||||
switch (field.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.RichText:
|
||||
case FieldType.SingleSelect:
|
||||
case FieldType.Checklist:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool get canCreateSort {
|
||||
if (hasSort) return false;
|
||||
|
||||
switch (field.fieldType) {
|
||||
case FieldType.RichText:
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.Number:
|
||||
case FieldType.DateTime:
|
||||
case FieldType.SingleSelect:
|
||||
case FieldType.MultiSelect:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
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';
|
||||
|
||||
+1
-14
@@ -1,7 +1,6 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_listener.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy/workspace/application/view/prelude.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
|
||||
@@ -115,18 +114,6 @@ class RowBannerBloc extends Bloc<RowBannerEvent, RowBannerState> {
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
// Set the icon and cover of the view
|
||||
ViewBackendService.updateView(
|
||||
viewId: viewId,
|
||||
iconURL: iconURL,
|
||||
coverURL: coverURL,
|
||||
).then((result) {
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +123,7 @@ class RowBannerEvent with _$RowBannerEvent {
|
||||
const factory RowBannerEvent.didReceiveRowMeta(RowMetaPB rowMeta) =
|
||||
_DidReceiveRowMeta;
|
||||
const factory RowBannerEvent.didReceiveFieldUpdate(FieldPB field) =
|
||||
_DidReceiveFieldUdate;
|
||||
_DidReceiveFieldUpdate;
|
||||
const factory RowBannerEvent.setIcon(String iconURL) = _SetIcon;
|
||||
const factory RowBannerEvent.setCover(String coverURL) = _SetCover;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:collection';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
@@ -6,7 +7,6 @@ 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';
|
||||
@@ -15,7 +15,7 @@ typedef RowUpdateCallback = void Function();
|
||||
|
||||
/// A delegate that provides the fields of the row.
|
||||
abstract class RowFieldsDelegate {
|
||||
UnmodifiableListView<FieldInfo> get fields;
|
||||
UnmodifiableListView<FieldInfo> get fieldInfos;
|
||||
void onFieldsChanged(void Function(List<FieldInfo>) callback);
|
||||
}
|
||||
|
||||
@@ -244,12 +244,12 @@ class RowCache {
|
||||
CellContextByFieldId _makeCells(RowMetaPB rowMeta) {
|
||||
// ignore: prefer_collection_literals
|
||||
final cellContextMap = CellContextByFieldId();
|
||||
for (final field in _fieldDelegate.fields) {
|
||||
if (field.visibility) {
|
||||
cellContextMap[field.id] = DatabaseCellContext(
|
||||
for (final fieldInfo in _fieldDelegate.fieldInfos) {
|
||||
if (fieldInfo.field.visibility) {
|
||||
cellContextMap[fieldInfo.id] = DatabaseCellContext(
|
||||
rowMeta: rowMeta,
|
||||
viewId: viewId,
|
||||
fieldInfo: field,
|
||||
fieldInfo: fieldInfo,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ class RowCache {
|
||||
RowInfo buildGridRow(RowMetaPB rowMetaPB) {
|
||||
return RowInfo(
|
||||
viewId: viewId,
|
||||
fields: _fieldDelegate.fields,
|
||||
fields: _fieldDelegate.fieldInfos,
|
||||
rowId: rowMetaPB.id,
|
||||
rowMeta: rowMetaPB,
|
||||
);
|
||||
|
||||
+8
-7
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -26,8 +27,8 @@ class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> {
|
||||
initial: () {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveFieldUpdate: (fieldContexts) {
|
||||
emit(state.copyWith(fieldContexts: fieldContexts));
|
||||
didReceiveFieldUpdate: (fieldInfos) {
|
||||
emit(state.copyWith(fieldInfos: fieldInfos));
|
||||
},
|
||||
setGroupByField: (String fieldId, FieldType fieldType) async {
|
||||
final result = await _groupBackendSvc.groupByField(
|
||||
@@ -50,8 +51,8 @@ class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> {
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_onFieldsFn = (fieldContexts) =>
|
||||
add(DatabaseGroupEvent.didReceiveFieldUpdate(fieldContexts));
|
||||
_onFieldsFn = (fieldInfos) =>
|
||||
add(DatabaseGroupEvent.didReceiveFieldUpdate(fieldInfos));
|
||||
_fieldController.addListener(
|
||||
onReceiveFields: _onFieldsFn,
|
||||
listenWhen: () => !isClosed,
|
||||
@@ -75,15 +76,15 @@ class DatabaseGroupEvent with _$DatabaseGroupEvent {
|
||||
class DatabaseGroupState with _$DatabaseGroupState {
|
||||
const factory DatabaseGroupState({
|
||||
required String viewId,
|
||||
required List<FieldInfo> fieldContexts,
|
||||
required List<FieldInfo> fieldInfos,
|
||||
}) = _DatabaseGroupState;
|
||||
|
||||
factory DatabaseGroupState.initial(
|
||||
String viewId,
|
||||
List<FieldInfo> fieldContexts,
|
||||
List<FieldInfo> fieldInfos,
|
||||
) =>
|
||||
DatabaseGroupState(
|
||||
viewId: viewId,
|
||||
fieldContexts: fieldContexts,
|
||||
fieldInfos: fieldInfos,
|
||||
);
|
||||
}
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
+11
-14
@@ -1,6 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:appflowy/plugins/database_view/application/defines.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy_board/appflowy_board.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
@@ -254,11 +256,14 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
||||
Future<void> _openGrid(Emitter<BoardState> emit) async {
|
||||
final result = await databaseController.open();
|
||||
result.fold(
|
||||
(grid) => emit(
|
||||
state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
|
||||
),
|
||||
(grid) {
|
||||
databaseController.setIsLoading(false);
|
||||
emit(
|
||||
state.copyWith(loadingState: LoadingState.finish(left(unit))),
|
||||
);
|
||||
},
|
||||
(err) => emit(
|
||||
state.copyWith(loadingState: GridLoadingState.finish(right(err))),
|
||||
state.copyWith(loadingState: LoadingState.finish(right(err))),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -323,7 +328,7 @@ class BoardState with _$BoardState {
|
||||
required Option<DatabasePB> grid,
|
||||
required List<String> groupIds,
|
||||
required Option<BoardEditingRow> editingRow,
|
||||
required GridLoadingState loadingState,
|
||||
required LoadingState loadingState,
|
||||
required Option<FlowyError> noneOrError,
|
||||
}) = _BoardState;
|
||||
|
||||
@@ -333,18 +338,10 @@ class BoardState with _$BoardState {
|
||||
groupIds: [],
|
||||
editingRow: none(),
|
||||
noneOrError: none(),
|
||||
loadingState: const _Loading(),
|
||||
loadingState: const LoadingState.loading(),
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
|
||||
class GridFieldEquatable extends Equatable {
|
||||
final UnmodifiableListView<FieldPB> _fields;
|
||||
const GridFieldEquatable(
|
||||
|
||||
@@ -35,6 +35,7 @@ class BoardPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
||||
BuildContext context,
|
||||
ViewPB view,
|
||||
DatabaseController controller,
|
||||
bool shrinkWrap,
|
||||
) {
|
||||
return BoardPage(
|
||||
key: _makeValueKey(controller),
|
||||
@@ -298,6 +299,7 @@ class _BoardContentState extends State<BoardContent> {
|
||||
rowCache: rowCache,
|
||||
cardData: groupData.group.groupId,
|
||||
groupingFieldId: groupItem.fieldInfo.id,
|
||||
groupId: groupData.group.groupId,
|
||||
isEditing: isEditing,
|
||||
cellBuilder: cellBuilder,
|
||||
renderHook: renderHook,
|
||||
|
||||
+2
-2
@@ -12,10 +12,10 @@ class BoardSettingBar extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 40,
|
||||
height: 20,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
const Spacer(),
|
||||
SettingButton(databaseController: databaseController),
|
||||
],
|
||||
),
|
||||
|
||||
+11
-14
@@ -1,5 +1,7 @@
|
||||
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/defines.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
@@ -133,11 +135,14 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
Future<void> _openDatabase(Emitter<CalendarState> emit) async {
|
||||
final result = await databaseController.open();
|
||||
result.fold(
|
||||
(database) => emit(
|
||||
state.copyWith(loadingState: DatabaseLoadingState.finish(left(unit))),
|
||||
),
|
||||
(database) {
|
||||
databaseController.setIsLoading(false);
|
||||
emit(
|
||||
state.copyWith(loadingState: LoadingState.finish(left(unit))),
|
||||
);
|
||||
},
|
||||
(err) => emit(
|
||||
state.copyWith(loadingState: DatabaseLoadingState.finish(right(err))),
|
||||
state.copyWith(loadingState: LoadingState.finish(right(err))),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -425,7 +430,7 @@ class CalendarState with _$CalendarState {
|
||||
CalendarEventData<CalendarDayEvent>? updateEvent,
|
||||
required List<String> deleteEventIds,
|
||||
required Option<CalendarLayoutSettingPB> settings,
|
||||
required DatabaseLoadingState loadingState,
|
||||
required LoadingState loadingState,
|
||||
required Option<FlowyError> noneOrError,
|
||||
}) = _CalendarState;
|
||||
|
||||
@@ -436,18 +441,10 @@ class CalendarState with _$CalendarState {
|
||||
deleteEventIds: [],
|
||||
settings: none(),
|
||||
noneOrError: none(),
|
||||
loadingState: const _Loading(),
|
||||
loadingState: const LoadingState.loading(),
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DatabaseLoadingState with _$DatabaseLoadingState {
|
||||
const factory DatabaseLoadingState.loading() = _Loading;
|
||||
const factory DatabaseLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
|
||||
class CalendarEditingRow {
|
||||
RowPB row;
|
||||
int? index;
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
|
||||
+16
-11
@@ -254,18 +254,23 @@ class _EventList extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Flexible(
|
||||
child: ListView.separated(
|
||||
itemBuilder: (BuildContext context, int index) => EventCard(
|
||||
event: events[index],
|
||||
viewId: viewId,
|
||||
rowCache: rowCache,
|
||||
constraints: constraints,
|
||||
child: ScrollConfiguration(
|
||||
behavior: ScrollConfiguration.of(context).copyWith(
|
||||
scrollbars: true,
|
||||
),
|
||||
child: ListView.separated(
|
||||
itemBuilder: (BuildContext context, int index) => EventCard(
|
||||
event: events[index],
|
||||
viewId: viewId,
|
||||
rowCache: rowCache,
|
||||
constraints: constraints,
|
||||
),
|
||||
itemCount: events.length,
|
||||
padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 8.0),
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
shrinkWrap: true,
|
||||
),
|
||||
itemCount: events.length,
|
||||
padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 8.0),
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
shrinkWrap: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
+41
-25
@@ -1,7 +1,6 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
@@ -27,11 +26,13 @@ class CalendarPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
||||
BuildContext context,
|
||||
ViewPB view,
|
||||
DatabaseController controller,
|
||||
bool shrinkWrap,
|
||||
) {
|
||||
return CalendarPage(
|
||||
key: _makeValueKey(controller),
|
||||
view: view,
|
||||
databaseController: controller,
|
||||
shrinkWrap: shrinkWrap,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -59,9 +60,11 @@ class CalendarPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
||||
class CalendarPage extends StatefulWidget {
|
||||
final ViewPB view;
|
||||
final DatabaseController databaseController;
|
||||
final bool shrinkWrap;
|
||||
const CalendarPage({
|
||||
required this.view,
|
||||
required this.databaseController,
|
||||
this.shrinkWrap = false,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -95,12 +98,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return CalendarControllerProvider(
|
||||
controller: _eventController,
|
||||
child: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<CalendarBloc>.value(
|
||||
value: _calendarBloc,
|
||||
)
|
||||
],
|
||||
child: BlocProvider<CalendarBloc>.value(
|
||||
value: _calendarBloc,
|
||||
child: MultiBlocListener(
|
||||
listeners: [
|
||||
BlocListener<CalendarBloc, CalendarState>(
|
||||
@@ -159,14 +158,21 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
],
|
||||
child: BlocBuilder<CalendarBloc, CalendarState>(
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
children: [
|
||||
_buildCalendar(
|
||||
return ValueListenableBuilder<bool>(
|
||||
valueListenable: widget.databaseController.isLoading,
|
||||
builder: (_, value, ___) {
|
||||
if (value) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
);
|
||||
}
|
||||
return _buildCalendar(
|
||||
context,
|
||||
_eventController,
|
||||
state.settings
|
||||
.foldLeft(0, (previous, a) => a.firstDayOfWeek),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -175,19 +181,29 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCalendar(EventController eventController, int firstDayOfWeek) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: GridSize.contentInsets,
|
||||
child: MonthView(
|
||||
key: _calendarState,
|
||||
controller: _eventController,
|
||||
cellAspectRatio: .6,
|
||||
startDay: _weekdayFromInt(firstDayOfWeek),
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
headerBuilder: _headerNavigatorBuilder,
|
||||
weekDayBuilder: _headerWeekDayBuilder,
|
||||
cellBuilder: _calendarDayBuilder,
|
||||
Widget _buildCalendar(
|
||||
BuildContext context,
|
||||
EventController eventController,
|
||||
int firstDayOfWeek,
|
||||
) {
|
||||
return Padding(
|
||||
padding: CalendarSize.contentInsets,
|
||||
child: LayoutBuilder(
|
||||
// must specify MonthView width for useAvailableVerticalSpace to work properly
|
||||
builder: (context, constraints) => ScrollConfiguration(
|
||||
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
|
||||
child: MonthView(
|
||||
key: _calendarState,
|
||||
controller: _eventController,
|
||||
width: constraints.maxWidth,
|
||||
cellAspectRatio: 0.6,
|
||||
startDay: _weekdayFromInt(firstDayOfWeek),
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
headerBuilder: _headerNavigatorBuilder,
|
||||
weekDayBuilder: _headerWeekDayBuilder,
|
||||
cellBuilder: _calendarDayBuilder,
|
||||
useAvailableVerticalSpace: widget.shrinkWrap,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
+11
-1
@@ -1,9 +1,19 @@
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class CalendarSize {
|
||||
static double scale = 1;
|
||||
|
||||
static double get scrollBarSize => 12 * scale;
|
||||
static double get headerContainerPadding => 12 * scale;
|
||||
|
||||
static EdgeInsets get contentInsets => EdgeInsets.fromLTRB(
|
||||
GridSize.leadingHeaderPadding,
|
||||
CalendarSize.headerContainerPadding,
|
||||
GridSize.leadingHeaderPadding,
|
||||
CalendarSize.headerContainerPadding,
|
||||
);
|
||||
|
||||
static double get scrollBarSize => 8 * scale;
|
||||
static double get navigatorButtonWidth => 20 * scale;
|
||||
static double get navigatorButtonHeight => 25 * scale;
|
||||
static EdgeInsets get daysOfWeekInsets =>
|
||||
|
||||
+9
-2
@@ -8,6 +8,7 @@ import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.da
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -23,11 +24,12 @@ class CalendarSettingBar extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 40,
|
||||
height: 20,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
UnscheduleEventsButton(databaseController: databaseController),
|
||||
const HSpace(2),
|
||||
SettingButton(
|
||||
databaseController: databaseController,
|
||||
),
|
||||
@@ -82,9 +84,14 @@ class _UnscheduleEventsButtonState extends State<UnscheduleEventsButton> {
|
||||
builder: (context, state) {
|
||||
return FlowyTextButton(
|
||||
"${LocaleKeys.calendar_settings_noDateTitle.tr()} (${state.unscheduleEvents.length})",
|
||||
fontSize: FontSizes.s11,
|
||||
fontColor: AFThemeExtension.of(context).textColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fillColor: Colors.transparent,
|
||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||
padding: GridSize.typeOptionContentInsets,
|
||||
padding: GridSize.toolbarSettingButtonInsets,
|
||||
radius: Corners.s4Border,
|
||||
onPressed: () => _popoverController.show(),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/filter/filter_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/filter_info.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
+16
-22
@@ -1,16 +1,16 @@
|
||||
import 'dart:async';
|
||||
import 'package:appflowy/plugins/database_view/application/defines.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/filter_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_info.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import '../../application/field/field_controller.dart';
|
||||
import '../../application/database_controller.dart';
|
||||
import 'dart:collection';
|
||||
|
||||
@@ -134,12 +134,13 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final result = await databaseController.open();
|
||||
result.fold(
|
||||
(grid) {
|
||||
databaseController.setIsLoading(false);
|
||||
emit(
|
||||
state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
|
||||
state.copyWith(loadingState: LoadingState.finish(left(unit))),
|
||||
);
|
||||
},
|
||||
(err) => emit(
|
||||
state.copyWith(loadingState: GridLoadingState.finish(right(err))),
|
||||
state.copyWith(loadingState: LoadingState.finish(right(err))),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -177,7 +178,7 @@ class GridState with _$GridState {
|
||||
required GridFieldEquatable fields,
|
||||
required List<RowInfo> rowInfos,
|
||||
required int rowCount,
|
||||
required GridLoadingState loadingState,
|
||||
required LoadingState loadingState,
|
||||
required bool reorderable,
|
||||
required ChangedReason reason,
|
||||
required List<SortInfo> sorts,
|
||||
@@ -191,40 +192,33 @@ class GridState with _$GridState {
|
||||
grid: none(),
|
||||
viewId: viewId,
|
||||
reorderable: true,
|
||||
loadingState: const _Loading(),
|
||||
loadingState: const LoadingState.loading(),
|
||||
reason: const InitialListState(),
|
||||
filters: [],
|
||||
sorts: [],
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
|
||||
class GridFieldEquatable extends Equatable {
|
||||
final List<FieldInfo> _fields;
|
||||
final List<FieldInfo> _fieldInfos;
|
||||
const GridFieldEquatable(
|
||||
List<FieldInfo> fields,
|
||||
) : _fields = fields;
|
||||
List<FieldInfo> fieldInfos,
|
||||
) : _fieldInfos = fieldInfos;
|
||||
|
||||
@override
|
||||
List<Object?> get props {
|
||||
if (_fields.isEmpty) {
|
||||
if (_fieldInfos.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
_fields.length,
|
||||
_fields
|
||||
.map((field) => field.width)
|
||||
_fieldInfos.length,
|
||||
_fieldInfos
|
||||
.map((fieldInfo) => fieldInfo.field.width)
|
||||
.reduce((value, element) => value + element),
|
||||
];
|
||||
}
|
||||
|
||||
UnmodifiableListView<FieldInfo> get value => UnmodifiableListView(_fields);
|
||||
UnmodifiableListView<FieldInfo> get value =>
|
||||
UnmodifiableListView(_fieldInfos);
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -26,7 +27,7 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
|
||||
emit(
|
||||
state.copyWith(
|
||||
fields: value.fields
|
||||
.where((element) => element.visibility)
|
||||
.where((element) => element.field.visibility)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
|
||||
+5
-1
@@ -15,6 +15,7 @@ class RowActionSheetBloc
|
||||
RowActionSheetBloc({
|
||||
required String viewId,
|
||||
required RowId rowId,
|
||||
String? groupId,
|
||||
}) : _rowService = RowBackendService(viewId: viewId),
|
||||
super(RowActionSheetState.initial(rowId)) {
|
||||
on<RowActionSheetEvent>(
|
||||
@@ -25,7 +26,10 @@ class RowActionSheetBloc
|
||||
logResult(result);
|
||||
},
|
||||
duplicateRow: () async {
|
||||
final result = await _rowService.duplicateRow(rowId: state.rowId);
|
||||
final result = await _rowService.duplicateRow(
|
||||
rowId: state.rowId,
|
||||
groupId: groupId,
|
||||
);
|
||||
logResult(result);
|
||||
},
|
||||
);
|
||||
|
||||
+7
-7
@@ -1,4 +1,5 @@
|
||||
import 'dart:collection';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_listener.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
@@ -7,7 +8,6 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import '../../../application/cell/cell_service.dart';
|
||||
import '../../../application/field/field_controller.dart';
|
||||
import '../../../application/row/row_cache.dart';
|
||||
import '../../../application/row/row_controller.dart';
|
||||
import '../../../application/row/row_service.dart';
|
||||
@@ -119,16 +119,16 @@ class RowState with _$RowState {
|
||||
}
|
||||
|
||||
class GridCellEquatable extends Equatable {
|
||||
final FieldInfo _fieldContext;
|
||||
final FieldInfo _fieldInfo;
|
||||
|
||||
const GridCellEquatable(FieldInfo field) : _fieldContext = field;
|
||||
const GridCellEquatable(FieldInfo field) : _fieldInfo = field;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
_fieldContext.id,
|
||||
_fieldContext.fieldType,
|
||||
_fieldContext.visibility,
|
||||
_fieldContext.width,
|
||||
_fieldInfo.id,
|
||||
_fieldInfo.fieldType,
|
||||
_fieldInfo.field.visibility,
|
||||
_fieldInfo.field.width,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/sort/sort_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import '../../../application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
|
||||
List<FieldInfo> getCreatableSorts(List<FieldInfo> fieldInfos) {
|
||||
final List<FieldInfo> creatableFields = List.from(fieldInfos);
|
||||
|
||||
@@ -50,6 +50,7 @@ class GridPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
||||
BuildContext context,
|
||||
ViewPB view,
|
||||
DatabaseController controller,
|
||||
bool shrinkWrap,
|
||||
) {
|
||||
return GridPage(
|
||||
key: _makeValueKey(controller),
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'sizes.dart';
|
||||
|
||||
class GridLayout {
|
||||
@@ -6,7 +6,7 @@ class GridLayout {
|
||||
if (fields.isEmpty) return 0;
|
||||
|
||||
final fieldsWidth = fields
|
||||
.map((field) => field.width.toDouble())
|
||||
.map((fieldInfo) => fieldInfo.field.width.toDouble())
|
||||
.reduce((value, element) => value + element);
|
||||
|
||||
return fieldsWidth +
|
||||
|
||||
+4
-1
@@ -3,7 +3,7 @@ import 'package:flutter/widgets.dart';
|
||||
class GridSize {
|
||||
static double scale = 1;
|
||||
|
||||
static double get scrollBarSize => 12 * scale;
|
||||
static double get scrollBarSize => 8 * scale;
|
||||
static double get headerHeight => 40 * scale;
|
||||
static double get footerHeight => 40 * scale;
|
||||
static double get leadingHeaderPadding => 50 * scale;
|
||||
@@ -30,6 +30,9 @@ class GridSize {
|
||||
|
||||
static EdgeInsets get typeOptionContentInsets => const EdgeInsets.all(4);
|
||||
|
||||
static EdgeInsets get toolbarSettingButtonInsets =>
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 2);
|
||||
|
||||
static EdgeInsets get footerContentInsets => EdgeInsets.fromLTRB(
|
||||
GridSize.leadingHeaderPadding,
|
||||
GridSize.headerContainerPadding,
|
||||
|
||||
+6
-2
@@ -107,7 +107,12 @@ class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> {
|
||||
height: 20,
|
||||
child: Row(
|
||||
children: [
|
||||
FlowyText(state.filterInfo.fieldInfo.name),
|
||||
Expanded(
|
||||
child: FlowyText(
|
||||
state.filterInfo.fieldInfo.field.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const HSpace(4),
|
||||
CheckboxFilterConditionList(
|
||||
filterInfo: state.filterInfo,
|
||||
@@ -118,7 +123,6 @@ class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> {
|
||||
.add(CheckboxFilterEditorEvent.updateCondition(condition));
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
DisclosureButton(
|
||||
popoverMutex: popoverMutex,
|
||||
onAction: (action) {
|
||||
|
||||
+6
-2
@@ -91,12 +91,16 @@ class ChecklistState extends State<ChecklistFilterEditor> {
|
||||
height: 20,
|
||||
child: Row(
|
||||
children: [
|
||||
FlowyText(state.filterInfo.fieldInfo.name),
|
||||
Expanded(
|
||||
child: FlowyText(
|
||||
state.filterInfo.fieldInfo.field.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const HSpace(4),
|
||||
ChecklistFilterConditionList(
|
||||
filterInfo: state.filterInfo,
|
||||
),
|
||||
const Spacer(),
|
||||
DisclosureButton(
|
||||
popoverMutex: widget.popoverMutex,
|
||||
onAction: (action) {
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ class ChoiceChipButton extends StatelessWidget {
|
||||
decoration: decoration,
|
||||
useIntrinsicWidth: true,
|
||||
text: FlowyText(
|
||||
filterInfo.fieldInfo.name,
|
||||
filterInfo.fieldInfo.field.name,
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
|
||||
+6
-2
@@ -142,7 +142,12 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
|
||||
height: 20,
|
||||
child: Row(
|
||||
children: [
|
||||
FlowyText(state.filterInfo.fieldInfo.name),
|
||||
Expanded(
|
||||
child: FlowyText(
|
||||
state.filterInfo.fieldInfo.field.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const HSpace(4),
|
||||
SelectOptionFilterConditionList(
|
||||
filterInfo: state.filterInfo,
|
||||
@@ -153,7 +158,6 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
|
||||
);
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
DisclosureButton(
|
||||
popoverMutex: popoverMutex,
|
||||
onAction: (action) {
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@@ -161,7 +162,7 @@ class GridFilterPropertyCell extends StatelessWidget {
|
||||
return FlowyButton(
|
||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||
text: FlowyText.medium(
|
||||
fieldInfo.name,
|
||||
fieldInfo.field.name,
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
onTap: () => onTap(fieldInfo),
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_filter.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_filter.pb.dart';
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ class _GridHeaderState extends State<_GridHeader> {
|
||||
buildWhen: (previous, current) => previous.fields != current.fields,
|
||||
builder: (context, state) {
|
||||
final cells = state.fields
|
||||
.where((field) => field.visibility)
|
||||
.where((fieldInfo) => fieldInfo.field.visibility)
|
||||
.map(
|
||||
(field) => FieldContext(
|
||||
viewId: widget.viewId,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_data_controller.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_entities.pb.dart';
|
||||
|
||||
Loaded 100 of 654 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user