Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e788c71602 | ||
|
|
7de2131431 | ||
|
|
47f3702ca9 | ||
|
|
3708a5b86a | ||
|
|
a63a7ea611 | ||
|
|
7867f0366e | ||
|
|
251c6d22b2 | ||
|
|
7cee8e392f | ||
|
|
765103dd22 | ||
|
|
50e612511d | ||
|
|
7eb20b232a | ||
|
|
3c7e636b65 | ||
|
|
889a313cc2 | ||
|
|
9586ea0e6f | ||
|
|
42e7317cd4 | ||
|
|
17651bf64c | ||
|
|
73f1c211c2 | ||
|
|
afc6473582 | ||
|
|
663f9d3423 | ||
|
|
5d4142d5b6 | ||
|
|
fe23183aef | ||
|
|
8116ea1dba | ||
|
|
3e6529aeb8 | ||
|
|
c4fc60612f | ||
|
|
4d82bb5322 | ||
|
|
2b684ae7bf | ||
|
|
eb54cf99d4 | ||
|
|
85af82acbe | ||
|
|
3434d447a7 | ||
|
|
1025b6d553 | ||
|
|
b35d6131d4 | ||
|
|
bc502c9c5b | ||
|
|
5f49c1748f | ||
|
|
73ea1a0685 | ||
|
|
a93d325e6a | ||
|
|
dc0af0f4c1 | ||
|
|
1ad85416d8 | ||
|
|
c34a7a92fb | ||
|
|
21d34d1fe0 | ||
|
|
3e088d48ac | ||
|
|
54dbcb7c5e | ||
|
|
59dff54edb | ||
|
|
d358e18f33 | ||
|
|
dd9b1fb78f | ||
|
|
e08a1a6974 | ||
|
|
7f4e7e6aa0 | ||
|
|
18bd91936c | ||
|
|
b9a25f449f | ||
|
|
993532a2f0 | ||
|
|
8a735799c6 | ||
|
|
197da5f425 | ||
|
|
e28e5a0649 | ||
|
|
09b4e19c9d | ||
|
|
653c831473 | ||
|
|
a2f2cdebb7 | ||
|
|
59e0a1325e | ||
|
|
c0446d7a96 | ||
|
|
1fbee02731 | ||
|
|
102fdbce5c | ||
|
|
71c6beb882 | ||
|
|
ce83042317 | ||
|
|
03598d3f22 | ||
|
|
c2eb2014a3 | ||
|
|
9416ba1bfc | ||
|
|
8c3984d21a | ||
|
|
1883dd6d7c | ||
|
|
a354f9fe52 | ||
|
|
41e2c74b5e | ||
|
|
74d9d427bd | ||
|
|
aa27c4e6d4 | ||
|
|
f40ae9ff25 | ||
|
|
e66087861b | ||
|
|
147637fcf5 | ||
|
|
48582cb718 | ||
|
|
ad21a61ffb | ||
|
|
d34eec1d99 | ||
|
|
95aeac201f | ||
|
|
cceee80799 | ||
|
|
71f80be8f7 | ||
|
|
16a4babdca | ||
|
|
85c0622245 | ||
|
|
e3410ec568 | ||
|
|
c0b0f12b0d | ||
|
|
70a2b7d9ab | ||
|
|
a84c47dc33 | ||
|
|
56c5d69b0f | ||
|
|
6c3d7d2079 | ||
|
|
25a98cda81 | ||
|
|
cd6e133c86 | ||
|
|
b16a102f85 | ||
|
|
d51c7f382f | ||
|
|
a57ca5c0cb | ||
|
|
1e9137fcfe | ||
|
|
8e5b6b6e27 | ||
|
|
7e101b8bf1 | ||
|
|
bf0cfa798c | ||
|
|
1793a28cbc | ||
|
|
e565d0ee32 | ||
|
|
f60462a853 |
No files matched your search
@@ -22,15 +22,17 @@ on:
|
||||
- "!frontend/appflowy_tauri/**"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
CARGO_TERM_COLOR: always
|
||||
FLUTTER_VERSION: "3.10.4"
|
||||
RUST_TOOLCHAIN: "1.70"
|
||||
CARGO_MAKE_VERSION: "0.36.6"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
prepare:
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -76,28 +78,26 @@ jobs:
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.os }}
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
cache-all-crates: true
|
||||
|
||||
- uses: davidB/rust-cargo-make@v1
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
version: '0.36.6'
|
||||
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}, duckscript_cli
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo install --force duckscript_cli
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
|
||||
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
|
||||
sudo apt-get install keybinder-3.0 libnotify-dev
|
||||
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
vcpkg integrate install
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
@@ -106,32 +106,92 @@ jobs:
|
||||
cargo make appflowy-flutter-deps-tools
|
||||
shell: bash
|
||||
|
||||
- name: Enable Flutter Desktop
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
flutter config --enable-linux-desktop
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
git config --system core.longpaths true
|
||||
flutter config --enable-windows-desktop
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Build AppFlowy
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
|
||||
cargo make --profile ${{ matrix.flutter_profile }} appflowy-core-dev
|
||||
|
||||
- name: Run code generation
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make code_generation
|
||||
|
||||
- name: Flutter Analyzer
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: |
|
||||
flutter analyze .
|
||||
|
||||
- name: Compress appflowy_flutter
|
||||
run: tar -czf appflowy_flutter.tar.gz frontend/appflowy_flutter
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.run_id }}-${{ matrix.os }}
|
||||
path: appflowy_flutter.tar.gz
|
||||
|
||||
unit_test:
|
||||
needs: [prepare]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest]
|
||||
include:
|
||||
- os: macos-latest
|
||||
flutter_profile: development-mac-x86_64
|
||||
target: x86_64-apple-darwin
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
id: rust_toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
profile: minimal
|
||||
|
||||
- name: Install flutter
|
||||
id: flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.os }}
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
cache-all-crates: true
|
||||
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}, duckscript_cli
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||
cargo make appflowy-flutter-deps-tools
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Run Flutter unit tests
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make dart_unit_test
|
||||
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
|
||||
cargo make dart_unit_test
|
||||
else
|
||||
cargo make dart_unit_test_no_build
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: Wandalen/wretry.action@v1.0.36
|
||||
@@ -147,3 +207,190 @@ jobs:
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
||||
|
||||
integration_test:
|
||||
needs: [prepare]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest,windows-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: windows-latest
|
||||
flutter_profile: development-windows-x86
|
||||
target: x86_64-pc-windows-msvc
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
id: rust_toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
profile: minimal
|
||||
|
||||
- name: Install flutter
|
||||
id: flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
|
||||
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Enable Flutter Desktop
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
flutter config --enable-linux-desktop
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
git config --system core.longpaths true
|
||||
flutter config --enable-windows-desktop
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ github.run_id }}-${{ matrix.os }}
|
||||
|
||||
- name: Uncompress appflowy_flutter
|
||||
run: tar -xf appflowy_flutter.tar.gz
|
||||
|
||||
- name: Run code generation
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make code_generation
|
||||
|
||||
- name: Run Flutter integration tests
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
export DISPLAY=:99
|
||||
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
||||
sudo apt-get install network-manager
|
||||
flutter test integration_test/runner.dart -d Linux --coverage
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter test integration_test/runner.dart -d macOS --coverage
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
flutter test integration_test/runner.dart -d Windows --coverage
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: Wandalen/wretry.action@v1.0.36
|
||||
with:
|
||||
action: codecov/codecov-action@v3
|
||||
with: |
|
||||
name: appflowy
|
||||
flags: appflowy_flutter_integrateion_test
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
os: ${{ matrix.os }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
||||
|
||||
build:
|
||||
needs: [prepare]
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
flutter_profile: development-mac-x86_64
|
||||
target: x86_64-apple-darwin
|
||||
- os: windows-latest
|
||||
flutter_profile: development-windows-x86
|
||||
target: x86_64-pc-windows-msvc
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
id: rust_toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
profile: minimal
|
||||
|
||||
- name: Install flutter
|
||||
id: flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
|
||||
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Enable Flutter Desktop
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
flutter config --enable-linux-desktop
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
git config --system core.longpaths true
|
||||
flutter config --enable-windows-desktop
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ github.run_id }}-${{ matrix.os }}
|
||||
|
||||
- name: Uncompress appflowy_flutter
|
||||
run: tar -xf appflowy_flutter.tar.gz
|
||||
|
||||
- name: Run code generation
|
||||
if: matrix.os == 'windows-latest'
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make code_generation
|
||||
|
||||
- name: Build flutter product
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make --profile ${{ matrix.flutter_profile }} appflowy-make-product-dev
|
||||
@@ -1,26 +1,23 @@
|
||||
name: integration test
|
||||
name: Mobile-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "release/*"
|
||||
paths:
|
||||
- ".github/workflows/integration_test.yml"
|
||||
- ".github/workflows/mobile_ci.yaml"
|
||||
- "frontend/**"
|
||||
- "!frontend/appflowy_tauri/**"
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
- "release/*"
|
||||
paths:
|
||||
- ".github/workflows/integration_test.yml"
|
||||
- ".github/workflows/mobile_ci.yaml"
|
||||
- "frontend/**"
|
||||
- "!frontend/appflowy_tauri/**"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
RUST_TOOLCHAIN: "1.70"
|
||||
|
||||
@@ -34,14 +31,10 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: windows-latest
|
||||
flutter_profile: development-windows-x86
|
||||
target: x86_64-pc-windows-msvc
|
||||
target: aarch64-linux-android
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
@@ -51,8 +44,8 @@ jobs:
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/share/boost
|
||||
df -h
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
@@ -74,27 +67,36 @@ jobs:
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: "r24"
|
||||
add-to-path: true
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.os }}
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
cache-all-crates: true
|
||||
|
||||
- uses: davidB/rust-cargo-make@v1
|
||||
with:
|
||||
version: '0.36.6'
|
||||
version: "0.36.6"
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
rustup target install aarch64-linux-android
|
||||
rustup target install x86_64-linux-android
|
||||
cargo install --force duckscript_cli
|
||||
cargo install cargo-ndk
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
|
||||
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
|
||||
sudo apt-get install keybinder-3.0 libnotify-dev
|
||||
sudo apt-get install gcc-multilib
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
vcpkg integrate install
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
@@ -103,48 +105,9 @@ jobs:
|
||||
cargo make appflowy-flutter-deps-tools
|
||||
shell: bash
|
||||
|
||||
- name: Enable Flutter Desktop
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
flutter config --enable-linux-desktop
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
git config --system core.longpaths true
|
||||
flutter config --enable-windows-desktop
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Build AppFlowy
|
||||
working-directory: frontend
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
run: |
|
||||
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
|
||||
|
||||
- name: Run Flutter integration tests
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
export DISPLAY=:99
|
||||
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
||||
sudo apt-get install network-manager
|
||||
flutter test integration_test/runner.dart -d Linux --coverage
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter test integration_test/runner.dart -d macOS --coverage
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
flutter test integration_test/runner.dart -d Windows --coverage
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: Wandalen/wretry.action@v1.0.36
|
||||
with:
|
||||
action: codecov/codecov-action@v3
|
||||
with: |
|
||||
name: appflowy
|
||||
flags: appflowy_flutter_integrateion_test
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
os: ${{ matrix.os }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
||||
cargo make --profile development-android appflowy-android-dev
|
||||
@@ -59,7 +59,6 @@ jobs:
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -70,11 +69,6 @@ jobs:
|
||||
components: rustfmt
|
||||
profile: minimal
|
||||
|
||||
- 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: |
|
||||
@@ -151,7 +145,6 @@ jobs:
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -162,11 +155,6 @@ jobs:
|
||||
components: rustfmt
|
||||
profile: minimal
|
||||
|
||||
- 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: |
|
||||
@@ -257,7 +245,6 @@ jobs:
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -266,11 +253,6 @@ jobs:
|
||||
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: |
|
||||
@@ -366,7 +348,6 @@ jobs:
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -377,11 +358,6 @@ jobs:
|
||||
components: rustfmt
|
||||
profile: minimal
|
||||
|
||||
- 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: |
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="ProtoBuf_Gen" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --manifest-path ${flowy_tool} -- pb-gen --rust_sources=${rust_lib},${shared_lib} --derive_meta=${derive_meta} --flutter_package_lib=${flutter_package_lib}" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$/frontend" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs>
|
||||
<env name="flowy_tool" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/scripts/flowy-tool/Cargo.toml" />
|
||||
<env name="rust_lib" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/" />
|
||||
<env name="shared_lib" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/../shared_lib" />
|
||||
<env name="flutter_lib" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/appflowy_flutter/packages" />
|
||||
<env name="derive_meta" value="${shared_lib}/flowy-derive/src/derive_cache/derive_cache.rs" />
|
||||
<env name="flutter_package_lib" value="${flutter_lib}/flowy_sdk/lib" />
|
||||
</envs>
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,18 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run backend" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --package backend --bin backend" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$/backend" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs>
|
||||
<env name="APP_ENVIRONMENT" value="production" />
|
||||
</envs>
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,16 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="dart-event" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --manifest-path $PROJECT_DIR$/scripts/flowy-tool/Cargo.toml -- dart-event --rust_source=$PROJECT_DIR$/rust-lib/ --output=$PROJECT_DIR$/appflowy_flutter/packages/flowy_sdk/lib/dispatch/dart_event.dart" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,5 +1,43 @@
|
||||
# Release Notes
|
||||
|
||||
## Version 0.3.8 - 11/13/2023
|
||||
|
||||
### New Features
|
||||
- Support hiding any stack in a board
|
||||
- Support customizing page icons in menu
|
||||
- Display visual hint when card contains notes
|
||||
- Quick action for adding new stack to a board
|
||||
- Support more ways of inserting page references in documents
|
||||
- Shift + click on a checkbox to power toggle its children
|
||||
|
||||
### Bug fixes
|
||||
- Improved color of the "Share"-button text
|
||||
- Text overflow issue in Calendar properties
|
||||
- Default font (Roboto) added to application
|
||||
- Placeholder added for the editor inside a Card
|
||||
- Toggle notifications in settings have been fixed
|
||||
- Dialog for linking board/grid/calendar opens in correct position
|
||||
- Quick add Card in Board at top, correctly adds a new Card at the top
|
||||
|
||||
## Version 0.3.7 - 10/30/2023
|
||||
|
||||
### New Features
|
||||
- Support showing checklist items inline in row page.
|
||||
- Support inserting date from slash menu.
|
||||
- Support renaming a stack directly by clicking on the stack name.
|
||||
- Show the detailed reminder content in the notification center.
|
||||
- Save card order in Board view.
|
||||
- Allow to hide the ungrouped stack.
|
||||
- Segmented the checklist progress bar.
|
||||
|
||||
### Bug fixes
|
||||
- Optimize side panel animation.
|
||||
- Fix calendar with hidden date or title doesn't show options correctly.
|
||||
- Fix the horizontal scroll bar disappears in Grid view.
|
||||
- Improve setting tab UI in Grid view.
|
||||
- Improve theme of the code block.
|
||||
- Fix some UI issues.
|
||||
|
||||
## Version 0.3.6 - 10/16/2023
|
||||
|
||||
### New Features
|
||||
@@ -7,8 +45,7 @@
|
||||
- Added Ukrainian language.
|
||||
- Support auto-hiding sidebar feature, ensuring a streamlined view even when resizing to a smaller window.
|
||||
- Support toggling the notifitcation on/off.
|
||||
- Added Lemonade theme.
|
||||
|
||||
- Added Lemonade theme.
|
||||
|
||||
### Bug fixes
|
||||
- Improve Vietnamese translations.
|
||||
|
||||
@@ -18,7 +18,7 @@ You are in charge of your data and customizations.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="http://www.appflowy.io"><b>Website</b></a> •
|
||||
<a href="https://www.appflowy.io"><b>Website</b></a> •
|
||||
<a href="https://discord.gg/9Q2xaN37tV"><b>Discord</b></a> •
|
||||
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
|
||||
</p>
|
||||
|
||||
@@ -4,6 +4,18 @@
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// This task only builds the Dart code of AppFlowy.
|
||||
// It supports both the desktop and mobile version.
|
||||
"name": "AF: Build Dart Only",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"env": {
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
// This task builds the Rust and Dart code of AppFlowy.
|
||||
"name": "AF-desktop: Build All",
|
||||
@@ -17,17 +29,6 @@
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
// This task only builds the Dart code of AppFlowy.
|
||||
"name": "AF-desktop: Build Dart Only",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"env": {
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
// This task builds will:
|
||||
// - call the clean task,
|
||||
@@ -65,6 +66,17 @@
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
"name": "AF-Android: Clean + Rebuild All",
|
||||
"request": "launch",
|
||||
"program": "./lib/main.dart",
|
||||
"type": "dart",
|
||||
"preLaunchTask": "AF: Clean + Rebuild All (Android)",
|
||||
"env": {
|
||||
"RUST_LOG": "trace"
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
{
|
||||
"name": "AF-desktop: Debug Rust",
|
||||
"request": "attach",
|
||||
|
||||
@@ -84,6 +84,34 @@
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Clean + Rebuild All (Android)",
|
||||
"type": "shell",
|
||||
"dependsOrder": "sequence",
|
||||
"dependsOn": [
|
||||
"AF: Dart Clean",
|
||||
"AF: Flutter Clean",
|
||||
"AF: Build Appflowy Core For Android",
|
||||
"AF: Flutter Pub Get",
|
||||
"AF: Flutter Package Get",
|
||||
"AF: Generate Language Files",
|
||||
"AF: Generate Freezed Files",
|
||||
"AF: Generate Svg Files"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Build Appflowy Core For Android",
|
||||
"type": "shell",
|
||||
"command": "cargo make --profile development-android appflowy-core-dev-android",
|
||||
"group": "build",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Build Appflowy Core",
|
||||
"type": "shell",
|
||||
@@ -286,13 +314,5 @@
|
||||
"cwd": "${workspaceFolder}/appflowy_flutter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Generate AppFlowyEnv",
|
||||
"type": "shell",
|
||||
"command": "dart run build_runner build --delete-conflicting-outputs",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/appflowy_flutter/packages/appflowy_backend"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -25,7 +25,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.3.6"
|
||||
CURRENT_APP_VERSION = "0.3.8"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
|
||||
PRODUCT_NAME = "AppFlowy"
|
||||
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
|
||||
@@ -186,6 +186,29 @@ RUST_COMPILE_TARGET = "aarch64-apple-ios"
|
||||
BUILD_ARCHS = "arm64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.production-ios-arm64]
|
||||
BUILD_FLAG = "release"
|
||||
TARGET_OS = "ios"
|
||||
FLUTTER_OUTPUT_DIR = "Release"
|
||||
RUST_COMPILE_TARGET = "aarch64-apple-ios"
|
||||
BUILD_ARCHS = "arm64"
|
||||
CRATE_TYPE = "staticlib"
|
||||
|
||||
[env.development-android]
|
||||
BUILD_FLAG = "debug"
|
||||
TARGET_OS = "android"
|
||||
CRATE_TYPE = "cdylib"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
LIB_EXT = "so"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
|
||||
|
||||
[env.production-android]
|
||||
BUILD_FLAG = "release"
|
||||
TARGET_OS = "android"
|
||||
CRATE_TYPE = "cdylib"
|
||||
FLUTTER_OUTPUT_DIR = "Release"
|
||||
LIB_EXT = "so"
|
||||
|
||||
[tasks.echo_env]
|
||||
script = ['''
|
||||
echo "-------- Env Parameters --------"
|
||||
@@ -201,21 +224,6 @@ script = ['''
|
||||
''']
|
||||
script_runner = "@shell"
|
||||
|
||||
[env.development-android]
|
||||
BUILD_FLAG = "debug"
|
||||
TARGET_OS = "android"
|
||||
CRATE_TYPE = "cdylib"
|
||||
FLUTTER_OUTPUT_DIR = "Debug"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
|
||||
|
||||
[env.production-android]
|
||||
CARGO_PROFILE = "release"
|
||||
BUILD_FLAG = "release"
|
||||
TARGET_OS = "android"
|
||||
CRATE_TYPE = "cdylib"
|
||||
FLUTTER_OUTPUT_DIR = "Release"
|
||||
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
|
||||
|
||||
[tasks.setup-crate-type]
|
||||
private = true
|
||||
script = [
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
# This file should be version controlled.
|
||||
|
||||
version:
|
||||
revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
channel: stable
|
||||
revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
|
||||
channel: unknown
|
||||
|
||||
project_type: app
|
||||
|
||||
@@ -13,11 +13,11 @@ project_type: app
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
- platform: windows
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
|
||||
base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
|
||||
- platform: android
|
||||
create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
|
||||
base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
|
||||
|
||||
# User provided section
|
||||
|
||||
|
||||
@@ -11,3 +11,5 @@ GeneratedPluginRegistrant.java
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
|
||||
.cxx
|
||||
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
compileSdkVersion 33
|
||||
ndkVersion "24.0.8215888"
|
||||
|
||||
compileOptions {
|
||||
@@ -46,11 +46,16 @@ android {
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "io.appflowy.appflowy"
|
||||
minSdkVersion 19
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 31
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
multiDexEnabled true
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_STL=c++_shared"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -63,6 +68,14 @@ android {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
|
||||
namespace 'io.appflowy.appflowy'
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "src/main/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="io.appflowy.appflowy">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
|
||||
@@ -1,42 +1,48 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="io.appflowy.appflowy">
|
||||
<application
|
||||
android:label="appflowy_flutter"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:name="${applicationName}">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<!-- Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
gap between the end of Android's launch screen and the painting of
|
||||
Flutter's first frame. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:label="AppFlowy" android:icon="@mipmap/ic_launcher"
|
||||
android:name="${applicationName}">
|
||||
<activity android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
|
||||
<!--
|
||||
Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI.
|
||||
-->
|
||||
<meta-data android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme" />
|
||||
<!--
|
||||
Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
gap between the end of Android's launch screen and the painting of
|
||||
Flutter's first frame.
|
||||
-->
|
||||
<meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="appflowy-flutter" />
|
||||
<!-- <data android:host="login-callback" /> -->
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!--
|
||||
Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java
|
||||
-->
|
||||
<meta-data android:name="flutterEmbedding" android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
|
||||
project(AppFlowy)
|
||||
|
||||
# arm64-v8a
|
||||
file(COPY
|
||||
${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so
|
||||
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/arm64-v8a
|
||||
)
|
||||
|
||||
# x86_64
|
||||
file(COPY
|
||||
${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_shared.so
|
||||
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/x86_64
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int64_t init_sdk(char *path);
|
||||
|
||||
void async_event(int64_t port, const uint8_t *input, uintptr_t len);
|
||||
|
||||
const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
|
||||
|
||||
int32_t set_stream_port(int64_t port);
|
||||
|
||||
void link_me_please(void);
|
||||
|
||||
void backend_log(int64_t level, const char *data);
|
||||
|
||||
void set_env(const char *data);
|
||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 16 KiB |
@@ -1,5 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="io.appflowy.appflowy">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.kotlin_version = '1.8.0'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@ subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
@@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
org.gradle.caching=true
|
||||
android.suppressUnsupportedCompileSdk=33
|
||||
@@ -1,5 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1 @@
|
||||
use_precompiled_binaries: true
|
||||
@@ -1,23 +1,41 @@
|
||||
# Initial Setup
|
||||
# 1. Copy the dev.env file to .env:
|
||||
# cp dev.env .env
|
||||
# 2. Alternatively, you can generate the .env file using the "Generate Env File" task in VSCode.
|
||||
|
||||
# Configuring Cloud Type
|
||||
# This configuration file is used to specify the cloud type and the necessary configurations for each cloud type. The available options are:
|
||||
# 1. Copy the dev.env file to .env:
|
||||
# cp dev.env .env
|
||||
# Update the environment parameters as needed.
|
||||
|
||||
# 2. Generate the env.dart from this .env file:
|
||||
# You can use the "Generate Env File" task in VSCode.
|
||||
# Alternatively, execute the following commands:
|
||||
# cd appflowy_flutter
|
||||
# dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
|
||||
# Cloud Type Configuration
|
||||
# Use this configuration file to specify the cloud type and its associated settings. The available cloud types are:
|
||||
# Local: 0
|
||||
# Supabase: 1
|
||||
# AppFlowy Cloud: 2
|
||||
|
||||
# By default, it's set to Local.
|
||||
CLOUD_TYPE=0
|
||||
|
||||
# Supabase Configuration
|
||||
# If you're using Supabase (CLOUD_TYPE=1), you need to provide the following configurations:
|
||||
SUPABASE_URL=replace-with-your-supabase-url
|
||||
SUPABASE_ANON_KEY=replace-with-your-supabase-key
|
||||
# If using Supabase (CLOUD_TYPE=1), provide the following details:
|
||||
SUPABASE_URL=
|
||||
SUPABASE_ANON_KEY=
|
||||
|
||||
# AppFlowy Cloud Configuration
|
||||
# If you're using AppFlowy Cloud (CLOUD_TYPE=2), you need to provide the following configurations:
|
||||
APPFLOWY_CLOUD_BASE_URL=replace-with-your-appflowy-cloud-url
|
||||
APPFLOWY_CLOUD_WS_BASE_URL=replace-with-your-appflowy-cloud-ws-url
|
||||
APPFLOWY_CLOUD_GOTRUE_URL=replace-with-your-appflowy-cloud-gotrue-url
|
||||
# If using AppFlowy Cloud (CLOUD_TYPE=2), provide the following details:
|
||||
# For instance:
|
||||
# APPFLOWY_CLOUD_BASE_URL=https://xxxxxxxxx
|
||||
# APPFLOWY_CLOUD_WS_BASE_URL=wss://xxxxxxxxx
|
||||
# APPFLOWY_CLOUD_GOTRUE_URL=https://xxxxxxxxx
|
||||
#
|
||||
# Local host machine(For local develop)
|
||||
# APPFLOWY_CLOUD_BASE_URL=http://localhost:8000
|
||||
# APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws
|
||||
# APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998
|
||||
|
||||
APPFLOWY_CLOUD_BASE_URL=
|
||||
APPFLOWY_CLOUD_WS_BASE_URL=
|
||||
APPFLOWY_CLOUD_GOTRUE_URL=
|
||||
@@ -25,8 +25,8 @@ void main() {
|
||||
await tester.openSettingsPage(SettingsPage.user);
|
||||
await tester.tapButton(find.byType(SettingLogoutButton));
|
||||
|
||||
tester.expectToSeeText(LocaleKeys.button_OK.tr());
|
||||
await tester.tapButtonWithName(LocaleKeys.button_OK.tr());
|
||||
tester.expectToSeeText(LocaleKeys.button_ok.tr());
|
||||
await tester.tapButtonWithName(LocaleKeys.button_ok.tr());
|
||||
|
||||
// Go to the sign in page again
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_column_header.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_board/appflowy_board.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/util.dart';
|
||||
|
||||
const defaultFirstCardName = 'Card 1';
|
||||
const defaultLastCardName = 'Card 3';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('board add row test', () {
|
||||
testWidgets('Add card from header', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
|
||||
final findFirstCard = find.descendant(
|
||||
of: find.byType(AppFlowyGroupCard),
|
||||
matching: find.byType(FlowyText),
|
||||
);
|
||||
|
||||
FlowyText firstCardText = tester.firstWidget(findFirstCard);
|
||||
expect(firstCardText.text, defaultFirstCardName);
|
||||
|
||||
await tester.tap(
|
||||
find
|
||||
.descendant(
|
||||
of: find.byType(BoardColumnHeader),
|
||||
matching: find.byWidgetPredicate(
|
||||
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.add_s,
|
||||
),
|
||||
)
|
||||
.at(1),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
const newCardName = 'Card 4';
|
||||
await tester.enterText(
|
||||
find.descendant(
|
||||
of: find.byType(IntrinsicHeight),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
newCardName,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byType(AppFlowyBoard));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
firstCardText = tester.firstWidget(findFirstCard);
|
||||
expect(firstCardText.text, newCardName);
|
||||
});
|
||||
|
||||
testWidgets('Add card from footer', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
|
||||
final findLastCard = find.descendant(
|
||||
of: find.byType(AppFlowyGroupCard),
|
||||
matching: find.byType(FlowyText),
|
||||
);
|
||||
|
||||
FlowyText? lastCardText =
|
||||
tester.widgetList(findLastCard).last as FlowyText;
|
||||
expect(lastCardText.text, defaultLastCardName);
|
||||
|
||||
await tester.tap(
|
||||
find
|
||||
.descendant(
|
||||
of: find.byType(AppFlowyGroupFooter),
|
||||
matching: find.byType(FlowySvg),
|
||||
)
|
||||
.at(1),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
const newCardName = 'Card 4';
|
||||
await tester.enterText(
|
||||
find.descendant(
|
||||
of: find.byType(IntrinsicHeight),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
newCardName,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byType(AppFlowyBoard));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
lastCardText = tester.widgetList(findLastCard).last as FlowyText;
|
||||
expect(lastCardText.text, newCardName);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_column_header.dart';
|
||||
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_hidden_groups.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.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('board hide groups test', () {
|
||||
testWidgets('expand/collapse hidden groups', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
|
||||
final collapseFinder = find.byFlowySvg(FlowySvgs.pull_left_outlined_s);
|
||||
final expandFinder = find.byFlowySvg(FlowySvgs.hamburger_s_s);
|
||||
|
||||
// Is expanded by default
|
||||
expect(collapseFinder, findsOneWidget);
|
||||
expect(expandFinder, findsNothing);
|
||||
|
||||
// Collapse hidden groups
|
||||
await tester.tap(collapseFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Is collapsed
|
||||
expect(collapseFinder, findsNothing);
|
||||
expect(expandFinder, findsOneWidget);
|
||||
|
||||
// Expand hidden groups
|
||||
await tester.tap(expandFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Is expanded
|
||||
expect(collapseFinder, findsOneWidget);
|
||||
expect(expandFinder, findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('hide first group, and show it again', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
|
||||
// Tap the options of the first group
|
||||
final optionsFinder = find
|
||||
.descendant(
|
||||
of: find.byType(BoardColumnHeader),
|
||||
matching: find.byFlowySvg(FlowySvgs.details_horizontal_s),
|
||||
)
|
||||
.first;
|
||||
|
||||
await tester.tap(optionsFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Tap the hide option
|
||||
await tester.tap(find.byFlowySvg(FlowySvgs.hide_s));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
int shownGroups =
|
||||
tester.widgetList(find.byType(BoardColumnHeader)).length;
|
||||
|
||||
// We still show Doing, Done, No Status
|
||||
expect(shownGroups, 3);
|
||||
|
||||
final hiddenCardFinder = find.byType(HiddenGroupCard);
|
||||
await tester.hoverOnWidget(hiddenCardFinder);
|
||||
await tester.tap(find.byFlowySvg(FlowySvgs.show_m));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
shownGroups = tester.widgetList(find.byType(BoardColumnHeader)).length;
|
||||
expect(shownGroups, 4);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
extension FlowySvgFinder on CommonFinders {
|
||||
Finder byFlowySvg(FlowySvgData svg) => _FlowySvgFinder(svg);
|
||||
}
|
||||
|
||||
class _FlowySvgFinder extends MatchFinder {
|
||||
_FlowySvgFinder(this.svg);
|
||||
|
||||
final FlowySvgData svg;
|
||||
|
||||
@override
|
||||
String get description => 'flowy_svg "$svg"';
|
||||
|
||||
@override
|
||||
bool matches(Element candidate) {
|
||||
final Widget widget = candidate.widget;
|
||||
return widget is FlowySvg && widget.svg == svg;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
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:appflowy_board/appflowy_board.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/util.dart';
|
||||
import '../util/database_test_op.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -46,5 +49,56 @@ void main() {
|
||||
await tester.tapButtonWithName(LocaleKeys.button_duplicate.tr());
|
||||
expect(find.textContaining(name, findRichText: true), findsNWidgets(2));
|
||||
});
|
||||
|
||||
testWidgets('add new group', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
|
||||
|
||||
// assert number of groups
|
||||
tester.assertNumberOfGroups(4);
|
||||
|
||||
// scroll the board horizontally to ensure add new group button appears
|
||||
await tester.scrollBoardToEnd();
|
||||
|
||||
// assert and click on add new group button
|
||||
tester.assertNewGroupTextField(false);
|
||||
await tester.tapNewGroupButton();
|
||||
tester.assertNewGroupTextField(true);
|
||||
|
||||
// enter new group name and submit
|
||||
await tester.enterNewGroupName('needs design', submit: true);
|
||||
|
||||
// assert number of groups has increased
|
||||
tester.assertNumberOfGroups(5);
|
||||
|
||||
// assert text field has disappeared
|
||||
await tester.scrollBoardToEnd();
|
||||
tester.assertNewGroupTextField(false);
|
||||
|
||||
// click on add new group button
|
||||
await tester.tapNewGroupButton();
|
||||
tester.assertNewGroupTextField(true);
|
||||
|
||||
// type some things
|
||||
await tester.enterNewGroupName('needs planning', submit: false);
|
||||
|
||||
// click on clear button and assert empty contents
|
||||
await tester.clearNewGroupTextField();
|
||||
|
||||
// press escape to cancel
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await tester.pumpAndSettle();
|
||||
tester.assertNewGroupTextField(false);
|
||||
|
||||
// click on add new group button
|
||||
await tester.tapNewGroupButton();
|
||||
tester.assertNewGroupTextField(true);
|
||||
|
||||
// press elsewhere to cancel
|
||||
await tester.tap(find.byType(AppFlowyBoard));
|
||||
await tester.pumpAndSettle();
|
||||
tester.assertNewGroupTextField(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'board_row_test.dart' as board_row_test;
|
||||
import 'board_add_row_test.dart' as board_add_row_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Board integration tests
|
||||
board_row_test.main();
|
||||
board_add_row_test.main();
|
||||
}
|
||||
@@ -174,25 +174,23 @@ void main() {
|
||||
await tester.openCalendarEvent(index: 0, date: sameDayNextWeek);
|
||||
await tester.deleteEventFromEventEditor();
|
||||
|
||||
// Create a new event in today's calendar cell
|
||||
await tester.scrollToToday();
|
||||
await tester.doubleClickCalendarCell(today);
|
||||
// Create another event on the 5th of this month
|
||||
final fifthOfThisMonth = DateTime(today.year, today.month, 5);
|
||||
await tester.doubleClickCalendarCell(fifthOfThisMonth);
|
||||
await tester.dismissEventEditor();
|
||||
|
||||
// Make sure that the event is today
|
||||
tester.assertNumberOfEventsOnSpecificDay(1, today);
|
||||
// Make sure that the event is on the 4t
|
||||
tester.assertNumberOfEventsOnSpecificDay(1, fifthOfThisMonth);
|
||||
|
||||
// Click on the event
|
||||
await tester.openCalendarEvent(index: 0);
|
||||
await tester.openCalendarEvent(index: 0, date: fifthOfThisMonth);
|
||||
|
||||
// Open the date editor of the event
|
||||
await tester.tapDateCellInRowDetailPage();
|
||||
await tester.findDateEditor(findsOneWidget);
|
||||
|
||||
// Edit the event's date. To avoid selecting a day outside of the current month, the new date will be one day closer to the middle of the month.
|
||||
final newDate = today.day < 15
|
||||
? today.add(const Duration(days: 1))
|
||||
: today.subtract(const Duration(days: 1));
|
||||
// Edit the event's date
|
||||
final newDate = fifthOfThisMonth.add(const Duration(days: 1));
|
||||
await tester.selectDay(content: newDate.day);
|
||||
await tester.dismissCellEditor();
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ void main() {
|
||||
await tester.hoverRowBanner();
|
||||
|
||||
await tester.openEmojiPicker();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.tapEmoji('😀');
|
||||
|
||||
// After select the emoji, the EmojiButton will show up
|
||||
@@ -60,12 +59,10 @@ void main() {
|
||||
await tester.openFirstRowDetailPage();
|
||||
await tester.hoverRowBanner();
|
||||
await tester.openEmojiPicker();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.tapEmoji('😀');
|
||||
|
||||
// Update existing selected emoji
|
||||
await tester.tapButton(find.byType(EmojiButton));
|
||||
await tester.switchToEmojiList();
|
||||
await tester.tapEmoji('😅');
|
||||
|
||||
// The emoji already displayed in the row banner
|
||||
@@ -89,7 +86,6 @@ void main() {
|
||||
await tester.openFirstRowDetailPage();
|
||||
await tester.hoverRowBanner();
|
||||
await tester.openEmojiPicker();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.tapEmoji('😀');
|
||||
|
||||
// Remove the emoji
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/link_to_page_widget.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
||||
import 'package:flowy_infra/uuid.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/keyboard.dart';
|
||||
import '../util/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('insert inline document reference', () {
|
||||
testWidgets('insert by slash menu', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final name = await createDocumentToReference(tester);
|
||||
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await triggerReferenceDocumentBySlashMenu(tester);
|
||||
|
||||
// Search for prefix of document
|
||||
await enterDocumentText(tester);
|
||||
|
||||
// Select result
|
||||
final optionFinder = find.descendant(
|
||||
of: find.byType(LinkToPageMenu),
|
||||
matching: find.text(name),
|
||||
);
|
||||
|
||||
await tester.tap(optionFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('insert by `[[` character shortcut', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final name = await createDocumentToReference(tester);
|
||||
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.ime.insertText('[[');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Select result
|
||||
await tester.editor.tapAtMenuItemWithName(name);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('insert by `+` character shortcut', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final name = await createDocumentToReference(tester);
|
||||
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.ime.insertText('+');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Select result
|
||||
await tester.editor.tapAtMenuItemWithName(name);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createDocumentToReference(WidgetTester tester) async {
|
||||
final name = 'document_${uuid()}';
|
||||
|
||||
await tester.createNewPageWithName(
|
||||
name: name,
|
||||
layout: ViewLayoutPB.Document,
|
||||
openAfterCreated: false,
|
||||
);
|
||||
|
||||
// This is a workaround since the openAfterCreated
|
||||
// option does not work in createNewPageWithName method
|
||||
await tester.tap(find.byType(SingleInnerViewItem).first);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
Future<void> triggerReferenceDocumentBySlashMenu(WidgetTester tester) async {
|
||||
await tester.editor.showSlashMenu();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Search for referenced document action
|
||||
await enterDocumentText(tester);
|
||||
|
||||
// Select item
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
LogicalKeyboardKey.enter,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> enterDocumentText(WidgetTester tester) async {
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.keyO,
|
||||
LogicalKeyboardKey.keyC,
|
||||
LogicalKeyboardKey.keyU,
|
||||
LogicalKeyboardKey.keyM,
|
||||
LogicalKeyboardKey.keyE,
|
||||
LogicalKeyboardKey.keyN,
|
||||
LogicalKeyboardKey.keyT,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -16,6 +16,8 @@ import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
|
||||
import 'document_with_outline_block_test.dart' as document_with_outline_block;
|
||||
import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
|
||||
import 'edit_document_test.dart' as document_edit_test;
|
||||
import 'document_inline_page_reference_test.dart'
|
||||
as document_inline_page_reference_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -35,4 +37,5 @@ void startTesting() {
|
||||
document_text_direction_test.main();
|
||||
document_option_action_test.main();
|
||||
document_with_image_block_test.main();
|
||||
document_inline_page_reference_test.main();
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:emoji_mart/emoji_mart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
@@ -17,7 +22,6 @@ void main() {
|
||||
|
||||
// Hover over cover toolbar to show 'Add Cover' and 'Add Icon' buttons
|
||||
await tester.editor.hoverOnCoverToolbar();
|
||||
tester.expectToSeePluginAddCoverAndIconButton();
|
||||
|
||||
// Insert a document cover
|
||||
await tester.editor.tapOnAddCover();
|
||||
@@ -53,15 +57,10 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
tester.expectToSeeDocumentIcon(null);
|
||||
|
||||
// Hover over cover toolbar to show the 'Add Cover' and 'Add Icon' buttons
|
||||
await tester.editor.hoverOnCoverToolbar();
|
||||
tester.expectToSeePluginAddCoverAndIconButton();
|
||||
tester.expectToSeeDocumentIcon('⭐️');
|
||||
|
||||
// Insert a document icon
|
||||
await tester.editor.tapAddIconButton();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.editor.tapGettingStartedIcon();
|
||||
await tester.tapEmoji('😀');
|
||||
tester.expectToSeeDocumentIcon('😀');
|
||||
|
||||
@@ -73,13 +72,11 @@ void main() {
|
||||
// Add the icon back for further testing
|
||||
await tester.editor.hoverOnCoverToolbar();
|
||||
await tester.editor.tapAddIconButton();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.tapEmoji('😀');
|
||||
tester.expectToSeeDocumentIcon('😀');
|
||||
|
||||
// Change the document icon
|
||||
await tester.editor.tapOnIconWidget();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.tapEmoji('😅');
|
||||
tester.expectToSeeDocumentIcon('😅');
|
||||
|
||||
@@ -93,19 +90,15 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
tester.expectToSeeDocumentIcon(null);
|
||||
tester.expectToSeeDocumentIcon('⭐️');
|
||||
tester.expectToSeeNoDocumentCover();
|
||||
|
||||
// Hover over cover toolbar to show the 'Add Cover' and 'Add Icon' buttons
|
||||
await tester.editor.hoverOnCoverToolbar();
|
||||
tester.expectToSeePluginAddCoverAndIconButton();
|
||||
|
||||
// Insert a document icon
|
||||
await tester.editor.tapAddIconButton();
|
||||
await tester.switchToEmojiList();
|
||||
await tester.editor.tapGettingStartedIcon();
|
||||
await tester.tapEmoji('😀');
|
||||
|
||||
// Insert a document cover
|
||||
await tester.editor.hoverOnCoverToolbar();
|
||||
await tester.editor.tapOnAddCover();
|
||||
|
||||
// Expect to see the icon and cover at the same time
|
||||
@@ -116,5 +109,48 @@ void main() {
|
||||
await tester.editor.hoverOnCoverToolbar();
|
||||
tester.expectToSeeEmptyDocumentHeaderToolbar();
|
||||
});
|
||||
|
||||
testWidgets('shuffle icon', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.editor.tapGettingStartedIcon();
|
||||
|
||||
// click the shuffle button
|
||||
await tester.tapButton(
|
||||
find.byTooltip(LocaleKeys.emoji_random.tr()),
|
||||
);
|
||||
tester.expectDocumentIconNotNull();
|
||||
});
|
||||
|
||||
testWidgets('change skin tone', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.editor.tapGettingStartedIcon();
|
||||
|
||||
final searchEmojiTextField = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is TextField &&
|
||||
widget.decoration!.hintText == LocaleKeys.emoji_search.tr(),
|
||||
);
|
||||
await tester.enterText(
|
||||
searchEmojiTextField,
|
||||
'hand',
|
||||
);
|
||||
|
||||
// change skin tone
|
||||
await tester.editor.changeEmojiSkinTone(EmojiSkinTone.dark);
|
||||
|
||||
// select an icon with skin tone
|
||||
const hand = '👋🏿';
|
||||
await tester.tapEmoji(hand);
|
||||
tester.expectToSeeDocumentIcon(hand);
|
||||
tester.expectViewHasIcon(
|
||||
gettingStarted,
|
||||
ViewLayoutPB.Document,
|
||||
hand,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -15,7 +15,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await insertingInlinePage(tester, ViewLayoutPB.Grid);
|
||||
await insertInlinePage(tester, ViewLayoutPB.Grid);
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
@@ -26,7 +26,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await insertingInlinePage(tester, ViewLayoutPB.Board);
|
||||
await insertInlinePage(tester, ViewLayoutPB.Board);
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
@@ -37,7 +37,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await insertingInlinePage(tester, ViewLayoutPB.Calendar);
|
||||
await insertInlinePage(tester, ViewLayoutPB.Calendar);
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
@@ -48,7 +48,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await insertingInlinePage(tester, ViewLayoutPB.Document);
|
||||
await insertInlinePage(tester, ViewLayoutPB.Document);
|
||||
|
||||
final mentionBlock = find.byType(MentionPageBlock);
|
||||
expect(mentionBlock, findsOneWidget);
|
||||
@@ -59,7 +59,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Document);
|
||||
final pageName = await insertInlinePage(tester, ViewLayoutPB.Document);
|
||||
|
||||
// rename
|
||||
const newName = 'RenameToNewPageName';
|
||||
@@ -78,7 +78,7 @@ void main() {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Grid);
|
||||
final pageName = await insertInlinePage(tester, ViewLayoutPB.Grid);
|
||||
|
||||
// rename
|
||||
await tester.hoverOnPageName(
|
||||
@@ -98,7 +98,7 @@ void main() {
|
||||
}
|
||||
|
||||
/// Insert a referenced database of [layout] into the document
|
||||
Future<String> insertingInlinePage(
|
||||
Future<String> insertInlinePage(
|
||||
WidgetTester tester,
|
||||
ViewLayoutPB layout,
|
||||
) async {
|
||||
@@ -110,15 +110,19 @@ Future<String> insertingInlinePage(
|
||||
layout: layout,
|
||||
openAfterCreated: false,
|
||||
);
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
name: 'insert_a_inline_page_${layout.name}',
|
||||
layout: ViewLayoutPB.Document,
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
|
||||
// insert a inline page
|
||||
await tester.editor.showAtMenu();
|
||||
await tester.editor.tapAtMenuItemWithName(name);
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -15,14 +15,23 @@ void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('toggle list in document', () {
|
||||
Finder findToggleListIcon({
|
||||
required bool isExpanded,
|
||||
}) {
|
||||
final turns = isExpanded ? 0.25 : 0.0;
|
||||
return find.byWidgetPredicate(
|
||||
(widget) => widget is AnimatedRotation && widget.turns == turns,
|
||||
);
|
||||
}
|
||||
|
||||
void expectToggleListOpened() {
|
||||
expect(find.byIcon(Icons.arrow_drop_down), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_right), findsNothing);
|
||||
expect(findToggleListIcon(isExpanded: true), findsOneWidget);
|
||||
expect(findToggleListIcon(isExpanded: false), findsNothing);
|
||||
}
|
||||
|
||||
void expectToggleListClosed() {
|
||||
expect(find.byIcon(Icons.arrow_drop_down), findsNothing);
|
||||
expect(find.byIcon(Icons.arrow_right), findsOneWidget);
|
||||
expect(findToggleListIcon(isExpanded: false), findsOneWidget);
|
||||
expect(findToggleListIcon(isExpanded: true), findsNothing);
|
||||
}
|
||||
|
||||
testWidgets('convert > to toggle list, and click the icon to close it',
|
||||
@@ -63,7 +72,7 @@ void main() {
|
||||
expect(find.text(text2, findRichText: true), findsOneWidget);
|
||||
|
||||
// Click the toggle list icon to close it
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_right);
|
||||
await tester.tapButton(toggleListIcon);
|
||||
|
||||
// expect the toggle list to be closed
|
||||
@@ -88,7 +97,7 @@ void main() {
|
||||
await tester.ime.insertText('> $text');
|
||||
|
||||
// Click the toggle list icon to close it
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_right);
|
||||
await tester.tapButton(toggleListIcon);
|
||||
|
||||
// Press the enter key
|
||||
@@ -164,7 +173,7 @@ void main() {
|
||||
|
||||
// Press the enter key
|
||||
// Click the toggle list icon to close it
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_right);
|
||||
await tester.tapButton(toggleListIcon);
|
||||
|
||||
await tester.editor.updateSelection(
|
||||
|
||||
@@ -113,9 +113,9 @@ const _sample = r'''
|
||||
|
||||
[] Type followed by bullet or num to create a list.
|
||||
|
||||
[x] Click `+ New Page` button at the bottom of your sidebar to add a new page.
|
||||
[x] Click `New Page` button at the bottom of your sidebar to add a new page.
|
||||
|
||||
[] Click `+` next to any page title in the sidebar to quickly add a new subpage, `Document`, `Grid`, or `Kanban Board`.
|
||||
[] Click the plus sign next to any page title in the sidebar to quickly add a new subpage, `Document`, `Grid`, or `Kanban Board`.
|
||||
---
|
||||
* bulleted list 1
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'util/util.dart';
|
||||
|
||||
// This test is meaningless, just for preventing the CI from failing.
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('Empty', () {
|
||||
testWidgets('toggle theme mode', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
import 'package:appflowy/env/env.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'appearance_settings_test.dart' as appearance_test_runner;
|
||||
import 'auth/auth_test.dart' as auth_test_runner;
|
||||
import 'board/board_test_runner.dart' as board_test_runner;
|
||||
import 'database_calendar_test.dart' as database_calendar_test;
|
||||
import 'database_cell_test.dart' as database_cell_test;
|
||||
import 'database_field_test.dart' as database_field_test;
|
||||
import 'database_field_settings_test.dart' as database_field_settings_test;
|
||||
import 'database_field_test.dart' as database_field_test;
|
||||
import 'database_filter_test.dart' as database_filter_test;
|
||||
import 'database_row_page_test.dart' as database_row_page_test;
|
||||
import 'database_row_test.dart' as database_row_test;
|
||||
@@ -13,17 +16,14 @@ import 'database_share_test.dart' as database_share_test;
|
||||
import 'database_sort_test.dart' as database_sort_test;
|
||||
import 'database_view_test.dart' as database_view_test;
|
||||
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;
|
||||
import 'empty_test.dart' as first_test;
|
||||
import 'hotkeys_test.dart' as hotkeys_test;
|
||||
import 'appearance_settings_test.dart' as appearance_test_runner;
|
||||
import 'auth/auth_test.dart' as auth_test_runner;
|
||||
import 'settings/user_icon_test.dart' as user_icon_test;
|
||||
import 'settings/user_language_test.dart' as user_language_test;
|
||||
import 'import_files_test.dart' as import_files_test;
|
||||
import 'settings/settings_runner.dart' as settings_test_runner;
|
||||
import 'share_markdown_test.dart' as share_markdown_test;
|
||||
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
|
||||
import 'switch_folder_test.dart' as switch_folder_test;
|
||||
import 'tabs_test.dart' as tabs_test;
|
||||
|
||||
/// The main task runner for all integration tests in AppFlowy.
|
||||
///
|
||||
@@ -34,6 +34,10 @@ import 'settings/user_language_test.dart' as user_language_test;
|
||||
/// as the test target.
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// This test must be run first, otherwise the CI will fail.
|
||||
first_test.main();
|
||||
|
||||
switch_folder_test.main();
|
||||
share_markdown_test.main();
|
||||
import_files_test.main();
|
||||
@@ -70,8 +74,7 @@ void main() {
|
||||
appearance_test_runner.main();
|
||||
|
||||
// User settings
|
||||
user_icon_test.main();
|
||||
user_language_test.main();
|
||||
settings_test_runner.main();
|
||||
|
||||
if (isCloudEnabled) {
|
||||
auth_test_runner.main();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.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('board add row test', () {
|
||||
testWidgets('Add card from header', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
await tester.openSettings();
|
||||
await tester.openSettingsPage(SettingsPage.notifications);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final switchFinder = find.byType(Switch);
|
||||
|
||||
// Defaults to enabled
|
||||
Switch switchWidget = tester.widget(switchFinder);
|
||||
expect(switchWidget.value, true);
|
||||
|
||||
// Disable
|
||||
await tester.tap(switchFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
switchWidget = tester.widget(switchFinder);
|
||||
expect(switchWidget.value, false);
|
||||
|
||||
// Enable again
|
||||
await tester.tap(switchFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
switchWidget = tester.widget(switchFinder);
|
||||
expect(switchWidget.value, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'notifications_settings_test.dart' as notifications_settings_test;
|
||||
import 'user_icon_test.dart' as user_icon_test;
|
||||
import 'user_language_test.dart' as user_language_test;
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
notifications_settings_test.main();
|
||||
user_icon_test.main();
|
||||
user_language_test.main();
|
||||
}
|
||||
@@ -16,9 +16,6 @@ void main() {
|
||||
final context = await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// expect to see a readme page
|
||||
tester.expectToSeePageName(gettingStarted);
|
||||
|
||||
// mock the file picker
|
||||
final path = await mockSaveFilePath(
|
||||
p.join(context.applicationDataDirectory, 'test.md'),
|
||||
|
||||
@@ -99,7 +99,7 @@ void main() {
|
||||
);
|
||||
expect(
|
||||
tester.findFavoritePageName(name),
|
||||
findsNothing,
|
||||
findsOneWidget,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -127,7 +127,7 @@ void main() {
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget is SingleInnerViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
),
|
||||
@@ -144,12 +144,7 @@ void main() {
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
),
|
||||
tester.findAllFavoritePages(),
|
||||
findsNWidgets(3),
|
||||
);
|
||||
|
||||
@@ -163,12 +158,7 @@ void main() {
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
),
|
||||
tester.findAllFavoritePages(),
|
||||
findsNothing,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.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();
|
||||
|
||||
const emoji = '😁';
|
||||
|
||||
group('Icon', () {
|
||||
testWidgets('Update page icon in sidebar', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create document, board, grid and calendar views
|
||||
for (final value in ViewLayoutPB.values) {
|
||||
await tester.createNewPageWithName(
|
||||
name: value.name,
|
||||
parentName: gettingStarted,
|
||||
layout: value,
|
||||
);
|
||||
|
||||
// update its icon
|
||||
await tester.updatePageIconInSidebarByName(
|
||||
name: value.name,
|
||||
parentName: gettingStarted,
|
||||
layout: value,
|
||||
icon: emoji,
|
||||
);
|
||||
|
||||
tester.expectViewHasIcon(
|
||||
value.name,
|
||||
value,
|
||||
emoji,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Update page icon in title bar', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create document, board, grid and calendar views
|
||||
for (final value in ViewLayoutPB.values) {
|
||||
await tester.createNewPageWithName(
|
||||
name: value.name,
|
||||
parentName: gettingStarted,
|
||||
layout: value,
|
||||
);
|
||||
|
||||
// update its icon
|
||||
await tester.updatePageIconInTitleBarByName(
|
||||
name: value.name,
|
||||
layout: value,
|
||||
icon: emoji,
|
||||
);
|
||||
|
||||
tester.expectViewHasIcon(
|
||||
value.name,
|
||||
value,
|
||||
emoji,
|
||||
);
|
||||
|
||||
tester.expectViewTitleHasIcon(
|
||||
value.name,
|
||||
value,
|
||||
emoji,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
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;
|
||||
import 'sidebar_icon_test.dart' as sidebar_icon_test;
|
||||
import 'sidebar_test.dart' as sidebar_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -11,4 +12,5 @@ void startTesting() {
|
||||
sidebar_test.main();
|
||||
sidebar_expanded_test.main();
|
||||
sidebar_favorite_test.main();
|
||||
sidebar_icon_test.main();
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/env/env.dart';
|
||||
import 'package:appflowy/startup/entry_point.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/presentation/presentation.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
|
||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||
import 'package:flowy_infra/uuid.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@@ -81,9 +83,15 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
}
|
||||
|
||||
Future<void> waitUntilSignInPageShow() async {
|
||||
final finder = find.byType(GoButton);
|
||||
await pumpUntilFound(finder);
|
||||
expect(finder, findsOneWidget);
|
||||
if (isCloudEnabled) {
|
||||
final finder = find.byType(SignInAnonymousButton);
|
||||
await pumpUntilFound(finder);
|
||||
expect(finder, findsOneWidget);
|
||||
} else {
|
||||
final finder = find.byType(GoButton);
|
||||
await pumpUntilFound(finder);
|
||||
expect(finder, findsOneWidget);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> pumpUntilFound(
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/core/config/kv.dart';
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/presentation/screens/screens.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
|
||||
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/workspace/presentation/settings/widgets/settings_language_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@@ -20,13 +25,25 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'emoji.dart';
|
||||
import 'util.dart';
|
||||
|
||||
extension CommonOperations on WidgetTester {
|
||||
/// Tap the GetStart button on the launch page.
|
||||
Future<void> tapGoButton() async {
|
||||
// local version
|
||||
final goButton = find.byType(GoButton);
|
||||
await tapButton(goButton);
|
||||
if (goButton.evaluate().isNotEmpty) {
|
||||
await tapButton(goButton);
|
||||
} else {
|
||||
// cloud version
|
||||
final anonymousButton = find.byType(SignInAnonymousButton);
|
||||
await tapButton(anonymousButton);
|
||||
}
|
||||
|
||||
if (Platform.isWindows) {
|
||||
await pumpAndSettle(const Duration(milliseconds: 200));
|
||||
}
|
||||
}
|
||||
|
||||
/// Tap the + button on the home page.
|
||||
@@ -230,7 +247,7 @@ extension CommonOperations on WidgetTester {
|
||||
final okButton = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is PrimaryTextButton &&
|
||||
widget.label == LocaleKeys.button_OK.tr(),
|
||||
widget.label == LocaleKeys.button_ok.tr(),
|
||||
);
|
||||
await tapButton(okButton);
|
||||
}
|
||||
@@ -428,6 +445,47 @@ extension CommonOperations on WidgetTester {
|
||||
);
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
// update the page icon in the sidebar
|
||||
Future<void> updatePageIconInSidebarByName({
|
||||
required String name,
|
||||
required String parentName,
|
||||
required ViewLayoutPB layout,
|
||||
required String icon,
|
||||
}) async {
|
||||
final iconButton = find.descendant(
|
||||
of: findPageName(
|
||||
name,
|
||||
layout: layout,
|
||||
parentName: parentName,
|
||||
),
|
||||
matching:
|
||||
find.byTooltip(LocaleKeys.document_plugins_cover_changeIcon.tr()),
|
||||
);
|
||||
await tapButton(iconButton);
|
||||
await tapEmoji(icon);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
// update the page icon in the sidebar
|
||||
Future<void> updatePageIconInTitleBarByName({
|
||||
required String name,
|
||||
required ViewLayoutPB layout,
|
||||
required String icon,
|
||||
}) async {
|
||||
await openPage(
|
||||
name,
|
||||
layout: layout,
|
||||
);
|
||||
final title = find.descendant(
|
||||
of: find.byType(ViewTitleBar),
|
||||
matching: find.text(name),
|
||||
);
|
||||
await tapButton(title);
|
||||
await tapButton(find.byType(EmojiPickerButton));
|
||||
await tapEmoji(icon);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewLayoutPBTest on ViewLayoutPB {
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
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/board/presentation/widgets/board_column_header.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_day.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_event_card.dart';
|
||||
@@ -38,7 +39,6 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar
|
||||
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/field/grid_property.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_cell_editor.dart';
|
||||
@@ -52,15 +52,15 @@ 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/row_property.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/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/setting/setting_property_list.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.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:appflowy_board/appflowy_board.dart';
|
||||
import 'package:calendar_view/calendar_view.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@@ -530,7 +530,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
|
||||
final widget = this.widget<ChecklistItem>(task);
|
||||
assert(
|
||||
widget.option.data.name == name && widget.option.isSelected == isChecked,
|
||||
widget.task.data.name == name && widget.task.isSelected == isChecked,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -619,7 +619,6 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
|
||||
Future<void> openEmojiPicker() async {
|
||||
await tapButton(find.byType(EmojiPickerButton));
|
||||
await tapButton(find.byType(EmojiSelectionMenu));
|
||||
}
|
||||
|
||||
Future<void> tapDateCellInRowDetailPage() async {
|
||||
@@ -748,7 +747,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
final field = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is PrimaryTextButton &&
|
||||
widget.label == LocaleKeys.button_OK.tr(),
|
||||
widget.label == LocaleKeys.button_ok.tr(),
|
||||
);
|
||||
await tapButton(field);
|
||||
}
|
||||
@@ -1132,7 +1131,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
|
||||
/// Should call [tapDatabaseSettingButton] first.
|
||||
Future<void> tapViewPropertiesButton() async {
|
||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
||||
final findSettingItem = find.byType(DatabaseSettingListPopover);
|
||||
final findLayoutButton = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is FlowyText &&
|
||||
@@ -1149,7 +1148,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
|
||||
/// Should call [tapDatabaseSettingButton] first.
|
||||
Future<void> tapDatabaseLayoutButton() async {
|
||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
||||
final findSettingItem = find.byType(DatabaseSettingListPopover);
|
||||
final findLayoutButton = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is FlowyText &&
|
||||
@@ -1165,7 +1164,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
}
|
||||
|
||||
Future<void> tapCalendarLayoutSettingButton() async {
|
||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
||||
final findSettingItem = find.byType(DatabaseSettingListPopover);
|
||||
final findLayoutButton = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is FlowyText &&
|
||||
@@ -1302,7 +1301,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await doubleTapAt(location);
|
||||
}
|
||||
|
||||
Future<void> openCalendarEvent({required index, DateTime? date}) async {
|
||||
Future<void> openCalendarEvent({required int index, DateTime? date}) async {
|
||||
final findDayCell = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is CalendarDayCard &&
|
||||
@@ -1393,6 +1392,84 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapButton(findCreateButton);
|
||||
}
|
||||
|
||||
void assertNumberOfGroups(int number) {
|
||||
final groups = find.byType(BoardColumnHeader, skipOffstage: false);
|
||||
expect(groups, findsNWidgets(number));
|
||||
}
|
||||
|
||||
Future<void> scrollBoardToEnd() async {
|
||||
final scrollable = find
|
||||
.descendant(
|
||||
of: find.byType(AppFlowyBoard),
|
||||
matching: find.byWidgetPredicate(
|
||||
(widget) => widget is Scrollable && widget.axis == Axis.horizontal,
|
||||
),
|
||||
)
|
||||
.first;
|
||||
await scrollUntilVisible(
|
||||
find.byType(BoardTrailing),
|
||||
300,
|
||||
scrollable: scrollable,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> tapNewGroupButton() async {
|
||||
final button = find.descendant(
|
||||
of: find.byType(BoardTrailing),
|
||||
matching: find.byWidgetPredicate(
|
||||
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.add_s,
|
||||
),
|
||||
);
|
||||
expect(button, findsOneWidget);
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
void assertNewGroupTextField(bool isVisible) {
|
||||
final textField = find.descendant(
|
||||
of: find.byType(BoardTrailing),
|
||||
matching: find.byType(TextField),
|
||||
);
|
||||
if (isVisible) {
|
||||
expect(textField, findsOneWidget);
|
||||
} else {
|
||||
expect(textField, findsNothing);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> enterNewGroupName(String name, {required bool submit}) async {
|
||||
final textField = find.descendant(
|
||||
of: find.byType(BoardTrailing),
|
||||
matching: find.byType(TextField),
|
||||
);
|
||||
await enterText(textField, name);
|
||||
await pumpAndSettle();
|
||||
if (submit) {
|
||||
await testTextInput.receiveAction(TextInputAction.done);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> clearNewGroupTextField() async {
|
||||
final textField = find.descendant(
|
||||
of: find.byType(BoardTrailing),
|
||||
matching: find.byType(TextField),
|
||||
);
|
||||
await tapButton(
|
||||
find.descendant(
|
||||
of: textField,
|
||||
matching: find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is FlowySvg && widget.svg == FlowySvgs.close_filled_m,
|
||||
),
|
||||
),
|
||||
);
|
||||
final textFieldWidget = widget<TextField>(textField);
|
||||
assert(
|
||||
textFieldWidget.controller != null &&
|
||||
textFieldWidget.controller!.text.isEmpty,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> tapTabBarLinkedViewByViewName(String name) async {
|
||||
final viewButton = findTabBarLinkViewByViewName(name);
|
||||
await tapButton(viewButton);
|
||||
@@ -1433,7 +1510,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
final field = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is PrimaryTextButton &&
|
||||
widget.label == LocaleKeys.button_OK.tr(),
|
||||
widget.label == LocaleKeys.button_ok.tr(),
|
||||
);
|
||||
await tapButton(field);
|
||||
}
|
||||
@@ -1453,7 +1530,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
final okButton = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is PrimaryTextButton &&
|
||||
widget.label == LocaleKeys.button_OK.tr(),
|
||||
widget.label == LocaleKeys.button_ok.tr(),
|
||||
);
|
||||
await tapButton(okButton);
|
||||
}
|
||||
@@ -1505,7 +1582,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
) async {
|
||||
final field = find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is GridPropertyCell && widget.fieldInfo.name == fieldName,
|
||||
widget is DatabasePropertyCell && widget.fieldInfo.name == fieldName,
|
||||
);
|
||||
final toggleVisibilityButton =
|
||||
find.descendant(of: field, matching: find.byType(FlowyIconButton));
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_add_button.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/cover_editor.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/custom_cover_picker.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/plugins/document/presentation/editor_plugins/header/emoji_popover.dart';
|
||||
import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:emoji_mart/emoji_mart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@@ -54,7 +57,27 @@ class EditorOperations {
|
||||
await tester.tapButtonWithName(
|
||||
LocaleKeys.document_plugins_cover_addIcon.tr(),
|
||||
);
|
||||
expect(find.byType(EmojiPopover), findsOneWidget);
|
||||
expect(find.byType(FlowyEmojiPicker), findsOneWidget);
|
||||
}
|
||||
|
||||
Future<void> tapGettingStartedIcon() async {
|
||||
await tester.tapButton(
|
||||
find.descendant(
|
||||
of: find.byType(DocumentHeaderNodeWidget),
|
||||
matching: find.findTextInFlowyText('⭐️'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Taps on the 'Skin tone' button
|
||||
///
|
||||
/// Must call [tapAddIconButton] first.
|
||||
Future<void> changeEmojiSkinTone(EmojiSkinTone skinTone) async {
|
||||
await tester.tapButton(
|
||||
find.byTooltip(LocaleKeys.emoji_selectSkinTone.tr()),
|
||||
);
|
||||
final skinToneButton = find.byKey(emojiSkinToneKey(skinTone.icon));
|
||||
await tester.tapButton(skinToneButton);
|
||||
}
|
||||
|
||||
/// Taps the 'Remove Icon' button in the cover toolbar and the icon popover
|
||||
@@ -62,7 +85,10 @@ class EditorOperations {
|
||||
Finder button =
|
||||
find.text(LocaleKeys.document_plugins_cover_removeIcon.tr());
|
||||
if (isInPicker) {
|
||||
button = find.descendant(of: find.byType(EmojiPopover), matching: button);
|
||||
button = find.descendant(
|
||||
of: find.byType(FlowyIconPicker),
|
||||
matching: button,
|
||||
);
|
||||
}
|
||||
|
||||
await tester.tapButton(button);
|
||||
@@ -143,7 +169,7 @@ class EditorOperations {
|
||||
await tester.ime.insertCharacter('/');
|
||||
}
|
||||
|
||||
/// trigger the slash command (selection menu)
|
||||
/// trigger the mention (@) command
|
||||
Future<void> showAtMenu() async {
|
||||
await tester.ime.insertCharacter('@');
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:emoji_mart/emoji_mart.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'base.dart';
|
||||
|
||||
extension EmojiTestExtension on WidgetTester {
|
||||
/// Must call [openEmojiPicker] first
|
||||
Future<void> switchToEmojiList() async {
|
||||
final icon = find.byIcon(Icons.tag_faces);
|
||||
await tapButton(icon);
|
||||
}
|
||||
|
||||
Future<void> tapEmoji(String emoji) async {
|
||||
final emojiWidget = find.text(emoji);
|
||||
final emojiWidget = find.descendant(
|
||||
of: find.byType(EmojiPicker),
|
||||
matching: find.text(emoji),
|
||||
);
|
||||
await tapButton(emojiWidget);
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,14 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emo
|
||||
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/view/view_item.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.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 gettingStarted = '⭐️ Getting started';
|
||||
const String gettingStarted = 'Getting started';
|
||||
|
||||
extension Expectation on WidgetTester {
|
||||
/// Expect to see the home page and with a default read me page.
|
||||
@@ -108,6 +109,13 @@ extension Expectation on WidgetTester {
|
||||
expect(iconWidget, findsOneWidget);
|
||||
}
|
||||
|
||||
void expectDocumentIconNotNull() {
|
||||
final iconWidget = find.byWidgetPredicate(
|
||||
(widget) => widget is EmojiIconWidget && widget.emoji.isNotEmpty,
|
||||
);
|
||||
expect(iconWidget, findsOneWidget);
|
||||
}
|
||||
|
||||
void expectToSeeDocumentCover(CoverType type) {
|
||||
final findCover = find.byWidgetPredicate(
|
||||
(widget) => widget is DocumentCover && widget.coverType == type,
|
||||
@@ -157,7 +165,7 @@ extension Expectation on WidgetTester {
|
||||
}) {
|
||||
return find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is ViewItem &&
|
||||
widget is SingleInnerViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite &&
|
||||
widget.view.name == name &&
|
||||
@@ -166,6 +174,15 @@ extension Expectation on WidgetTester {
|
||||
);
|
||||
}
|
||||
|
||||
Finder findAllFavoritePages() {
|
||||
return find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is SingleInnerViewItem &&
|
||||
widget.view.isFavorite &&
|
||||
widget.categoryType == FolderCategoryType.favorite,
|
||||
);
|
||||
}
|
||||
|
||||
Finder findPageName(
|
||||
String name, {
|
||||
ViewLayoutPB layout = ViewLayoutPB.Document,
|
||||
@@ -193,4 +210,24 @@ extension Expectation on WidgetTester {
|
||||
matching: findPageName(name, layout: layout),
|
||||
);
|
||||
}
|
||||
|
||||
void expectViewHasIcon(String name, ViewLayoutPB layout, String emoji) {
|
||||
final pageName = findPageName(
|
||||
name,
|
||||
layout: layout,
|
||||
);
|
||||
final icon = find.descendant(
|
||||
of: pageName,
|
||||
matching: find.text(emoji),
|
||||
);
|
||||
expect(icon, findsOneWidget);
|
||||
}
|
||||
|
||||
void expectViewTitleHasIcon(String name, ViewLayoutPB layout, String emoji) {
|
||||
final icon = find.descendant(
|
||||
of: find.byType(ViewTitleBar),
|
||||
matching: find.text(emoji),
|
||||
);
|
||||
expect(icon, findsOneWidget);
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,13 @@ PODS:
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
- image_gallery_saver (2.0.2):
|
||||
- Flutter
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
- integration_test (0.0.1):
|
||||
- Flutter
|
||||
- irondash_engine_context (0.0.1):
|
||||
@@ -68,6 +75,9 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- sign_in_with_apple (0.0.1):
|
||||
- Flutter
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FMDB (>= 2.7.5)
|
||||
- super_native_extensions (0.0.1):
|
||||
- Flutter
|
||||
- SwiftyGif (5.4.3)
|
||||
@@ -86,6 +96,8 @@ DEPENDENCIES:
|
||||
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
@@ -93,6 +105,7 @@ DEPENDENCIES:
|
||||
- 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`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
||||
@@ -101,6 +114,7 @@ SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- FMDB
|
||||
- ReachabilitySwift
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
@@ -123,6 +137,10 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
image_gallery_saver:
|
||||
:path: ".symlinks/plugins/image_gallery_saver/ios"
|
||||
image_picker_ios:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
integration_test:
|
||||
:path: ".symlinks/plugins/integration_test/ios"
|
||||
irondash_engine_context:
|
||||
@@ -137,6 +155,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sign_in_with_apple:
|
||||
:path: ".symlinks/plugins/sign_in_with_apple/ios"
|
||||
sqflite:
|
||||
:path: ".symlinks/plugins/sqflite/ios"
|
||||
super_native_extensions:
|
||||
:path: ".symlinks/plugins/super_native_extensions/ios"
|
||||
url_launcher_ios:
|
||||
@@ -147,7 +167,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
|
||||
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
|
||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
|
||||
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
|
||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
@@ -155,6 +175,9 @@ SPEC CHECKSUMS:
|
||||
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
|
||||
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
|
||||
integration_test: 13825b8a9334a850581300559b8839134b124670
|
||||
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
|
||||
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||
@@ -164,12 +187,13 @@ SPEC CHECKSUMS:
|
||||
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
|
||||
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
|
||||
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
|
||||
super_native_extensions: 49e897b6039bb784226e7354e502a3c68e1659b5
|
||||
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
|
||||
super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7
|
||||
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
|
||||
|
||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||
PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.12.1
|
||||
@@ -13,22 +13,9 @@
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
9D1D47ADD7F5DE8237063BCA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 197F72694BED43249F1523E8 /* Pods_Runner.framework */; };
|
||||
FB3C2A642AE0D57700490715 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 197F72694BED43249F1523E8 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
@@ -47,6 +34,7 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FBE00AD62AE8E46A006B563F /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -54,7 +42,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9D1D47ADD7F5DE8237063BCA /* Pods_Runner.framework in Frameworks */,
|
||||
FB3C2A642AE0D57700490715 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -102,6 +90,7 @@
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBE00AD62AE8E46A006B563F /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
@@ -121,7 +110,6 @@
|
||||
580A1ED8E012CA1552E5EFD3 /* Pods-Runner.release.xcconfig */,
|
||||
4C2CB38DA64605A62D45B098 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -137,7 +125,6 @@
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
08FAA63113168DEC7FB74204 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
@@ -358,14 +345,26 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.appflowy;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRIP_STYLE = "non-global";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
@@ -482,15 +481,27 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.appflowy;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRIP_STYLE = "non-global";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -501,14 +512,26 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.appflowy;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRIP_STYLE = "non-global";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
@@ -1,122 +1 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Icon-App-1024x1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]}
|
||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,64 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>appflowy_flutter</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string></string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>appflowy-flutter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
<dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>AppFlowy requires access to the camera.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>AppFlowy requires access to the photo library.</string>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true />
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
</array>
|
||||
<key>FLTEnableImpeller</key>
|
||||
<false />
|
||||
<key>CFBundleName</key>
|
||||
<string>AppFlowy</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string></string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>appflowy-flutter</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true />
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true />
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false />
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -27,8 +27,8 @@ class NetworkListener {
|
||||
return _updateConnectionStatus(result);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_connectivitySubscription.cancel();
|
||||
Future<void> stop() async {
|
||||
await _connectivitySubscription.cancel();
|
||||
}
|
||||
|
||||
Future<void> _updateConnectionStatus(ConnectivityResult result) async {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
|
||||
// Run `dart run build_runner build` to generate the json serialization If the
|
||||
// file `env_serde.g.dart` is existed, delete it first.
|
||||
//
|
||||
// the file `env_serde.g.dart` will be generated in the same directory.
|
||||
part 'env_serde.g.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
part 'backend_env.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AppFlowyEnv {
|
||||
@@ -101,7 +101,10 @@ CloudType currentCloudType() {
|
||||
final value = Env.cloudType;
|
||||
if (value == 1) {
|
||||
if (Env.supabaseUrl.isEmpty || Env.supabaseAnonKey.isEmpty) {
|
||||
Log.error("Supabase is not configured");
|
||||
Log.error(
|
||||
"Supabase is not configured correctly. The values are: "
|
||||
"url: ${Env.supabaseUrl}, anonKey: ${Env.supabaseAnonKey}",
|
||||
);
|
||||
return CloudType.unknown;
|
||||
} else {
|
||||
return CloudType.supabase;
|
||||
@@ -109,8 +112,13 @@ CloudType currentCloudType() {
|
||||
}
|
||||
|
||||
if (value == 2) {
|
||||
if (Env.afCloudBaseUrl.isEmpty || Env.afCloudWSBaseUrl.isEmpty) {
|
||||
Log.error("AppFlowy cloud is not configured");
|
||||
if (Env.afCloudBaseUrl.isEmpty ||
|
||||
Env.afCloudWSBaseUrl.isEmpty ||
|
||||
Env.afCloudGoTrueUrl.isEmpty) {
|
||||
Log.error(
|
||||
"AppFlowy cloud is not configured correctly. The values are: "
|
||||
"baseUrl: ${Env.afCloudBaseUrl}, wsBaseUrl: ${Env.afCloudWSBaseUrl}, gotrueUrl: ${Env.afCloudGoTrueUrl}",
|
||||
);
|
||||
return CloudType.unknown;
|
||||
} else {
|
||||
return CloudType.appflowyCloud;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_board_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_calendar_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_grid_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/presentation.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.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:go_router/go_router.dart';
|
||||
|
||||
class MobileRouterRecord {
|
||||
PropertyValueNotifier<String> lastPushedRouter =
|
||||
PropertyValueNotifier<String>('');
|
||||
}
|
||||
|
||||
extension MobileRouter on BuildContext {
|
||||
Future<void> pushView(ViewPB view) async {
|
||||
await FolderEventSetLatestView(ViewIdPB(value: view.id)).send();
|
||||
getIt<MobileRouterRecord>().lastPushedRouter.value = view.routeName;
|
||||
push(
|
||||
Uri(
|
||||
path: view.routeName,
|
||||
queryParameters: view.queryParameters,
|
||||
).toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension on ViewPB {
|
||||
String get routeName {
|
||||
switch (layout) {
|
||||
case ViewLayoutPB.Document:
|
||||
return MobileEditorScreen.routeName;
|
||||
case ViewLayoutPB.Grid:
|
||||
return MobileGridScreen.routeName;
|
||||
case ViewLayoutPB.Calendar:
|
||||
return MobileCalendarScreen.routeName;
|
||||
case ViewLayoutPB.Board:
|
||||
return MobileBoardScreen.routeName;
|
||||
default:
|
||||
throw UnimplementedError('routeName for $this is not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> get queryParameters {
|
||||
switch (layout) {
|
||||
case ViewLayoutPB.Document:
|
||||
return {
|
||||
MobileEditorScreen.viewId: id,
|
||||
MobileEditorScreen.viewTitle: name,
|
||||
};
|
||||
case ViewLayoutPB.Grid:
|
||||
return {
|
||||
MobileGridScreen.viewId: id,
|
||||
MobileGridScreen.viewTitle: name,
|
||||
};
|
||||
case ViewLayoutPB.Calendar:
|
||||
return {
|
||||
MobileCalendarScreen.viewId: id,
|
||||
MobileCalendarScreen.viewTitle: name,
|
||||
};
|
||||
case ViewLayoutPB.Board:
|
||||
return {
|
||||
MobileBoardScreen.viewId: id,
|
||||
MobileBoardScreen.viewTitle: name,
|
||||
};
|
||||
default:
|
||||
throw UnimplementedError(
|
||||
'queryParameters for $this is not implemented',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,98 @@
|
||||
// ThemeData in mobile
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:flowy_infra/colorscheme/colorscheme.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
ThemeData getMobileThemeData() {
|
||||
const mobileColorTheme = ColorScheme(
|
||||
brightness: Brightness.light,
|
||||
primary: Color(0xFF2DA2F6), //primary 100
|
||||
onPrimary: Colors.white,
|
||||
// TODO(yijing): add color later
|
||||
secondary: Colors.white,
|
||||
onSecondary: Colors.white,
|
||||
error: Color(0xffFB006D),
|
||||
onError: Color(0xffFB006D),
|
||||
background: Colors.white,
|
||||
onBackground: Color(0xff2F3030), // title text
|
||||
outline: Color(0xffBDC0C5), //caption
|
||||
//Snack bar
|
||||
surface: Colors.white,
|
||||
onSurface: Color(0xff2F3030), // title text
|
||||
);
|
||||
const _primaryColor = Color(0xFF2DA2F6); //primary 100
|
||||
const _onBackgroundColor = Color(0xff2F3030); // text/title color
|
||||
const _onSurfaceColor = Color(0xff676666); // text/body color
|
||||
const _onSecondaryColor = Color(0xFFC5C7CB); // text/body2 color
|
||||
|
||||
// TODO(yijing): improve theme color before release
|
||||
ThemeData getMobileThemeData(
|
||||
Brightness brightness,
|
||||
FlowyColorScheme theme,
|
||||
String fontFamily,
|
||||
String monospaceFontFamily,
|
||||
) {
|
||||
final mobileColorTheme = (brightness == Brightness.light)
|
||||
? ColorScheme(
|
||||
brightness: brightness,
|
||||
primary: _primaryColor,
|
||||
onPrimary: Colors.white,
|
||||
// TODO(yijing): add color later
|
||||
secondary: Colors.white,
|
||||
onSecondary: _onSecondaryColor,
|
||||
error: const Color(0xffFB006D),
|
||||
onError: const Color(0xffFB006D),
|
||||
background: Colors.white,
|
||||
onBackground: _onBackgroundColor,
|
||||
outline: const Color(0xffBDC0C5), //caption
|
||||
outlineVariant: const Color(0xffCBD5E0).withOpacity(0.24),
|
||||
//Snack bar
|
||||
surface: Colors.white,
|
||||
onSurface: _onSurfaceColor, // text/body color
|
||||
surfaceVariant: const Color.fromARGB(255, 216, 216, 216),
|
||||
)
|
||||
: ColorScheme(
|
||||
brightness: brightness,
|
||||
primary: _primaryColor,
|
||||
onPrimary: Colors.white,
|
||||
// TODO(yijing): add color later
|
||||
secondary: Colors.black,
|
||||
onSecondary: Colors.white,
|
||||
error: const Color(0xffFB006D),
|
||||
onError: const Color(0xffFB006D),
|
||||
background: const Color(0xff1C1C1E), // BG/Secondary color
|
||||
onBackground: Colors.white,
|
||||
outline: const Color(0xff96989C), //caption
|
||||
outlineVariant: Colors.black,
|
||||
//Snack bar
|
||||
surface: const Color(0xff2F3030),
|
||||
onSurface: const Color(0xffC5C6C7), // text/body color
|
||||
);
|
||||
|
||||
return ThemeData(
|
||||
// color
|
||||
primaryColor: mobileColorTheme.primary, //primary 100
|
||||
primaryColorLight: const Color(0xFF57B5F8), //primary 80
|
||||
dividerColor: mobileColorTheme.outline, //caption
|
||||
hintColor: mobileColorTheme.outline,
|
||||
disabledColor: mobileColorTheme.outline,
|
||||
scaffoldBackgroundColor: mobileColorTheme.background,
|
||||
appBarTheme: AppBarTheme(
|
||||
foregroundColor: mobileColorTheme.onBackground,
|
||||
backgroundColor: mobileColorTheme.background,
|
||||
elevation: 0,
|
||||
centerTitle: false,
|
||||
titleTextStyle: TextStyle(
|
||||
fontFamily: 'Poppins',
|
||||
color: mobileColorTheme.onBackground,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.05,
|
||||
),
|
||||
shadowColor: mobileColorTheme.outlineVariant,
|
||||
),
|
||||
radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return mobileColorTheme.primary;
|
||||
}
|
||||
return mobileColorTheme.outline;
|
||||
}),
|
||||
),
|
||||
// button
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
fixedSize: MaterialStateProperty.all(const Size.fromHeight(48)),
|
||||
elevation: MaterialStateProperty.all(0),
|
||||
textStyle: MaterialStateProperty.all(
|
||||
const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
shadowColor: MaterialStateProperty.all(null),
|
||||
backgroundColor: MaterialStateProperty.resolveWith<Color>(
|
||||
(Set<MaterialState> states) {
|
||||
@@ -55,10 +107,16 @@ ThemeData getMobileThemeData() {
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
textStyle: MaterialStateProperty.all(
|
||||
const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
foregroundColor: MaterialStateProperty.all(
|
||||
mobileColorTheme.onBackground,
|
||||
),
|
||||
backgroundColor: MaterialStateProperty.all(Colors.white),
|
||||
backgroundColor: MaterialStateProperty.all(mobileColorTheme.background),
|
||||
shape: MaterialStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
@@ -71,7 +129,7 @@ ThemeData getMobileThemeData() {
|
||||
),
|
||||
),
|
||||
padding: MaterialStateProperty.all(
|
||||
const EdgeInsets.symmetric(horizontal: 16),
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
|
||||
),
|
||||
// splash color
|
||||
overlayColor: MaterialStateProperty.all(
|
||||
@@ -79,10 +137,19 @@ ThemeData getMobileThemeData() {
|
||||
),
|
||||
),
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
textStyle: MaterialStateProperty.all(
|
||||
const TextStyle(
|
||||
fontFamily: 'Poppins',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// text
|
||||
fontFamily: 'Poppins',
|
||||
textTheme: const TextTheme(
|
||||
displayLarge: TextStyle(
|
||||
textTheme: TextTheme(
|
||||
displayLarge: const TextStyle(
|
||||
color: Color(0xFF57B5F8),
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -90,7 +157,7 @@ ThemeData getMobileThemeData() {
|
||||
letterSpacing: 0.16,
|
||||
),
|
||||
displayMedium: TextStyle(
|
||||
color: Color(0xff2F3030),
|
||||
color: mobileColorTheme.onBackground,
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.20,
|
||||
@@ -98,33 +165,46 @@ ThemeData getMobileThemeData() {
|
||||
),
|
||||
// H1 Semi 26
|
||||
displaySmall: TextStyle(
|
||||
color: Color(0xFF2F3030),
|
||||
fontSize: 26,
|
||||
color: mobileColorTheme.onBackground,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.10,
|
||||
letterSpacing: 0.13,
|
||||
),
|
||||
// body2 14 Regular
|
||||
bodyMedium: TextStyle(
|
||||
color: Color(0xFFC5C7CB),
|
||||
color: mobileColorTheme.onBackground,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.20,
|
||||
letterSpacing: 0.07,
|
||||
),
|
||||
// blue text button
|
||||
// Trash empty title
|
||||
labelLarge: TextStyle(
|
||||
color: mobileColorTheme.onBackground,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: -0.3,
|
||||
),
|
||||
// setting item title
|
||||
labelMedium: TextStyle(
|
||||
color: Color(0xFF2DA2F6),
|
||||
fontSize: 14,
|
||||
color: mobileColorTheme.onSurface,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.20,
|
||||
),
|
||||
// setting group title
|
||||
labelSmall: TextStyle(
|
||||
color: mobileColorTheme.onBackground,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.05,
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
contentPadding: const EdgeInsets.all(8),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
width: 2,
|
||||
color: Color(0xFF2DA2F6), //primary 100
|
||||
color: _primaryColor,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
@@ -136,13 +216,55 @@ ThemeData getMobileThemeData() {
|
||||
borderSide: BorderSide(color: mobileColorTheme.error),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Color(0xffBDC0C5), //caption
|
||||
color: mobileColorTheme.outline,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
),
|
||||
colorScheme: mobileColorTheme,
|
||||
indicatorColor: Colors.blue,
|
||||
extensions: [
|
||||
AFThemeExtension(
|
||||
warning: theme.yellow,
|
||||
success: theme.green,
|
||||
tint1: theme.tint1,
|
||||
tint2: theme.tint2,
|
||||
tint3: theme.tint3,
|
||||
tint4: theme.tint4,
|
||||
tint5: theme.tint5,
|
||||
tint6: theme.tint6,
|
||||
tint7: theme.tint7,
|
||||
tint8: theme.tint8,
|
||||
tint9: theme.tint9,
|
||||
textColor: theme.text,
|
||||
greyHover: theme.hoverBG1,
|
||||
greySelect: theme.bg3,
|
||||
lightGreyHover: theme.hoverBG3,
|
||||
toggleOffFill: theme.shader5,
|
||||
progressBarBGColor: theme.progressBarBGColor,
|
||||
toggleButtonBGColor: theme.toggleButtonBGColor,
|
||||
calendarWeekendBGColor: theme.calendarWeekendBGColor,
|
||||
gridRowCountColor: theme.gridRowCountColor,
|
||||
code: getFontStyle(
|
||||
fontFamily: monospaceFontFamily,
|
||||
fontColor: theme.shader3,
|
||||
),
|
||||
callout: getFontStyle(
|
||||
fontFamily: fontFamily,
|
||||
fontSize: FontSizes.s11,
|
||||
fontColor: theme.shader3,
|
||||
),
|
||||
calloutBGColor: theme.hoverBG3,
|
||||
tableCellBGColor: theme.surface,
|
||||
caption: getFontStyle(
|
||||
fontFamily: fontFamily,
|
||||
fontSize: FontSizes.s11,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: theme.hint,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppBarBackButton extends StatelessWidget {
|
||||
const AppBarBackButton({
|
||||
super.key,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBarButton(
|
||||
onTap: onTap,
|
||||
child: const Icon(Icons.arrow_back_ios_new),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppBarMoreButton extends StatelessWidget {
|
||||
const AppBarMoreButton({
|
||||
super.key,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final void Function(BuildContext context) onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBarButton(
|
||||
onTap: () => onTap(context),
|
||||
child: const Icon(
|
||||
// replace with flowy icon
|
||||
Icons.more_horiz_sharp,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppBarButton extends StatelessWidget {
|
||||
const AppBarButton({
|
||||
super.key,
|
||||
this.extent = 16.0,
|
||||
required this.onTap,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
// used to extend the hit area of the more button
|
||||
final double extent;
|
||||
|
||||
final VoidCallback onTap;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
enableFeedback: true,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(extent),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FlowyBoxContainer extends StatelessWidget {
|
||||
const FlowyBoxContainer({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 6.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.onSecondary,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart';
|
||||
import 'package:appflowy/plugins/document/document_page.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:dartz/dartz.dart' hide State;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class MobileViewPage extends StatefulWidget {
|
||||
const MobileViewPage({
|
||||
super.key,
|
||||
required this.id,
|
||||
this.title,
|
||||
required this.viewLayout,
|
||||
});
|
||||
|
||||
/// view id
|
||||
final String id;
|
||||
final String? title;
|
||||
final ViewLayoutPB viewLayout;
|
||||
|
||||
@override
|
||||
State<MobileViewPage> createState() => _MobileViewPageState();
|
||||
}
|
||||
|
||||
class _MobileViewPageState extends State<MobileViewPage> {
|
||||
late final Future<Either<ViewPB, FlowyError>> future;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
future = ViewBackendService.getView(widget.id);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: future,
|
||||
builder: (context, state) {
|
||||
Widget body;
|
||||
ViewPB? viewPB;
|
||||
final actions = <Widget>[];
|
||||
if (state.connectionState != ConnectionState.done) {
|
||||
body = const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else if (!state.hasData) {
|
||||
body = FlowyMobileStateContainer.error(
|
||||
emoji: '😔',
|
||||
title: LocaleKeys.error_weAreSorry.tr(),
|
||||
description: LocaleKeys.error_loadingViewError.tr(),
|
||||
errorMsg: state.error.toString(),
|
||||
);
|
||||
} else {
|
||||
body = state.data!.fold((view) {
|
||||
viewPB = view;
|
||||
actions.add(_buildAppBarMoreButton(view));
|
||||
return view.plugin().widgetBuilder.buildWidget(shrinkWrap: false);
|
||||
}, (error) {
|
||||
return FlowyMobileStateContainer.error(
|
||||
emoji: '😔',
|
||||
title: LocaleKeys.error_weAreSorry.tr(),
|
||||
description: LocaleKeys.error_loadingViewError.tr(),
|
||||
errorMsg: error.toString(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (viewPB != null) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (_) =>
|
||||
FavoriteBloc()..add(const FavoriteEvent.initial()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (_) =>
|
||||
ViewBloc(view: viewPB!)..add(const ViewEvent.initial()),
|
||||
),
|
||||
],
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final view = context.watch<ViewBloc>().state.view;
|
||||
return _buildApp(
|
||||
view,
|
||||
actions,
|
||||
body,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return _buildApp(
|
||||
null,
|
||||
[],
|
||||
body,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildApp(ViewPB? view, List<Widget> actions, Widget child) {
|
||||
final icon = view?.icon.value;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
titleSpacing: 0,
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (icon != null)
|
||||
FlowyText(
|
||||
'$icon ',
|
||||
fontSize: 22.0,
|
||||
),
|
||||
Expanded(
|
||||
child: FlowyText.regular(
|
||||
view?.name ?? widget.title ?? '',
|
||||
fontSize: 14.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
actions: actions,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppBarMoreButton(ViewPB view) {
|
||||
return AppBarMoreButton(
|
||||
onTap: (context) {
|
||||
showMobileBottomSheet(
|
||||
context: context,
|
||||
builder: (_) => _buildViewPageBottomSheet(context),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildViewPageBottomSheet(BuildContext context) {
|
||||
final view = context.read<ViewBloc>().state.view;
|
||||
return ViewPageBottomSheet(
|
||||
view: view,
|
||||
onAction: (action) {
|
||||
switch (action) {
|
||||
case MobileViewBottomSheetBodyAction.duplicate:
|
||||
context.pop();
|
||||
context.read<ViewBloc>().add(const ViewEvent.duplicate());
|
||||
// show toast
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.share:
|
||||
// unimplemented
|
||||
context.pop();
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.delete:
|
||||
// pop to home page
|
||||
context
|
||||
..pop()
|
||||
..pop();
|
||||
context.read<ViewBloc>().add(const ViewEvent.delete());
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.addToFavorites:
|
||||
case MobileViewBottomSheetBodyAction.removeFromFavorites:
|
||||
context.pop();
|
||||
context.read<FavoriteBloc>().add(FavoriteEvent.toggle(view));
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.undo:
|
||||
context.dispatchNotification(
|
||||
const EditorNotification(type: EditorNotificationType.redo),
|
||||
);
|
||||
context.pop();
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.redo:
|
||||
context.pop();
|
||||
context.dispatchNotification(EditorNotification.redo());
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.helpCenter:
|
||||
// unimplemented
|
||||
context.pop();
|
||||
break;
|
||||
case MobileViewBottomSheetBodyAction.rename:
|
||||
// no need to implement, rename is handled by the onRename callback.
|
||||
throw UnimplementedError();
|
||||
}
|
||||
},
|
||||
onRename: (name) {
|
||||
if (name != view.name) {
|
||||
context.read<ViewBloc>().add(ViewEvent.rename(name));
|
||||
}
|
||||
context.pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export 'bottom_sheet_action_widget.dart';
|
||||
export 'bottom_sheet_add_new_page.dart';
|
||||
export 'bottom_sheet_drag_handler.dart';
|
||||
export 'bottom_sheet_rename_widget.dart';
|
||||
export 'bottom_sheet_view_item_body.dart';
|
||||
export 'bottom_sheet_view_item_header.dart';
|
||||
export 'bottom_sheet_view_page.dart';
|
||||
export 'default_mobile_action_pane.dart';
|
||||
export 'show_mobile_bottom_sheet.dart';
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BottomSheetActionWidget extends StatelessWidget {
|
||||
const BottomSheetActionWidget({
|
||||
super.key,
|
||||
required this.svg,
|
||||
required this.text,
|
||||
required this.onTap,
|
||||
this.iconColor,
|
||||
});
|
||||
|
||||
final FlowySvgData svg;
|
||||
final String text;
|
||||
final VoidCallback onTap;
|
||||
final Color? iconColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final iconColor =
|
||||
this.iconColor ?? Theme.of(context).colorScheme.onBackground;
|
||||
|
||||
return OutlinedButton.icon(
|
||||
icon: FlowySvg(
|
||||
svg,
|
||||
size: const Size.square(22.0),
|
||||
color: iconColor,
|
||||
),
|
||||
label: Text(text),
|
||||
style: Theme.of(context)
|
||||
.outlinedButtonTheme
|
||||
.style
|
||||
?.copyWith(alignment: Alignment.centerLeft),
|
||||
onPressed: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||