mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge remote-tracking branch 'origin/main' into develop
# Conflicts: # frontend/appflowy_flutter/lib/plugins/database_view/application/database_view_service.dart # frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/base/link_to_page_widget.dart # frontend/appflowy_flutter/lib/plugins/trash/application/trash_bloc.dart # frontend/appflowy_flutter/lib/plugins/trash/application/trash_service.dart # frontend/appflowy_flutter/lib/workspace/application/app/app_bloc.dart # frontend/appflowy_flutter/lib/workspace/application/app/app_service.dart # frontend/appflowy_flutter/lib/workspace/application/menu/menu_bloc.dart # frontend/appflowy_flutter/lib/workspace/application/workspace/workspace_service.dart # frontend/appflowy_flutter/lib/workspace/presentation/home/menu/app/header/header.dart # frontend/appflowy_flutter/test/bloc_test/grid_test/filter/filter_util.dart # frontend/appflowy_flutter/test/bloc_test/grid_test/grid_bloc_test.dart # frontend/appflowy_flutter/test/bloc_test/grid_test/util.dart # frontend/appflowy_flutter/test/bloc_test/home_test/view_bloc_test.dart # frontend/rust-lib/flowy-database/src/services/database/database_editor.rs # frontend/rust-lib/flowy-database/src/services/persistence/migration/database_view_migration.rs
This commit is contained in:
commit
c009347735
@ -1,4 +1 @@
|
||||
frontend/appflowy_flutter/
|
||||
frontend/scripts/
|
||||
frontend/rust-lib/target
|
||||
shared-lib/target/
|
||||
.git
|
||||
|
47
.github/workflows/docker_ci.yml
vendored
Normal file
47
.github/workflows/docker_ci.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: Docker-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/*
|
||||
paths:
|
||||
- frontend/**
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- release/*
|
||||
paths:
|
||||
- frontend/**
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- unlocked
|
||||
- ready_for_review
|
||||
|
||||
jobs:
|
||||
build-app:
|
||||
if: github.event.pull_request.draft != true
|
||||
concurrency:
|
||||
group: docker_ci-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build the app
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu -o pipefail
|
||||
cd frontend/scripts/docker-buildfiles
|
||||
docker-compose build --no-cache --progress=plain \
|
||||
| while read line; do \
|
||||
if [[ "$line" =~ ^Step[[:space:]] ]]; then \
|
||||
echo "$(date -u '+%H:%M:%S') | $line"; \
|
||||
else \
|
||||
echo "$line"; \
|
||||
fi; \
|
||||
done \
|
3
.github/workflows/flutter_ci.yaml
vendored
3
.github/workflows/flutter_ci.yaml
vendored
@ -99,7 +99,8 @@ jobs:
|
||||
|
||||
- name: Flutter Analyzer
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: flutter analyze
|
||||
run: |
|
||||
flutter analyze .
|
||||
|
||||
- name: Run Flutter unit tests
|
||||
working-directory: frontend
|
||||
|
11
.github/workflows/integration_test.yml
vendored
11
.github/workflows/integration_test.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
tests:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@ -105,11 +105,14 @@ jobs:
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
flutter test integration_test/runner.dart -d Linux --coverage
|
||||
export DISPLAY=:99
|
||||
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
||||
sudo apt-get install network-manager
|
||||
flutter test integration_test/runner.dart -d Linux --coverage --verbose
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter test integration_test/runner.dart -d macOS --coverage
|
||||
flutter test integration_test/runner.dart -d macOS --coverage --verbose
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
flutter test integration_test/runner.dart -d Windows --coverage
|
||||
flutter test integration_test/runner.dart -d Windows --coverage --verbose
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
|
@ -205,12 +205,17 @@ script = [
|
||||
]
|
||||
script_runner = "@duckscript"
|
||||
|
||||
[env.test-macos]
|
||||
[env.test-macos-x86_64]
|
||||
TEST_CRATE_TYPE = "cdylib"
|
||||
TEST_LIB_EXT = "dylib"
|
||||
# For the moment, the DynamicLibrary only supports open x86_64 architectures binary.
|
||||
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
|
||||
|
||||
[env.test-macos-arm64]
|
||||
TEST_CRATE_TYPE = "cdylib"
|
||||
TEST_LIB_EXT = "dylib"
|
||||
TEST_COMPILE_TARGET = "aarch64-apple-darwin"
|
||||
|
||||
[env.test-linux]
|
||||
TEST_CRATE_TYPE = "cdylib"
|
||||
TEST_LIB_EXT = "so"
|
||||
|
@ -14,9 +14,7 @@ analyzer:
|
||||
exclude:
|
||||
- "**/*.g.dart"
|
||||
- "**/*.freezed.dart"
|
||||
- "packages/appflowy_editor/**"
|
||||
- "packages/editor/**"
|
||||
# - "packages/flowy_infra_ui/**"
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
@ -30,8 +28,7 @@ linter:
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
- require_trailing_commas
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
|
@ -1,112 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg873"
|
||||
version="1.1"
|
||||
fill="none"
|
||||
viewBox="0 0 92 17"
|
||||
height="17"
|
||||
width="92">
|
||||
<metadata
|
||||
id="metadata877">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="g866"
|
||||
clip-path="url(#clip0)">
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path834"
|
||||
fill="black"
|
||||
d="M32.7324 4.84144H34.892V5.63601C35.4179 5.08166 36.4132 4.63818 37.5212 4.63818C39.8498 4.63818 41.3709 6.4121 41.3709 8.88818C41.3709 11.4197 39.6057 13.3969 36.8827 13.3969C36.1315 13.3969 35.3991 13.2675 34.9108 12.9904V16.9078H32.7512V4.84144H32.7324ZM34.9108 7.53927V10.9208C35.493 11.2904 35.9812 11.4012 36.6949 11.4012C38.1972 11.4012 39.0611 10.3295 39.0611 8.94362C39.0611 7.61318 38.2723 6.65231 36.8451 6.65231C36.1127 6.63384 35.4366 6.96644 34.9108 7.53927Z" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path836"
|
||||
fill="black"
|
||||
d="M27.3804 4.6748C24.6573 4.6748 22.8921 6.6335 22.8921 9.1835C22.8921 11.6596 24.3944 13.4335 26.7419 13.4335C27.8311 13.4335 28.8264 12.99 29.371 12.4357V13.2302H31.5306V6.22698C29.9156 5.02589 28.1315 4.6748 27.3804 4.6748ZM29.3522 10.5324C28.8264 11.1052 28.1503 11.4378 27.4179 11.4378C25.9907 11.4378 25.2019 10.477 25.2019 9.14654C25.2019 7.76067 26.0658 6.67046 27.5681 6.67046C28.2818 6.67046 28.77 6.78133 29.3522 7.15089V10.5324Z" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path838"
|
||||
fill="black"
|
||||
d="M42.291 4.84144H44.4506V5.63601C44.9765 5.08166 45.9718 4.63818 47.0797 4.63818C49.4084 4.63818 50.9295 6.4121 50.9295 8.88818C50.9295 11.4197 49.1642 13.3969 46.4412 13.3969C45.6901 13.3969 44.9577 13.2675 44.4694 12.9904V16.9078H42.3098V4.84144H42.291ZM44.4694 7.53927V10.9208C45.0516 11.2904 45.5398 11.4012 46.2535 11.4012C47.7558 11.4012 48.6196 10.3295 48.6196 8.94362C48.6196 7.61318 47.8309 6.65231 46.4037 6.65231C45.6713 6.63384 44.9952 6.96644 44.4694 7.53927Z" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path840"
|
||||
fill="black"
|
||||
d="M57.2019 2.43913C56.8826 2.21739 56.3756 1.99565 55.8685 1.99565C54.892 1.99565 54.3849 2.49457 54.3849 3.64022V4.82283H55.9061V6.83696H54.3849V13.175H52.2065V3.49239C52.2065 1.18261 53.3333 0 55.23 0C56.0939 0 56.8826 0.203261 57.446 0.554348H59.3615V10.0152C59.3615 10.9576 59.6056 11.3641 60.0939 11.3641C60.4507 11.3641 60.7324 11.2163 60.9953 11.0315L61.446 12.6576C60.9577 13.0457 60.2253 13.3598 59.2112 13.3598C57.9155 13.3598 57.2019 12.5837 57.2019 10.8837V2.43913Z" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path842"
|
||||
fill="black"
|
||||
d="M66.0846 4.63818C68.9015 4.63818 70.7043 6.50449 70.7043 9.01753C70.7043 11.5121 68.9015 13.3969 66.0846 13.3969C63.2677 13.3969 61.4648 11.5306 61.4648 9.01753C61.4648 6.50449 63.2864 4.63818 66.0846 4.63818ZM66.0846 11.4012C67.4179 11.4012 68.3944 10.4588 68.3944 9.01753C68.3944 7.61318 67.3991 6.65231 66.0846 6.65231C64.8076 6.65231 63.7935 7.57623 63.7935 9.01753C63.7935 10.4034 64.77 11.4012 66.0846 11.4012Z" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path844"
|
||||
fill="black"
|
||||
d="M81.4271 13.2307H79.4928L77.69 8.59264C77.5586 8.27851 77.5022 7.92742 77.4083 7.61329C77.3332 7.98286 77.2393 8.29699 77.1079 8.6296L75.305 13.2307H73.4647L70.7041 4.84155H73.014L74.3661 9.38721C74.4975 9.79373 74.5351 10.1079 74.6102 10.4959C74.7041 10.1448 74.7604 9.84916 74.9295 9.38721L76.5069 4.84155H78.4224L80.0562 9.36873C80.1877 9.73829 80.2816 10.1263 80.3755 10.5144C80.4506 10.1263 80.5445 9.71981 80.6384 9.31329L81.8778 4.84155H84.0562L81.4271 13.2307Z" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path846"
|
||||
fill="black"
|
||||
d="M88.6574 13.1936C87.4179 16.187 86.6292 16.9077 85.371 16.9077C84.601 16.9077 84.0377 16.612 83.5494 16.2609L84.2442 14.6533C84.4696 14.7827 84.7888 14.949 85.1269 14.949C85.6715 14.949 86.0658 14.524 86.4226 13.6555L86.6104 13.212L82.6855 4.85986H85.2959L87.2677 9.42399C87.4367 9.83052 87.5494 10.2186 87.6808 10.6251C87.756 10.237 87.8311 9.83052 87.9813 9.40552L89.5024 4.85986H91.9625L88.6574 13.1936Z" />
|
||||
<path
|
||||
id="path848"
|
||||
fill="#F7931E"
|
||||
d="M17.0142 10.4033C16.5259 13.0088 14.3851 15.2816 11.925 16.5566C11.6245 16.7229 11.2677 16.8153 10.9297 16.8338H16.1503C16.6574 16.8338 17.0142 16.4642 17.0142 16.0022V10.4033Z" />
|
||||
<path
|
||||
id="path850"
|
||||
fill="#8427E0"
|
||||
d="M6.57258 5.37743C6.49746 5.43286 6.42235 5.4883 6.34723 5.54373C5.07023 6.43069 1.20169 9.27634 0.319059 8.0383C-0.544791 6.83721 0.375397 3.43721 2.59136 1.79264C2.62892 1.75569 2.68526 1.73721 2.72281 1.70025C5.14535 0.0187313 6.94817 0.258949 7.8308 1.47851C8.65709 2.62417 7.7369 4.43504 6.57258 5.37743Z" />
|
||||
<path
|
||||
id="path852"
|
||||
fill="#00B5FF"
|
||||
d="M16.0373 8.02043C14.8354 8.85195 12.9575 7.89108 12.0185 6.69C11.981 6.63456 11.9434 6.59761 11.9059 6.54217C11.0045 5.28565 8.11244 1.47913 9.35188 0.629126C10.5913 -0.239352 14.1782 0.703039 15.812 2.99434C15.8495 3.04978 15.8871 3.08674 15.9246 3.14217C17.5021 5.45195 17.258 7.17043 16.0373 8.02043Z" />
|
||||
<path
|
||||
id="path854"
|
||||
fill="#FFBD00"
|
||||
d="M14.4226 15.5219C14.385 15.5589 14.3475 15.5773 14.2911 15.6143C11.8686 17.2958 10.0658 17.0556 9.18315 15.836C8.35686 14.6904 9.27705 12.8795 10.4414 11.9371C10.5165 11.8817 10.5916 11.8263 10.6667 11.7708C11.9437 10.9023 15.8123 8.03821 16.6761 9.27625C17.5587 10.4773 16.6573 13.8773 14.4226 15.5219Z" />
|
||||
<path
|
||||
id="path856"
|
||||
fill="#E3006D"
|
||||
d="M7.66182 16.6859C6.42238 17.5544 2.85431 16.612 1.22051 14.3207C1.18295 14.2838 1.14539 14.2283 1.12661 14.1914C-0.469635 11.8816 -0.206725 10.1446 1.01393 9.31311C2.21581 8.48159 4.09374 9.44246 5.03271 10.6435C5.07027 10.699 5.10783 10.7359 5.14539 10.7914C6.02802 12.0294 8.92004 15.8359 7.66182 16.6859Z" />
|
||||
<path
|
||||
id="path858"
|
||||
fill="#9327FF"
|
||||
d="M6.57283 5.37743C4.84513 6.13504 1.16438 7.68721 0.619779 6.43069C0.150295 5.37743 1.01415 3.23395 2.59161 1.79264C2.62917 1.75569 2.68551 1.73721 2.72307 1.70025C5.1456 0.0187312 6.94842 0.258949 7.83105 1.47851C8.65734 2.62417 7.73715 4.43504 6.57283 5.37743Z" />
|
||||
<path
|
||||
id="path860"
|
||||
fill="#00C8FF"
|
||||
d="M16.0374 8.01967C14.8355 8.8512 12.9576 7.89033 12.0186 6.68924C11.2487 4.9338 9.76511 1.47837 11.0045 0.960978C12.1313 0.480543 14.4599 1.44141 15.9435 3.14141C17.5022 5.4512 17.2581 7.16967 16.0374 8.01967Z" />
|
||||
<path
|
||||
id="path862"
|
||||
fill="#FFCE00"
|
||||
d="M14.4226 15.5217C14.385 15.5586 14.3475 15.5771 14.2911 15.6141C11.8686 17.2956 10.0658 17.0554 9.18315 15.8358C8.35686 14.6901 9.27705 12.8793 10.4414 11.9369C12.1691 11.1793 15.8498 9.6271 16.3944 10.8836C16.8827 11.9369 16.0188 14.0804 14.4226 15.5217Z" />
|
||||
<path
|
||||
id="path864"
|
||||
fill="#FB006D"
|
||||
d="M6.0468 16.3533C4.92004 16.8338 2.5914 15.8914 1.12661 14.1914C-0.469635 11.8816 -0.206725 10.1446 1.01393 9.31311C2.21581 8.48159 4.09374 9.44246 5.03271 10.6435C5.80266 12.3805 7.28623 15.8359 6.0468 16.3533Z" />
|
||||
</g>
|
||||
<defs
|
||||
id="defs871">
|
||||
<clipPath
|
||||
id="clip0">
|
||||
<rect
|
||||
id="rect868"
|
||||
fill="white"
|
||||
height="17"
|
||||
width="92" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 761.68 143.1"><title>Asset 16</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M271,40.73h18v6.7c4.37-4.68,12.64-8.42,21.69-8.42C330,39,342.5,54,342.5,74.74c0,21.38-14.67,37.92-37.14,37.92-6.24,0-12.32-1.09-16.38-3.44v32.93H271Zm18,22.78v28.4c4.84,3.12,8.89,4,14.82,4,12.48,0,19.66-9,19.66-20.75,0-11.24-6.55-19.35-18.41-19.35C299,55.86,293.35,58.67,289,63.51Z" style="fill:#fff"/><path d="M226.66,39.4c-22.48,0-37.14,16.54-37.14,37.91,0,20.76,12.47,35.74,31.83,35.74,9,0,17.31-3.75,21.68-8.43v6.72h18V52.42C247.68,42.36,232.89,39.4,226.66,39.4ZM243,88.55c-4.37,4.83-10,7.64-16.07,7.64-11.85,0-18.41-8.11-18.41-19.34,0-11.7,7.18-20.76,19.66-20.76,5.93,0,10,.94,14.82,4.07Z" style="fill:#fff"/><path d="M350.16,40.73h17.95v6.7c4.36-4.68,12.63-8.42,21.68-8.42,19.35,0,31.84,15,31.84,35.73,0,21.38-14.67,37.92-37.14,37.92-6.24,0-12.33-1.09-16.38-3.44v32.93H350.16Zm17.95,22.78v28.4c4.83,3.12,8.89,4,14.82,4,12.48,0,19.66-9,19.66-20.75,0-11.24-6.55-19.35-18.41-19.35C378.09,55.86,372.47,58.67,368.11,63.51Z" style="fill:#fff"/><path d="M473.63,20.6a20.34,20.34,0,0,0-11.08-3.75c-8.11,0-12.32,4.22-12.32,13.89v10h12.64V57.58H450.23v53.36h-18V29.34c0-19.51,9.36-29.34,25-29.34,7.18,0,13.73,1.72,18.41,4.68h15.92V84.26c0,8,2,11.39,6.08,11.39a12.6,12.6,0,0,0,7.49-2.81l3.75,13.73c-4.06,3.28-10.15,5.93-18.57,5.93-10.77,0-16.7-6.55-16.7-20.91Z" style="fill:#fff"/><path d="M547.12,39c23.25,0,38.23,15.76,38.23,36.82s-15,36.83-38.23,36.83S508.9,96.9,508.9,75.83,523.87,39,547.12,39Zm0,57c11.08,0,19.2-8,19.2-20.13,0-11.86-8.27-20-19.2-20-10.61,0-19,7.8-19,20C528.09,87.54,536.2,96,547.12,96Z" style="fill:#fff"/><path d="M674.14,111.25H658.07l-15-39c-1.1-2.65-1.56-5.61-2.34-8.27a50.32,50.32,0,0,1-2.5,8.59l-14.82,38.69h-15.3L585.35,40.73h19.2L615.78,79a73.76,73.76,0,0,1,2,9.37A91.46,91.46,0,0,1,620.46,79l13.11-38.22h15.91L663.06,78.8a98.26,98.26,0,0,1,2.65,9.67c.63-3.28,1.41-6.71,2.18-10.14l10.3-37.6h18.1Z" style="fill:#fff"/><path d="M734.06,110.94c-10.3,25.12-16.85,31.21-27.15,31.21-6.4,0-11.08-2.5-15.14-5.46l5.78-13.58c1.87,1.09,4.52,2.5,7.33,2.5,4.53,0,7.8-3.59,10.77-10.92l1.56-3.75L684.75,40.73h21.54l16.38,38.38c1.4,3.43,2.34,6.71,3.43,10.14A71.08,71.08,0,0,1,728.6,79l12.64-38.22h20.44Z" style="fill:#fff"/><path d="M140.91,87.45c-4,21.87-21.71,41-42.18,51.75-2.57,1.35-3.58,2.12-6.47,2.3h41.49a7,7,0,0,0,7.2-7V87.45Z" style="fill:#f7931e"/><path d="M95.68,140.24a15.15,15.15,0,0,1-2.52,0Z" style="fill:#ffce00"/><path d="M54.36,45.23c-.63.51-1.25,1-1.89,1.44C42,54.06,9.9,78,2.65,67.71-4.46,57.58,3,28.86,21.49,15c.35-.28.71-.53,1.06-.78,20-14.09,35-12.13,42.28-1.81C71.63,22.13,64,37.31,54.36,45.23Z" style="fill:#8427e0"/><path d="M132.72,67.41c-9.91,7-25.55-1.17-33.32-11.14-.31-.4-.61-.81-.91-1.22-7.38-10.51-31.34-42.57-21-49.82s39.94.67,53.45,19.9c.3.43.59.85.87,1.27C144.91,45.8,142.81,60.31,132.72,67.41Z" style="fill:#00b5ff"/><path d="M119.45,130.66c-.34.26-.69.52-1,.76-20,14.09-35,12.12-42.28,1.82-6.79-9.68.8-24.85,10.46-32.78.62-.52,1.26-1,1.9-1.45C99,91.62,131.06,67.67,138.31,78,145.42,88.1,137.93,116.83,119.45,130.66Z" style="fill:#ffbd00"/><path d="M63.51,140.45c-10.32,7.24-39.94-.67-53.45-19.91-.28-.38-.54-.77-.8-1.16a0,0,0,0,0,0,0c-13.19-19.44-11.1-34-1-41.08,9.9-7,25.55,1.15,33.31,11.12.31.4.62.82.91,1.23C49.86,101.14,73.82,133.2,63.51,140.45Z" style="fill:#e3006d"/><path d="M54.36,45.23C40,51.53,9.65,64.64,5.08,54.12,1.25,45.3,8.34,27.25,21.49,15c.35-.28.71-.53,1.06-.78,20-14.09,35-12.13,42.28-1.81C71.63,22.13,64,37.31,54.36,45.23Z" style="fill:#9327ff"/><path d="M132.72,67.41c-9.91,7-25.55-1.17-33.32-11.14C93,41.57,80.68,12.49,91,8c9.26-4,28.65,4,40.83,18.37C144.91,45.8,142.81,60.31,132.72,67.41Z" style="fill:#00c8ff"/><path d="M119.45,130.66c-.34.26-.69.52-1,.76-20,14.09-35,12.12-42.28,1.82-6.79-9.68.8-24.85,10.46-32.78,14.32-6.3,44.72-19.42,49.29-8.91C139.71,100.38,132.62,118.44,119.45,130.66Z" style="fill:#ffce00"/><path d="M50,137.65c-9.23,4-28.57-3.94-40.75-18.27a0,0,0,0,0,0,0c-13.19-19.44-11.1-34-1-41.08,9.9-7,25.55,1.15,33.31,11.12C48,104.11,60.28,133.2,50,137.65Z" style="fill:#fb006d"/></g></g></svg>
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 4.1 KiB |
@ -1,150 +1,159 @@
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Ich",
|
||||
"welcomeText": "Willkommen bei @:appName",
|
||||
"githubStarText": "GitHub Star vergeben",
|
||||
"subscribeNewsletterText": "Abonniere den Newsletter",
|
||||
"letsGoButtonText": "Los geht's",
|
||||
"title": "Titel",
|
||||
"signUp": {
|
||||
"buttonText": "Registrieren",
|
||||
"title": "Registriere dich bei @:appName",
|
||||
"getStartedText": "Erste Schritte",
|
||||
"emptyPasswordError": "Passwort darf nicht leer sein",
|
||||
"repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
|
||||
"unmatchedPasswordError": "Passwörter stimmen nicht überein",
|
||||
"alreadyHaveAnAccount": "Bereits registriert?",
|
||||
"emailHint": "E-Mail",
|
||||
"passwordHint": "Passwort",
|
||||
"repeatPasswordHint": "Wiederhole Passwort"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Bei @:appName einloggen",
|
||||
"loginButtonText": "Anmelden",
|
||||
"buttonText": "Anmelden",
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"emailHint": "E-Mail",
|
||||
"passwordHint": "Passwort",
|
||||
"dontHaveAnAccount": "Du besitzt noch kein Konto?",
|
||||
"repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
|
||||
"unmatchedPasswordError": "Passwörter stimmen nicht überein"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Arbeitsbereich erstellen",
|
||||
"hint": "Arbeitsbereich",
|
||||
"notFoundError": "Arbeitsbereich nicht gefunden"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Teilen",
|
||||
"workInProgress": "Demnächst verfügbar",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Link kopieren"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Umbenennen",
|
||||
"delete": "Löschen",
|
||||
"duplicate": "Duplizieren"
|
||||
},
|
||||
"blankPageTitle": "Leere Seite",
|
||||
"newPageText": "Neue Seite",
|
||||
"trash": {
|
||||
"text": "Papierkorb",
|
||||
"restoreAll": "Alles wiederherstellen",
|
||||
"deleteAll": "Alles löschen",
|
||||
"pageHeader": {
|
||||
"fileName": "Dateiname",
|
||||
"lastModified": "Letzte Änderung",
|
||||
"created": "Erstellt"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Diese Seite ist im Papierkorb",
|
||||
"restore": "Seite wiederherstellen",
|
||||
"deletePermanent": "Dauerhaft löschen"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Seitenname",
|
||||
"questionBubble": {
|
||||
"whatsNew": "Was gibt es Neues?",
|
||||
"help": "Hilfe & Support",
|
||||
"debug": {
|
||||
"name": "Debug-Informationen",
|
||||
"success": "Debug-Informationen in die Zwischenablage kopiert!",
|
||||
"fail": "Debug-Informationen können nicht in die Zwischenablage kopiert werden"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Schnell eine Seite innerhalb hinzufügen",
|
||||
"defaultNewPageName": "Unbenannt",
|
||||
"renameDialog": "Umbenennen"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Rückgängig",
|
||||
"redo": "Wiederherstellen",
|
||||
"bold": "Fett",
|
||||
"italic": "Kursiv",
|
||||
"underline": "Unterstreichen",
|
||||
"strike": "Durchstreichen",
|
||||
"numList": "Nummerierte Liste",
|
||||
"bulletList": "Aufzählung",
|
||||
"checkList": "Checkliste",
|
||||
"inlineCode": "Inline-Code",
|
||||
"quote": "Zitat",
|
||||
"header": "Überschrift",
|
||||
"highlight": "Hervorhebung"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "In den hellen Modus wechseln",
|
||||
"darkMode": "In den dunklen Modus wechseln"
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Kontakte",
|
||||
"whatsHappening": "Was geschieht diese Woche?",
|
||||
"addContact": "Kontakt hinzufügen",
|
||||
"editContact": "Kontakt bearbeiten"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Abbrechen",
|
||||
"signIn": "Anmelden",
|
||||
"signOut": "Abmelden",
|
||||
"complete": "Fertig",
|
||||
"save": "Speichern"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Willkommen!",
|
||||
"firstName": "Vorname",
|
||||
"middleName": "Zweiter Vorname",
|
||||
"lastName": "Nachname",
|
||||
"stepX": "Schritt {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Keine Verbindung zu Ihrem Konto möglich.",
|
||||
"failedMsg": "Bitte vergewissern Sie sich, dass Sie den Anmeldevorgang in Ihrem Browser abgeschlossen haben."
|
||||
},
|
||||
"google": {
|
||||
"title": "GOOGLE ANMELDUNG",
|
||||
"instruction1": "Um Ihre Google-Kontakte zu importieren, müssen Sie diese Anwendung über Ihren Webbrowser autorisieren.",
|
||||
"instruction2": "Kopieren Sie diesen Code in Ihre Zwischenablage, indem Sie auf das Symbol klicken oder den Text auswählen:",
|
||||
"instruction3": "Rufen Sie den folgenden Link in Ihrem Webbrowser auf, und geben Sie den obigen Code ein:",
|
||||
"instruction4": "Klicken Sie unten auf die Schaltfläche, wenn Sie die Anmeldung abgeschlossen haben:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Einstellungen",
|
||||
"menu": {
|
||||
"appearance": "Aussehen",
|
||||
"language": "Sprache",
|
||||
"open": "Einstellungen öffnen"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "Heller Modus",
|
||||
"darkLabel": "Dunkler Modus"
|
||||
}
|
||||
},
|
||||
"sideBar": {
|
||||
"openSidebar": "Open sidebar",
|
||||
"closeSidebar": "Close sidebar"
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Ich",
|
||||
"welcomeText": "Willkommen bei @:appName",
|
||||
"githubStarText": "GitHub Star vergeben",
|
||||
"subscribeNewsletterText": "Abonniere den Newsletter",
|
||||
"letsGoButtonText": "Los geht's",
|
||||
"title": "Titel",
|
||||
"signUp": {
|
||||
"buttonText": "Registrieren",
|
||||
"title": "Registriere dich bei @:appName",
|
||||
"getStartedText": "Erste Schritte",
|
||||
"emptyPasswordError": "Passwort darf nicht leer sein",
|
||||
"repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
|
||||
"unmatchedPasswordError": "Passwörter stimmen nicht überein",
|
||||
"alreadyHaveAnAccount": "Bereits registriert?",
|
||||
"emailHint": "E-Mail",
|
||||
"passwordHint": "Passwort",
|
||||
"repeatPasswordHint": "Wiederhole Passwort"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Bei @:appName einloggen",
|
||||
"loginButtonText": "Anmelden",
|
||||
"buttonText": "Anmelden",
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"emailHint": "E-Mail",
|
||||
"passwordHint": "Passwort",
|
||||
"dontHaveAnAccount": "Du besitzt noch kein Konto?",
|
||||
"repeatPasswordEmptyError": "Passwortwiederholung darf nicht leer sein",
|
||||
"unmatchedPasswordError": "Passwörter stimmen nicht überein"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Arbeitsbereich erstellen",
|
||||
"hint": "Arbeitsbereich",
|
||||
"notFoundError": "Arbeitsbereich nicht gefunden"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Teilen",
|
||||
"workInProgress": "Demnächst verfügbar",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Link kopieren"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Umbenennen",
|
||||
"delete": "Löschen",
|
||||
"duplicate": "Duplizieren"
|
||||
},
|
||||
"blankPageTitle": "Leere Seite",
|
||||
"newPageText": "Neue Seite",
|
||||
"trash": {
|
||||
"text": "Papierkorb",
|
||||
"restoreAll": "Alles wiederherstellen",
|
||||
"deleteAll": "Alles löschen",
|
||||
"pageHeader": {
|
||||
"fileName": "Dateiname",
|
||||
"lastModified": "Letzte Änderung",
|
||||
"created": "Erstellt"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Diese Seite ist im Papierkorb",
|
||||
"restore": "Seite wiederherstellen",
|
||||
"deletePermanent": "Dauerhaft löschen"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Seitenname",
|
||||
"questionBubble": {
|
||||
"whatsNew": "Was gibt es Neues?",
|
||||
"help": "Hilfe & Support",
|
||||
"debug": {
|
||||
"name": "Debug-Informationen",
|
||||
"success": "Debug-Informationen in die Zwischenablage kopiert!",
|
||||
"fail": "Debug-Informationen können nicht in die Zwischenablage kopiert werden"
|
||||
},
|
||||
"shortcuts": "Abkürzungen"
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Schnell eine Seite innerhalb hinzufügen",
|
||||
"defaultNewPageName": "Unbenannt",
|
||||
"renameDialog": "Umbenennen"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Rückgängig",
|
||||
"redo": "Wiederherstellen",
|
||||
"bold": "Fett",
|
||||
"italic": "Kursiv",
|
||||
"underline": "Unterstreichen",
|
||||
"strike": "Durchstreichen",
|
||||
"numList": "Nummerierte Liste",
|
||||
"bulletList": "Aufzählung",
|
||||
"checkList": "Checkliste",
|
||||
"inlineCode": "Inline-Code",
|
||||
"quote": "Zitat",
|
||||
"header": "Überschrift",
|
||||
"highlight": "Hervorhebung",
|
||||
"color": "Farbe"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "In den hellen Modus wechseln",
|
||||
"darkMode": "In den dunklen Modus wechseln",
|
||||
"openAsPage": "Als Seite öffnen"
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Kontakte",
|
||||
"whatsHappening": "Was geschieht diese Woche?",
|
||||
"addContact": "Kontakt hinzufügen",
|
||||
"editContact": "Kontakt bearbeiten"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Abbrechen",
|
||||
"signIn": "Anmelden",
|
||||
"signOut": "Abmelden",
|
||||
"complete": "Fertig",
|
||||
"save": "Speichern"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Willkommen!",
|
||||
"firstName": "Vorname",
|
||||
"middleName": "Zweiter Vorname",
|
||||
"lastName": "Nachname",
|
||||
"stepX": "Schritt {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Keine Verbindung zu Ihrem Konto möglich.",
|
||||
"failedMsg": "Bitte vergewissern Sie sich, dass Sie den Anmeldevorgang in Ihrem Browser abgeschlossen haben."
|
||||
},
|
||||
"google": {
|
||||
"title": "GOOGLE ANMELDUNG",
|
||||
"instruction1": "Um Ihre Google-Kontakte zu importieren, müssen Sie diese Anwendung über Ihren Webbrowser autorisieren.",
|
||||
"instruction2": "Kopieren Sie diesen Code in Ihre Zwischenablage, indem Sie auf das Symbol klicken oder den Text auswählen:",
|
||||
"instruction3": "Rufen Sie den folgenden Link in Ihrem Webbrowser auf, und geben Sie den obigen Code ein:",
|
||||
"instruction4": "Klicken Sie unten auf die Schaltfläche, wenn Sie die Anmeldung abgeschlossen haben:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Einstellungen",
|
||||
"menu": {
|
||||
"appearance": "Aussehen",
|
||||
"language": "Sprache",
|
||||
"open": "Einstellungen öffnen"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "Heller Modus",
|
||||
"darkLabel": "Dunkler Modus"
|
||||
}
|
||||
},
|
||||
"sideBar": {
|
||||
"openSidebar": "Open sidebar",
|
||||
"closeSidebar": "Close sidebar"
|
||||
},
|
||||
"moreAction": {
|
||||
"small": "klein",
|
||||
"medium": "mittel",
|
||||
"large": "groß",
|
||||
"fontSize": "Schriftgröße",
|
||||
"import": "Importieren"
|
||||
}
|
||||
|
||||
}
|
@ -282,6 +282,7 @@
|
||||
"dateFormatISO": "Year-Month-Day",
|
||||
"dateFormatLocal": "Month/Day/Year",
|
||||
"dateFormatUS": "Year/Month/Day",
|
||||
"dateFormatDayMonthYear": "Day/Month/Year",
|
||||
"timeFormat": "Time format",
|
||||
"invalidTimeFormat": "Invalid format",
|
||||
"timeFormatTwelveHour": "12 hour",
|
||||
@ -290,7 +291,7 @@
|
||||
"optionTitle": "Options",
|
||||
"addOption": "Add option",
|
||||
"editProperty": "Edit property",
|
||||
"newColumn": "New column",
|
||||
"newProperty": "New property",
|
||||
"deleteFieldPromptMessage": "Are you sure? This property will be deleted"
|
||||
},
|
||||
"sort": {
|
||||
@ -383,7 +384,9 @@
|
||||
"pickFromFiles": "Pick from files",
|
||||
"couldNotFetchImage": "Could not fetch image",
|
||||
"imageSavingFailed": "Image Saving Failed",
|
||||
"addIcon": "Add Icon"
|
||||
"addIcon": "Add Icon",
|
||||
"coverRemoveAlert": "It will be removed from cover after it is deleted.",
|
||||
"alertDialogConfirmation": "Are you sure, you want to continue?"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -410,4 +413,4 @@
|
||||
"layoutDateField": "Layout calendar by"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -271,7 +271,7 @@
|
||||
"optionTitle": "Aukerak",
|
||||
"addOption": "Gehitu aukera",
|
||||
"editProperty": "Editatu propietatea",
|
||||
"newColumn": "Zutabe berria",
|
||||
"newProperty": "Zutabe berria",
|
||||
"deleteFieldPromptMessage": "Ziur al zaude? Propietate hau ezabatu egingo da"
|
||||
},
|
||||
"sort": {
|
||||
@ -330,4 +330,4 @@
|
||||
"nextMonth": "Hurrengo hilabetea"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -195,7 +195,7 @@
|
||||
"optionTitle": "Options",
|
||||
"addOption": "Ajouter une option",
|
||||
"editProperty": "Modifier la propriété",
|
||||
"newColumn": "Nouvelle colonne",
|
||||
"newProperty": "Nouvelle colonne",
|
||||
"deleteFieldPromptMessage": "Vous voulez supprimer cette propriété ?"
|
||||
},
|
||||
"row": {
|
||||
|
@ -191,7 +191,7 @@
|
||||
"optionTitle": "옵션",
|
||||
"addOption": "옵션 추가",
|
||||
"editProperty": "속성 편집",
|
||||
"newColumn": "열 추가",
|
||||
"newProperty": "열 추가",
|
||||
"deleteFieldPromptMessage": "해당 속성을 삭제 하시겠습니까?"
|
||||
},
|
||||
"row": {
|
||||
|
@ -39,7 +39,7 @@
|
||||
"workInProgress": "Em breve",
|
||||
"markdown": "Marcador",
|
||||
"copyLink": "Copiar link"
|
||||
},
|
||||
},
|
||||
"moreAction": {
|
||||
"small": "pequeno",
|
||||
"medium": "médio",
|
||||
@ -177,7 +177,7 @@
|
||||
"system": "Adaptar-se ao sistema"
|
||||
},
|
||||
"theme": "Tema"
|
||||
},
|
||||
},
|
||||
"files": {
|
||||
"defaultLocation": "Onde os seus dados ficam armazenados",
|
||||
"doubleTapToCopy": "Clique duas vezes para copiar o caminho",
|
||||
@ -287,7 +287,7 @@
|
||||
"optionTitle": "Opções",
|
||||
"addOption": "Adicioar opção",
|
||||
"editProperty": "Editar propriedade",
|
||||
"newColumn": "Nova coluna",
|
||||
"newProperty": "Nova coluna",
|
||||
"deleteFieldPromptMessage": "Tem certeza? Esta propriedade será excluída"
|
||||
},
|
||||
"sort": {
|
||||
@ -320,7 +320,7 @@
|
||||
"pannelTitle": "Escolha uma opção ou crie uma",
|
||||
"searchOption": "Procurar uma opção"
|
||||
},
|
||||
"checklist": {
|
||||
"checklist": {
|
||||
"panelTitle": "Adicionar um item"
|
||||
},
|
||||
"menuName": "Grade"
|
||||
|
@ -1,150 +1,149 @@
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Me",
|
||||
"welcomeText": "Bem vindo ao @:appName",
|
||||
"githubStarText": "Star on GitHub",
|
||||
"subscribeNewsletterText": "Inscreve-te ao Newsletter",
|
||||
"letsGoButtonText": "Bora",
|
||||
"title": "Título",
|
||||
"signUp": {
|
||||
"buttonText": "Inscreve-te",
|
||||
"title": "Inscreve-te ao @:appName",
|
||||
"getStartedText": "Começar",
|
||||
"emptyPasswordError": "A palavra-passe não pode estar em branco.",
|
||||
"repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
|
||||
"unmatchedPasswordError": "As palavras-passes não coincidem.",
|
||||
"alreadyHaveAnAccount": "Já possuis uma conta?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Password",
|
||||
"repeatPasswordHint": "Confirma a tua password"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Entre no @:appName",
|
||||
"loginButtonText": "Login",
|
||||
"buttonText": "Entre",
|
||||
"forgotPassword": "Esqueceste-te da tua palavra-passe?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Palavra-passe",
|
||||
"dontHaveAnAccount": "Não possuis uma conta?",
|
||||
"repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
|
||||
"unmatchedPasswordError": "As palavras-passes não conferem."
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Cria um ambiente de trabalho",
|
||||
"hint": "ambiente de trabalho",
|
||||
"notFoundError": "Ambiente de trabalho não encontrada"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Partilhar",
|
||||
"workInProgress": "Em breve",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Copiar o link"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Renomear",
|
||||
"delete": "Apagar",
|
||||
"duplicate": "Duplicar"
|
||||
},
|
||||
"blankPageTitle": "Página em branco",
|
||||
"newPageText": "Nova página",
|
||||
"trash": {
|
||||
"text": "Lixo",
|
||||
"restoreAll": "Restaurar todos",
|
||||
"deleteAll": "Apagar todos",
|
||||
"pageHeader": {
|
||||
"fileName": "Nome do ficheiro",
|
||||
"lastModified": "Última modificação",
|
||||
"created": "Criado"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Esta página está no lixo",
|
||||
"restore": "Restaurar a página",
|
||||
"deletePermanent": "Apagar permanentemente"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Nome da página",
|
||||
"questionBubble": {
|
||||
"whatsNew": "O que há de novo?",
|
||||
"help": "Ajuda & Suporte",
|
||||
"debug": {
|
||||
"name": "Informação de depuração",
|
||||
"success": "Copiar informação de depuração para o clipboard!",
|
||||
"fail": "Falha em copiar a informação de depuração para o clipboard"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Adiciona uma nova página.",
|
||||
"defaultNewPageName": "Sem título",
|
||||
"renameDialog": "Renomear"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Desfazer",
|
||||
"redo": "Refazer",
|
||||
"bold": "Negrito",
|
||||
"italic": "Itálico",
|
||||
"underline": "Sublinhado",
|
||||
"strike": "Riscado",
|
||||
"numList": "Lista numerada",
|
||||
"bulletList": "Lista com marcadores",
|
||||
"checkList": "Lista de verificação",
|
||||
"inlineCode": "Embutir código",
|
||||
"quote": "Citação em bloco",
|
||||
"header": "Cabeçalho",
|
||||
"highlight": "Realçar"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "Mudar para o modo Claro.",
|
||||
"darkMode": "Mudar para o modo Escuro."
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Conctatos",
|
||||
"whatsHappening": "O que está a acontecer nesta semana?",
|
||||
"addContact": "Adicionar um conctato",
|
||||
"editContact": "Editar um conctato"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Cancelar",
|
||||
"signIn": "Entrar",
|
||||
"signOut": "Sair",
|
||||
"complete": "Completar",
|
||||
"save": "Guardar"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Bem vindo!",
|
||||
"firstName": "Nome",
|
||||
"middleName": "Nome do Meio",
|
||||
"lastName": "Apelido",
|
||||
"stepX": "Passo {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Erro ao conectar à sua conta.",
|
||||
"failedMsg": "Verifica se concluiste o processo de login no teu navegador."
|
||||
},
|
||||
"google": {
|
||||
"title": "GOOGLE SIGN-IN",
|
||||
"instruction1": "Para importar os teus Conctatos do Google, tens de autorizar esta aplicação usando o teu navegador web.",
|
||||
"instruction2": "Copia este código para a tua área de transferências clicando no ícone ou selecionando o texto:",
|
||||
"instruction3": "Navega até o link a seguir no seu navegador e digite o código acima:",
|
||||
"instruction4": "Clica no botão abaixo ao concluir a inscrição:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Definições",
|
||||
"menu": {
|
||||
"appearance": "Aparência",
|
||||
"language": "Idioma",
|
||||
"open": "Abrir as Definições"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "Modo Claro",
|
||||
"darkLabel": "Modo Escuro"
|
||||
}
|
||||
},
|
||||
"sideBar": {
|
||||
"openSidebar": "Open sidebar",
|
||||
"closeSidebar": "Close sidebar"
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Me",
|
||||
"welcomeText": "Bem vindo ao @:appName",
|
||||
"githubStarText": "Star on GitHub",
|
||||
"subscribeNewsletterText": "Inscreve-te ao Newsletter",
|
||||
"letsGoButtonText": "Bora",
|
||||
"title": "Título",
|
||||
"signUp": {
|
||||
"buttonText": "Inscreve-te",
|
||||
"title": "Inscreve-te ao @:appName",
|
||||
"getStartedText": "Começar",
|
||||
"emptyPasswordError": "A palavra-passe não pode estar em branco.",
|
||||
"repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
|
||||
"unmatchedPasswordError": "As palavras-passes não coincidem.",
|
||||
"alreadyHaveAnAccount": "Já possuis uma conta?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Password",
|
||||
"repeatPasswordHint": "Confirma a tua password"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Entre no @:appName",
|
||||
"loginButtonText": "Login",
|
||||
"buttonText": "Entre",
|
||||
"forgotPassword": "Esqueceste-te da tua palavra-passe?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Palavra-passe",
|
||||
"dontHaveAnAccount": "Não possuis uma conta?",
|
||||
"repeatPasswordEmptyError": "Confirmar a palavra-passe não pode estar em branco.",
|
||||
"unmatchedPasswordError": "As palavras-passes não conferem."
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Cria um ambiente de trabalho",
|
||||
"hint": "ambiente de trabalho",
|
||||
"notFoundError": "Ambiente de trabalho não encontrada"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Partilhar",
|
||||
"workInProgress": "Em breve",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Copiar o link"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Renomear",
|
||||
"delete": "Apagar",
|
||||
"duplicate": "Duplicar"
|
||||
},
|
||||
"blankPageTitle": "Página em branco",
|
||||
"newPageText": "Nova página",
|
||||
"trash": {
|
||||
"text": "Lixo",
|
||||
"restoreAll": "Restaurar todos",
|
||||
"deleteAll": "Apagar todos",
|
||||
"pageHeader": {
|
||||
"fileName": "Nome do ficheiro",
|
||||
"lastModified": "Última modificação",
|
||||
"created": "Criado"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Esta página está no lixo",
|
||||
"restore": "Restaurar a página",
|
||||
"deletePermanent": "Apagar permanentemente"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Nome da página",
|
||||
"questionBubble": {
|
||||
"whatsNew": "O que há de novo?",
|
||||
"help": "Ajuda & Suporte",
|
||||
"debug": {
|
||||
"name": "Informação de depuração",
|
||||
"success": "Copiar informação de depuração para o clipboard!",
|
||||
"fail": "Falha em copiar a informação de depuração para o clipboard"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Adiciona uma nova página.",
|
||||
"defaultNewPageName": "Sem título",
|
||||
"renameDialog": "Renomear"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Desfazer",
|
||||
"redo": "Refazer",
|
||||
"bold": "Negrito",
|
||||
"italic": "Itálico",
|
||||
"underline": "Sublinhado",
|
||||
"strike": "Riscado",
|
||||
"numList": "Lista numerada",
|
||||
"bulletList": "Lista com marcadores",
|
||||
"checkList": "Lista de verificação",
|
||||
"inlineCode": "Embutir código",
|
||||
"quote": "Citação em bloco",
|
||||
"header": "Cabeçalho",
|
||||
"highlight": "Realçar"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "Mudar para o modo Claro.",
|
||||
"darkMode": "Mudar para o modo Escuro."
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Conctatos",
|
||||
"whatsHappening": "O que está a acontecer nesta semana?",
|
||||
"addContact": "Adicionar um conctato",
|
||||
"editContact": "Editar um conctato"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Cancelar",
|
||||
"signIn": "Entrar",
|
||||
"signOut": "Sair",
|
||||
"complete": "Completar",
|
||||
"save": "Guardar"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Bem vindo!",
|
||||
"firstName": "Nome",
|
||||
"middleName": "Nome do Meio",
|
||||
"lastName": "Apelido",
|
||||
"stepX": "Passo {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Erro ao conectar à sua conta.",
|
||||
"failedMsg": "Verifica se concluiste o processo de login no teu navegador."
|
||||
},
|
||||
"google": {
|
||||
"title": "GOOGLE SIGN-IN",
|
||||
"instruction1": "Para importar os teus Conctatos do Google, tens de autorizar esta aplicação usando o teu navegador web.",
|
||||
"instruction2": "Copia este código para a tua área de transferências clicando no ícone ou selecionando o texto:",
|
||||
"instruction3": "Navega até o link a seguir no seu navegador e digite o código acima:",
|
||||
"instruction4": "Clica no botão abaixo ao concluir a inscrição:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Definições",
|
||||
"menu": {
|
||||
"appearance": "Aparência",
|
||||
"language": "Idioma",
|
||||
"open": "Abrir as Definições"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "Modo Claro",
|
||||
"darkLabel": "Modo Escuro"
|
||||
}
|
||||
},
|
||||
"sideBar": {
|
||||
"openSidebar": "Open sidebar",
|
||||
"closeSidebar": "Close sidebar"
|
||||
}
|
||||
|
||||
}
|
@ -1,348 +1,413 @@
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Я",
|
||||
"welcomeText": "Добро пожаловать в @:appName",
|
||||
"githubStarText": "Поставить звезду на GitHub",
|
||||
"subscribeNewsletterText": "Подписаться на рассылку",
|
||||
"letsGoButtonText": "Начнём",
|
||||
"title": "Заголовок",
|
||||
"signUp": {
|
||||
"buttonText": "Зарегистрироваться",
|
||||
"title": "Регистрация в @:appName",
|
||||
"getStartedText": "Начать",
|
||||
"emptyPasswordError": "Пароль не может быть пустым",
|
||||
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
|
||||
"unmatchedPasswordError": "Пароли не совпадают",
|
||||
"alreadyHaveAnAccount": "Уже есть аккаунт?",
|
||||
"emailHint": "Электронная почта",
|
||||
"passwordHint": "Пароль",
|
||||
"repeatPasswordHint": "Повторите пароль"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Войти в @:appName",
|
||||
"loginButtonText": "Войти",
|
||||
"buttonText": "Авторизация",
|
||||
"forgotPassword": "Забыли пароль?",
|
||||
"emailHint": "Электронная почта",
|
||||
"passwordHint": "Пароль",
|
||||
"dontHaveAnAccount": "Нет аккаунта?",
|
||||
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
|
||||
"unmatchedPasswordError": "Пароли не совпадают"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Создать рабочее пространство",
|
||||
"hint": "рабочее пространство",
|
||||
"notFoundError": "Нет такого рабочего пространства"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Поделиться",
|
||||
"workInProgress": "В разработке",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Скопировать ссылку"
|
||||
},
|
||||
"moreAction": {
|
||||
"small": "маленький",
|
||||
"medium": "средний",
|
||||
"large": "большой",
|
||||
"fontSize": "Размер шрифта"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Переименовать",
|
||||
"delete": "Удалить",
|
||||
"duplicate": "Дублировать"
|
||||
},
|
||||
"blankPageTitle": "Пустая страница",
|
||||
"newPageText": "Новая страница",
|
||||
"trash": {
|
||||
"text": "Корзина",
|
||||
"restoreAll": "Восстановить всё",
|
||||
"deleteAll": "Очистить",
|
||||
"pageHeader": {
|
||||
"fileName": "Имя",
|
||||
"lastModified": "Последнее изменение",
|
||||
"created": "Создан"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Эта страница в Корзине",
|
||||
"restore": "Восстановить страницу",
|
||||
"deletePermanent": "Удалить навсегда"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Имя страницы",
|
||||
"questionBubble": {
|
||||
"whatsNew": "Что нового?",
|
||||
"help": "Помощь",
|
||||
"debug": {
|
||||
"name": "Отладочная информация",
|
||||
"success": "Скопировано в буфер обмена!",
|
||||
"fail": "Не получилось скопировать"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Быстро добавить новую страницу",
|
||||
"defaultNewPageName": "Без заголовка",
|
||||
"renameDialog": "Переименовать"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Отменить",
|
||||
"redo": "Повторить",
|
||||
"bold": "Жирный",
|
||||
"italic": "Курсив",
|
||||
"underline": "Подчёркнутый",
|
||||
"strike": "Зачёркнутый",
|
||||
"numList": "Нумерованный список",
|
||||
"bulletList": "Маркированный список",
|
||||
"checkList": "Список To-Do",
|
||||
"inlineCode": "Код",
|
||||
"quote": "Цитата",
|
||||
"header": "Заголовок",
|
||||
"highlight": "Выделение",
|
||||
"color": "Цвет"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "Переключить на светлую тему",
|
||||
"darkMode": "Переключить на тёмную тему",
|
||||
"openAsPage": "Открыть как страницу",
|
||||
"addNewRow": "Добавить новую строку",
|
||||
"openMenu": "Открыть меню",
|
||||
"viewDataBase": "Просмотр базы данных",
|
||||
"referencePage": "Ссылаются на {name}"
|
||||
},
|
||||
"sideBar": {
|
||||
"closeSidebar": "Закрыть боковое меню",
|
||||
"openSidebar": "Открыть боковое меню"
|
||||
},
|
||||
"notifications": {
|
||||
"export": {
|
||||
"markdown": "Заметка экспортирована в Markdown",
|
||||
"path": "Документы/flowy"
|
||||
}
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Контакты",
|
||||
"whatsHappening": "Какие события на этой неделе?",
|
||||
"addContact": "Добавить контакт",
|
||||
"editContact": "Редактировать контакт"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Отмена",
|
||||
"signIn": "Войти",
|
||||
"signOut": "Выйти",
|
||||
"complete": "Завершить",
|
||||
"save": "Сохранить"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Добро пожаловать!",
|
||||
"firstName": "Имя",
|
||||
"middleName": "Отчество",
|
||||
"lastName": "Фамилия",
|
||||
"stepX": "Этап {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Не удалось подключиться к вашей учетной записи.",
|
||||
"failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
|
||||
},
|
||||
"google": {
|
||||
"title": "Вход через Google",
|
||||
"instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
|
||||
"instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
|
||||
"instruction3": "Пройдите по ссылке и введите этот код:",
|
||||
"instruction4": "Нажмите на кнопку ниже, когда завершите вход:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Настройки",
|
||||
"menu": {
|
||||
"appearance": "Внешний вид",
|
||||
"language": "Язык",
|
||||
"user": "Пользователь",
|
||||
"files": "Файлы",
|
||||
"open": "Открыть настройки"
|
||||
},
|
||||
"appearance": {
|
||||
"themeMode": {
|
||||
"label": "Режим темы",
|
||||
"light": "Светлая",
|
||||
"dark": "Тёмная",
|
||||
"system": "Системная"
|
||||
},
|
||||
"theme": "Тема"
|
||||
},
|
||||
"files": {
|
||||
"defaultLocation": "Где сейчас хранятся ваши данные",
|
||||
"doubleTapToCopy": "Нажмите дважды, чтобы скопировать путь",
|
||||
"restoreLocation": "Восстановить путь AppFlowy по умолчанию",
|
||||
"customizeLocation": "Открыть другую папку",
|
||||
"restartApp": "Пожалуйста, перезапустите приложение, чтобы изменения вступили в силу.",
|
||||
"exportDatabase": "Экспорт базы данных",
|
||||
"selectFiles": "Выбрать файлы, которые необходимо экспортировать",
|
||||
"createNewFolder": "Создать новую папку",
|
||||
"createNewFolderDesc": "Указать, где хранить свои данные ...",
|
||||
"open": "Открыть",
|
||||
"openFolder": "Открыть существующую папку",
|
||||
"openFolderDesc": "Чтение и запись в существующую папку AppFlowy ...",
|
||||
"folderHintText": "имя папки",
|
||||
"location": "Создание новой папки",
|
||||
"locationDesc": "Выбрать имя папки данных AppFlowy",
|
||||
"browser": "Обзор",
|
||||
"create": "Создать",
|
||||
"folderPath": "Путь к вашей папке",
|
||||
"locationCannotBeEmpty": "Путь не может быть пустым"
|
||||
}
|
||||
},
|
||||
"grid": {
|
||||
"settings": {
|
||||
"filter": "Фильтр",
|
||||
"sort": "Сортировать",
|
||||
"sortBy": "Сортировать по",
|
||||
"Properties": "Свойства",
|
||||
"group": "Группировать",
|
||||
"addFilter": "Добавить фильтр",
|
||||
"deleteFilter": "Удалить фильтр",
|
||||
"filterBy": "Фильтровать по...",
|
||||
"typeAValue": "Введите значение..."
|
||||
},
|
||||
"textFilter": {
|
||||
"contains": "Содержит",
|
||||
"doesNotContain": "Не содержит",
|
||||
"endsWith": "Заканчивается на",
|
||||
"startWith": "Начинается с",
|
||||
"is": "Является",
|
||||
"isNot": "Не является",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто",
|
||||
"choicechipPrefix": {
|
||||
"isNot": "Не является",
|
||||
"startWith": "Начинается с",
|
||||
"endWith": "Заканчивается на",
|
||||
"isEmpty": "пусто",
|
||||
"isNotEmpty": "не пусто"
|
||||
}
|
||||
},
|
||||
"checkboxFilter": {
|
||||
"isChecked": "Отмечено",
|
||||
"isUnchecked": "Не отмечено",
|
||||
"choicechipPrefix": {
|
||||
"is": "является"
|
||||
}
|
||||
},
|
||||
"checklistFilter": {
|
||||
"isComplete": "завершено",
|
||||
"isIncomplted": "не завершено"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"is": "Является",
|
||||
"isNot": "Не является",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Содержит",
|
||||
"doesNotContain": "Не содержит",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто"
|
||||
},
|
||||
"field": {
|
||||
"hide": "Скрыть",
|
||||
"insertLeft": "Вставить слева",
|
||||
"insertRight": "Вставить справа",
|
||||
"duplicate": "Дублировать",
|
||||
"delete": "Удалить",
|
||||
"textFieldName": "Текст",
|
||||
"checkboxFieldName": "Чекбокс",
|
||||
"dateFieldName": "Дата",
|
||||
"numberFieldName": "Число",
|
||||
"singleSelectFieldName": "Выбор",
|
||||
"multiSelectFieldName": "Выбор нескольких",
|
||||
"urlFieldName": "URL",
|
||||
"checklistFieldName": "Контрольный список",
|
||||
"numberFormat": "Формат числа",
|
||||
"dateFormat": "Формат даты",
|
||||
"includeTime": "Время",
|
||||
"dateFormatFriendly": "День Месяц, Год",
|
||||
"dateFormatISO": "Год-Месяц-День",
|
||||
"dateFormatLocal": "Месяц/День/Год",
|
||||
"dateFormatUS": "Год/Месяц/День",
|
||||
"timeFormat": "Форматировать время",
|
||||
"invalidTimeFormat": "Неверный формат",
|
||||
"timeFormatTwelveHour": "12 часов",
|
||||
"timeFormatTwentyFourHour": "24 часа",
|
||||
"addSelectOption": "Добавить вариант",
|
||||
"optionTitle": "Варианты",
|
||||
"addOption": "Добавить",
|
||||
"editProperty": "Редактировать свойство",
|
||||
"newColumn": "Добавить колонку",
|
||||
"deleteFieldPromptMessage": "Вы уверены? Свойство будет удалено"
|
||||
},
|
||||
"sort": {
|
||||
"ascending": "По возрастанию",
|
||||
"descending": "По убыванию",
|
||||
"deleteSort": "Удалить сортировку",
|
||||
"addSort": "Добавить сортировку"
|
||||
},
|
||||
"row": {
|
||||
"duplicate": "Дублировать",
|
||||
"delete": "Удалить",
|
||||
"textPlaceholder": "Пусто",
|
||||
"copyProperty": "Свойство скопировано",
|
||||
"count": "Количество",
|
||||
"newRow": "Новая строка"
|
||||
},
|
||||
"selectOption": {
|
||||
"create": "Создать",
|
||||
"purpleColor": "Фиолетовый",
|
||||
"pinkColor": "Розовый",
|
||||
"lightPinkColor": "Светло-розовый",
|
||||
"orangeColor": "Оранжевый",
|
||||
"yellowColor": "Желтый",
|
||||
"limeColor": "Ярко-зелёный",
|
||||
"greenColor": "Зелёный",
|
||||
"aquaColor": "Бирюзовый",
|
||||
"blueColor": "Синий",
|
||||
"deleteTag": "Удалить вариант",
|
||||
"colorPanelTitle": "Цвета",
|
||||
"panelTitle": "Выберите или создайте вариант",
|
||||
"searchOption": "Поиск"
|
||||
},
|
||||
"checklist": {
|
||||
"panelTitle": "Добавить элемент"
|
||||
},
|
||||
"menuName": "Сетка"
|
||||
},
|
||||
"document": {
|
||||
"menuName": "Документ",
|
||||
"date": {
|
||||
"timeHintTextInTwelveHour": "01:00 PM",
|
||||
"timeHintTextInTwentyFourHour": "13:00"
|
||||
},
|
||||
"slashMenu": {
|
||||
"board": {
|
||||
"selectABoardToLinkTo": "Выбрать доску для связи с"
|
||||
},
|
||||
"grid": {
|
||||
"selectAGridToLinkTo": "Выберите сетку для связи с"
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"referencedBoard": "Связанные доски",
|
||||
"referencedGrid": "Связанные сетки"
|
||||
}
|
||||
},
|
||||
"board": {
|
||||
"column": {
|
||||
"create_new_card": "Создать"
|
||||
},
|
||||
"menuName": "Доска"
|
||||
},
|
||||
"calendar": {
|
||||
"menuName": "Календарь",
|
||||
"navigation": {
|
||||
"today": "Сегодня",
|
||||
"jumpToday": "Перейти к сегодняшнему дню",
|
||||
"previousMonth": "Предыдущий месяц",
|
||||
"nextMonth": "Следующий месяц"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Я",
|
||||
"welcomeText": "Добро пожаловать в @:appName",
|
||||
"githubStarText": "Поставить звезду на GitHub",
|
||||
"subscribeNewsletterText": "Подписаться на рассылку",
|
||||
"letsGoButtonText": "Начнём",
|
||||
"title": "Заголовок",
|
||||
"signUp": {
|
||||
"buttonText": "Зарегистрироваться",
|
||||
"title": "Регистрация в @:appName",
|
||||
"getStartedText": "Начать",
|
||||
"emptyPasswordError": "Пароль не может быть пустым",
|
||||
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
|
||||
"unmatchedPasswordError": "Пароли не совпадают",
|
||||
"alreadyHaveAnAccount": "Уже есть аккаунт?",
|
||||
"emailHint": "Электронная почта",
|
||||
"passwordHint": "Пароль",
|
||||
"repeatPasswordHint": "Повторите пароль"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Войти в @:appName",
|
||||
"loginButtonText": "Войти",
|
||||
"buttonText": "Авторизация",
|
||||
"forgotPassword": "Забыли пароль?",
|
||||
"emailHint": "Электронная почта",
|
||||
"passwordHint": "Пароль",
|
||||
"dontHaveAnAccount": "Нет аккаунта?",
|
||||
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
|
||||
"unmatchedPasswordError": "Пароли не совпадают"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Создать рабочее пространство",
|
||||
"hint": "рабочее пространство",
|
||||
"notFoundError": "Нет такого рабочего пространства"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Поделиться",
|
||||
"workInProgress": "В разработке",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Скопировать ссылку"
|
||||
},
|
||||
"moreAction": {
|
||||
"small": "маленький",
|
||||
"medium": "средний",
|
||||
"large": "большой",
|
||||
"fontSize": "Размер шрифта"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Переименовать",
|
||||
"delete": "Удалить",
|
||||
"duplicate": "Дублировать"
|
||||
},
|
||||
"blankPageTitle": "Пустая страница",
|
||||
"newPageText": "Новая страница",
|
||||
"trash": {
|
||||
"text": "Корзина",
|
||||
"restoreAll": "Восстановить всё",
|
||||
"deleteAll": "Очистить",
|
||||
"pageHeader": {
|
||||
"fileName": "Имя",
|
||||
"lastModified": "Последнее изменение",
|
||||
"created": "Создан"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Эта страница в Корзине",
|
||||
"restore": "Восстановить страницу",
|
||||
"deletePermanent": "Удалить навсегда"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Имя страницы",
|
||||
"questionBubble": {
|
||||
"whatsNew": "Что нового?",
|
||||
"help": "Помощь",
|
||||
"debug": {
|
||||
"name": "Отладочная информация",
|
||||
"success": "Скопировано в буфер обмена!",
|
||||
"fail": "Не получилось скопировать"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Быстро добавить новую страницу",
|
||||
"defaultNewPageName": "Без заголовка",
|
||||
"renameDialog": "Переименовать"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Отменить",
|
||||
"redo": "Повторить",
|
||||
"bold": "Жирный",
|
||||
"italic": "Курсив",
|
||||
"underline": "Подчёркнутый",
|
||||
"strike": "Зачёркнутый",
|
||||
"numList": "Нумерованный список",
|
||||
"bulletList": "Маркированный список",
|
||||
"checkList": "Список To-Do",
|
||||
"inlineCode": "Код",
|
||||
"quote": "Цитата",
|
||||
"header": "Заголовок",
|
||||
"highlight": "Выделение",
|
||||
"color": "Цвет"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "Переключить на светлую тему",
|
||||
"darkMode": "Переключить на тёмную тему",
|
||||
"openAsPage": "Открыть как страницу",
|
||||
"addNewRow": "Добавить новую строку",
|
||||
"openMenu": "Открыть меню",
|
||||
"viewDataBase": "Просмотр базы данных",
|
||||
"referencePage": "Ссылаются на {name}"
|
||||
},
|
||||
"sideBar": {
|
||||
"closeSidebar": "Закрыть боковое меню",
|
||||
"openSidebar": "Открыть боковое меню"
|
||||
},
|
||||
"notifications": {
|
||||
"export": {
|
||||
"markdown": "Заметка экспортирована в Markdown",
|
||||
"path": "Документы/flowy"
|
||||
}
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Контакты",
|
||||
"whatsHappening": "Какие события на этой неделе?",
|
||||
"addContact": "Добавить контакт",
|
||||
"editContact": "Редактировать контакт"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Отмена",
|
||||
"signIn": "Войти",
|
||||
"signOut": "Выйти",
|
||||
"complete": "Завершить",
|
||||
"save": "Сохранить",
|
||||
"generate": "Сгенерировать",
|
||||
"esc": "ESC",
|
||||
"keep": "Оставить",
|
||||
"tryAgain": "Повторить",
|
||||
"discard": "Отменить",
|
||||
"replace": "Заменить",
|
||||
"insertBelow": "Вставить ниже"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Добро пожаловать!",
|
||||
"firstName": "Имя",
|
||||
"middleName": "Отчество",
|
||||
"lastName": "Фамилия",
|
||||
"stepX": "Этап {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Не удалось подключиться к вашей учетной записи.",
|
||||
"failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
|
||||
},
|
||||
"google": {
|
||||
"title": "Вход через Google",
|
||||
"instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
|
||||
"instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
|
||||
"instruction3": "Пройдите по ссылке и введите этот код:",
|
||||
"instruction4": "Нажмите на кнопку ниже, когда завершите вход:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Настройки",
|
||||
"menu": {
|
||||
"appearance": "Внешний вид",
|
||||
"language": "Язык",
|
||||
"user": "Пользователь",
|
||||
"files": "Файлы",
|
||||
"open": "Открыть настройки"
|
||||
},
|
||||
"appearance": {
|
||||
"themeMode": {
|
||||
"label": "Режим темы",
|
||||
"light": "Светлая",
|
||||
"dark": "Тёмная",
|
||||
"system": "Системная"
|
||||
},
|
||||
"theme": "Тема"
|
||||
},
|
||||
"files": {
|
||||
"defaultLocation": "Где сейчас хранятся ваши данные",
|
||||
"doubleTapToCopy": "Нажмите дважды, чтобы скопировать путь",
|
||||
"restoreLocation": "Восстановить путь AppFlowy по умолчанию",
|
||||
"customizeLocation": "Открыть другую папку",
|
||||
"restartApp": "Пожалуйста, перезапустите приложение, чтобы изменения вступили в силу.",
|
||||
"exportDatabase": "Экспорт базы данных",
|
||||
"selectFiles": "Выбрать файлы, которые необходимо экспортировать",
|
||||
"createNewFolder": "Создать новую папку",
|
||||
"createNewFolderDesc": "Указать, где хранить свои данные ...",
|
||||
"open": "Открыть",
|
||||
"openFolder": "Открыть существующую папку",
|
||||
"openFolderDesc": "Чтение и запись в существующую папку AppFlowy ...",
|
||||
"folderHintText": "имя папки",
|
||||
"location": "Создание новой папки",
|
||||
"locationDesc": "Выбрать имя папки данных AppFlowy",
|
||||
"browser": "Обзор",
|
||||
"create": "Создать",
|
||||
"folderPath": "Путь к вашей папке",
|
||||
"locationCannotBeEmpty": "Путь не может быть пустым",
|
||||
"pathCopiedSnackbar": "File storage path copied to clipboard!"
|
||||
},
|
||||
"user": {
|
||||
"name": "Имя",
|
||||
"icon": "Иконка",
|
||||
"selectAnIcon": "Выбрать иконку",
|
||||
"pleaseInputYourOpenAIKey": "Введите токен OpenAI"
|
||||
}
|
||||
},
|
||||
"grid": {
|
||||
"settings": {
|
||||
"filter": "Фильтр",
|
||||
"sort": "Сортировать",
|
||||
"sortBy": "Сортировать по",
|
||||
"Properties": "Свойства",
|
||||
"group": "Группировать",
|
||||
"addFilter": "Добавить фильтр",
|
||||
"deleteFilter": "Удалить фильтр",
|
||||
"filterBy": "Фильтровать по...",
|
||||
"typeAValue": "Введите значение..."
|
||||
},
|
||||
"textFilter": {
|
||||
"contains": "Содержит",
|
||||
"doesNotContain": "Не содержит",
|
||||
"endsWith": "Заканчивается на",
|
||||
"startWith": "Начинается с",
|
||||
"is": "Является",
|
||||
"isNot": "Не является",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто",
|
||||
"choicechipPrefix": {
|
||||
"isNot": "Не является",
|
||||
"startWith": "Начинается с",
|
||||
"endWith": "Заканчивается на",
|
||||
"isEmpty": "пусто",
|
||||
"isNotEmpty": "не пусто"
|
||||
}
|
||||
},
|
||||
"checkboxFilter": {
|
||||
"isChecked": "Отмечено",
|
||||
"isUnchecked": "Не отмечено",
|
||||
"choicechipPrefix": {
|
||||
"is": "является"
|
||||
}
|
||||
},
|
||||
"checklistFilter": {
|
||||
"isComplete": "завершено",
|
||||
"isIncomplted": "не завершено"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"is": "Является",
|
||||
"isNot": "Не является",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Содержит",
|
||||
"doesNotContain": "Не содержит",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто"
|
||||
},
|
||||
"field": {
|
||||
"hide": "Скрыть",
|
||||
"insertLeft": "Вставить слева",
|
||||
"insertRight": "Вставить справа",
|
||||
"duplicate": "Дублировать",
|
||||
"delete": "Удалить",
|
||||
"textFieldName": "Текст",
|
||||
"checkboxFieldName": "Чекбокс",
|
||||
"dateFieldName": "Дата",
|
||||
"numberFieldName": "Число",
|
||||
"singleSelectFieldName": "Выбор",
|
||||
"multiSelectFieldName": "Выбор нескольких",
|
||||
"urlFieldName": "URL",
|
||||
"checklistFieldName": "Контрольный список",
|
||||
"numberFormat": "Формат числа",
|
||||
"dateFormat": "Формат даты",
|
||||
"includeTime": "Время",
|
||||
"dateFormatFriendly": "День Месяц, Год",
|
||||
"dateFormatISO": "Год-Месяц-День",
|
||||
"dateFormatLocal": "Месяц/День/Год",
|
||||
"dateFormatUS": "Год/Месяц/День",
|
||||
"dateFormatDayMonthYear": "День/Mесяц/Год",
|
||||
"timeFormat": "Формат времени",
|
||||
"invalidTimeFormat": "Неверный формат",
|
||||
"timeFormatTwelveHour": "12 часов",
|
||||
"timeFormatTwentyFourHour": "24 часа",
|
||||
"addSelectOption": "Добавить вариант",
|
||||
"optionTitle": "Варианты",
|
||||
"addOption": "Добавить",
|
||||
"editProperty": "Редактировать свойство",
|
||||
"newProperty": "Добавить колонку",
|
||||
"deleteFieldPromptMessage": "Вы уверены? Свойство будет удалено"
|
||||
},
|
||||
"sort": {
|
||||
"ascending": "По возрастанию",
|
||||
"descending": "По убыванию",
|
||||
"deleteSort": "Удалить сортировку",
|
||||
"addSort": "Добавить сортировку"
|
||||
},
|
||||
"row": {
|
||||
"duplicate": "Дублировать",
|
||||
"delete": "Удалить",
|
||||
"textPlaceholder": "Пусто",
|
||||
"copyProperty": "Свойство скопировано",
|
||||
"count": "Количество",
|
||||
"newRow": "Новая строка"
|
||||
},
|
||||
"selectOption": {
|
||||
"create": "Создать",
|
||||
"purpleColor": "Фиолетовый",
|
||||
"pinkColor": "Розовый",
|
||||
"lightPinkColor": "Светло-розовый",
|
||||
"orangeColor": "Оранжевый",
|
||||
"yellowColor": "Желтый",
|
||||
"limeColor": "Ярко-зелёный",
|
||||
"greenColor": "Зелёный",
|
||||
"aquaColor": "Бирюзовый",
|
||||
"blueColor": "Синий",
|
||||
"deleteTag": "Удалить вариант",
|
||||
"colorPanelTitle": "Цвета",
|
||||
"panelTitle": "Выберите или создайте вариант",
|
||||
"searchOption": "Поиск"
|
||||
},
|
||||
"checklist": {
|
||||
"panelTitle": "Добавить элемент"
|
||||
},
|
||||
"menuName": "Сетка",
|
||||
"referencedGridPrefix": "Просмотр"
|
||||
},
|
||||
"document": {
|
||||
"menuName": "Документ",
|
||||
"date": {
|
||||
"timeHintTextInTwelveHour": "01:00 PM",
|
||||
"timeHintTextInTwentyFourHour": "13:00"
|
||||
},
|
||||
"slashMenu": {
|
||||
"board": {
|
||||
"selectABoardToLinkTo": "Выбрать доску для связи с",
|
||||
"createANewBoard": "Создать доску"
|
||||
},
|
||||
"grid": {
|
||||
"selectAGridToLinkTo": "Выберите сетку для связи с",
|
||||
"createANewGrid": "Создать сетку"
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"referencedBoard": "Связанные доски",
|
||||
"referencedGrid": "Связанные сетки",
|
||||
"autoGeneratorMenuItemName": "Генератор OpenAI",
|
||||
"autoGeneratorTitleName": "OpenAI: попросить ИИ написать что угодно...",
|
||||
"autoGeneratorLearnMore": "Узнать больше",
|
||||
"autoGeneratorGenerate": "Генерировать",
|
||||
"autoGeneratorHintText": "Спросить OpenAI ...",
|
||||
"autoGeneratorCantGetOpenAIKey": "Не могу получить токен OpenAI",
|
||||
"smartEdit": "ИИ ассистенты",
|
||||
"openAI": "OpenAI",
|
||||
"smartEditFixSpelling": "Исправить правописание",
|
||||
"warning": "⚠️ Ответы ИИ могут быть неправильными или неточными.",
|
||||
"smartEditSummarize": "Выделить суть",
|
||||
"smartEditCouldNotFetchResult": "Не могу получить ответ от OpenAI",
|
||||
"smartEditCouldNotFetchKey": "Не могу получить токен OpenAI",
|
||||
"smartEditDisabled": "Подключить OpenAI",
|
||||
"discardResponse": "Хотите убрать ответы ИИ?",
|
||||
"cover": {
|
||||
"changeCover": "Сменить обложку",
|
||||
"colors": "Цвета",
|
||||
"images": "Изображения",
|
||||
"clearAll": "Очистить",
|
||||
"abstract": "Абстракные",
|
||||
"addCover": "Добавить обложку",
|
||||
"addLocalImage": "Добавить изображение с диска",
|
||||
"invalidImageUrl": "Некорректная ссылка на изображение",
|
||||
"failedToAddImageToGallery": "Ошибка добавления изображения в галерею",
|
||||
"enterImageUrl": "Введите ссылку на изображение",
|
||||
"add": "Добавить",
|
||||
"back": "Назад",
|
||||
"saveToGallery": "Сохранить в галерею",
|
||||
"removeIcon": "Удалить иконку",
|
||||
"pasteImageUrl": "Вставить ссылку на изображение",
|
||||
"or": "ИЛИ",
|
||||
"pickFromFiles": "Выбрать с диска",
|
||||
"couldNotFetchImage": "Не удалось получить изображение",
|
||||
"imageSavingFailed": "Не удалось сохранить изображение",
|
||||
"addIcon": "Добавить иконку",
|
||||
"coverRemoveAlert": "Изображение будет удалено с обложки",
|
||||
"alertDialogConfirmation": "Вы хотите продолжить?"
|
||||
}
|
||||
}
|
||||
},
|
||||
"board": {
|
||||
"column": {
|
||||
"create_new_card": "Создать"
|
||||
},
|
||||
"menuName": "Доска",
|
||||
"referencedBoardPrefix": "Просмотр"
|
||||
},
|
||||
"calendar": {
|
||||
"menuName": "Календарь",
|
||||
"defaultNewCalendarTitle": "Безымянный",
|
||||
"navigation": {
|
||||
"today": "Сегодня",
|
||||
"jumpToday": "Перейти к сегодняшнему дню",
|
||||
"previousMonth": "Предыдущий месяц",
|
||||
"nextMonth": "Следующий месяц"
|
||||
},
|
||||
"settings": {
|
||||
"showWeekNumbers": "Показывать номера недель",
|
||||
"showWeekends": "Показывать выходные",
|
||||
"firstDayOfWeek": "Первый день недели",
|
||||
"layoutDateField": "Вид календаря"
|
||||
}
|
||||
}
|
||||
}
|
@ -195,7 +195,7 @@
|
||||
"optionTitle": "Alternativ",
|
||||
"addOption": "Lägg till alternativ",
|
||||
"editProperty": "Redigera egenskap",
|
||||
"newColumn": "Ny kolumn",
|
||||
"newProperty": "Ny kolumn",
|
||||
"deleteFieldPromptMessage": "Är du säker? Denna egenskap kommer att raderas."
|
||||
},
|
||||
"row": {
|
||||
|
@ -195,7 +195,7 @@
|
||||
"optionTitle": "标签",
|
||||
"addOption": "添加标签",
|
||||
"editProperty": "编辑列属性",
|
||||
"newColumn": "增加一列",
|
||||
"newProperty": "增加一列",
|
||||
"deleteFieldPromptMessage": "确定要删除这个属性吗? "
|
||||
},
|
||||
"row": {
|
||||
|
@ -290,7 +290,7 @@
|
||||
"optionTitle": "選項",
|
||||
"addOption": "新增選項",
|
||||
"editProperty": "編輯內容",
|
||||
"newColumn": "新欄位",
|
||||
"newProperty": "新欄位",
|
||||
"deleteFieldPromptMessage": "你確定嗎?這個內容將被刪除"
|
||||
},
|
||||
"sort": {
|
||||
|
@ -35,7 +35,9 @@ void main() {
|
||||
setUpAll(() async => await service.setUpAll());
|
||||
setUp(() async => await service.setUp());
|
||||
|
||||
testWidgets('integration test unzips the proper workspace and loads it correctly.', (tester) async {
|
||||
testWidgets(
|
||||
'integration test unzips the proper workspace and loads it correctly.',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
expect(find.byType(AppFlowyBoard), findsOneWidget);
|
||||
});
|
||||
|
@ -31,7 +31,8 @@ void main() {
|
||||
setUpAll(() async => await service.setUpAll());
|
||||
setUp(() async => await service.setUp());
|
||||
|
||||
testWidgets('/board shortcut creates a new board and view of the board', (tester) async {
|
||||
testWidgets('/board shortcut creates a new board and view of the board',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
// Needs tab to obtain focus for the app flowy editor.
|
||||
@ -44,24 +45,30 @@ void main() {
|
||||
// does not contain any EditableText widgets.
|
||||
// to interact with the app during an integration test,
|
||||
// simulate physical keyboard events.
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent([
|
||||
LogicalKeyboardKey.slash,
|
||||
LogicalKeyboardKey.keyB,
|
||||
LogicalKeyboardKey.keyO,
|
||||
LogicalKeyboardKey.keyA,
|
||||
LogicalKeyboardKey.keyR,
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.arrowDown,
|
||||
], tester: tester);
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
LogicalKeyboardKey.slash,
|
||||
LogicalKeyboardKey.keyB,
|
||||
LogicalKeyboardKey.keyO,
|
||||
LogicalKeyboardKey.keyA,
|
||||
LogicalKeyboardKey.keyR,
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.arrowDown,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
|
||||
// Checks whether the options in the selection menu
|
||||
// for /board exist.
|
||||
expect(find.byType(SelectionMenuItemWidget), findsAtLeastNWidgets(2));
|
||||
|
||||
// Finalizes the slash command that creates the board.
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent([
|
||||
LogicalKeyboardKey.enter,
|
||||
], tester: tester);
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
LogicalKeyboardKey.enter,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
|
||||
// Checks whether new board is referenced and properly on the page.
|
||||
expect(find.byType(BuiltInPageWidget), findsOneWidget);
|
||||
@ -75,7 +82,8 @@ void main() {
|
||||
expect(find.text(viewOfBoardLabel), findsNWidgets(2));
|
||||
});
|
||||
|
||||
testWidgets('/grid shortcut creates a new grid and view of the grid', (tester) async {
|
||||
testWidgets('/grid shortcut creates a new grid and view of the grid',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
// Needs tab to obtain focus for the app flowy editor.
|
||||
@ -88,14 +96,17 @@ void main() {
|
||||
// does not contain any EditableText widgets.
|
||||
// to interact with the app during an integration test,
|
||||
// simulate physical keyboard events.
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent([
|
||||
LogicalKeyboardKey.slash,
|
||||
LogicalKeyboardKey.keyG,
|
||||
LogicalKeyboardKey.keyR,
|
||||
LogicalKeyboardKey.keyI,
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.arrowDown,
|
||||
], tester: tester);
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
LogicalKeyboardKey.slash,
|
||||
LogicalKeyboardKey.keyG,
|
||||
LogicalKeyboardKey.keyR,
|
||||
LogicalKeyboardKey.keyI,
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.arrowDown,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
|
||||
// Checks whether the options in the selection menu
|
||||
// for /grid exist.
|
||||
|
@ -61,6 +61,8 @@ class TestWorkspaceService {
|
||||
InputFileStream(await workspace.zip.then((value) => value.path));
|
||||
final archive = ZipDecoder().decodeBuffer(inputStream);
|
||||
extractArchiveToDisk(
|
||||
archive, await TestWorkspace._parent.then((value) => value.path));
|
||||
archive,
|
||||
await TestWorkspace._parent.then((value) => value.path),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart' as flutter_test;
|
||||
|
||||
class FlowyTestKeyboard {
|
||||
static Future<void> simulateKeyDownEvent(List<LogicalKeyboardKey> keys,
|
||||
{required flutter_test.WidgetTester tester}) async {
|
||||
static Future<void> simulateKeyDownEvent(
|
||||
List<LogicalKeyboardKey> keys, {
|
||||
required flutter_test.WidgetTester tester,
|
||||
}) async {
|
||||
for (final LogicalKeyboardKey key in keys) {
|
||||
await flutter_test.simulateKeyDownEvent(key);
|
||||
await tester.pumpAndSettle();
|
||||
|
@ -16,9 +16,10 @@ typedef FolderNotificationCallback = void Function(
|
||||
|
||||
class FolderNotificationParser
|
||||
extends NotificationParser<FolderNotification, FlowyError> {
|
||||
FolderNotificationParser(
|
||||
{String? id, required FolderNotificationCallback callback})
|
||||
: super(
|
||||
FolderNotificationParser({
|
||||
String? id,
|
||||
required FolderNotificationCallback callback,
|
||||
}) : super(
|
||||
id: id,
|
||||
callback: callback,
|
||||
tyParser: (ty) => FolderNotification.valueOf(ty),
|
||||
|
@ -16,9 +16,10 @@ typedef DatabaseNotificationCallback = void Function(
|
||||
|
||||
class DatabaseNotificationParser
|
||||
extends NotificationParser<DatabaseNotification, FlowyError> {
|
||||
DatabaseNotificationParser(
|
||||
{String? id, required DatabaseNotificationCallback callback})
|
||||
: super(
|
||||
DatabaseNotificationParser({
|
||||
String? id,
|
||||
required DatabaseNotificationCallback callback,
|
||||
}) : super(
|
||||
id: id,
|
||||
callback: callback,
|
||||
tyParser: (ty) => DatabaseNotification.valueOf(ty),
|
||||
@ -27,7 +28,9 @@ class DatabaseNotificationParser
|
||||
}
|
||||
|
||||
typedef DatabaseNotificationHandler = Function(
|
||||
DatabaseNotification ty, Either<Uint8List, FlowyError> result);
|
||||
DatabaseNotification ty,
|
||||
Either<Uint8List, FlowyError> result,
|
||||
);
|
||||
|
||||
class DatabaseNotificationListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
|
@ -9,11 +9,12 @@ class NotificationParser<T, E> {
|
||||
T? Function(int) tyParser;
|
||||
E Function(Uint8List) errorParser;
|
||||
|
||||
NotificationParser(
|
||||
{this.id,
|
||||
required this.callback,
|
||||
required this.errorParser,
|
||||
required this.tyParser});
|
||||
NotificationParser({
|
||||
this.id,
|
||||
required this.callback,
|
||||
required this.errorParser,
|
||||
required this.tyParser,
|
||||
});
|
||||
void parse(SubscribeObject subject) {
|
||||
if (id != null) {
|
||||
if (subject.id != id) {
|
||||
|
@ -16,9 +16,10 @@ typedef UserNotificationCallback = void Function(
|
||||
|
||||
class UserNotificationParser
|
||||
extends NotificationParser<UserNotification, FlowyError> {
|
||||
UserNotificationParser(
|
||||
{required String id, required UserNotificationCallback callback})
|
||||
: super(
|
||||
UserNotificationParser({
|
||||
required String id,
|
||||
required UserNotificationCallback callback,
|
||||
}) : super(
|
||||
id: id,
|
||||
callback: callback,
|
||||
tyParser: (ty) => UserNotification.valueOf(ty),
|
||||
@ -27,7 +28,9 @@ class UserNotificationParser
|
||||
}
|
||||
|
||||
typedef UserNotificationHandler = Function(
|
||||
UserNotification ty, Either<Uint8List, FlowyError> result);
|
||||
UserNotification ty,
|
||||
Either<Uint8List, FlowyError> result,
|
||||
);
|
||||
|
||||
class UserNotificationListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
|
@ -73,28 +73,35 @@ class CellController<T, D> extends Equatable {
|
||||
/// For example:
|
||||
/// user input: 12
|
||||
/// cell display: $12
|
||||
_cellListener?.start(onCellChanged: (result) {
|
||||
result.fold(
|
||||
(_) {
|
||||
_cellCache.remove(_cacheKey);
|
||||
_loadData();
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener?.start(
|
||||
onCellChanged: (result) {
|
||||
result.fold(
|
||||
(_) {
|
||||
_cellCache.remove(_cacheKey);
|
||||
_loadData();
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
/// 2.Listen on the field event and load the cell data if needed.
|
||||
_fieldListener.start(onFieldChanged: (result) {
|
||||
result.fold((fieldPB) {
|
||||
/// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
|
||||
/// For example:
|
||||
/// ¥12 -> $12
|
||||
if (_cellDataLoader.reloadOnFieldChanged) {
|
||||
_loadData();
|
||||
}
|
||||
_onCellFieldChanged?.call();
|
||||
}, (err) => Log.error(err));
|
||||
});
|
||||
_fieldListener.start(
|
||||
onFieldChanged: (result) {
|
||||
result.fold(
|
||||
(fieldPB) {
|
||||
/// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
|
||||
/// For example:
|
||||
/// ¥12 -> $12
|
||||
if (_cellDataLoader.reloadOnFieldChanged) {
|
||||
_loadData();
|
||||
}
|
||||
_onCellFieldChanged?.call();
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Listen on the cell content or field changes
|
||||
@ -130,7 +137,8 @@ class CellController<T, D> extends Equatable {
|
||||
/// Return the TypeOptionPB that can be parsed into corresponding class using the [parser].
|
||||
/// [PD] is the type that the parser return.
|
||||
Future<Either<PD, FlowyError>> getTypeOption<PD, P extends TypeOptionParser>(
|
||||
P parser) {
|
||||
P parser,
|
||||
) {
|
||||
return _fieldBackendSvc
|
||||
.getFieldTypeOptionData(fieldType: fieldType)
|
||||
.then((result) {
|
||||
|
@ -19,7 +19,9 @@ class CellListener {
|
||||
void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) {
|
||||
_updateCellNotifier?.addPublishListener(onCellChanged);
|
||||
_listener = DatabaseNotificationListener(
|
||||
objectId: "$rowId:$fieldId", handler: _handler);
|
||||
objectId: "$rowId:$fieldId",
|
||||
handler: _handler,
|
||||
);
|
||||
}
|
||||
|
||||
void _handler(DatabaseNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
|
@ -187,8 +187,10 @@ class DatabaseController {
|
||||
);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveGroup(
|
||||
{required String fromGroupId, required String toGroupId}) {
|
||||
Future<Either<Unit, FlowyError>> moveGroup({
|
||||
required String fromGroupId,
|
||||
required String toGroupId,
|
||||
}) {
|
||||
return _databaseViewBackendSvc.moveGroup(
|
||||
fromGroupId: fromGroupId,
|
||||
toGroupId: toGroupId,
|
||||
@ -196,7 +198,8 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
Future<void> updateCalenderLayoutSetting(
|
||||
CalendarLayoutSettingsPB layoutSetting) async {
|
||||
CalendarLayoutSettingsPB layoutSetting,
|
||||
) async {
|
||||
await _databaseViewBackendSvc
|
||||
.updateLayoutSetting(calendarLayoutSetting: layoutSetting)
|
||||
.then((result) {
|
||||
@ -234,16 +237,20 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
void _listenOnRowsChanged() {
|
||||
final callbacks =
|
||||
DatabaseViewCallbacks(onRowsChanged: (rows, rowByRowId, reason) {
|
||||
_databaseCallbacks?.onRowsChanged?.call(rows, rowByRowId, reason);
|
||||
}, onRowsDeleted: (ids) {
|
||||
_databaseCallbacks?.onRowsDeleted?.call(ids);
|
||||
}, onRowsUpdated: (ids) {
|
||||
_databaseCallbacks?.onRowsUpdated?.call(ids);
|
||||
}, onRowsCreated: (ids) {
|
||||
_databaseCallbacks?.onRowsCreated?.call(ids);
|
||||
});
|
||||
final callbacks = DatabaseViewCallbacks(
|
||||
onRowsChanged: (rows, rowByRowId, reason) {
|
||||
_databaseCallbacks?.onRowsChanged?.call(rows, rowByRowId, reason);
|
||||
},
|
||||
onRowsDeleted: (ids) {
|
||||
_databaseCallbacks?.onRowsDeleted?.call(ids);
|
||||
},
|
||||
onRowsUpdated: (ids) {
|
||||
_databaseCallbacks?.onRowsUpdated?.call(ids);
|
||||
},
|
||||
onRowsCreated: (ids) {
|
||||
_databaseCallbacks?.onRowsCreated?.call(ids);
|
||||
},
|
||||
);
|
||||
_viewCache.addListener(callbacks);
|
||||
}
|
||||
|
||||
@ -261,42 +268,58 @@ class DatabaseController {
|
||||
void _listenOnGroupChanged() {
|
||||
groupListener.start(
|
||||
onNumOfGroupsChanged: (result) {
|
||||
result.fold((changeset) {
|
||||
if (changeset.updateGroups.isNotEmpty) {
|
||||
_groupCallbacks?.onUpdateGroup?.call(changeset.updateGroups);
|
||||
}
|
||||
result.fold(
|
||||
(changeset) {
|
||||
if (changeset.updateGroups.isNotEmpty) {
|
||||
_groupCallbacks?.onUpdateGroup?.call(changeset.updateGroups);
|
||||
}
|
||||
|
||||
if (changeset.deletedGroups.isNotEmpty) {
|
||||
_groupCallbacks?.onDeleteGroup?.call(changeset.deletedGroups);
|
||||
}
|
||||
if (changeset.deletedGroups.isNotEmpty) {
|
||||
_groupCallbacks?.onDeleteGroup?.call(changeset.deletedGroups);
|
||||
}
|
||||
|
||||
for (final insertedGroup in changeset.insertedGroups) {
|
||||
_groupCallbacks?.onInsertGroup?.call(insertedGroup);
|
||||
}
|
||||
}, (r) => Log.error(r));
|
||||
for (final insertedGroup in changeset.insertedGroups) {
|
||||
_groupCallbacks?.onInsertGroup?.call(insertedGroup);
|
||||
}
|
||||
},
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
},
|
||||
onGroupByNewField: (result) {
|
||||
result.fold((groups) {
|
||||
_groupCallbacks?.onGroupByField?.call(groups);
|
||||
}, (r) => Log.error(r));
|
||||
result.fold(
|
||||
(groups) {
|
||||
_groupCallbacks?.onGroupByField?.call(groups);
|
||||
},
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _listenOnLayoutChanged() {
|
||||
layoutListener.start(onLayoutChanged: (result) {
|
||||
result.fold((l) {
|
||||
_layoutCallbacks?.onLayoutChanged(l);
|
||||
}, (r) => Log.error(r));
|
||||
});
|
||||
layoutListener.start(
|
||||
onLayoutChanged: (result) {
|
||||
result.fold(
|
||||
(l) {
|
||||
_layoutCallbacks?.onLayoutChanged(l);
|
||||
},
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _listenOnCalendarLayoutChanged() {
|
||||
calendarLayoutListener.start(onCalendarLayoutChanged: (result) {
|
||||
result.fold((l) {
|
||||
_calendarLayoutCallbacks?.onCalendarLayoutChanged(l);
|
||||
}, (r) => Log.error(r));
|
||||
});
|
||||
calendarLayoutListener.start(
|
||||
onCalendarLayoutChanged: (result) {
|
||||
result.fold(
|
||||
(l) {
|
||||
_calendarLayoutCallbacks?.onCalendarLayoutChanged(l);
|
||||
},
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,9 @@ class DatabaseViewBackendService {
|
||||
return DatabaseEventMoveGroup(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<List<FieldPB>, FlowyError>> getFields(
|
||||
{List<FieldIdPB>? fieldIds}) {
|
||||
Future<Either<List<FieldPB>, FlowyError>> getFields({
|
||||
List<FieldIdPB>? fieldIds,
|
||||
}) {
|
||||
var payload = GetFieldPayloadPB.create()..viewId = viewId;
|
||||
|
||||
if (fieldIds != null) {
|
||||
@ -86,15 +87,17 @@ class DatabaseViewBackendService {
|
||||
}
|
||||
|
||||
Future<Either<LayoutSettingPB, FlowyError>> getLayoutSetting(
|
||||
DatabaseLayoutPB layoutType) {
|
||||
DatabaseLayoutPB layoutType,
|
||||
) {
|
||||
final payload = DatabaseLayoutIdPB.create()
|
||||
..viewId = viewId
|
||||
..layout = layoutType;
|
||||
return DatabaseEventGetLayoutSetting(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> updateLayoutSetting(
|
||||
{CalendarLayoutSettingsPB? calendarLayoutSetting}) {
|
||||
Future<Either<Unit, FlowyError>> updateLayoutSetting({
|
||||
CalendarLayoutSettingsPB? calendarLayoutSetting,
|
||||
}) {
|
||||
final layoutSetting = LayoutSettingPB.create();
|
||||
if (calendarLayoutSetting != null) {
|
||||
layoutSetting.calendar = calendarLayoutSetting;
|
||||
|
@ -17,7 +17,9 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||
required FieldCellContext cellContext,
|
||||
}) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
|
||||
_fieldBackendSvc = FieldBackendService(
|
||||
viewId: cellContext.viewId, fieldId: cellContext.field.id),
|
||||
viewId: cellContext.viewId,
|
||||
fieldId: cellContext.field.id,
|
||||
),
|
||||
super(FieldCellState.initial(cellContext)) {
|
||||
on<FieldCellEvent>(
|
||||
(event, emit) async {
|
||||
@ -49,15 +51,17 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_fieldListener.start(onFieldChanged: (result) {
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start(
|
||||
onFieldChanged: (result) {
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,24 +255,26 @@ class FieldController {
|
||||
}
|
||||
}
|
||||
|
||||
_filtersListener.start(onFilterChanged: (result) {
|
||||
result.fold(
|
||||
(FilterChangesetNotificationPB changeset) {
|
||||
final List<FilterInfo> filters = filterInfos;
|
||||
// Deletes the filters
|
||||
deleteFilterFromChangeset(filters, changeset);
|
||||
_filtersListener.start(
|
||||
onFilterChanged: (result) {
|
||||
result.fold(
|
||||
(FilterChangesetNotificationPB changeset) {
|
||||
final List<FilterInfo> filters = filterInfos;
|
||||
// Deletes the filters
|
||||
deleteFilterFromChangeset(filters, changeset);
|
||||
|
||||
// Inserts the new filter if it's not exist
|
||||
insertFilterFromChangeset(filters, changeset);
|
||||
// Inserts the new filter if it's not exist
|
||||
insertFilterFromChangeset(filters, changeset);
|
||||
|
||||
updateFilterFromChangeset(filters, changeset);
|
||||
updateFilterFromChangeset(filters, changeset);
|
||||
|
||||
_updateFieldInfos();
|
||||
_filterNotifier?.filters = filters;
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_updateFieldInfos();
|
||||
_filterNotifier?.filters = filters;
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _listenOnSortChanged() {
|
||||
@ -347,48 +349,54 @@ class FieldController {
|
||||
}
|
||||
}
|
||||
|
||||
_sortsListener.start(onSortChanged: (result) {
|
||||
result.fold(
|
||||
(SortChangesetNotificationPB changeset) {
|
||||
final List<SortInfo> newSortInfos = sortInfos;
|
||||
deleteSortFromChangeset(newSortInfos, changeset);
|
||||
insertSortFromChangeset(newSortInfos, changeset);
|
||||
updateSortFromChangeset(newSortInfos, changeset);
|
||||
_sortsListener.start(
|
||||
onSortChanged: (result) {
|
||||
result.fold(
|
||||
(SortChangesetNotificationPB changeset) {
|
||||
final List<SortInfo> newSortInfos = sortInfos;
|
||||
deleteSortFromChangeset(newSortInfos, changeset);
|
||||
insertSortFromChangeset(newSortInfos, changeset);
|
||||
updateSortFromChangeset(newSortInfos, changeset);
|
||||
|
||||
_updateFieldInfos();
|
||||
_sortNotifier?.sorts = newSortInfos;
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_updateFieldInfos();
|
||||
_sortNotifier?.sorts = newSortInfos;
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _listenOnSettingChanges() {
|
||||
//Listen on setting changes
|
||||
_settingListener.start(onSettingUpdated: (result) {
|
||||
result.fold(
|
||||
(setting) => _updateSetting(setting),
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
});
|
||||
_settingListener.start(
|
||||
onSettingUpdated: (result) {
|
||||
result.fold(
|
||||
(setting) => _updateSetting(setting),
|
||||
(r) => Log.error(r),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _listenOnFieldChanges() {
|
||||
//Listen on field's changes
|
||||
_fieldListener.start(onFieldsChanged: (result) {
|
||||
result.fold(
|
||||
(changeset) {
|
||||
_deleteFields(changeset.deletedFields);
|
||||
_insertFields(changeset.insertedFields);
|
||||
_fieldListener.start(
|
||||
onFieldsChanged: (result) {
|
||||
result.fold(
|
||||
(changeset) {
|
||||
_deleteFields(changeset.deletedFields);
|
||||
_insertFields(changeset.insertedFields);
|
||||
|
||||
final updatedFields = _updateFields(changeset.updatedFields);
|
||||
for (final listener in _updatedFieldCallbacks.values) {
|
||||
listener(updatedFields);
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
final updatedFields = _updateFields(changeset.updatedFields);
|
||||
for (final listener in _updatedFieldCallbacks.values) {
|
||||
listener(updatedFields);
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _updateSetting(DatabaseViewSettingPB setting) {
|
||||
|
@ -36,11 +36,13 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
}
|
||||
},
|
||||
didReceiveFieldChanged: (FieldPB field) {
|
||||
emit(state.copyWith(
|
||||
field: Some(field),
|
||||
name: field.name,
|
||||
canDelete: field.isPrimary,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
field: Some(field),
|
||||
name: field.name,
|
||||
canDelete: field.isPrimary,
|
||||
),
|
||||
);
|
||||
},
|
||||
deleteField: () {
|
||||
state.field.fold(
|
||||
|
@ -17,8 +17,9 @@ class SingleFieldListener {
|
||||
|
||||
SingleFieldListener({required this.fieldId});
|
||||
|
||||
void start(
|
||||
{required void Function(UpdateFieldNotifiedValue) onFieldChanged}) {
|
||||
void start({
|
||||
required void Function(UpdateFieldNotifiedValue) onFieldChanged,
|
||||
}) {
|
||||
_updateFieldNotifier?.addPublishListener(onFieldChanged);
|
||||
_listener = DatabaseNotificationListener(
|
||||
objectId: fieldId,
|
||||
@ -60,8 +61,9 @@ class FieldsListener {
|
||||
DatabaseNotificationListener? _listener;
|
||||
FieldsListener({required this.viewId});
|
||||
|
||||
void start(
|
||||
{required void Function(UpdateFieldsNotifiedValue) onFieldsChanged}) {
|
||||
void start({
|
||||
required void Function(UpdateFieldsNotifiedValue) onFieldsChanged,
|
||||
}) {
|
||||
updateFieldsNotifier?.addPublishListener(onFieldsChanged);
|
||||
_listener = DatabaseNotificationListener(
|
||||
objectId: viewId,
|
||||
|
@ -15,16 +15,25 @@ class DateTypeOptionBloc
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
didSelectDateFormat: (_DidSelectDateFormat value) {
|
||||
emit(state.copyWith(
|
||||
typeOption: _updateTypeOption(dateFormat: value.format)));
|
||||
emit(
|
||||
state.copyWith(
|
||||
typeOption: _updateTypeOption(dateFormat: value.format),
|
||||
),
|
||||
);
|
||||
},
|
||||
didSelectTimeFormat: (_DidSelectTimeFormat value) {
|
||||
emit(state.copyWith(
|
||||
typeOption: _updateTypeOption(timeFormat: value.format)));
|
||||
emit(
|
||||
state.copyWith(
|
||||
typeOption: _updateTypeOption(timeFormat: value.format),
|
||||
),
|
||||
);
|
||||
},
|
||||
includeTime: (_IncludeTime value) {
|
||||
emit(state.copyWith(
|
||||
typeOption: _updateTypeOption(includeTime: value.includeTime)));
|
||||
emit(
|
||||
state.copyWith(
|
||||
typeOption: _updateTypeOption(includeTime: value.includeTime),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
@ -7,16 +7,20 @@ class NumberFormatBloc extends Bloc<NumberFormatEvent, NumberFormatState> {
|
||||
NumberFormatBloc() : super(NumberFormatState.initial()) {
|
||||
on<NumberFormatEvent>(
|
||||
(event, emit) async {
|
||||
event.map(setFilter: (_SetFilter value) {
|
||||
final List<NumberFormat> formats = List.from(NumberFormat.values);
|
||||
if (value.filter.isNotEmpty) {
|
||||
formats.retainWhere((element) => element
|
||||
.title()
|
||||
.toLowerCase()
|
||||
.contains(value.filter.toLowerCase()));
|
||||
}
|
||||
emit(state.copyWith(formats: formats, filter: value.filter));
|
||||
});
|
||||
event.map(
|
||||
setFilter: (_SetFilter value) {
|
||||
final List<NumberFormat> formats = List.from(NumberFormat.values);
|
||||
if (value.filter.isNotEmpty) {
|
||||
formats.retainWhere(
|
||||
(element) => element
|
||||
.title()
|
||||
.toLowerCase()
|
||||
.contains(value.filter.toLowerCase()),
|
||||
);
|
||||
}
|
||||
emit(state.copyWith(formats: formats, filter: value.filter));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -59,9 +59,11 @@ class SelectOptionTypeOptionEvent with _$SelectOptionTypeOptionEvent {
|
||||
const factory SelectOptionTypeOptionEvent.endAddingOption() =
|
||||
_EndAddingOption;
|
||||
const factory SelectOptionTypeOptionEvent.updateOption(
|
||||
SelectOptionPB option) = _UpdateOption;
|
||||
SelectOptionPB option,
|
||||
) = _UpdateOption;
|
||||
const factory SelectOptionTypeOptionEvent.deleteOption(
|
||||
SelectOptionPB option) = _DeleteOption;
|
||||
SelectOptionPB option,
|
||||
) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -158,7 +158,9 @@ abstract class IFieldTypeOptionLoader {
|
||||
Future<Either<TypeOptionPB, FlowyError>> load();
|
||||
|
||||
Future<Either<Unit, FlowyError>> switchToField(
|
||||
String fieldId, FieldType fieldType) {
|
||||
String fieldId,
|
||||
FieldType fieldType,
|
||||
) {
|
||||
final payload = UpdateFieldTypePayloadPB.create()
|
||||
..viewId = viewId
|
||||
..fieldId = fieldId
|
||||
|
@ -107,7 +107,8 @@ class FilterListener {
|
||||
case DatabaseNotification.DidUpdateFilter:
|
||||
result.fold(
|
||||
(payload) => handleChangeset(
|
||||
FilterChangesetNotificationPB.fromBuffer(payload)),
|
||||
FilterChangesetNotificationPB.fromBuffer(payload),
|
||||
),
|
||||
(error) {},
|
||||
);
|
||||
break;
|
||||
|
@ -97,7 +97,8 @@ class FilterBackendService {
|
||||
filter.end = $fixnum.Int64(end);
|
||||
} else {
|
||||
throw Exception(
|
||||
"Start and end should not be null if the timestamp is null");
|
||||
"Start and end should not be null if the timestamp is null",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,9 @@ class DatabaseCalendarLayoutListener {
|
||||
DatabaseNotificationListener? _listener;
|
||||
DatabaseCalendarLayoutListener(this.viewId);
|
||||
|
||||
void start(
|
||||
{required void Function(NewLayoutFieldValue) onCalendarLayoutChanged}) {
|
||||
void start({
|
||||
required void Function(NewLayoutFieldValue) onCalendarLayoutChanged,
|
||||
}) {
|
||||
_newLayoutFieldNotifier?.addPublishListener(onCalendarLayoutChanged);
|
||||
_listener = DatabaseNotificationListener(
|
||||
objectId: viewId,
|
||||
|
@ -102,11 +102,16 @@ class RowCache {
|
||||
final rowInfo = _rowList.get(reorderRow.rowId);
|
||||
if (rowInfo != null) {
|
||||
_rowList.moveRow(
|
||||
reorderRow.rowId, reorderRow.oldIndex, reorderRow.newIndex);
|
||||
_rowChangeReasonNotifier.receive(RowsChangedReason.reorderSingleRow(
|
||||
reorderRow,
|
||||
rowInfo,
|
||||
));
|
||||
reorderRow.rowId,
|
||||
reorderRow.oldIndex,
|
||||
reorderRow.newIndex,
|
||||
);
|
||||
_rowChangeReasonNotifier.receive(
|
||||
RowsChangedReason.reorderSingleRow(
|
||||
reorderRow,
|
||||
rowInfo,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +330,9 @@ class RowsChangedReason with _$RowsChangedReason {
|
||||
const factory RowsChangedReason.initial() = InitialListState;
|
||||
const factory RowsChangedReason.reorderRows() = _ReorderRows;
|
||||
const factory RowsChangedReason.reorderSingleRow(
|
||||
ReorderSingleRowPB reorderRow, RowInfo rowInfo) = _ReorderSingleRow;
|
||||
ReorderSingleRowPB reorderRow,
|
||||
RowInfo rowInfo,
|
||||
) = _ReorderSingleRow;
|
||||
}
|
||||
|
||||
class InsertedIndex {
|
||||
|
@ -23,10 +23,12 @@ class RowController {
|
||||
}
|
||||
|
||||
void addListener({OnRowChanged? onRowChanged}) {
|
||||
_onRowChangedListeners.add(_rowCache.addListener(
|
||||
rowId: rowId,
|
||||
onCellUpdated: onRowChanged,
|
||||
));
|
||||
_onRowChangedListeners.add(
|
||||
_rowCache.addListener(
|
||||
rowId: rowId,
|
||||
onCellUpdated: onRowChanged,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
|
@ -85,10 +85,12 @@ class RowList {
|
||||
insert(index, builder(insertRow.row));
|
||||
|
||||
if (!isContains) {
|
||||
insertIndexs.add(InsertedIndex(
|
||||
index: index,
|
||||
rowId: insertRow.row.id,
|
||||
));
|
||||
insertIndexs.add(
|
||||
InsertedIndex(
|
||||
index: index,
|
||||
rowId: insertRow.row.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return insertIndexs;
|
||||
|
@ -67,7 +67,8 @@ class DatabaseGroupEvent with _$DatabaseGroupEvent {
|
||||
FieldType fieldType,
|
||||
) = _DatabaseGroupEvent;
|
||||
const factory DatabaseGroupEvent.didReceiveFieldUpdate(
|
||||
List<FieldInfo> fields) = _DidReceiveFieldUpdate;
|
||||
List<FieldInfo> fields,
|
||||
) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -78,7 +79,9 @@ class DatabaseGroupState with _$DatabaseGroupState {
|
||||
}) = _DatabaseGroupState;
|
||||
|
||||
factory DatabaseGroupState.initial(
|
||||
String viewId, List<FieldInfo> fieldContexts) =>
|
||||
String viewId,
|
||||
List<FieldInfo> fieldContexts,
|
||||
) =>
|
||||
DatabaseGroupState(
|
||||
viewId: viewId,
|
||||
fieldContexts: fieldContexts,
|
||||
|
@ -13,11 +13,13 @@ class DatabasePropertyBloc
|
||||
final FieldController _fieldController;
|
||||
Function(List<FieldInfo>)? _onFieldsFn;
|
||||
|
||||
DatabasePropertyBloc(
|
||||
{required String viewId, required FieldController fieldController})
|
||||
: _fieldController = fieldController,
|
||||
DatabasePropertyBloc({
|
||||
required String viewId,
|
||||
required FieldController fieldController,
|
||||
}) : _fieldController = fieldController,
|
||||
super(
|
||||
DatabasePropertyState.initial(viewId, fieldController.fieldInfos)) {
|
||||
DatabasePropertyState.initial(viewId, fieldController.fieldInfos),
|
||||
) {
|
||||
on<DatabasePropertyEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -68,9 +70,12 @@ class DatabasePropertyBloc
|
||||
class DatabasePropertyEvent with _$DatabasePropertyEvent {
|
||||
const factory DatabasePropertyEvent.initial() = _Initial;
|
||||
const factory DatabasePropertyEvent.setFieldVisibility(
|
||||
String fieldId, bool visibility) = _SetFieldVisibility;
|
||||
String fieldId,
|
||||
bool visibility,
|
||||
) = _SetFieldVisibility;
|
||||
const factory DatabasePropertyEvent.didReceiveFieldUpdate(
|
||||
List<FieldInfo> fields) = _DidReceiveFieldUpdate;
|
||||
List<FieldInfo> fields,
|
||||
) = _DidReceiveFieldUpdate;
|
||||
const factory DatabasePropertyEvent.moveField(int fromIndex, int toIndex) =
|
||||
_MoveField;
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ class DatabaseSettingBloc
|
||||
: super(DatabaseSettingState.initial()) {
|
||||
on<DatabaseSettingEvent>(
|
||||
(event, emit) async {
|
||||
event.map(performAction: (_PerformAction value) {
|
||||
emit(state.copyWith(selectedAction: Some(value.action)));
|
||||
});
|
||||
event.map(
|
||||
performAction: (_PerformAction value) {
|
||||
emit(state.copyWith(selectedAction: Some(value.action)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -22,7 +24,8 @@ class DatabaseSettingBloc
|
||||
@freezed
|
||||
class DatabaseSettingEvent with _$DatabaseSettingEvent {
|
||||
const factory DatabaseSettingEvent.performAction(
|
||||
DatabaseSettingAction action) = _PerformAction;
|
||||
DatabaseSettingAction action,
|
||||
) = _PerformAction;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -28,12 +28,14 @@ class SettingController {
|
||||
});
|
||||
|
||||
// Listen on the setting changes
|
||||
_listener.start(onSettingUpdated: (result) {
|
||||
result.fold(
|
||||
(newSetting) => updateSetting(newSetting),
|
||||
(err) => _onError?.call(err),
|
||||
);
|
||||
});
|
||||
_listener.start(
|
||||
onSettingUpdated: (result) {
|
||||
result.fold(
|
||||
(newSetting) => updateSetting(newSetting),
|
||||
(err) => _onError?.call(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void startListening({
|
||||
|
@ -69,9 +69,11 @@ class DatabaseViewCache {
|
||||
}
|
||||
|
||||
if (changeset.insertedRows.isNotEmpty) {
|
||||
_callbacks?.onRowsCreated?.call(changeset.insertedRows
|
||||
.map((insertedRow) => insertedRow.row.id)
|
||||
.toList());
|
||||
_callbacks?.onRowsCreated?.call(
|
||||
changeset.insertedRows
|
||||
.map((insertedRow) => insertedRow.row.id)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
|
@ -105,23 +105,31 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
||||
);
|
||||
},
|
||||
didCreateRow: (group, row, int? index) {
|
||||
emit(state.copyWith(
|
||||
editingRow: Some(BoardEditingRow(
|
||||
group: group,
|
||||
row: row,
|
||||
index: index,
|
||||
)),
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
editingRow: Some(
|
||||
BoardEditingRow(
|
||||
group: group,
|
||||
row: row,
|
||||
index: index,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
_groupItemStartEditing(group, row, true);
|
||||
},
|
||||
startEditingRow: (group, row) {
|
||||
emit(state.copyWith(
|
||||
editingRow: Some(BoardEditingRow(
|
||||
group: group,
|
||||
row: row,
|
||||
index: null,
|
||||
)),
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
editingRow: Some(
|
||||
BoardEditingRow(
|
||||
group: group,
|
||||
row: row,
|
||||
index: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
_groupItemStartEditing(group, row, true);
|
||||
},
|
||||
endEditingRow: (rowId) {
|
||||
@ -175,10 +183,12 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
||||
groupControllers.clear();
|
||||
boardController.clear();
|
||||
|
||||
boardController.addGroups(groups
|
||||
.where((group) => fieldController.getField(group.fieldId) != null)
|
||||
.map((group) => initializeGroupData(group))
|
||||
.toList());
|
||||
boardController.addGroups(
|
||||
groups
|
||||
.where((group) => fieldController.getField(group.fieldId) != null)
|
||||
.map((group) => initializeGroupData(group))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
for (final group in groups) {
|
||||
final controller = initializeGroupController(group);
|
||||
@ -334,7 +344,8 @@ class BoardState with _$BoardState {
|
||||
class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
|
||||
class GridFieldEquatable extends Equatable {
|
||||
|
@ -41,44 +41,46 @@ class GroupController {
|
||||
}
|
||||
|
||||
void startListening() {
|
||||
_listener.start(onGroupChanged: (result) {
|
||||
result.fold(
|
||||
(GroupRowsNotificationPB changeset) {
|
||||
for (final deletedRow in changeset.deletedRows) {
|
||||
group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
|
||||
delegate.removeRow(group, deletedRow);
|
||||
}
|
||||
|
||||
for (final insertedRow in changeset.insertedRows) {
|
||||
final index = insertedRow.hasIndex() ? insertedRow.index : null;
|
||||
if (insertedRow.hasIndex() &&
|
||||
group.rows.length > insertedRow.index) {
|
||||
group.rows.insert(insertedRow.index, insertedRow.row);
|
||||
} else {
|
||||
group.rows.add(insertedRow.row);
|
||||
_listener.start(
|
||||
onGroupChanged: (result) {
|
||||
result.fold(
|
||||
(GroupRowsNotificationPB changeset) {
|
||||
for (final deletedRow in changeset.deletedRows) {
|
||||
group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
|
||||
delegate.removeRow(group, deletedRow);
|
||||
}
|
||||
|
||||
if (insertedRow.isNew) {
|
||||
delegate.addNewRow(group, insertedRow.row, index);
|
||||
} else {
|
||||
delegate.insertRow(group, insertedRow.row, index);
|
||||
}
|
||||
}
|
||||
for (final insertedRow in changeset.insertedRows) {
|
||||
final index = insertedRow.hasIndex() ? insertedRow.index : null;
|
||||
if (insertedRow.hasIndex() &&
|
||||
group.rows.length > insertedRow.index) {
|
||||
group.rows.insert(insertedRow.index, insertedRow.row);
|
||||
} else {
|
||||
group.rows.add(insertedRow.row);
|
||||
}
|
||||
|
||||
for (final updatedRow in changeset.updatedRows) {
|
||||
final index = group.rows.indexWhere(
|
||||
(rowPB) => rowPB.id == updatedRow.id,
|
||||
);
|
||||
|
||||
if (index != -1) {
|
||||
group.rows[index] = updatedRow;
|
||||
delegate.updateRow(group, updatedRow);
|
||||
if (insertedRow.isNew) {
|
||||
delegate.addNewRow(group, insertedRow.row, index);
|
||||
} else {
|
||||
delegate.insertRow(group, insertedRow.row, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
for (final updatedRow in changeset.updatedRows) {
|
||||
final index = group.rows.indexWhere(
|
||||
(rowPB) => rowPB.id == updatedRow.id,
|
||||
);
|
||||
|
||||
if (index != -1) {
|
||||
group.rows[index] = updatedRow;
|
||||
delegate.updateRow(group, updatedRow);
|
||||
}
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
|
@ -10,9 +10,11 @@ class BoardSettingBloc extends Bloc<BoardSettingEvent, BoardSettingState> {
|
||||
: super(BoardSettingState.initial()) {
|
||||
on<BoardSettingEvent>(
|
||||
(event, emit) async {
|
||||
event.when(performAction: (action) {
|
||||
emit(state.copyWith(selectedAction: Some(action)));
|
||||
});
|
||||
event.when(
|
||||
performAction: (action) {
|
||||
emit(state.copyWith(selectedAction: Some(action)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ class _BoardContentState extends State<BoardContent> {
|
||||
late AppFlowyBoardScrollController scrollManager;
|
||||
final cardConfiguration = CardConfiguration<String>();
|
||||
|
||||
final config = AppFlowyBoardConfig(
|
||||
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||
final config = const AppFlowyBoardConfig(
|
||||
groupBackgroundColor: Color(0xffF7F8FC),
|
||||
);
|
||||
|
||||
@override
|
||||
@ -292,9 +292,10 @@ class _BoardContentState extends State<BoardContent> {
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0,
|
||||
);
|
||||
final isLightMode = Theme.of(context).brightness == Brightness.light;
|
||||
return BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
border: Border.fromBorderSide(borderSide),
|
||||
border: isLightMode ? Border.fromBorderSide(borderSide) : null,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
);
|
||||
}
|
||||
@ -349,15 +350,6 @@ class _ToolbarBlocAdaptor extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
extension HexColor on Color {
|
||||
static Color fromHex(String hexString) {
|
||||
final buffer = StringBuffer();
|
||||
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
|
||||
buffer.write(hexString.replaceFirst('#', ''));
|
||||
return Color(int.parse(buffer.toString(), radix: 16));
|
||||
}
|
||||
}
|
||||
|
||||
Widget? _buildHeaderIcon(GroupData customData) {
|
||||
Widget? widget;
|
||||
switch (customData.fieldType) {
|
||||
|
@ -7,6 +7,7 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
@ -104,8 +105,12 @@ class _SettingItem extends StatelessWidget {
|
||||
return SizedBox(
|
||||
height: 30,
|
||||
child: FlowyButton(
|
||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||
isSelected: isSelected,
|
||||
text: FlowyText.medium(action.title()),
|
||||
text: FlowyText.medium(
|
||||
action.title(),
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
onTap: () {
|
||||
context
|
||||
.read<BoardSettingBloc>()
|
||||
|
@ -71,6 +71,7 @@ class _SettingButtonState extends State<_SettingButton> {
|
||||
margin: EdgeInsets.zero,
|
||||
child: FlowyTextButton(
|
||||
LocaleKeys.settings_title.tr(),
|
||||
fontColor: AFThemeExtension.of(context).textColor,
|
||||
fillColor: Colors.transparent,
|
||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||
padding: GridSize.typeOptionContentInsets,
|
||||
|
@ -67,16 +67,20 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
if (index != -1) {
|
||||
allEvents[index] = eventData;
|
||||
}
|
||||
emit(state.copyWith(
|
||||
allEvents: allEvents,
|
||||
updateEvent: eventData,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
allEvents: allEvents,
|
||||
updateEvent: eventData,
|
||||
),
|
||||
);
|
||||
},
|
||||
didReceiveNewEvent: (CalendarEventData<CalendarDayEvent> event) {
|
||||
emit(state.copyWith(
|
||||
allEvents: [...state.allEvents, event],
|
||||
newEvent: event,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
allEvents: [...state.allEvents, event],
|
||||
newEvent: event,
|
||||
),
|
||||
);
|
||||
},
|
||||
didDeleteEvents: (List<String> deletedRowIds) {
|
||||
var events = [...state.allEvents];
|
||||
@ -155,7 +159,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
}
|
||||
|
||||
Future<void> _updateCalendarLayoutSetting(
|
||||
CalendarLayoutSettingsPB layoutSetting) async {
|
||||
CalendarLayoutSettingsPB layoutSetting,
|
||||
) async {
|
||||
return _databaseController.updateCalenderLayoutSetting(layoutSetting);
|
||||
}
|
||||
|
||||
@ -198,7 +203,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
}
|
||||
|
||||
CalendarEventData<CalendarDayEvent>? _calendarEventDataFromEventPB(
|
||||
CalendarEventPB eventPB) {
|
||||
CalendarEventPB eventPB,
|
||||
) {
|
||||
final fieldInfo = fieldInfoByFieldId[eventPB.titleFieldId];
|
||||
if (fieldInfo != null) {
|
||||
final cellId = CellIdentifier(
|
||||
@ -214,7 +220,6 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
|
||||
final date = DateTime.fromMillisecondsSinceEpoch(
|
||||
eventPB.timestamp.toInt() * 1000,
|
||||
isUtc: true,
|
||||
);
|
||||
return CalendarEventData(
|
||||
title: eventPB.title,
|
||||
@ -267,7 +272,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
);
|
||||
|
||||
final onCalendarLayoutFieldChanged = CalendarLayoutCallbacks(
|
||||
onCalendarLayoutChanged: _didReceiveNewLayoutField);
|
||||
onCalendarLayoutChanged: _didReceiveNewLayoutField,
|
||||
);
|
||||
|
||||
_databaseController.addListener(
|
||||
onDatabaseChanged: onDatabaseChanged,
|
||||
@ -299,7 +305,8 @@ class CalendarEvent with _$CalendarEvent {
|
||||
|
||||
// Called after loading the calendar layout setting from the backend
|
||||
const factory CalendarEvent.didReceiveCalendarSettings(
|
||||
CalendarLayoutSettingsPB settings) = _ReceiveCalendarSettings;
|
||||
CalendarLayoutSettingsPB settings,
|
||||
) = _ReceiveCalendarSettings;
|
||||
|
||||
// Called after loading all the current evnets
|
||||
const factory CalendarEvent.didLoadAllEvents(Events events) =
|
||||
@ -307,11 +314,13 @@ class CalendarEvent with _$CalendarEvent {
|
||||
|
||||
// Called when specific event was updated
|
||||
const factory CalendarEvent.didUpdateEvent(
|
||||
CalendarEventData<CalendarDayEvent> event) = _DidUpdateEvent;
|
||||
CalendarEventData<CalendarDayEvent> event,
|
||||
) = _DidUpdateEvent;
|
||||
|
||||
// Called after creating a new event
|
||||
const factory CalendarEvent.didReceiveNewEvent(
|
||||
CalendarEventData<CalendarDayEvent> event) = _DidReceiveNewEvent;
|
||||
CalendarEventData<CalendarDayEvent> event,
|
||||
) = _DidReceiveNewEvent;
|
||||
|
||||
// Called when deleting events
|
||||
const factory CalendarEvent.didDeleteEvents(List<String> rowIds) =
|
||||
@ -323,13 +332,15 @@ class CalendarEvent with _$CalendarEvent {
|
||||
|
||||
// Called when updating the calendar's layout settings
|
||||
const factory CalendarEvent.updateCalendarLayoutSetting(
|
||||
CalendarLayoutSettingsPB layoutSetting) = _UpdateCalendarLayoutSetting;
|
||||
CalendarLayoutSettingsPB layoutSetting,
|
||||
) = _UpdateCalendarLayoutSetting;
|
||||
|
||||
const factory CalendarEvent.didReceiveDatabaseUpdate(DatabasePB database) =
|
||||
_ReceiveDatabaseUpdate;
|
||||
|
||||
const factory CalendarEvent.didReceiveNewLayoutField(
|
||||
CalendarLayoutSettingsPB layoutSettings) = _DidReceiveNewLayoutField;
|
||||
CalendarLayoutSettingsPB layoutSettings,
|
||||
) = _DidReceiveNewLayoutField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -361,7 +372,8 @@ class CalendarState with _$CalendarState {
|
||||
class DatabaseLoadingState with _$DatabaseLoadingState {
|
||||
const factory DatabaseLoadingState.loading() = _Loading;
|
||||
const factory DatabaseLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
|
||||
class CalendarEditingRow {
|
||||
|
@ -22,7 +22,6 @@ class CalendarSettingBloc
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -33,7 +32,8 @@ class CalendarSettingState with _$CalendarSettingState {
|
||||
}) = _CalendarSettingState;
|
||||
|
||||
factory CalendarSettingState.initial(
|
||||
CalendarLayoutSettingsPB? layoutSettings) =>
|
||||
CalendarLayoutSettingsPB? layoutSettings,
|
||||
) =>
|
||||
CalendarSettingState(
|
||||
selectedAction: none(),
|
||||
layoutSetting: layoutSettings == null ? none() : Some(layoutSettings),
|
||||
@ -43,9 +43,11 @@ class CalendarSettingState with _$CalendarSettingState {
|
||||
@freezed
|
||||
class CalendarSettingEvent with _$CalendarSettingEvent {
|
||||
const factory CalendarSettingEvent.performAction(
|
||||
CalendarSettingAction action) = _PerformAction;
|
||||
CalendarSettingAction action,
|
||||
) = _PerformAction;
|
||||
const factory CalendarSettingEvent.updateLayoutSetting(
|
||||
CalendarLayoutSettingsPB setting) = _UpdateLayoutSetting;
|
||||
CalendarLayoutSettingsPB setting,
|
||||
) = _UpdateLayoutSetting;
|
||||
}
|
||||
|
||||
enum CalendarSettingAction {
|
||||
|
@ -62,30 +62,32 @@ class CalendarDayCard extends StatelessWidget {
|
||||
);
|
||||
}).toList();
|
||||
|
||||
final child = Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_Header(
|
||||
date: date,
|
||||
isInMonth: isInMonth,
|
||||
isToday: isToday,
|
||||
onCreate: () => onCreateEvent(date),
|
||||
),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
Flexible(
|
||||
child: ListView.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return children[index];
|
||||
},
|
||||
itemCount: children.length,
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
final child = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: _Header(
|
||||
date: date,
|
||||
isInMonth: isInMonth,
|
||||
isToday: isToday,
|
||||
onCreate: () => onCreateEvent(date),
|
||||
),
|
||||
),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
Flexible(
|
||||
child: ListView.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return children[index];
|
||||
},
|
||||
itemCount: children.length,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return Container(
|
||||
color: backgroundColor,
|
||||
@ -93,7 +95,10 @@ class CalendarDayCard extends StatelessWidget {
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (p) => notifyEnter(context, true),
|
||||
onExit: (p) => notifyEnter(context, false),
|
||||
child: child,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
@ -148,6 +153,15 @@ class _DayEventCell extends StatelessWidget {
|
||||
onTap: onClick,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.fromBorderSide(
|
||||
BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
borderRadius: Corners.s6Border,
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
|
@ -73,9 +73,11 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
listenWhen: (p, c) => p.updateEvent != c.updateEvent,
|
||||
listener: (context, state) {
|
||||
if (state.updateEvent != null) {
|
||||
_eventController.removeWhere((element) =>
|
||||
state.updateEvent!.event!.eventId ==
|
||||
element.event!.eventId);
|
||||
_eventController.removeWhere(
|
||||
(element) =>
|
||||
state.updateEvent!.event!.eventId ==
|
||||
element.event!.eventId,
|
||||
);
|
||||
_eventController.add(state.updateEvent!);
|
||||
}
|
||||
},
|
||||
|
@ -18,6 +18,8 @@ import 'package:protobuf/protobuf.dart';
|
||||
|
||||
import 'calendar_setting.dart';
|
||||
|
||||
/// Widget that displays a list of settings that alters the appearance of the
|
||||
/// calendar
|
||||
class CalendarLayoutSetting extends StatefulWidget {
|
||||
final CalendarSettingContext settingContext;
|
||||
final Function(CalendarLayoutSettingsPB? layoutSettings) onUpdated;
|
||||
@ -96,18 +98,15 @@ class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> {
|
||||
fieldId: settings.layoutFieldId,
|
||||
popoverMutex: popoverMutex,
|
||||
onUpdated: (fieldId) {
|
||||
_updateLayoutSettings(context,
|
||||
onUpdated: widget.onUpdated, layoutFieldId: fieldId);
|
||||
_updateLayoutSettings(
|
||||
context,
|
||||
onUpdated: widget.onUpdated,
|
||||
layoutFieldId: fieldId,
|
||||
);
|
||||
},
|
||||
);
|
||||
default:
|
||||
return ShowWeekends(
|
||||
showWeekends: settings.showWeekends,
|
||||
onUpdated: (showWeekends) {
|
||||
_updateLayoutSettings(context,
|
||||
onUpdated: widget.onUpdated, showWeekends: showWeekends);
|
||||
},
|
||||
);
|
||||
return const SizedBox();
|
||||
}
|
||||
}).toList();
|
||||
|
||||
@ -129,7 +128,8 @@ class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> {
|
||||
}
|
||||
|
||||
List<CalendarLayoutSettingAction> _availableCalendarSettings(
|
||||
CalendarLayoutSettingsPB layoutSettings) {
|
||||
CalendarLayoutSettingsPB layoutSettings,
|
||||
) {
|
||||
List<CalendarLayoutSettingAction> settings = [
|
||||
CalendarLayoutSettingAction.layoutField,
|
||||
// CalendarLayoutSettingAction.layoutType,
|
||||
@ -220,8 +220,9 @@ class LayoutDateField extends StatelessWidget {
|
||||
popupBuilder: (context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<DatabasePropertyBloc>(
|
||||
param1: viewId, param2: fieldController)
|
||||
..add(const DatabasePropertyEvent.initial()),
|
||||
param1: viewId,
|
||||
param2: fieldController,
|
||||
)..add(const DatabasePropertyEvent.initial()),
|
||||
child: BlocBuilder<DatabasePropertyBloc, DatabasePropertyState>(
|
||||
builder: (context, state) {
|
||||
final items = state.fieldContexts
|
||||
@ -264,7 +265,8 @@ class LayoutDateField extends StatelessWidget {
|
||||
child: FlowyButton(
|
||||
margin: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 10.0),
|
||||
text: FlowyText.medium(
|
||||
LocaleKeys.calendar_settings_layoutDateField.tr()),
|
||||
LocaleKeys.calendar_settings_layoutDateField.tr(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -368,7 +370,8 @@ class FirstDayOfWeek extends StatelessWidget {
|
||||
child: FlowyButton(
|
||||
margin: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 10.0),
|
||||
text: FlowyText.medium(
|
||||
LocaleKeys.calendar_settings_firstDayOfWeek.tr()),
|
||||
LocaleKeys.calendar_settings_firstDayOfWeek.tr(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -15,8 +15,8 @@ import 'package:styled_widget/styled_widget.dart';
|
||||
import 'calendar_layout_setting.dart';
|
||||
|
||||
/// The highest-level widget shown in the popover triggered by clicking the
|
||||
/// "Settings" button. By default, shows [AllCalendarSettings] but upon
|
||||
/// selecting a category, replaces contents with contents of the submenu.
|
||||
/// "Settings" button. Shows [AllCalendarSettings] by default, but replaces its
|
||||
/// contents with the submenu when a category is selected.
|
||||
class CalendarSetting extends StatelessWidget {
|
||||
final CalendarSettingContext settingContext;
|
||||
final CalendarLayoutSettingsPB? layoutSettings;
|
||||
|
@ -45,10 +45,12 @@ class CheckboxFilterEditorBloc
|
||||
didReceiveFilter: (FilterPB filter) {
|
||||
final filterInfo = state.filterInfo.copyWith(filter: filter);
|
||||
final checkboxFilter = filterInfo.checkboxFilter()!;
|
||||
emit(state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: checkboxFilter,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: checkboxFilter,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -79,7 +81,8 @@ class CheckboxFilterEditorEvent with _$CheckboxFilterEditorEvent {
|
||||
const factory CheckboxFilterEditorEvent.didReceiveFilter(FilterPB filter) =
|
||||
_DidReceiveFilter;
|
||||
const factory CheckboxFilterEditorEvent.updateCondition(
|
||||
CheckboxFilterConditionPB condition) = _UpdateCondition;
|
||||
CheckboxFilterConditionPB condition,
|
||||
) = _UpdateCondition;
|
||||
const factory CheckboxFilterEditorEvent.delete() = _Delete;
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,12 @@ class ChecklistFilterEditorBloc
|
||||
didReceiveFilter: (FilterPB filter) {
|
||||
final filterInfo = state.filterInfo.copyWith(filter: filter);
|
||||
final checklistFilter = filterInfo.checklistFilter()!;
|
||||
emit(state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: checklistFilter,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: checklistFilter,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -82,7 +84,8 @@ class ChecklistFilterEditorEvent with _$ChecklistFilterEditorEvent {
|
||||
const factory ChecklistFilterEditorEvent.didReceiveFilter(FilterPB filter) =
|
||||
_DidReceiveFilter;
|
||||
const factory ChecklistFilterEditorEvent.updateCondition(
|
||||
ChecklistFilterConditionPB condition) = _UpdateCondition;
|
||||
ChecklistFilterConditionPB condition,
|
||||
) = _UpdateCondition;
|
||||
const factory ChecklistFilterEditorEvent.delete() = _Delete;
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,13 @@ class GridFilterMenuBloc
|
||||
void Function(List<FieldInfo>)? _onFieldFn;
|
||||
|
||||
GridFilterMenuBloc({required this.viewId, required this.fieldController})
|
||||
: super(GridFilterMenuState.initial(
|
||||
viewId,
|
||||
fieldController.filterInfos,
|
||||
fieldController.fieldInfos,
|
||||
)) {
|
||||
: super(
|
||||
GridFilterMenuState.initial(
|
||||
viewId,
|
||||
fieldController.filterInfos,
|
||||
fieldController.fieldInfos,
|
||||
),
|
||||
) {
|
||||
on<GridFilterMenuEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
@ -82,7 +84,8 @@ class GridFilterMenuBloc
|
||||
class GridFilterMenuEvent with _$GridFilterMenuEvent {
|
||||
const factory GridFilterMenuEvent.initial() = _Initial;
|
||||
const factory GridFilterMenuEvent.didReceiveFilters(
|
||||
List<FilterInfo> filters) = _DidReceiveFilters;
|
||||
List<FilterInfo> filters,
|
||||
) = _DidReceiveFilters;
|
||||
const factory GridFilterMenuEvent.didReceiveFields(List<FieldInfo> fields) =
|
||||
_DidReceiveFields;
|
||||
const factory GridFilterMenuEvent.toggleMenu() = _SetMenuVisibility;
|
||||
|
@ -61,10 +61,12 @@ class SelectOptionFilterEditorBloc
|
||||
didReceiveFilter: (FilterPB filter) {
|
||||
final filterInfo = state.filterInfo.copyWith(filter: filter);
|
||||
final selectOptionFilter = filterInfo.selectOptionFilter()!;
|
||||
emit(state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: selectOptionFilter,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: selectOptionFilter,
|
||||
),
|
||||
);
|
||||
},
|
||||
updateFilterDescription: (String desc) {
|
||||
emit(state.copyWith(filterDesc: desc));
|
||||
@ -112,13 +114,17 @@ class SelectOptionFilterEditorBloc
|
||||
class SelectOptionFilterEditorEvent with _$SelectOptionFilterEditorEvent {
|
||||
const factory SelectOptionFilterEditorEvent.initial() = _Initial;
|
||||
const factory SelectOptionFilterEditorEvent.didReceiveFilter(
|
||||
FilterPB filter) = _DidReceiveFilter;
|
||||
FilterPB filter,
|
||||
) = _DidReceiveFilter;
|
||||
const factory SelectOptionFilterEditorEvent.updateCondition(
|
||||
SelectOptionConditionPB condition) = _UpdateCondition;
|
||||
SelectOptionConditionPB condition,
|
||||
) = _UpdateCondition;
|
||||
const factory SelectOptionFilterEditorEvent.updateContent(
|
||||
List<String> optionIds) = _UpdateContent;
|
||||
List<String> optionIds,
|
||||
) = _UpdateContent;
|
||||
const factory SelectOptionFilterEditorEvent.updateFilterDescription(
|
||||
String desc) = _UpdateDesc;
|
||||
String desc,
|
||||
) = _UpdateDesc;
|
||||
const factory SelectOptionFilterEditorEvent.delete() = _Delete;
|
||||
}
|
||||
|
||||
|
@ -43,15 +43,22 @@ class SelectOptionFilterListBloc<T>
|
||||
didReceiveOptions: (newOptions) {
|
||||
List<SelectOptionPB> options = List.from(newOptions);
|
||||
options.retainWhere(
|
||||
(element) => element.name.contains(state.predicate));
|
||||
(element) => element.name.contains(state.predicate),
|
||||
);
|
||||
|
||||
final visibleOptions = options.map((option) {
|
||||
return VisibleSelectOption(
|
||||
option, state.selectedOptionIds.contains(option.id));
|
||||
option,
|
||||
state.selectedOptionIds.contains(option.id),
|
||||
);
|
||||
}).toList();
|
||||
|
||||
emit(state.copyWith(
|
||||
options: options, visibleOptions: visibleOptions));
|
||||
emit(
|
||||
state.copyWith(
|
||||
options: options,
|
||||
visibleOptions: visibleOptions,
|
||||
),
|
||||
);
|
||||
},
|
||||
filterOption: (optionName) {
|
||||
_updateSelectOptions(predicate: optionName, emit: emit);
|
||||
@ -71,11 +78,13 @@ class SelectOptionFilterListBloc<T>
|
||||
selectedOptionIds ?? state.selectedOptionIds,
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
predicate: predicate ?? state.predicate,
|
||||
visibleOptions: visibleOptions,
|
||||
selectedOptionIds: selectedOptionIds ?? state.selectedOptionIds,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
predicate: predicate ?? state.predicate,
|
||||
visibleOptions: visibleOptions,
|
||||
selectedOptionIds: selectedOptionIds ?? state.selectedOptionIds,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<VisibleSelectOption> _makeVisibleOptions(
|
||||
@ -105,11 +114,14 @@ class SelectOptionFilterListBloc<T>
|
||||
class SelectOptionFilterListEvent with _$SelectOptionFilterListEvent {
|
||||
const factory SelectOptionFilterListEvent.initial() = _Initial;
|
||||
const factory SelectOptionFilterListEvent.selectOption(
|
||||
SelectOptionPB option) = _SelectOption;
|
||||
SelectOptionPB option,
|
||||
) = _SelectOption;
|
||||
const factory SelectOptionFilterListEvent.unselectOption(
|
||||
SelectOptionPB option) = _UnSelectOption;
|
||||
SelectOptionPB option,
|
||||
) = _UnSelectOption;
|
||||
const factory SelectOptionFilterListEvent.didReceiveOptions(
|
||||
List<SelectOptionPB> options) = _DidReceiveOptions;
|
||||
List<SelectOptionPB> options,
|
||||
) = _DidReceiveOptions;
|
||||
const factory SelectOptionFilterListEvent.filterOption(String optionName) =
|
||||
_SelectOptionFilter;
|
||||
}
|
||||
|
@ -54,10 +54,12 @@ class TextFilterEditorBloc
|
||||
didReceiveFilter: (FilterPB filter) {
|
||||
final filterInfo = state.filterInfo.copyWith(filter: filter);
|
||||
final textFilter = filterInfo.textFilter()!;
|
||||
emit(state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: textFilter,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
filterInfo: filterInfo,
|
||||
filter: textFilter,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -88,7 +90,8 @@ class TextFilterEditorEvent with _$TextFilterEditorEvent {
|
||||
const factory TextFilterEditorEvent.didReceiveFilter(FilterPB filter) =
|
||||
_DidReceiveFilter;
|
||||
const factory TextFilterEditorEvent.updateCondition(
|
||||
TextFilterConditionPB condition) = _UpdateCondition;
|
||||
TextFilterConditionPB condition,
|
||||
) = _UpdateCondition;
|
||||
const factory TextFilterEditorEvent.updateContent(String content) =
|
||||
_UpdateContent;
|
||||
const factory TextFilterEditorEvent.delete() = _Delete;
|
||||
|
@ -8,9 +8,11 @@ class GridAccessoryMenuBloc
|
||||
final String viewId;
|
||||
|
||||
GridAccessoryMenuBloc({required this.viewId})
|
||||
: super(GridAccessoryMenuState.initial(
|
||||
viewId,
|
||||
)) {
|
||||
: super(
|
||||
GridAccessoryMenuState.initial(
|
||||
viewId,
|
||||
),
|
||||
) {
|
||||
on<GridAccessoryMenuEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
|
@ -39,16 +39,20 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
emit(state.copyWith(grid: Some(grid)));
|
||||
},
|
||||
didReceiveFieldUpdate: (fields) {
|
||||
emit(state.copyWith(
|
||||
fields: GridFieldEquatable(fields),
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
fields: GridFieldEquatable(fields),
|
||||
),
|
||||
);
|
||||
},
|
||||
didReceiveRowUpdate: (newRowInfos, reason) {
|
||||
emit(state.copyWith(
|
||||
rowInfos: newRowInfos,
|
||||
rowCount: newRowInfos.length,
|
||||
reason: reason,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
rowInfos: newRowInfos,
|
||||
rowCount: newRowInfos.length,
|
||||
reason: reason,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -146,7 +150,8 @@ class GridState with _$GridState {
|
||||
class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
Either<Unit, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
|
||||
class GridFieldEquatable extends Equatable {
|
||||
|
@ -40,7 +40,9 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
|
||||
}
|
||||
|
||||
Future<void> _moveField(
|
||||
_MoveField value, Emitter<GridHeaderState> emit) async {
|
||||
_MoveField value,
|
||||
Emitter<GridHeaderState> emit,
|
||||
) async {
|
||||
final fields = List<FieldInfo>.from(state.fields);
|
||||
fields.insert(value.toIndex, fields.removeAt(value.fromIndex));
|
||||
emit(state.copyWith(fields: fields));
|
||||
@ -69,7 +71,10 @@ class GridHeaderEvent with _$GridHeaderEvent {
|
||||
const factory GridHeaderEvent.didReceiveFieldUpdate(List<FieldInfo> fields) =
|
||||
_DidReceiveFieldUpdate;
|
||||
const factory GridHeaderEvent.moveField(
|
||||
FieldPB field, int fromIndex, int toIndex) = _MoveField;
|
||||
FieldPB field,
|
||||
int fromIndex,
|
||||
int toIndex,
|
||||
) = _MoveField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -35,11 +35,13 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
final cells = cellByFieldId.values
|
||||
.map((e) => GridCellEquatable(e.fieldInfo))
|
||||
.toList();
|
||||
emit(state.copyWith(
|
||||
cellByFieldId: cellByFieldId,
|
||||
cells: UnmodifiableListView(cells),
|
||||
changeReason: reason,
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
cellByFieldId: cellByFieldId,
|
||||
cells: UnmodifiableListView(cells),
|
||||
changeReason: reason,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -68,8 +70,9 @@ class RowEvent with _$RowEvent {
|
||||
const factory RowEvent.initial() = _InitialRow;
|
||||
const factory RowEvent.createRow() = _CreateRow;
|
||||
const factory RowEvent.didReceiveCells(
|
||||
CellByFieldId cellsByFieldId, RowsChangedReason reason) =
|
||||
_DidReceiveCells;
|
||||
CellByFieldId cellsByFieldId,
|
||||
RowsChangedReason reason,
|
||||
) = _DidReceiveCells;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -59,7 +59,8 @@ class RowDetailEvent with _$RowDetailEvent {
|
||||
const factory RowDetailEvent.initial() = _Initial;
|
||||
const factory RowDetailEvent.deleteField(String fieldId) = _DeleteField;
|
||||
const factory RowDetailEvent.didReceiveCellDatas(
|
||||
List<CellIdentifier> gridCells) = _DidReceiveCellDatas;
|
||||
List<CellIdentifier> gridCells,
|
||||
) = _DidReceiveCellDatas;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -82,9 +82,10 @@ class CreateSortBloc extends Bloc<CreateSortEvent, CreateSortState> {
|
||||
|
||||
Future<Either<Unit, FlowyError>> _createDefaultSort(FieldInfo field) async {
|
||||
final result = await _sortBackendSvc.insertSort(
|
||||
fieldId: field.id,
|
||||
fieldType: field.fieldType,
|
||||
condition: SortConditionPB.Ascending);
|
||||
fieldId: field.id,
|
||||
fieldType: field.fieldType,
|
||||
condition: SortConditionPB.Ascending,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -100,7 +100,9 @@ class SortEditorEvent with _$SortEditorEvent {
|
||||
const factory SortEditorEvent.didReceiveSorts(List<SortInfo> sortInfos) =
|
||||
_DidReceiveSorts;
|
||||
const factory SortEditorEvent.setCondition(
|
||||
SortInfo sortInfo, SortConditionPB condition) = _SetCondition;
|
||||
SortInfo sortInfo,
|
||||
SortConditionPB condition,
|
||||
) = _SetCondition;
|
||||
const factory SortEditorEvent.deleteSort(SortInfo sortInfo) = _DeleteSort;
|
||||
const factory SortEditorEvent.deleteAllSorts() = _DeleteAllSorts;
|
||||
}
|
||||
|
@ -14,11 +14,13 @@ class SortMenuBloc extends Bloc<SortMenuEvent, SortMenuState> {
|
||||
void Function(List<FieldInfo>)? _onFieldFn;
|
||||
|
||||
SortMenuBloc({required this.viewId, required this.fieldController})
|
||||
: super(SortMenuState.initial(
|
||||
viewId,
|
||||
fieldController.sortInfos,
|
||||
fieldController.fieldInfos,
|
||||
)) {
|
||||
: super(
|
||||
SortMenuState.initial(
|
||||
viewId,
|
||||
fieldController.sortInfos,
|
||||
fieldController.fieldInfos,
|
||||
),
|
||||
) {
|
||||
on<SortMenuEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
|
@ -117,7 +117,8 @@ class FlowyGrid extends StatefulWidget {
|
||||
|
||||
class _FlowyGridState extends State<FlowyGrid> {
|
||||
final _scrollController = GridScrollController(
|
||||
scrollGroupController: LinkedScrollControllerGroup());
|
||||
scrollGroupController: LinkedScrollControllerGroup(),
|
||||
);
|
||||
late ScrollController headerScrollController;
|
||||
|
||||
@override
|
||||
@ -319,13 +320,14 @@ class _GridRowsState extends State<_GridRows> {
|
||||
);
|
||||
|
||||
FlowyOverlay.show(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return RowDetailPage(
|
||||
cellBuilder: cellBuilder,
|
||||
dataController: dataController,
|
||||
);
|
||||
});
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return RowDetailPage(
|
||||
cellBuilder: cellBuilder,
|
||||
dataController: dataController,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,9 @@ class GridScrollController {
|
||||
|
||||
final List<ScrollController> _linkHorizontalControllers = [];
|
||||
|
||||
GridScrollController(
|
||||
{required LinkedScrollControllerGroup scrollGroupController})
|
||||
: _scrollGroupController = scrollGroupController,
|
||||
GridScrollController({
|
||||
required LinkedScrollControllerGroup scrollGroupController,
|
||||
}) : _scrollGroupController = scrollGroupController,
|
||||
verticalController = ScrollController(),
|
||||
horizontalController = scrollGroupController.addAndGet();
|
||||
|
||||
|
@ -28,10 +28,7 @@ class GridSize {
|
||||
vertical: GridSize.cellVPadding,
|
||||
);
|
||||
|
||||
static EdgeInsets get typeOptionContentInsets => const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
);
|
||||
static EdgeInsets get typeOptionContentInsets => const EdgeInsets.all(4);
|
||||
|
||||
static EdgeInsets get footerContentInsets => EdgeInsets.fromLTRB(
|
||||
GridSize.leadingHeaderPadding,
|
||||
|
@ -21,10 +21,11 @@ class GridAccessoryMenu extends StatelessWidget {
|
||||
child: MultiBlocListener(
|
||||
listeners: [
|
||||
BlocListener<GridFilterMenuBloc, GridFilterMenuState>(
|
||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
||||
listener: (context, state) => context
|
||||
.read<GridAccessoryMenuBloc>()
|
||||
.add(const GridAccessoryMenuEvent.toggleMenu())),
|
||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
||||
listener: (context, state) => context
|
||||
.read<GridAccessoryMenuBloc>()
|
||||
.add(const GridAccessoryMenuEvent.toggleMenu()),
|
||||
),
|
||||
BlocListener<SortMenuBloc, SortMenuState>(
|
||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
||||
listener: (context, state) => context
|
||||
|
@ -100,7 +100,9 @@ class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> {
|
||||
}
|
||||
|
||||
Widget _buildFilterPanel(
|
||||
BuildContext context, CheckboxFilterEditorState state) {
|
||||
BuildContext context,
|
||||
CheckboxFilterEditorState state,
|
||||
) {
|
||||
return SizedBox(
|
||||
height: 20,
|
||||
child: Row(
|
||||
|
@ -70,9 +70,11 @@ class _ChecklistFilterChoicechipState extends State<ChecklistFilterChoicechip> {
|
||||
class ChecklistFilterEditor extends StatefulWidget {
|
||||
final ChecklistFilterEditorBloc bloc;
|
||||
final PopoverMutex popoverMutex;
|
||||
const ChecklistFilterEditor(
|
||||
{required this.bloc, required this.popoverMutex, Key? key})
|
||||
: super(key: key);
|
||||
const ChecklistFilterEditor({
|
||||
required this.bloc,
|
||||
required this.popoverMutex,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
ChecklistState createState() => ChecklistState();
|
||||
|
@ -65,8 +65,10 @@ class _ChoicechipFilterDesc extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final arrow = Transform.rotate(
|
||||
angle: -math.pi / 2,
|
||||
child: svgWidget("home/arrow_left",
|
||||
color: AFThemeExtension.of(context).textColor),
|
||||
child: svgWidget(
|
||||
"home/arrow_left",
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
|
@ -110,7 +110,10 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
|
||||
selectedOptionIds: state.filter.optionIds,
|
||||
onSelectedOptions: (optionIds) {
|
||||
context.read<SelectOptionFilterEditorBloc>().add(
|
||||
SelectOptionFilterEditorEvent.updateContent(optionIds));
|
||||
SelectOptionFilterEditorEvent.updateContent(
|
||||
optionIds,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -132,7 +135,9 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
|
||||
}
|
||||
|
||||
Widget _buildFilterPanel(
|
||||
BuildContext context, SelectOptionFilterEditorState state) {
|
||||
BuildContext context,
|
||||
SelectOptionFilterEditorState state,
|
||||
) {
|
||||
return SizedBox(
|
||||
height: 20,
|
||||
child: Row(
|
||||
@ -144,7 +149,8 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
|
||||
popoverMutex: popoverMutex,
|
||||
onCondition: (condition) {
|
||||
context.read<SelectOptionFilterEditorBloc>().add(
|
||||
SelectOptionFilterEditorEvent.updateCondition(condition));
|
||||
SelectOptionFilterEditorEvent.updateCondition(condition),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
|
@ -147,7 +147,9 @@ class _TextFilterEditorState extends State<TextFilterEditor> {
|
||||
}
|
||||
|
||||
Widget _buildFilterTextField(
|
||||
BuildContext context, TextFilterEditorState state) {
|
||||
BuildContext context,
|
||||
TextFilterEditorState state,
|
||||
) {
|
||||
return FlowyTextField(
|
||||
text: state.filter.content,
|
||||
hintText: LocaleKeys.grid_settings_typeAValue.tr(),
|
||||
|
@ -18,8 +18,10 @@ class ConditionButton extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final arrow = Transform.rotate(
|
||||
angle: -math.pi / 2,
|
||||
child: svgWidget("home/arrow_left",
|
||||
color: AFThemeExtension.of(context).textColor),
|
||||
child: svgWidget(
|
||||
"home/arrow_left",
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
|
@ -117,7 +117,10 @@ class _FilterTextFieldDelegate extends SliverPersistentHeaderDelegate {
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
BuildContext context,
|
||||
double shrinkOffset,
|
||||
bool overlapsContent,
|
||||
) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
height: fixHeight,
|
||||
|
@ -95,17 +95,20 @@ class _GridHeaderCellContainer extends StatelessWidget {
|
||||
width: 1.0,
|
||||
);
|
||||
final decoration = BoxDecoration(
|
||||
border: Border(
|
||||
top: borderSide,
|
||||
right: borderSide,
|
||||
bottom: borderSide,
|
||||
));
|
||||
border: Border(
|
||||
top: borderSide,
|
||||
right: borderSide,
|
||||
bottom: borderSide,
|
||||
),
|
||||
);
|
||||
|
||||
return Container(
|
||||
width: width,
|
||||
decoration: decoration,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.expand(), child: child),
|
||||
constraints: const BoxConstraints.expand(),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -149,10 +152,12 @@ class FieldCellButton extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
final FieldPB field;
|
||||
final int? maxLines;
|
||||
final BorderRadius? radius;
|
||||
const FieldCellButton({
|
||||
required this.field,
|
||||
required this.onTap,
|
||||
this.maxLines = 1,
|
||||
this.radius = BorderRadius.zero,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -169,7 +174,7 @@ class FieldCellButton extends StatelessWidget {
|
||||
leftIcon: FlowySvg(
|
||||
name: field.fieldType.iconName(),
|
||||
),
|
||||
radius: BorderRadius.zero,
|
||||
radius: radius,
|
||||
text: FlowyText.medium(
|
||||
text,
|
||||
maxLines: maxLines,
|
||||
|
@ -101,25 +101,27 @@ class _FieldOperationList extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(children: [
|
||||
Flex(
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
_actionCell(FieldAction.hide),
|
||||
HSpace(GridSize.typeOptionSeparatorHeight),
|
||||
_actionCell(FieldAction.duplicate),
|
||||
],
|
||||
),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
Flex(
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
_actionCell(FieldAction.delete),
|
||||
HSpace(GridSize.typeOptionSeparatorHeight),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
]);
|
||||
return Column(
|
||||
children: [
|
||||
Flex(
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
_actionCell(FieldAction.hide),
|
||||
HSpace(GridSize.typeOptionSeparatorHeight),
|
||||
_actionCell(FieldAction.duplicate),
|
||||
],
|
||||
),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
Flex(
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
_actionCell(FieldAction.delete),
|
||||
HSpace(GridSize.typeOptionSeparatorHeight),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _actionCell(FieldAction action) {
|
||||
|
@ -90,11 +90,13 @@ class _SwitchFieldButton extends StatelessWidget {
|
||||
mutex: popoverMutex,
|
||||
offset: const Offset(8, 0),
|
||||
popupBuilder: (popOverContext) {
|
||||
return FieldTypeList(onSelectField: (newFieldType) {
|
||||
context
|
||||
.read<FieldTypeOptionEditBloc>()
|
||||
.add(FieldTypeOptionEditEvent.switchToField(newFieldType));
|
||||
});
|
||||
return FieldTypeList(
|
||||
onSelectField: (newFieldType) {
|
||||
context
|
||||
.read<FieldTypeOptionEditBloc>()
|
||||
.add(FieldTypeOptionEditEvent.switchToField(newFieldType));
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
|
@ -39,7 +39,9 @@ class _GridHeaderSliverAdaptorState extends State<GridHeaderSliverAdaptor> {
|
||||
return BlocProvider(
|
||||
create: (context) {
|
||||
final bloc = getIt<GridHeaderBloc>(
|
||||
param1: widget.viewId, param2: widget.fieldController);
|
||||
param1: widget.viewId,
|
||||
param2: widget.fieldController,
|
||||
);
|
||||
bloc.add(const GridHeaderEvent.initial());
|
||||
return bloc;
|
||||
},
|
||||
@ -98,10 +100,16 @@ class _GridHeaderState extends State<_GridHeader> {
|
||||
builder: (context, state) {
|
||||
final cells = state.fields
|
||||
.where((field) => field.visibility)
|
||||
.map((field) =>
|
||||
FieldCellContext(viewId: widget.viewId, field: field.field))
|
||||
.map((ctx) =>
|
||||
GridFieldCell(key: _getKeyById(ctx.field.id), cellContext: ctx))
|
||||
.map(
|
||||
(field) =>
|
||||
FieldCellContext(viewId: widget.viewId, field: field.field),
|
||||
)
|
||||
.map(
|
||||
(ctx) => GridFieldCell(
|
||||
key: _getKeyById(ctx.field.id),
|
||||
cellContext: ctx,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
return Container(
|
||||
@ -124,8 +132,12 @@ class _GridHeaderState extends State<_GridHeader> {
|
||||
);
|
||||
}
|
||||
|
||||
void _onReorder(List<GridFieldCell> cells, int oldIndex, BuildContext context,
|
||||
int newIndex) {
|
||||
void _onReorder(
|
||||
List<GridFieldCell> cells,
|
||||
int oldIndex,
|
||||
BuildContext context,
|
||||
int newIndex,
|
||||
) {
|
||||
if (cells.length > oldIndex) {
|
||||
final field = cells[oldIndex].cellContext.field;
|
||||
context
|
||||
@ -177,7 +189,7 @@ class CreateFieldButton extends StatelessWidget {
|
||||
constraints: BoxConstraints.loose(const Size(240, 600)),
|
||||
child: FlowyButton(
|
||||
radius: BorderRadius.zero,
|
||||
text: FlowyText.medium(LocaleKeys.grid_field_newColumn.tr()),
|
||||
text: FlowyText.medium(LocaleKeys.grid_field_newProperty.tr()),
|
||||
hoverColor: AFThemeExtension.of(context).greyHover,
|
||||
onTap: () {},
|
||||
leftIcon: const FlowySvg(name: 'home/add'),
|
||||
@ -197,12 +209,17 @@ class SliverHeaderDelegateImplementation
|
||||
final String gridId;
|
||||
final List<FieldPB> fields;
|
||||
|
||||
SliverHeaderDelegateImplementation(
|
||||
{required this.gridId, required this.fields});
|
||||
SliverHeaderDelegateImplementation({
|
||||
required this.gridId,
|
||||
required this.fields,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
BuildContext context,
|
||||
double shrinkOffset,
|
||||
bool overlapsContent,
|
||||
) {
|
||||
return _GridHeader(viewId: gridId);
|
||||
}
|
||||
|
||||
|
@ -76,12 +76,13 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
return DateTypeOptionWidgetBuilder(
|
||||
makeTypeOptionContextWithDataController<DateTypeOptionPB>(
|
||||
viewId: viewId,
|
||||
fieldType: fieldType,
|
||||
dataController: dataController,
|
||||
),
|
||||
popoverMutex);
|
||||
makeTypeOptionContextWithDataController<DateTypeOptionPB>(
|
||||
viewId: viewId,
|
||||
fieldType: fieldType,
|
||||
dataController: dataController,
|
||||
),
|
||||
popoverMutex,
|
||||
);
|
||||
case FieldType.SingleSelect:
|
||||
return SingleSelectTypeOptionWidgetBuilder(
|
||||
makeTypeOptionContextWithDataController<SingleSelectTypeOptionPB>(
|
||||
|
@ -4,7 +4,8 @@ import 'builder.dart';
|
||||
|
||||
class ChecklistTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
|
||||
ChecklistTypeOptionWidgetBuilder(
|
||||
ChecklistTypeOptionContext typeOptionContext);
|
||||
ChecklistTypeOptionContext typeOptionContext,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget? build(BuildContext context) => null;
|
||||
|
@ -299,6 +299,8 @@ extension DateFormatExtension on DateFormat {
|
||||
return LocaleKeys.grid_field_dateFormatLocal.tr();
|
||||
case DateFormat.US:
|
||||
return LocaleKeys.grid_field_dateFormatUS.tr();
|
||||
case DateFormat.DayMonthYear:
|
||||
return LocaleKeys.grid_field_dateFormatDayMonthYear.tr();
|
||||
default:
|
||||
throw UnimplementedError;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import 'package:appflowy/plugins/database_view/application/field/type_option/num
|
||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database/format.pbenum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -28,10 +29,13 @@ class NumberTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
|
||||
|
||||
@override
|
||||
Widget? build(BuildContext context) {
|
||||
return Column(children: [
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
_widget,
|
||||
]);
|
||||
return Column(
|
||||
children: [
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
const TypeOptionSeparator(),
|
||||
_widget,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,55 +53,65 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
return BlocProvider(
|
||||
create: (context) =>
|
||||
NumberTypeOptionBloc(typeOptionContext: typeOptionContext),
|
||||
child: SizedBox(
|
||||
height: GridSize.popoverItemHeight,
|
||||
child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
|
||||
listener: (context, state) =>
|
||||
typeOptionContext.typeOption = state.typeOption,
|
||||
builder: (context, state) {
|
||||
final button = SizedBox(
|
||||
height: GridSize.popoverItemHeight,
|
||||
child: FlowyButton(
|
||||
margin: GridSize.typeOptionContentInsets,
|
||||
rightIcon: svgWidget(
|
||||
"grid/more",
|
||||
color: Theme.of(context).iconTheme.color,
|
||||
),
|
||||
text: Row(
|
||||
children: [
|
||||
FlowyText.medium(LocaleKeys.grid_field_numberFormat.tr()),
|
||||
const Spacer(),
|
||||
FlowyText.regular(state.typeOption.format.title()),
|
||||
],
|
||||
),
|
||||
child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
|
||||
listener: (context, state) =>
|
||||
typeOptionContext.typeOption = state.typeOption,
|
||||
builder: (context, state) {
|
||||
final selectNumUnitButton = SizedBox(
|
||||
height: GridSize.popoverItemHeight,
|
||||
child: FlowyButton(
|
||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||
margin: GridSize.typeOptionContentInsets,
|
||||
rightIcon: svgWidget(
|
||||
"grid/more",
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
);
|
||||
text: FlowyText.regular(
|
||||
state.typeOption.format.title(),
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return AppFlowyPopover(
|
||||
mutex: popoverMutex,
|
||||
triggerActions:
|
||||
PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
||||
offset: const Offset(8, 0),
|
||||
constraints: BoxConstraints.loose(const Size(460, 440)),
|
||||
margin: EdgeInsets.zero,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: button,
|
||||
),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return NumberFormatList(
|
||||
onSelected: (format) {
|
||||
context
|
||||
.read<NumberTypeOptionBloc>()
|
||||
.add(NumberTypeOptionEvent.didSelectFormat(format));
|
||||
PopoverContainer.of(popoverContext).close();
|
||||
final numFormatTitle = Container(
|
||||
padding: const EdgeInsets.only(left: 6),
|
||||
height: GridSize.popoverItemHeight,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.grid_field_numberFormat.tr(),
|
||||
color: AFThemeExtension.of(context).textColor,
|
||||
),
|
||||
);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
numFormatTitle,
|
||||
AppFlowyPopover(
|
||||
mutex: popoverMutex,
|
||||
triggerActions:
|
||||
PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
||||
offset: const Offset(8, 0),
|
||||
constraints: BoxConstraints.loose(const Size(460, 440)),
|
||||
margin: EdgeInsets.zero,
|
||||
child: selectNumUnitButton,
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return NumberFormatList(
|
||||
onSelected: (format) {
|
||||
context
|
||||
.read<NumberTypeOptionBloc>()
|
||||
.add(NumberTypeOptionEvent.didSelectFormat(format));
|
||||
PopoverContainer.of(popoverContext).close();
|
||||
},
|
||||
selectedFormat: state.typeOption.format,
|
||||
);
|
||||
},
|
||||
selectedFormat: state.typeOption.format,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -108,9 +122,11 @@ typedef SelectNumberFormatCallback = Function(NumberFormat format);
|
||||
class NumberFormatList extends StatelessWidget {
|
||||
final SelectNumberFormatCallback onSelected;
|
||||
final NumberFormat selectedFormat;
|
||||
const NumberFormatList(
|
||||
{required this.selectedFormat, required this.onSelected, Key? key})
|
||||
: super(key: key);
|
||||
const NumberFormatList({
|
||||
required this.selectedFormat,
|
||||
required this.onSelected,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -127,11 +143,12 @@ class NumberFormatList extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
final cells = state.formats.map((format) {
|
||||
return NumberFormatCell(
|
||||
isSelected: format == selectedFormat,
|
||||
format: format,
|
||||
onSelected: (format) {
|
||||
onSelected(format);
|
||||
});
|
||||
isSelected: format == selectedFormat,
|
||||
format: format,
|
||||
onSelected: (format) {
|
||||
onSelected(format);
|
||||
},
|
||||
);
|
||||
}).toList();
|
||||
|
||||
final list = ListView.separated(
|
||||
|
@ -71,9 +71,11 @@ class OptionTitle extends StatelessWidget {
|
||||
return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTypeOptionState>(
|
||||
builder: (context, state) {
|
||||
List<Widget> children = [
|
||||
FlowyText.medium(
|
||||
LocaleKeys.grid_field_optionTitle.tr(),
|
||||
color: Theme.of(context).hintColor,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 9),
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.grid_field_optionTitle.tr(),
|
||||
),
|
||||
)
|
||||
];
|
||||
if (state.options.isNotEmpty && !state.isEditingOption) {
|
||||
|
@ -66,7 +66,8 @@ class SelectOptionTypeOptionEditor extends StatelessWidget {
|
||||
if (showOptions) {
|
||||
cells.add(const TypeOptionSeparator());
|
||||
cells.add(
|
||||
SelectOptionColorList(selectedColor: state.option.color));
|
||||
SelectOptionColorList(selectedColor: state.option.color),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
@ -126,9 +127,11 @@ class _DeleteTag extends StatelessWidget {
|
||||
class _OptionNameTextField extends StatelessWidget {
|
||||
final String name;
|
||||
final bool autoFocus;
|
||||
const _OptionNameTextField(
|
||||
{required this.name, required this.autoFocus, Key? key})
|
||||
: super(key: key);
|
||||
const _OptionNameTextField({
|
||||
required this.name,
|
||||
required this.autoFocus,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -157,7 +160,9 @@ class SelectOptionColorList extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final cells = SelectOptionColorPB.values.map((color) {
|
||||
return _SelectOptionColorCell(
|
||||
color: color, isSelected: selectedColor == color);
|
||||
color: color,
|
||||
isSelected: selectedColor == color,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
return Column(
|
||||
@ -195,9 +200,11 @@ class SelectOptionColorList extends StatelessWidget {
|
||||
class _SelectOptionColorCell extends StatelessWidget {
|
||||
final SelectOptionColorPB color;
|
||||
final bool isSelected;
|
||||
const _SelectOptionColorCell(
|
||||
{required this.color, required this.isSelected, Key? key})
|
||||
: super(key: key);
|
||||
const _SelectOptionColorCell({
|
||||
required this.color,
|
||||
required this.isSelected,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -68,11 +68,13 @@ class _GridRowState extends State<GridRow> {
|
||||
),
|
||||
);
|
||||
|
||||
return Row(children: [
|
||||
const _RowLeading(),
|
||||
content,
|
||||
const _RowTrailing(),
|
||||
]);
|
||||
return Row(
|
||||
children: [
|
||||
const _RowLeading(),
|
||||
content,
|
||||
const _RowTrailing(),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -129,9 +131,11 @@ class _RowLeadingState extends State<_RowLeading> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const _InsertButton(),
|
||||
_MenuButton(openMenu: () {
|
||||
popoverController.show();
|
||||
}),
|
||||
_MenuButton(
|
||||
openMenu: () {
|
||||
popoverController.show();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -216,12 +220,13 @@ class RowContent extends StatelessWidget {
|
||||
!listEquals(previous.cells, current.cells),
|
||||
builder: (context, state) {
|
||||
return IntrinsicHeight(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: _makeCells(context, state.cellByFieldId),
|
||||
));
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: _makeCells(context, state.cellByFieldId),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -116,7 +116,10 @@ class _FilterTextFieldDelegate extends SliverPersistentHeaderDelegate {
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
BuildContext context,
|
||||
double shrinkOffset,
|
||||
bool overlapsContent,
|
||||
) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
height: fixHeight,
|
||||
|
@ -76,13 +76,15 @@ class _SortList extends StatelessWidget {
|
||||
return BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||
builder: (context, state) {
|
||||
final List<Widget> children = state.sortInfos
|
||||
.map((info) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: _SortItem(
|
||||
sortInfo: info,
|
||||
popoverMutex: popoverMutex,
|
||||
),
|
||||
))
|
||||
.map(
|
||||
(info) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: _SortItem(
|
||||
sortInfo: info,
|
||||
popoverMutex: popoverMutex,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
return Column(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user