Compare commits

..
4 Commits
Author SHA1 Message Date
Lucas.Xu 05603c9472 chore: bump version 0.5.7 2024-05-10 15:29:08 +08:00
Richard Shiue e28d463cb9 fix: kanban board card text input inconsistency (#5307) 2024-05-10 15:16:31 +08:00
Lucas.Xu bdc66103c8 fix: android navigation bar issues (#5294) 2024-05-10 15:00:48 +08:00
Lucas.Xu e2b6e14762 refactor: mobile view page (#5288)
* refactor: mobile view page

* fix: provider not found

* chore: add page style integration tests

* fix: android title bar padding

* fix: unable to click mentioned page on Android

* fix: font family not available log
2024-05-10 15:00:40 +08:00
1416 changed files with 14333 additions and 57915 deletions

No files matched your search

+1 -1
View File
@@ -63,7 +63,7 @@ runs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
elif [ "$RUNNER_OS" == "Windows" ]; then
vcpkg integrate install
elif [ "$RUNNER_OS" == "macOS" ]; then
@@ -52,7 +52,7 @@ runs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev network-manager libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev network-manager
shell: bash
- name: Enable Flutter Desktop
+1 -1
View File
@@ -19,7 +19,7 @@
# env:
# CARGO_TERM_COLOR: always
# FLUTTER_VERSION: "3.22.0"
# FLUTTER_VERSION: "3.19.0"
# RUST_TOOLCHAIN: "1.77.2"
# CARGO_MAKE_VERSION: "0.36.6"
+28
View File
@@ -0,0 +1,28 @@
name: Build Bot
on:
issue_comment:
types: [created]
jobs:
dispatch_slash_command:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
# get build name from pubspec.yaml
- name: Get build version
working-directory: frontend/appflowy_flutter
id: get_build_name
run: |
echo "fetching version from pubspec.yaml..."
echo "build_name=$(grep 'version: ' pubspec.yaml | awk '{print $2}')" >> $GITHUB_OUTPUT
- uses: peter-evans/slash-command-dispatch@v4
with:
token: ${{ secrets.PAT }}
commands: build
static-args: |
ref=refs/pull/${{ github.event.issue.number }}/head
build_name=${{ steps.get_build_name.outputs.build_name }}
+2 -2
View File
@@ -62,11 +62,11 @@ jobs:
with:
SSH_PRIVATE_KEY: ${{ env.SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i"
SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/server.cjs frontend/appflowy_web_app/start.sh frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key"
SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key"
REMOTE_HOST: ${{ env.REMOTE_HOST }}
REMOTE_USER: ${{ env.REMOTE_USER }}
EXCLUDE: "frontend/appflowy_web_app/dist/, frontend/appflowy_web_app/node_modules/"
SCRIPT_AFTER: |
docker build -t appflowy-web-app .
docker rm -f appflowy-web-app || true
docker run -d -p 80:80 -p 443:443 --env-file .env --name appflowy-web-app appflowy-web-app
docker run -d -p 80:80 -p 443:443 --name appflowy-web-app appflowy-web-app
+3 -23
View File
@@ -25,7 +25,7 @@ on:
env:
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.22.0"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.77.2"
CARGO_MAKE_VERSION: "0.36.6"
@@ -89,7 +89,6 @@ jobs:
with:
os: ${{ matrix.os }}
flutter_version: ${{ env.FLUTTER_VERSION }}
DISABLE_CI_TEST_LOG: "true"
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
@@ -173,7 +172,7 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
fi
shell: bash
@@ -203,7 +202,6 @@ jobs:
- name: Run Flutter unit tests
env:
DISABLE_EVENT_LOG: true
DISABLE_CI_TEST_LOG: "true"
working-directory: frontend
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
@@ -274,7 +272,7 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
shell: bash
- name: Enable Flutter Desktop
@@ -321,12 +319,6 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install video dependency
run: |
sudo apt-get update
sudo apt-get -y install libmpv-dev mpv
shell: bash
- name: Flutter Integration Test 1
uses: ./.github/actions/flutter_integration_test
with:
@@ -351,12 +343,6 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install video dependency
run: |
sudo apt-get update
sudo apt-get -y install libmpv-dev mpv
shell: bash
- name: Flutter Integration Test 2
uses: ./.github/actions/flutter_integration_test
with:
@@ -381,12 +367,6 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install video dependency
run: |
sudo apt-get update
sudo apt-get -y install libmpv-dev mpv
shell: bash
- name: Flutter Integration Test 3
uses: ./.github/actions/flutter_integration_test
with:
+1 -1
View File
@@ -20,7 +20,7 @@ on:
- "!frontend/appflowy_web_app/**"
env:
FLUTTER_VERSION: "3.22.0"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.77.2"
concurrency:
+3 -3
View File
@@ -6,7 +6,7 @@ on:
- "*"
env:
FLUTTER_VERSION: "3.22.0"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.77.2"
jobs:
@@ -367,8 +367,8 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo apt-get update
sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
sudo apt-get install -y alien libnotify-dev libmpv-dev mpv
sudo apt-get install keybinder-3.0 libnotify-dev
sudo apt-get -y install alien
source $HOME/.cargo/env
cargo install --force cargo-make
cargo install --force duckscript_cli
+8 -8
View File
@@ -32,14 +32,14 @@ jobs:
# swap-size-mb: 1024
# remove-dotnet: 'true'
# the following step is required to avoid running out of space
- name: Maximize build space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
sudo docker image prune --all --force
# # the following step is required to avoid running out of space
# - name: Maximize build space
# run: |
# sudo rm -rf /usr/share/dotnet
# sudo rm -rf /opt/ghc
# sudo rm -rf "/usr/local/share/boost"
# sudo rm -rf "$AGENT_TOOLSDIRECTORY"
# sudo docker image prune --all --force
- name: Checkout source code
uses: actions/checkout@v4
+1 -1
View File
@@ -10,7 +10,7 @@ on:
env:
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.22.0"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.77.2"
jobs:
+2 -2
View File
@@ -52,11 +52,11 @@ jobs:
working-directory: frontend/appflowy_web_app
run: |
pnpm install
- name: Run lint check
- name: test and lint
working-directory: frontend/appflowy_web_app
run: |
pnpm run lint
pnpm run test:unit
- name: build and analyze
working-directory: frontend/appflowy_web_app
run: |
@@ -1,4 +1,4 @@
name: Web Code Coverage
name: Cypress Tests
on:
pull_request:
@@ -6,7 +6,6 @@ on:
- ".github/workflows/web2_ci.yaml"
- "frontend/appflowy_web_app/**"
- "frontend/resources/**"
env:
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
@@ -14,7 +13,7 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
cypress-run:
if: github.event.pull_request.draft != true
runs-on: ubuntu-22.04
steps:
@@ -46,20 +45,4 @@ jobs:
component: true
build: pnpm run build
start: pnpm run start
browser: chrome
- name: Jest run
working-directory: frontend/appflowy_web_app
run: |
pnpm run test:unit
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
token: cf9245e0-e136-4e21-b0ee-35755fa0c493
files: frontend/appflowy_web_app/coverage/jest/lcov.info,frontend/appflowy_web_app/coverage/cypress/lcov.info
flags: appflowy_web_app
name: frontend/appflowy_web_app
fail_ci_if_error: true
verbose: true
browser: chrome
+1 -34
View File
@@ -1,37 +1,4 @@
# Release Notes
## Version 0.6.0 - 19/06/2024
### New Features
- Introduced the "Space" feature to help you organize your pages more efficiently.
### Bug Fixes
- Resolved shortcut conflicts on the board page.
- Resolved an issue where underscores could cause the editor to freeze.
## Version 0.5.9 - 06/06/2024
### New Features
- Revamped the sidebar for both Desktop and Mobile.
- Added support for embedding videos in documents.
- Introduced a hotkey (Cmd/Ctrl + 0) to reset the app scale.
- Supported searching the workspace by page title.
### Bug Fixes
- Fixed the issue preventing the use of Backspace to delete words in Kanban boards.
## Version 0.5.8 - 05/20/2024
### New Features
- Improvement to the Callout block to insert new lines
- New settings page "Manage data" replaced the "Files" page
- New settings page "Workspace" replaced the "Appearance" and "Language" pages
- A custom implementation of a title bar for Windows users
- Added support for selecting Cards in kanban and performing grouped keyboard shortcuts
- Added support for default system font family
- Support for scaling the application up/down using a keyboard shortcut (CMD/CTRL + PLUS/MINUS)
### Bug Fixes
- Resolved and refined the UI on Mobile
- Resolved issue with text editing in database
- Improved appearance of empty text cells in kanban/calendar
- Resolved an issue where a page's more actions (delete, duplicate) did not work properly
- Resolved and inconsistency in padding on get started screen on Desktop
## Version 0.5.7 - 05/10/2024
### Bug Fixes
- Resolved page opening issue on Android.
@@ -121,7 +88,7 @@
- Fixed a bug where newly created rows were not being automatically sorted.
- Fixed issues related to deleting a sorting field or sort not removing existing sorts properly.
### Notes
- Windows 7, Windows 8, and iOS 11 are not yet supported due to the upgrade to Flutter 3.22.0.
- Windows 7, Windows 8, and iOS 11 are not yet supported due to the upgrade to Flutter 3.19.0.
## Version 0.4.9 - 02/17/2024
### Bug Fixes
+1 -1
View File
@@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
APPFLOWY_VERSION = "0.6.1"
APPFLOWY_VERSION = "0.5.7"
FLUTTER_DESKTOP_FEATURES = "dart"
PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0"
@@ -52,7 +52,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "io.appflowy.appflowy"
minSdkVersion 24
minSdkVersion 23
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@@ -58,11 +58,4 @@
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
<!--
Media access permissions.
Android 13 or higher.
Used for VideoBlock (edia_kit)
-->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
</manifest>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

@@ -1,6 +1,7 @@
import 'anon_user_continue_test.dart' as anon_user_continue_test;
import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
import 'empty_test.dart' as preset_af_cloud_env_test;
// import 'document_sync_test.dart' as document_sync_test;
import 'user_setting_sync_test.dart' as user_sync_test;
import 'workspace/change_name_and_icon_test.dart'
as change_workspace_name_and_icon_test;
@@ -9,8 +10,13 @@ import 'workspace/collaborative_workspace_test.dart'
Future<void> main() async {
preset_af_cloud_env_test.main();
appflowy_cloud_auth_test.main();
// document_sync_test.main();
user_sync_test.main();
anon_user_continue_test.main();
// workspace
@@ -2,6 +2,8 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
@@ -10,15 +12,14 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
@@ -32,69 +33,66 @@ import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// final email = '${uuid()}@appflowy.io';
final email = '${uuid()}@appflowy.io';
group('collaborative workspace', () {
// combine the create and delete workspace test to reduce the time
testWidgets('create a new workspace, open it and then delete it',
(tester) async {
// only run the test when the feature flag is on
// if (!FeatureFlag.collaborativeWorkspace.isOn) {
// return;
// }
if (!FeatureFlag.collaborativeWorkspace.isOn) {
return;
}
// await tester.initializeAppFlowy(
// cloudType: AuthenticatorType.appflowyCloudSelfHost,
// email: email,
// );
// await tester.tapGoogleLoginInButton();
// await tester.expectToSeeHomePageWithGetStartedPage();
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// const name = 'AppFlowy.IO';
// // the workspace will be opened after created
// await tester.createCollaborativeWorkspace(name);
const name = 'AppFlowy.IO';
// the workspace will be opened after created
await tester.createCollaborativeWorkspace(name);
// final loading = find.byType(Loading);
// await tester.pumpUntilNotFound(loading);
final loading = find.byType(Loading);
await tester.pumpUntilNotFound(loading);
// Finder success;
Finder success;
// final Finder items = find.byType(WorkspaceMenuItem);
// delete the newly created workspace
await tester.openCollaborativeWorkspaceMenu();
final Finder items = find.byType(WorkspaceMenuItem);
expect(items, findsNWidgets(2));
expect(
tester.widget<WorkspaceMenuItem>(items.last).workspace.name,
name,
);
// // delete the newly created workspace
// await tester.openCollaborativeWorkspaceMenu();
// await tester.pumpUntilFound(items);
// expect(items, findsNWidgets(2));
// expect(
// tester.widget<WorkspaceMenuItem>(items.last).workspace.name,
// name,
// );
// final secondWorkspace = find.byType(WorkspaceMenuItem).last;
// await tester.hoverOnWidget(
// secondWorkspace,
// onHover: () async {
// // click the more button
// final moreButton = find.byType(WorkspaceMoreActionList);
// expect(moreButton, findsOneWidget);
// await tester.tapButton(moreButton);
// // click the delete button
// final deleteButton = find.text(LocaleKeys.button_delete.tr());
// expect(deleteButton, findsOneWidget);
// await tester.tapButton(deleteButton);
// // see the delete confirm dialog
// final confirm =
// find.text(LocaleKeys.workspace_deleteWorkspaceHintText.tr());
// expect(confirm, findsOneWidget);
// await tester.tapButton(find.text(LocaleKeys.button_ok.tr()));
// // delete success
// success = find.text(LocaleKeys.workspace_createSuccess.tr());
// await tester.pumpUntilFound(success);
// expect(success, findsOneWidget);
// await tester.pumpUntilNotFound(success);
// },
// );
final secondWorkspace = find.byType(WorkspaceMenuItem).last;
await tester.hoverOnWidget(
secondWorkspace,
onHover: () async {
// click the more button
final moreButton = find.byType(WorkspaceMoreActionList);
expect(moreButton, findsOneWidget);
await tester.tapButton(moreButton);
// click the delete button
final deleteButton = find.text(LocaleKeys.button_delete.tr());
expect(deleteButton, findsOneWidget);
await tester.tapButton(deleteButton);
// see the delete confirm dialog
final confirm =
find.text(LocaleKeys.workspace_deleteWorkspaceHintText.tr());
expect(confirm, findsOneWidget);
await tester.tapButton(find.text(LocaleKeys.button_ok.tr()));
// delete success
success = find.text(LocaleKeys.workspace_createSuccess.tr());
await tester.pumpUntilFound(success);
expect(success, findsOneWidget);
await tester.pumpUntilNotFound(success);
},
);
});
});
}
@@ -1,5 +1,4 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
@@ -83,19 +82,23 @@ void main() {
findsOneWidget,
);
await tester.tapButton(
find.byType(BoardColumnFooter).at(1),
await tester.tap(
find
.descendant(
of: find.byType(AppFlowyGroupFooter),
matching: find.byType(FlowySvg),
)
.at(1),
);
const newCardName = 'Card 4';
await tester.enterText(
find.descendant(
of: find.byType(BoardColumnFooter),
of: lastCard,
matching: find.byType(TextField),
),
newCardName,
);
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.tap(find.byType(AppFlowyBoard));
@@ -1,37 +0,0 @@
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board field test', () {
testWidgets('change field type whithin card #5360', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.text(name);
await tester.tapButton(card1);
const fieldName = "test change field";
await tester.createField(
FieldType.RichText,
fieldName,
layout: ViewLayoutPB.Board,
);
await tester.tapButton(card1);
await tester.changeFieldTypeOfFieldWithName(
fieldName,
FieldType.Checkbox,
layout: ViewLayoutPB.Board,
);
await tester.hoverOnWidget(find.text('Card 2'));
});
});
}
@@ -29,7 +29,6 @@ void main() {
},
);
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
await tester.tapOKButton();
expect(find.text(name), findsNothing);
});
@@ -1,10 +1,10 @@
import 'package:integration_test/integration_test.dart';
import 'board_row_test.dart' as board_row_test;
import 'board_add_row_test.dart' as board_add_row_test;
import 'board_group_test.dart' as board_group_test;
import 'board_row_test.dart' as board_row_test;
void main() {
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Board integration tests
@@ -41,16 +41,15 @@ void main() {
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid(() async {
// Open the row menu and then click the delete
await tester.tapRowMenuButtonInGrid();
await tester.pumpAndSettle();
await tester.tapDeleteOnRowMenu();
await tester.pumpAndSettle();
await tester.hoverOnFirstRowOfGrid();
// 3 initial rows - 1 deleted
await tester.assertNumberOfRowsInGridPage(2);
});
// Open the row menu and then click the delete
await tester.tapRowMenuButtonInGrid();
await tester.tapDeleteOnRowMenu();
// 3 initial rows - 1 deleted
await tester.assertNumberOfRowsInGridPage(2);
await tester.pumpAndSettle();
});
testWidgets('check number of row indicator in the initial grid',
@@ -66,7 +66,6 @@ void main() {
LogicalKeyboardKey.keyR,
],
tester: tester,
withKeyUp: true,
);
expect(first.attributes[blockComponentAlign], rightAlignmentKey);
@@ -78,7 +77,6 @@ void main() {
LogicalKeyboardKey.keyE,
],
tester: tester,
withKeyUp: true,
);
expect(first.attributes[blockComponentAlign], centerAlignmentKey);
@@ -90,7 +88,6 @@ void main() {
LogicalKeyboardKey.keyL,
],
tester: tester,
withKeyUp: true,
);
expect(first.attributes[blockComponentAlign], leftAlignmentKey);
});
@@ -111,7 +111,6 @@ Future<void> triggerReferenceDocumentBySlashMenu(WidgetTester tester) async {
LogicalKeyboardKey.enter,
],
tester: tester,
withKeyUp: true,
);
await tester.pumpAndSettle();
@@ -130,7 +129,6 @@ Future<void> enterDocumentText(WidgetTester tester) async {
LogicalKeyboardKey.keyT,
],
tester: tester,
withKeyUp: true,
);
await tester.pumpAndSettle();
}
@@ -1,34 +0,0 @@
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('MoreViewActions', () {
testWidgets('can duplicate and delete from menu', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.pumpAndSettle();
final pageFinder = find.byType(ViewItem);
expect(pageFinder, findsNWidgets(1));
// Duplicate
await tester.openMoreViewActions();
await tester.duplicateByMoreViewActions();
await tester.pumpAndSettle();
expect(pageFinder, findsNWidgets(2));
// Delete
await tester.openMoreViewActions();
await tester.deleteByMoreViewActions();
await tester.pumpAndSettle();
expect(pageFinder, findsNWidgets(1));
});
});
}
@@ -6,9 +6,6 @@ import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
import 'document_create_and_delete_test.dart'
as document_create_and_delete_test;
import 'document_option_action_test.dart' as document_option_action_test;
import 'document_inline_page_reference_test.dart'
as document_inline_page_reference_test;
import 'document_more_actions_test.dart' as document_more_actions_test;
import 'document_text_direction_test.dart' as document_text_direction_test;
import 'document_with_cover_image_test.dart' as document_with_cover_image_test;
import 'document_with_database_test.dart' as document_with_database_test;
@@ -19,6 +16,8 @@ import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
import 'document_with_outline_block_test.dart' as document_with_outline_block;
import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
import 'edit_document_test.dart' as document_edit_test;
import 'document_inline_page_reference_test.dart'
as document_inline_page_reference_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -39,5 +38,4 @@ void startTesting() {
document_option_action_test.main();
document_with_image_block_test.main();
document_inline_page_reference_test.main();
document_more_actions_test.main();
}
@@ -130,24 +130,24 @@ void main() {
final searchEmojiTextField = find.byWidgetPredicate(
(widget) =>
widget is TextField &&
widget.decoration!.hintText == LocaleKeys.search_label.tr(),
widget.decoration!.hintText == LocaleKeys.emoji_search.tr(),
);
await tester.enterText(
searchEmojiTextField,
'punch',
'hand',
);
// change skin tone
await tester.editor.changeEmojiSkinTone(EmojiSkinTone.dark);
// select an icon with skin tone
const punch = '👊🏿';
await tester.tapEmoji(punch);
tester.expectToSeeDocumentIcon(punch);
const hand = '👋🏿';
await tester.tapEmoji(hand);
tester.expectToSeeDocumentIcon(hand);
tester.expectViewHasIcon(
gettingStarted,
ViewLayoutPB.Document,
punch,
hand,
);
});
});
@@ -56,7 +56,7 @@ void main() {
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.byType(DesktopBoardPage),
matching: find.byType(BoardPage),
),
findsOneWidget,
);
@@ -104,7 +104,7 @@ void main() {
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.byType(DesktopBoardPage),
matching: find.byType(BoardPage),
),
findsOneWidget,
);
@@ -1,5 +1,5 @@
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -8,8 +8,8 @@ import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('notification test', () {
testWidgets('enable notification', (tester) async {
group('board add row test', () {
testWidgets('Add card from header', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -17,25 +17,25 @@ void main() {
await tester.openSettingsPage(SettingsPage.notifications);
await tester.pumpAndSettle();
final toggleFinder = find.byType(Toggle).first;
final switchFinder = find.byType(Switch);
// Defaults to enabled
Toggle toggleWidget = tester.widget(toggleFinder);
expect(toggleWidget.value, true);
Switch switchWidget = tester.widget(switchFinder);
expect(switchWidget.value, true);
// Disable
await tester.tap(toggleFinder);
await tester.tap(switchFinder);
await tester.pumpAndSettle();
toggleWidget = tester.widget(toggleFinder);
expect(toggleWidget.value, false);
switchWidget = tester.widget(switchFinder);
expect(switchWidget.value, false);
// Enable again
await tester.tap(toggleFinder);
await tester.tap(switchFinder);
await tester.pumpAndSettle();
toggleWidget = tester.widget(toggleFinder);
expect(toggleWidget.value, true);
switchWidget = tester.widget(switchFinder);
expect(switchWidget.value, true);
});
});
}
@@ -1,50 +0,0 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/auth_operation.dart';
import '../../shared/base.dart';
import '../../shared/expectation.dart';
import '../../shared/settings.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Settings Billing', () {
testWidgets('Local auth cannot see plan+billing', (tester) async {
await tester.initializeAppFlowy();
await tester.tapSignInAsGuest();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.pumpAndSettle();
// We check that another settings page is present to ensure
// it's not a fluke
expect(
find.text(
LocaleKeys.settings_workspacePage_menuLabel.tr(),
skipOffstage: false,
),
findsOneWidget,
);
expect(
find.text(
LocaleKeys.settings_planPage_menuLabel.tr(),
skipOffstage: false,
),
findsNothing,
);
expect(
find.text(
LocaleKeys.settings_billingPage_menuLabel.tr(),
skipOffstage: false,
),
findsNothing,
);
});
});
}
@@ -1,13 +1,11 @@
import 'package:integration_test/integration_test.dart';
import 'notifications_settings_test.dart' as notifications_settings_test;
import 'settings_billing_test.dart' as settings_billing_test;
import 'shortcuts_settings_test.dart' as shortcuts_settings_test;
import 'user_language_test.dart' as user_language_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
notifications_settings_test.main();
settings_billing_test.main();
shortcuts_settings_test.main();
user_language_test.main();
}
@@ -1,90 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_shortcuts_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/keyboard.dart';
import '../../shared/util.dart';
import '../board/board_hide_groups_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('shortcuts test', () {
testWidgets('can change and overwrite shortcut', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.shortcuts);
await tester.pumpAndSettle();
final backspaceCmd =
LocaleKeys.settings_shortcutsPage_keybindings_backspace.tr();
// Input "Delete" into the search field
await tester.enterText(find.byType(TextField), backspaceCmd);
await tester.pumpAndSettle();
await tester.hoverOnWidget(
find.descendant(
of: find.byType(ShortcutSettingTile),
matching: find.text(backspaceCmd),
),
onHover: () async {
await tester.tap(find.byFlowySvg(FlowySvgs.edit_s));
await tester.pumpAndSettle();
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.delete,
LogicalKeyboardKey.enter,
],
tester: tester,
);
await tester.pumpAndSettle();
},
);
// We expect to see conflict dialog
expect(
find.text(
LocaleKeys.settings_shortcutsPage_conflictDialog_confirmLabel.tr(),
),
findsOneWidget,
);
// Press on confirm label
await tester.tap(
find.text(
LocaleKeys.settings_shortcutsPage_conflictDialog_confirmLabel.tr(),
),
);
await tester.pumpAndSettle();
// We expect the first ShortcutSettingTile to have one
// [KeyBadge] with `delete` label
final first = tester.widget(find.byType(ShortcutSettingTile).first)
as ShortcutSettingTile;
expect(
first.command.command,
'delete',
);
// And the second one which is `Delete left character` to have none
// as it will have been overwritten
final second = tester.widget(find.byType(ShortcutSettingTile).at(1))
as ShortcutSettingTile;
expect(
second.command.command,
'',
);
});
});
}
@@ -0,0 +1,70 @@
import 'dart:ui';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Settings: user language tests', () {
testWidgets('select language, language changed', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.language);
final userLanguageFinder = find.descendant(
of: find.byType(SettingsLanguageView),
matching: find.byType(LanguageSelector),
);
// Grab current locale
LanguageSelector userLanguage =
tester.widget<LanguageSelector>(userLanguageFinder);
Locale currentLocale = userLanguage.currentLocale;
// Open language selector
await tester.tap(userLanguageFinder);
await tester.pumpAndSettle();
// Select first option that isn't default
await tester.tap(find.byType(LanguageItem).at(1));
await tester.pumpAndSettle();
// Make sure the new locale is not the same as previous one
userLanguage = tester.widget<LanguageSelector>(userLanguageFinder);
expect(
userLanguage.currentLocale,
isNot(equals(currentLocale)),
reason: "new language shouldn't equal the previous selected language",
);
// Update the current locale to a new one
currentLocale = userLanguage.currentLocale;
// Tried the same flow for the second time
// Open language selector
await tester.tap(userLanguageFinder);
await tester.pumpAndSettle();
// Select second option that isn't default
await tester.tap(find.byType(LanguageItem).at(2));
await tester.pumpAndSettle();
// Make sure the new locale is not the same as previous one
userLanguage = tester.widget<LanguageSelector>(userLanguageFinder);
expect(
userLanguage.currentLocale,
isNot(equals(currentLocale)),
reason: "new language shouldn't equal the previous selected language",
);
});
});
}
@@ -1,6 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -12,8 +12,8 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sidebar expand test', () {
bool isExpanded({required FolderSpaceType type}) {
if (type == FolderSpaceType.private) {
bool isExpanded({required FolderCategoryType type}) {
if (type == FolderCategoryType.private) {
return find
.descendant(
of: find.byType(PrivateSectionFolder),
@@ -30,19 +30,19 @@ void main() {
await tester.tapAnonymousSignInButton();
// first time is expanded
expect(isExpanded(type: FolderSpaceType.private), true);
expect(isExpanded(type: FolderCategoryType.private), true);
// collapse the personal folder
await tester.tapButton(
find.byTooltip(LocaleKeys.sideBar_clickToHidePrivate.tr()),
);
expect(isExpanded(type: FolderSpaceType.private), false);
expect(isExpanded(type: FolderCategoryType.private), false);
// expand the personal folder
await tester.tapButton(
find.byTooltip(LocaleKeys.sideBar_clickToHidePrivate.tr()),
);
expect(isExpanded(type: FolderSpaceType.private), true);
expect(isExpanded(type: FolderCategoryType.private), true);
});
});
}
@@ -1,5 +1,5 @@
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/_favorite_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
@@ -46,7 +46,7 @@ void main() {
await tester.favoriteViewByName(names[1]);
expect(
tester.findFavoritePageName(names[1]),
findsNWidgets(1),
findsNWidgets(2),
);
await tester.unfavoriteViewByName(gettingStarted);
@@ -120,9 +120,9 @@ void main() {
(widget) =>
widget is SingleInnerViewItem &&
widget.view.isFavorite &&
widget.spaceType == FolderSpaceType.favorite,
widget.categoryType == FolderCategoryType.favorite,
),
findsNWidgets(3),
findsNWidgets(6),
);
await tester.hoverOnPageName(
@@ -135,7 +135,7 @@ void main() {
expect(
tester.findAllFavoritePages(),
findsNWidgets(2),
findsNWidgets(3),
);
await tester.hoverOnPageName(
@@ -168,7 +168,7 @@ void main() {
widget.isSelected != null &&
widget.isSelected!(),
),
findsNWidgets(1),
findsNWidgets(2),
);
},
);
@@ -18,9 +18,6 @@ void main() {
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
if (value == ViewLayoutPB.Chat) {
continue;
}
await tester.createNewPageWithNameUnderParent(
name: value.name,
parentName: gettingStarted,
@@ -49,9 +46,6 @@ void main() {
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
if (value == ViewLayoutPB.Chat) {
continue;
}
await tester.createNewPageWithNameUnderParent(
name: value.name,
parentName: gettingStarted,
@@ -39,9 +39,6 @@ void main() {
await tester.tapAnonymousSignInButton();
for (final layout in ViewLayoutPB.values) {
if (layout == ViewLayoutPB.Chat) {
continue;
}
// create a new page
final name = 'AppFlowy_$layout';
await tester.createNewPageWithNameUnderParent(
@@ -64,13 +61,11 @@ void main() {
expect(find.byType(GridPage), findsOneWidget);
break;
case ViewLayoutPB.Board:
expect(find.byType(DesktopBoardPage), findsOneWidget);
expect(find.byType(BoardPage), findsOneWidget);
break;
case ViewLayoutPB.Calendar:
expect(find.byType(CalendarPage), findsOneWidget);
break;
case ViewLayoutPB.Chat:
break;
}
await tester.openPage(gettingStarted);
@@ -4,7 +4,7 @@ import 'sidebar_favorites_test.dart' as sidebar_favorite_test;
import 'sidebar_icon_test.dart' as sidebar_icon_test;
import 'sidebar_test.dart' as sidebar_test;
void main() {
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Sidebar integration tests
@@ -0,0 +1,93 @@
import 'package:appflowy/util/font_family_extension.dart';
import 'package:appflowy/workspace/application/appearance_defaults.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/settings_appearance.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('appearance settings tests', () {
testWidgets('after editing text field, button should be able to be clicked',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
final dropDown = find.byKey(ThemeFontFamilySetting.popoverKey);
await tester.tap(dropDown);
await tester.pumpAndSettle();
final textField = find.byKey(ThemeFontFamilySetting.textFieldKey);
await tester.tap(textField);
await tester.pumpAndSettle();
await tester.enterText(textField, 'Abel');
await tester.pumpAndSettle();
final fontFamilyButton = find.byKey(const Key('Abel'));
expect(fontFamilyButton, findsOneWidget);
await tester.tap(fontFamilyButton);
await tester.pumpAndSettle();
// just switch the page and verify that the font family was set after that
await tester.openSettingsPage(SettingsPage.files);
await tester.openSettingsPage(SettingsPage.appearance);
expect(find.textContaining('Abel'), findsOneWidget);
});
testWidgets('reset the font family', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
final dropDown = find.byKey(ThemeFontFamilySetting.popoverKey);
await tester.tap(dropDown);
await tester.pumpAndSettle();
final textField = find.byKey(ThemeFontFamilySetting.textFieldKey);
await tester.tap(textField);
await tester.pumpAndSettle();
await tester.enterText(textField, 'Abel');
await tester.pumpAndSettle();
final fontFamilyButton = find.byKey(const Key('Abel'));
expect(fontFamilyButton, findsOneWidget);
await tester.tap(fontFamilyButton);
await tester.pumpAndSettle();
// just switch the page and verify that the font family was set after that
await tester.openSettingsPage(SettingsPage.files);
await tester.openSettingsPage(SettingsPage.appearance);
final resetButton = find.byKey(ThemeFontFamilySetting.resetButtonKey);
await tester.tap(resetButton);
await tester.pumpAndSettle();
// just switch the page and verify that the font family was set after that
await tester.openSettingsPage(SettingsPage.files);
await tester.openSettingsPage(SettingsPage.appearance);
expect(
find.textContaining(
DefaultAppearanceSettings.kDefaultFontFamily.fontFamilyDisplayName,
),
findsNWidgets(2),
);
});
});
}
@@ -1,13 +1,11 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -25,35 +23,31 @@ void main() {
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.workspace);
await tester.openSettingsPage(SettingsPage.appearance);
await tester.pumpAndSettle();
final appFinder = find.byType(MaterialApp).first;
ThemeMode? themeMode = tester.widget<MaterialApp>(appFinder).themeMode;
expect(themeMode, ThemeMode.system);
tester.expectToSeeText(
LocaleKeys.settings_appearance_themeMode_system.tr(),
);
await tester.tapButton(
find.bySemanticsLabel(
LocaleKeys.settings_workspacePage_appearance_options_light.tr(),
LocaleKeys.settings_appearance_themeMode_system.tr(),
),
);
await tester.pumpAndSettle();
themeMode = tester.widget<MaterialApp>(appFinder).themeMode;
expect(themeMode, ThemeMode.light);
await tester.pumpAndSettle();
await tester.tapButton(
find.bySemanticsLabel(
LocaleKeys.settings_workspacePage_appearance_options_dark.tr(),
LocaleKeys.settings_appearance_themeMode_dark.tr(),
),
);
await tester.pumpAndSettle();
themeMode = tester.widget<MaterialApp>(appFinder).themeMode;
expect(themeMode, ThemeMode.dark);
await tester.pumpAndSettle(const Duration(seconds: 1));
await tester.tap(find.byType(SettingsDialog));
await tester.pumpAndSettle();
await FlowyTestKeyboard.simulateKeyDownEvent(
@@ -66,10 +60,12 @@ void main() {
],
tester: tester,
);
await tester.pumpAndSettle();
themeMode = tester.widget<MaterialApp>(appFinder).themeMode;
expect(themeMode, ThemeMode.light);
tester.expectToSeeText(
LocaleKeys.settings_appearance_themeMode_light.tr(),
);
});
testWidgets('show or hide home menu', (tester) async {
@@ -1,4 +1,4 @@
import 'package:appflowy/user/presentation/screens/skip_log_in_screen.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -101,7 +101,7 @@ void main() {
// open settings and restore the location
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.manageData);
await tester.openSettingsPage(SettingsPage.files);
await tester.restoreLocation();
expect(
@@ -3,6 +3,8 @@ import 'package:integration_test/integration_test.dart';
import 'desktop/board/board_test_runner.dart' as board_test_runner;
import 'desktop/settings/settings_runner.dart' as settings_test_runner;
import 'desktop/sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
import 'desktop/uncategorized/appearance_settings_test.dart'
as appearance_test_runner;
import 'desktop/uncategorized/emoji_shortcut_test.dart' as emoji_shortcut_test;
import 'desktop/uncategorized/empty_test.dart' as first_test;
import 'desktop/uncategorized/hotkeys_test.dart' as hotkeys_test;
@@ -24,10 +26,11 @@ Future<void> runIntegration3OnDesktop() async {
emoji_shortcut_test.main();
hotkeys_test.main();
emoji_shortcut_test.main();
appearance_test_runner.main();
settings_test_runner.main();
share_markdown_test.main();
import_files_test.main();
sidebar_test_runner.main();
board_test_runner.main();
sidebar_test_runner.startTesting();
board_test_runner.startTesting();
tabs_test.main();
}
@@ -5,7 +5,6 @@ import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widget
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -45,12 +44,6 @@ extension AppFlowyAuthTest on WidgetTester {
assert(isSwitched == value);
}
void assertToggleValue(Finder finder, bool value) {
final Toggle switchWidget = widget(finder);
final isSwitched = switchWidget.value;
assert(isSwitched == value);
}
void assertEnableEncryptSwitchValue(bool value) {
assertSwitchValue(
find.descendant(
@@ -72,10 +65,10 @@ extension AppFlowyAuthTest on WidgetTester {
}
void assertAppFlowyCloudEnableSyncSwitchValue(bool value) {
assertToggleValue(
assertSwitchValue(
find.descendant(
of: find.byType(AppFlowyCloudEnableSync),
matching: find.byWidgetPredicate((widget) => widget is Toggle),
matching: find.byWidgetPredicate((widget) => widget is Switch),
),
value,
);
@@ -93,7 +86,7 @@ extension AppFlowyAuthTest on WidgetTester {
Future<void> toggleEnableSync(Type syncButton) async {
final finder = find.descendant(
of: find.byType(syncButton),
matching: find.byWidgetPredicate((widget) => widget is Toggle),
matching: find.byWidgetPredicate((widget) => widget is Switch),
);
await tapButton(finder);
@@ -173,39 +173,27 @@ extension AppFlowyTestBase on WidgetTester {
int buttons = kPrimaryButton,
bool warnIfMissed = false,
int milliseconds = 500,
bool pumpAndSettle = true,
}) async {
await tap(
finder,
buttons: buttons,
warnIfMissed: warnIfMissed,
);
if (pumpAndSettle) {
await this.pumpAndSettle(
Duration(milliseconds: milliseconds),
EnginePhase.sendSemanticsUpdate,
const Duration(seconds: 5),
);
}
await pumpAndSettle(
Duration(milliseconds: milliseconds),
EnginePhase.sendSemanticsUpdate,
const Duration(seconds: 5),
);
}
Future<void> tapButtonWithName(
String tr, {
int milliseconds = 500,
bool pumpAndSettle = true,
}) async {
Future<void> tapButtonWithName(String tr, {int milliseconds = 500}) async {
Finder button = find.text(tr, findRichText: true, skipOffstage: false);
if (button.evaluate().isEmpty) {
button = find.byWidgetPredicate(
(widget) => widget is FlowyText && widget.text == tr,
);
}
await tapButton(
button,
milliseconds: milliseconds,
pumpAndSettle: pumpAndSettle,
);
await tapButton(button, milliseconds: milliseconds);
}
Future<void> doubleTapAt(
@@ -1,10 +1,5 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
@@ -16,9 +11,9 @@ import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/screens/screens.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_new_page_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
@@ -27,14 +22,16 @@ import 'package:appflowy/workspace/presentation/notifications/widgets/flowy_tab.
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_button.dart';
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu.dart';
import 'package:appflowy/workspace/presentation/widgets/more_view_actions/more_view_actions.dart';
import 'package:appflowy/workspace/presentation/widgets/more_view_actions/widgets/common_view_action.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'emoji.dart';
@@ -61,7 +58,6 @@ extension CommonOperations on WidgetTester {
/// Tap the + button on the home page.
Future<void> tapAddViewButton({
String name = gettingStarted,
ViewLayoutPB layout = ViewLayoutPB.Document,
}) async {
await hoverOnPageName(
name,
@@ -281,7 +277,7 @@ extension CommonOperations on WidgetTester {
bool openAfterCreated = true,
}) async {
// create a new page
await tapAddViewButton(name: parentName ?? gettingStarted, layout: layout);
await tapAddViewButton(name: parentName ?? gettingStarted);
await tapButtonWithName(layout.menuName);
final settingsOrFailure = await getIt<KeyValueStorage>().getWithFormat(
KVKeys.showRenameDialogWhenCreatingNewFile,
@@ -515,9 +511,8 @@ extension CommonOperations on WidgetTester {
final workspace = find.byType(SidebarWorkspace);
expect(workspace, findsOneWidget);
await tapButton(workspace, pumpAndSettle: false);
await pump(const Duration(seconds: 5));
// click it
await tapButton(workspace, milliseconds: 2000);
}
Future<void> createCollaborativeWorkspace(String name) async {
@@ -532,8 +527,7 @@ extension CommonOperations on WidgetTester {
// click the create button
final createButton = find.byKey(createWorkspaceButtonKey);
expect(createButton, findsOneWidget);
await tapButton(createButton, pumpAndSettle: false);
await pump(const Duration(seconds: 5));
await tapButton(createButton);
// see the create workspace dialog
final createWorkspaceDialog = find.byType(CreateWorkspaceDialog);
@@ -542,8 +536,7 @@ extension CommonOperations on WidgetTester {
// input the workspace name
await enterText(find.byType(TextField), name);
await tapButtonWithName(LocaleKeys.button_ok.tr(), pumpAndSettle: false);
await pump(const Duration(seconds: 5));
await tapButtonWithName(LocaleKeys.button_ok.tr());
}
// For mobile platform to launch the app in anonymous mode
@@ -569,44 +562,6 @@ extension CommonOperations on WidgetTester {
);
await tapButton(button);
}
Future<void> openMoreViewActions() async {
final button = find.byType(MoreViewActions);
await tap(button);
await pumpAndSettle();
}
/// Presses on the Duplicate ViewAction in the [MoreViewActions] popup.
///
/// [openMoreViewActions] must be called beforehand!
///
Future<void> duplicateByMoreViewActions() async {
final button = find.descendant(
of: find.byType(ListView),
matching: find.byWidgetPredicate(
(widget) =>
widget is ViewAction && widget.type == ViewActionType.duplicate,
),
);
await tap(button);
await pump();
}
/// Presses on the Delete ViewAction in the [MoreViewActions] popup.
///
/// [openMoreViewActions] must be called beforehand!
///
Future<void> deleteByMoreViewActions() async {
final button = find.descendant(
of: find.byType(ListView),
matching: find.byWidgetPredicate(
(widget) =>
widget is ViewAction && widget.type == ViewActionType.delete,
),
);
await tap(button);
await pump();
}
}
extension SettingsFinder on CommonFinders {
@@ -621,18 +576,6 @@ extension SettingsFinder on CommonFinders {
matching: find.byType(Scrollable),
)
.first;
Finder findSettingsMenuScrollable() => find
.descendant(
of: find
.descendant(
of: find.byType(SettingsMenu),
matching: find.byType(SingleChildScrollView),
)
.first,
matching: find.byType(Scrollable),
)
.first;
}
extension ViewLayoutPBTest on ViewLayoutPB {
@@ -130,12 +130,12 @@ extension AppFlowyDatabaseTest on WidgetTester {
await openPage('v020', layout: ViewLayoutPB.Grid);
}
Future<void> hoverOnFirstRowOfGrid([Future<void> Function()? onHover]) async {
Future<void> hoverOnFirstRowOfGrid() async {
final findRow = find.byType(GridRow);
expect(findRow, findsWidgets);
final firstRow = findRow.first;
await hoverOnWidget(firstRow, onHover: onHover);
await hoverOnWidget(firstRow);
}
Future<void> editCell({
@@ -661,13 +661,10 @@ extension AppFlowyDatabaseTest on WidgetTester {
Future<void> changeFieldTypeOfFieldWithName(
String name,
FieldType type, {
ViewLayoutPB layout = ViewLayoutPB.Grid,
}) async {
FieldType type,
) async {
await tapGridFieldWithName(name);
if (layout == ViewLayoutPB.Grid) {
await tapEditFieldButton();
}
await tapEditFieldButton();
await tapSwitchFieldTypeButton();
await selectFieldType(type);
@@ -876,24 +873,16 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> tapRowMenuButtonInGrid() async {
expect(find.byType(RowMenuButton), findsOneWidget);
await tapButton(find.byType(RowMenuButton));
}
/// Should call [tapRowMenuButtonInGrid] first.
Future<void> tapDeleteOnRowMenu() async {
expect(find.text(LocaleKeys.grid_row_delete.tr()), findsOneWidget);
await tapButtonWithName(LocaleKeys.grid_row_delete.tr());
}
Future<void> createField(
FieldType fieldType,
String name, {
ViewLayoutPB layout = ViewLayoutPB.Grid,
}) async {
if (layout == ViewLayoutPB.Grid) {
await scrollToRight(find.byType(GridPage));
}
Future<void> createField(FieldType fieldType, String name) async {
await scrollToRight(find.byType(GridPage));
await tapNewPropertyButton();
await renameField(name);
await tapSwitchFieldTypeButton();
@@ -1474,7 +1463,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
void assertCurrentDatabaseTagIs(DatabaseLayoutPB layout) => switch (layout) {
DatabaseLayoutPB.Board =>
expect(find.byType(DesktopBoardPage), findsOneWidget),
expect(find.byType(BoardPage), findsOneWidget),
DatabaseLayoutPB.Calendar =>
expect(find.byType(CalendarPage), findsOneWidget),
DatabaseLayoutPB.Grid => expect(find.byType(GridPage), findsOneWidget),
@@ -1532,7 +1521,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Finder finderForDatabaseLayoutType(DatabaseLayoutPB layout) => switch (layout) {
DatabaseLayoutPB.Board => find.byType(DesktopBoardPage),
DatabaseLayoutPB.Board => find.byType(BoardPage),
DatabaseLayoutPB.Calendar => find.byType(CalendarPage),
DatabaseLayoutPB.Grid => find.byType(GridPage),
_ => throw Exception('Unknown database layout type: $layout'),
@@ -81,12 +81,15 @@ class EditorOperations {
/// Taps the 'Remove Icon' button in the cover toolbar and the icon popover
Future<void> tapRemoveIconButton({bool isInPicker = false}) async {
final Finder button = !isInPicker
? find.text(LocaleKeys.document_plugins_cover_removeIcon.tr())
: find.descendant(
of: find.byType(FlowyIconPicker),
matching: find.text(LocaleKeys.button_remove.tr()),
);
Finder button =
find.text(LocaleKeys.document_plugins_cover_removeIcon.tr());
if (isInPicker) {
button = find.descendant(
of: find.byType(FlowyIconPicker),
matching: button,
);
}
await tester.tapButton(button);
}
@@ -165,7 +165,7 @@ extension Expectation on WidgetTester {
(widget) =>
widget is SingleInnerViewItem &&
widget.view.isFavorite &&
widget.spaceType == FolderSpaceType.favorite &&
widget.categoryType == FolderCategoryType.favorite &&
widget.view.name == name &&
widget.view.layout == layout,
skipOffstage: false,
@@ -175,7 +175,7 @@ extension Expectation on WidgetTester {
(widget) =>
widget is SingleInnerViewItem &&
widget.view.isFavorite &&
widget.spaceType == FolderSpaceType.favorite,
widget.categoryType == FolderCategoryType.favorite,
);
Finder findPageName(
@@ -5,18 +5,10 @@ class FlowyTestKeyboard {
static Future<void> simulateKeyDownEvent(
List<LogicalKeyboardKey> keys, {
required flutter_test.WidgetTester tester,
bool withKeyUp = false,
}) async {
for (final LogicalKeyboardKey key in keys) {
await flutter_test.simulateKeyDownEvent(key);
await tester.pumpAndSettle();
}
if (withKeyUp) {
for (final LogicalKeyboardKey key in keys) {
await flutter_test.simulateKeyUpEvent(key);
await tester.pumpAndSettle();
}
}
}
}
@@ -1,12 +1,11 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_setting.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_workspace_view.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/direction_setting.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -14,7 +13,6 @@ import 'package:flutter_test/flutter_test.dart';
import '../desktop/board/board_hide_groups_test.dart';
import 'base.dart';
import 'common_operations.dart';
extension AppFlowySettings on WidgetTester {
/// Open settings page
@@ -32,14 +30,6 @@ extension AppFlowySettings on WidgetTester {
final button = find.byWidgetPredicate(
(widget) => widget is SettingsMenuElement && widget.page == page,
);
await scrollUntilVisible(
button,
0,
scrollable: find.findSettingsMenuScrollable(),
);
await pump();
expect(button, findsOneWidget);
await tapButton(button);
return;
@@ -47,14 +37,10 @@ extension AppFlowySettings on WidgetTester {
/// Restore the AppFlowy data storage location
Future<void> restoreLocation() async {
final button = find.text(LocaleKeys.settings_common_reset.tr());
final button =
find.byTooltip(LocaleKeys.settings_files_recoverLocationTooltips.tr());
expect(button, findsOneWidget);
await tapButton(button);
await pumpAndSettle();
final confirmButton = find.text(LocaleKeys.button_confirm.tr());
expect(confirmButton, findsOneWidget);
await tapButton(confirmButton);
return;
}
@@ -91,21 +77,12 @@ extension AppFlowySettings on WidgetTester {
// go to settings page and toggle enable RTL toolbar items
Future<void> toggleEnableRTLToolbarItems() async {
await openSettings();
await openSettingsPage(SettingsPage.workspace);
await openSettingsPage(SettingsPage.appearance);
final scrollable = find.findSettingsScrollable();
await scrollUntilVisible(
find.byType(EnableRTLItemsSwitcher),
0,
scrollable: scrollable,
);
final switcher = find.descendant(
of: find.byType(EnableRTLItemsSwitcher),
matching: find.byType(Toggle),
);
await tap(switcher);
final switchButton =
find.byKey(EnableRTLToolbarItemsSetting.enableRTLSwitchKey);
expect(switchButton, findsOneWidget);
await tapButton(switchButton);
// tap anywhere to close the settings page
await tapAt(Offset.zero);
@@ -1,14 +1,14 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'util.dart';
import 'base.dart';
extension AppFlowyWorkspace on WidgetTester {
/// Open workspace menu
@@ -36,19 +36,12 @@ extension AppFlowyWorkspace on WidgetTester {
matching: find.byType(WorkspaceMoreActionList),
);
expect(moreButton, findsOneWidget);
await hoverOnWidget(
moreButton,
onHover: () async {
await tapButton(moreButton);
await tapButton(
find.findTextInFlowyText(LocaleKeys.button_rename.tr()),
);
final input = find.byType(TextFormField);
expect(input, findsOneWidget);
await enterText(input, name);
await tapButton(find.text(LocaleKeys.button_ok.tr()));
},
);
await tapButton(moreButton);
await tapButton(find.findTextInFlowyText(LocaleKeys.button_rename.tr()));
final input = find.byType(TextFormField);
expect(input, findsOneWidget);
await enterText(input, name);
await tapButton(find.text(LocaleKeys.button_ok.tr()));
}
Future<void> changeWorkspaceIcon(String icon) async {
+1 -1
View File
@@ -173,7 +173,7 @@ SPEC CHECKSUMS:
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
integration_test: 13825b8a9334a850581300559b8839134b124670
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
@@ -66,10 +66,5 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false />
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
</plist>
@@ -65,40 +65,9 @@ class KVKeys {
/// {'feature_flag_1': true, 'feature_flag_2': false}
static const String featureFlag = 'featureFlag';
/// The key for saving show notification icon option
///
/// The value is a boolean string
static const String showNotificationIcon = 'showNotificationIcon';
/// The key for saving the last opened workspace id
///
/// The workspace id is a string.
@Deprecated('deprecated in version 0.5.5')
static const String lastOpenedWorkspaceId = 'lastOpenedWorkspaceId';
/// The key for saving the scale factor
///
/// The value is a double string.
static const String scaleFactor = 'scaleFactor';
/// The key for saving the last opened tab (favorite, recent, space etc.)
///
/// The value is a int string.
static const String lastOpenedSpace = 'lastOpenedSpace';
/// The key for saving the space tab order
///
/// The value is a json string with the following format:
/// [0, 1, 2]
static const String spaceOrder = 'spaceOrder';
/// The key for saving the last opened space id (space A, space B)
///
/// The value is a string.
static const String lastOpenedSpaceId = 'lastOpenedSpaceId';
/// The key for saving the upgrade space tag
///
/// The value is a boolean string
static const String hasUpgradedSpace = 'hasUpgradedSpace060';
}
@@ -1,17 +1,6 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/window_title_bar.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart';
import 'dart:io' show Platform;
class CocoaWindowChannel {
CocoaWindowChannel._();
@@ -37,14 +26,9 @@ class CocoaWindowChannel {
}
class MoveWindowDetector extends StatefulWidget {
const MoveWindowDetector({
super.key,
this.child,
this.showTitleBar = false,
});
const MoveWindowDetector({super.key, this.child});
final Widget? child;
final bool showTitleBar;
@override
MoveWindowDetectorState createState() => MoveWindowDetectorState();
@@ -56,32 +40,15 @@ class MoveWindowDetectorState extends State<MoveWindowDetector> {
@override
Widget build(BuildContext context) {
if (!Platform.isMacOS && !Platform.isWindows) {
if (!Platform.isMacOS) {
return widget.child ?? const SizedBox.shrink();
}
if (Platform.isWindows) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.showTitleBar) ...[
WindowTitleBar(
leftChildren: [
_buildToggleMenuButton(context),
],
),
] else ...[
const SizedBox(height: 5),
],
widget.child ?? const SizedBox.shrink(),
],
);
}
return GestureDetector(
// https://stackoverflow.com/questions/52965799/flutter-gesturedetector-not-working-with-containers-in-stack
behavior: HitTestBehavior.translucent,
onDoubleTap: () async => CocoaWindowChannel.instance.zoom(),
onDoubleTap: () async {
await CocoaWindowChannel.instance.zoom();
},
onPanStart: (DragStartDetails details) {
winX = details.globalPosition.dx;
winY = details.globalPosition.dy;
@@ -98,47 +65,4 @@ class MoveWindowDetectorState extends State<MoveWindowDetector> {
child: widget.child,
);
}
Widget _buildToggleMenuButton(BuildContext context) {
if (!context.read<HomeSettingBloc>().state.isMenuCollapsed) {
return const SizedBox.shrink();
}
final color = Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan(
children: [
TextSpan(
text: '${LocaleKeys.sideBar_openSidebar.tr()}\n',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: color),
),
TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Theme.of(context).hintColor),
),
],
);
return FlowyTooltip(
richMessage: textSpan,
child: Listener(
behavior: HitTestBehavior.translucent,
onPointerDown: (_) => context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.collapseMenu()),
child: FlowyHover(
child: Container(
width: 24,
padding: const EdgeInsets.all(4),
child: const RotatedBox(
quarterTurns: 2,
child: FlowySvg(FlowySvgs.hide_menu_s),
),
),
),
),
);
}
}
@@ -1,10 +1,9 @@
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy_backend/log.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:string_validator/string_validator.dart';
import 'package:url_launcher/url_launcher.dart' as launcher;
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -1,9 +1,9 @@
import 'package:scaled_app/scaled_app.dart';
import 'package:flutter/material.dart';
import 'startup/startup.dart';
Future<void> main() async {
ScaledWidgetsFlutterBinding.ensureInitialized(scaleFactor: (_) => 1.0);
WidgetsFlutterBinding.ensureInitialized();
await runAppFlowy();
}
@@ -1,10 +1,8 @@
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@@ -23,9 +21,6 @@ class MobileViewPageBloc
initial: () async {
_registerListeners();
final userProfilePB =
await UserBackendService.getCurrentUserProfile()
.fold((s) => s, (f) => null);
final result = await ViewBackendService.getView(viewId);
final isImmersiveMode =
_isImmersiveMode(result.fold((s) => s, (f) => null));
@@ -34,7 +29,6 @@ class MobileViewPageBloc
isLoading: false,
result: result,
isImmersiveMode: isImmersiveMode,
userProfilePB: userProfilePB,
),
);
},
@@ -77,7 +71,7 @@ class MobileViewPageBloc
final cover = view.cover;
if (cover == null || cover.type == PageStyleCoverImageType.none) {
return false;
} else if (view.layout == ViewLayoutPB.Document && !cover.isPresets) {
} else if (view.layout == ViewLayoutPB.Document) {
// only support immersive mode for document layout
return true;
}
@@ -99,7 +93,6 @@ class MobileViewPageState with _$MobileViewPageState {
@Default(true) bool isLoading,
@Default(null) FlowyResult<ViewPB, FlowyError>? result,
@Default(false) bool isImmersiveMode,
@Default(null) UserProfilePB? userProfilePB,
}) = _MobileViewPageState;
factory MobileViewPageState.initial() => const MobileViewPageState();
@@ -1,7 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:appflowy/mobile/presentation/chat/mobile_chat_screen.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:flutter/material.dart';
@@ -16,15 +14,15 @@ import 'package:go_router/go_router.dart';
extension MobileRouter on BuildContext {
Future<void> pushView(ViewPB view, [Map<String, dynamic>? arguments]) async {
// set the current view before pushing the new view
getIt<MenuSharedState>().latestOpenView = view;
unawaited(getIt<CachedRecentService>().updateRecentViews([view.id], true));
final uri = Uri(
path: view.routeName,
queryParameters: view.queryParameters(arguments),
).toString();
await push(uri);
await push(
Uri(
path: view.routeName,
queryParameters: view.queryParameters(arguments),
).toString(),
).then((value) {
getIt<MenuSharedState>().latestOpenView = view;
getIt<CachedRecentService>().updateRecentViews([view.id], true);
});
}
}
@@ -39,9 +37,6 @@ extension on ViewPB {
return MobileCalendarScreen.routeName;
case ViewLayoutPB.Board:
return MobileBoardScreen.routeName;
case ViewLayoutPB.Chat:
return MobileChatScreen.routeName;
default:
throw UnimplementedError('routeName for $this is not implemented');
}
@@ -70,11 +65,6 @@ extension on ViewPB {
MobileBoardScreen.viewId: id,
MobileBoardScreen.viewTitle: name,
};
case ViewLayoutPB.Chat:
return {
MobileChatScreen.viewId: id,
MobileChatScreen.viewTitle: name,
};
default:
throw UnimplementedError(
'queryParameters for $this is not implemented',
@@ -57,19 +57,7 @@ class RecentViewBloc extends Bloc<RecentViewEvent, RecentViewState> {
}
},
);
// only document supports the cover
if (view.layout != ViewLayoutPB.Document) {
emit(
state.copyWith(
name: view.name,
icon: view.icon.value,
),
);
}
final cover = getCoverV2();
if (cover != null) {
emit(
state.copyWith(
@@ -37,7 +37,6 @@ class FlowyAppBar extends AppBar {
Widget? title,
String? titleText,
FlowyAppBarLeadingType leadingType = FlowyAppBarLeadingType.back,
double? leadingWidth,
Widget? leading,
super.centerTitle,
VoidCallback? onTapLeading,
@@ -53,7 +52,7 @@ class FlowyAppBar extends AppBar {
titleSpacing: 0,
elevation: 0,
leading: leading ?? leadingType.getWidget(onTapLeading),
leadingWidth: leadingWidth ?? leadingType.width,
leadingWidth: leadingType.width,
toolbarHeight: 44.0,
bottom: showDivider
? const PreferredSize(
@@ -6,8 +6,8 @@ import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.dart
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart';
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
import 'package:appflowy/plugins/document/presentation/document_collaborators.dart';
import 'package:appflowy/plugins/shared/sync_indicator.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/plugin/plugin.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
@@ -154,10 +154,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
(view) {
final plugin = view.plugin(arguments: widget.arguments ?? const {})
..init();
return plugin.widgetBuilder.buildWidget(
shrinkWrap: false,
context: PluginContext(userProfile: state.userProfilePB),
);
return plugin.widgetBuilder.buildWidget(shrinkWrap: false);
},
(error) {
return FlowyMobileStateContainer.error(
@@ -194,6 +191,13 @@ class _MobileViewPageState extends State<MobileViewPage> {
padding: const EdgeInsets.symmetric(vertical: 8),
view: view,
),
const HSpace(16.0),
DocumentSyncIndicator(view: view),
const HSpace(12.0),
]);
} else {
actions.addAll([
DatabaseSyncIndicator(view: view),
const HSpace(12.0),
]);
}
@@ -1,5 +1,5 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder;
import 'package:flutter/material.dart';
class TypeOptionMenuItemValue<T> {
@@ -12,7 +12,6 @@ import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -44,9 +43,8 @@ class MobileViewPageImmersiveAppBar extends StatelessWidget
AppBarTheme.of(context).backgroundColor?.withOpacity(opacity),
showDivider: false,
title: Opacity(opacity: opacity >= 0.99 ? 1.0 : 0, child: title),
leadingWidth: 44,
leading: Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 4.0, left: 12.0),
padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 4.0),
child: _buildAppBarBackButton(context),
),
actions: actions,
@@ -61,7 +59,7 @@ class MobileViewPageImmersiveAppBar extends StatelessWidget
child: _ImmersiveAppBarButton(
icon: FlowySvgs.m_app_bar_back_s,
dimension: 30.0,
iconPadding: 3.0,
iconPadding: 6.0,
isImmersiveMode:
context.read<MobileViewPageBloc>().state.isImmersiveMode,
appBarOpacity: appBarOpacity,
@@ -93,7 +91,7 @@ class MobileViewPageMoreButton extends StatelessWidget {
context,
showDragHandle: true,
showDivider: false,
backgroundColor: AFThemeExtension.of(context).background,
backgroundColor: Theme.of(context).colorScheme.background,
builder: (_) => MultiBlocProvider(
providers: [
BlocProvider.value(value: context.read<ViewBloc>()),
@@ -106,7 +104,7 @@ class MobileViewPageMoreButton extends StatelessWidget {
child: _ImmersiveAppBarButton(
icon: FlowySvgs.m_app_bar_more_s,
dimension: 30.0,
iconPadding: 3.0,
iconPadding: 5.0,
isImmersiveMode: isImmersiveMode,
appBarOpacity: appBarOpacity,
),
@@ -145,12 +143,9 @@ class MobileViewPageLayoutButton extends StatelessWidget {
showDoneButton: true,
showHeader: true,
title: LocaleKeys.pageStyle_title.tr(),
backgroundColor: AFThemeExtension.of(context).background,
builder: (_) => MultiBlocProvider(
providers: [
BlocProvider.value(value: context.read<DocumentPageStyleBloc>()),
BlocProvider.value(value: context.read<MobileViewPageBloc>()),
],
backgroundColor: Theme.of(context).colorScheme.background,
builder: (_) => BlocProvider.value(
value: context.read<DocumentPageStyleBloc>(),
child: PageStyleBottomSheet(
view: context.read<ViewBloc>().state.view,
),
@@ -160,7 +155,7 @@ class MobileViewPageLayoutButton extends StatelessWidget {
child: _ImmersiveAppBarButton(
icon: FlowySvgs.m_layout_s,
dimension: 30.0,
iconPadding: 3.0,
iconPadding: 5.0,
isImmersiveMode: isImmersiveMode,
appBarOpacity: appBarOpacity,
),
@@ -38,7 +38,6 @@ class MobileViewPageMoreBottomSheet extends StatelessWidget {
case MobileViewBottomSheetBodyAction.removeFromFavorites:
context.pop();
context.read<FavoriteBloc>().add(FavoriteEvent.toggle(view));
break;
case MobileViewBottomSheetBodyAction.undo:
EditorNotification.undo().post();
@@ -1,5 +1,4 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -20,7 +19,7 @@ class BottomSheetActionWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final iconColor =
this.iconColor ?? AFThemeExtension.of(context).onBackground;
this.iconColor ?? Theme.of(context).colorScheme.onBackground;
if (svg == null) {
return OutlinedButton(
@@ -21,54 +21,40 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
children: [
FlowyOptionTile.text(
text: LocaleKeys.document_menuName.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.icon_document_s,
size: Size.square(18),
FlowySvgs.document_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Document),
),
FlowyOptionTile.text(
text: LocaleKeys.grid_menuName.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.icon_grid_s,
size: Size.square(18),
FlowySvgs.grid_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Grid),
),
FlowyOptionTile.text(
text: LocaleKeys.board_menuName.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.icon_board_s,
size: Size.square(18),
FlowySvgs.board_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Board),
),
FlowyOptionTile.text(
text: LocaleKeys.calendar_menuName.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.icon_calendar_s,
size: Size.square(18),
FlowySvgs.date_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Calendar),
),
FlowyOptionTile.text(
text: LocaleKeys.chat_newChat.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.chat_ai_page_s,
size: Size.square(18),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Chat),
),
],
);
}
@@ -33,7 +33,6 @@ class BlockActionBottomSheet extends StatelessWidget {
FlowySvgs.arrow_up_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(BlockActionBottomSheetType.insertAbove),
),
FlowyOptionTile.text(
@@ -49,7 +48,7 @@ class BlockActionBottomSheet extends StatelessWidget {
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.button_duplicate.tr(),
leftIcon: const FlowySvg(FlowySvgs.m_duplicate_s),
leftIcon: const FlowySvg(FlowySvgs.m_field_copy_s),
onTap: () => onAction(BlockActionBottomSheetType.duplicate),
),
@@ -1,17 +1,9 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/widgets/show_flowy_mobile_confirm_dialog.dart';
import 'package:appflowy/startup/tasks/app_widget.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/recent/recent_views_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluttertoast/fluttertoast.dart';
enum MobileBottomSheetType {
view,
@@ -22,13 +14,11 @@ class MobileViewItemBottomSheet extends StatefulWidget {
const MobileViewItemBottomSheet({
super.key,
required this.view,
required this.actions,
this.defaultType = MobileBottomSheetType.view,
});
final ViewPB view;
final MobileBottomSheetType defaultType;
final List<MobileViewItemBottomSheetBodyAction> actions;
@override
State<MobileViewItemBottomSheet> createState() =>
@@ -37,14 +27,12 @@ class MobileViewItemBottomSheet extends StatefulWidget {
class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
MobileBottomSheetType type = MobileBottomSheetType.view;
final fToast = FToast();
@override
void initState() {
super.initState();
type = widget.defaultType;
fToast.init(AppGlobals.context);
}
@override
@@ -52,7 +40,6 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
switch (type) {
case MobileBottomSheetType.view:
return MobileViewItemBottomSheetBody(
actions: widget.actions,
isFavorite: widget.view.isFavorite,
onAction: (action) {
switch (action) {
@@ -72,6 +59,7 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
case MobileViewItemBottomSheetBodyAction.delete:
Navigator.pop(context);
context.read<ViewBloc>().add(const ViewEvent.delete());
break;
case MobileViewItemBottomSheetBodyAction.addToFavorites:
case MobileViewItemBottomSheetBodyAction.removeFromFavorites:
@@ -80,11 +68,6 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(widget.view));
break;
case MobileViewItemBottomSheetBodyAction.removeFromRecent:
_removeFromRecent(context);
break;
case MobileViewItemBottomSheetBodyAction.divider:
break;
}
},
);
@@ -100,74 +83,4 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
);
}
}
Future<void> _removeFromRecent(BuildContext context) async {
final viewId = context.read<ViewBloc>().view.id;
final recentViewsBloc = context.read<RecentViewsBloc>();
Navigator.pop(context);
await _showConfirmDialog(
onDelete: () {
recentViewsBloc.add(RecentViewsEvent.removeRecentViews([viewId]));
fToast.showToast(
child: const _RemoveToast(),
positionedToastBuilder: (context, child) {
return Positioned.fill(
top: 450,
child: child,
);
},
);
},
);
}
Future<void> _showConfirmDialog({required VoidCallback onDelete}) async {
await showFlowyCupertinoConfirmDialog(
title: LocaleKeys.sideBar_removePageFromRecent.tr(),
leftButton: FlowyText.regular(
LocaleKeys.button_cancel.tr(),
color: const Color(0xFF1456F0),
),
rightButton: FlowyText.medium(
LocaleKeys.button_delete.tr(),
color: const Color(0xFFFE0220),
),
onRightButtonPressed: (context) {
onDelete();
Navigator.pop(context);
},
);
}
}
class _RemoveToast extends StatelessWidget {
const _RemoveToast();
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 13.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: const Color(0xE5171717),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const FlowySvg(
FlowySvgs.success_s,
blendMode: null,
),
const HSpace(8.0),
FlowyText.regular(
LocaleKeys.sideBar_removeSuccess.tr(),
fontSize: 16.0,
color: Colors.white,
),
],
),
);
}
}
@@ -1,6 +1,6 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -11,8 +11,6 @@ enum MobileViewItemBottomSheetBodyAction {
delete,
addToFavorites,
removeFromFavorites,
divider,
removeFromRecent,
}
class MobileViewItemBottomSheetBody extends StatelessWidget {
@@ -20,134 +18,63 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
super.key,
this.isFavorite = false,
required this.onAction,
required this.actions,
});
final bool isFavorite;
final void Function(MobileViewItemBottomSheetBodyAction action) onAction;
final List<MobileViewItemBottomSheetBodyAction> actions;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children:
actions.map((action) => _buildActionButton(context, action)).toList(),
);
}
Widget _buildActionButton(
BuildContext context,
MobileViewItemBottomSheetBodyAction action,
) {
switch (action) {
case MobileViewItemBottomSheetBodyAction.rename:
return FlowyOptionTile.text(
children: [
MobileQuickActionButton(
text: LocaleKeys.button_rename.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.view_item_rename_s,
size: Size.square(18),
),
showTopBorder: false,
showBottomBorder: false,
icon: FlowySvgs.m_rename_s,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.rename,
),
);
case MobileViewItemBottomSheetBodyAction.duplicate:
return FlowyOptionTile.text(
text: LocaleKeys.button_duplicate.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.duplicate_s,
size: Size.square(18),
),
_divider(),
MobileQuickActionButton(
text: isFavorite
? LocaleKeys.button_removeFromFavorites.tr()
: LocaleKeys.button_addToFavorites.tr(),
icon: isFavorite
? FlowySvgs.m_favorite_selected_lg
: FlowySvgs.m_favorite_unselected_lg,
iconColor: isFavorite ? Colors.yellow : null,
onTap: () => onAction(
isFavorite
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
: MobileViewItemBottomSheetBodyAction.addToFavorites,
),
showTopBorder: false,
showBottomBorder: false,
),
_divider(),
MobileQuickActionButton(
text: LocaleKeys.button_duplicate.tr(),
icon: FlowySvgs.m_duplicate_s,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.duplicate,
),
);
case MobileViewItemBottomSheetBodyAction.share:
return FlowyOptionTile.text(
text: LocaleKeys.button_share.tr(),
height: 52.0,
leftIcon: const FlowySvg(
FlowySvgs.share_s,
size: Size.square(18),
),
showTopBorder: false,
showBottomBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.share,
),
);
case MobileViewItemBottomSheetBodyAction.delete:
return FlowyOptionTile.text(
),
_divider(),
MobileQuickActionButton(
text: LocaleKeys.button_delete.tr(),
height: 52.0,
textColor: Theme.of(context).colorScheme.error,
leftIcon: FlowySvg(
FlowySvgs.trash_s,
size: const Size.square(18),
color: Theme.of(context).colorScheme.error,
),
showTopBorder: false,
showBottomBorder: false,
icon: FlowySvgs.m_delete_s,
iconColor: Theme.of(context).colorScheme.error,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.delete,
),
);
case MobileViewItemBottomSheetBodyAction.addToFavorites:
return FlowyOptionTile.text(
height: 52.0,
text: LocaleKeys.button_addToFavorites.tr(),
leftIcon: const FlowySvg(
FlowySvgs.favorite_s,
size: Size.square(18),
),
showTopBorder: false,
showBottomBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.addToFavorites,
),
);
case MobileViewItemBottomSheetBodyAction.removeFromFavorites:
return FlowyOptionTile.text(
height: 52.0,
text: LocaleKeys.button_removeFromFavorites.tr(),
leftIcon: const FlowySvg(
FlowySvgs.favorite_section_remove_from_favorite_s,
size: Size.square(18),
),
showTopBorder: false,
showBottomBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.removeFromFavorites,
),
);
case MobileViewItemBottomSheetBodyAction.removeFromRecent:
return FlowyOptionTile.text(
height: 52.0,
text: LocaleKeys.button_removeFromRecent.tr(),
leftIcon: const FlowySvg(
FlowySvgs.remove_from_recent_s,
size: Size.square(18),
),
showTopBorder: false,
showBottomBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.removeFromRecent,
),
);
case MobileViewItemBottomSheetBodyAction.divider:
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 12.0),
child: Divider(height: 0.5),
);
}
),
_divider(),
],
);
}
Widget _divider() => const Divider(
height: 8.5,
thickness: 0.5,
);
}
@@ -89,7 +89,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
children: [
MobileQuickActionButton(
text: LocaleKeys.button_rename.tr(),
icon: FlowySvgs.view_item_rename_s,
icon: FlowySvgs.m_rename_s,
onTap: () => onAction(
MobileViewBottomSheetBodyAction.rename,
),
@@ -99,7 +99,10 @@ class MobileViewBottomSheetBody extends StatelessWidget {
text: isFavorite
? LocaleKeys.button_removeFromFavorites.tr()
: LocaleKeys.button_addToFavorites.tr(),
icon: isFavorite ? FlowySvgs.unfavorite_s : FlowySvgs.favorite_s,
icon: isFavorite
? FlowySvgs.m_favorite_selected_lg
: FlowySvgs.m_favorite_unselected_lg,
iconColor: isFavorite ? Colors.yellow : null,
onTap: () => onAction(
isFavorite
? MobileViewBottomSheetBodyAction.removeFromFavorites
@@ -109,7 +112,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
_divider(),
MobileQuickActionButton(
text: LocaleKeys.button_duplicate.tr(),
icon: FlowySvgs.duplicate_s,
icon: FlowySvgs.m_duplicate_s,
onTap: () => onAction(
MobileViewBottomSheetBodyAction.duplicate,
),
@@ -118,7 +121,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
MobileQuickActionButton(
text: LocaleKeys.button_delete.tr(),
textColor: Theme.of(context).colorScheme.error,
icon: FlowySvgs.trash_s,
icon: FlowySvgs.m_delete_s,
iconColor: Theme.of(context).colorScheme.error,
onTap: () => onAction(
MobileViewBottomSheetBodyAction.delete,
@@ -1,15 +1,8 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/home/shared/mobile_page_card.dart';
import 'package:appflowy/mobile/presentation/page_item/mobile_slide_action_button.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/recent/recent_views_bloc.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
@@ -18,14 +11,11 @@ enum MobilePaneActionType {
delete,
addToFavorites,
removeFromFavorites,
more,
add;
more;
MobileSlideActionButton actionButton(
BuildContext context, {
MobilePageCardType? cardType,
FolderSpaceType? spaceType,
}) {
BuildContext context,
) {
switch (this) {
case MobilePaneActionType.delete:
return MobileSlideActionButton(
@@ -37,89 +27,45 @@ enum MobilePaneActionType {
);
case MobilePaneActionType.removeFromFavorites:
return MobileSlideActionButton(
backgroundColor: const Color(0xFFFA217F),
svg: FlowySvgs.favorite_section_remove_from_favorite_s,
size: 24.0,
backgroundColor: Colors.orange,
svg: FlowySvgs.favorite_s,
onPressed: (context) => context
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(context.read<ViewBloc>().view)),
);
case MobilePaneActionType.addToFavorites:
return MobileSlideActionButton(
backgroundColor: const Color(0xFF00C8FF),
svg: FlowySvgs.favorite_s,
size: 24.0,
backgroundColor: Colors.orange,
svg: FlowySvgs.m_favorite_unselected_lg,
size: 34.0,
onPressed: (context) => context
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(context.read<ViewBloc>().view)),
);
case MobilePaneActionType.add:
case MobilePaneActionType.more:
return MobileSlideActionButton(
backgroundColor: const Color(0xFF00C8FF),
svg: FlowySvgs.add_m,
backgroundColor: Colors.grey,
svg: FlowySvgs.three_dots_vertical_s,
size: 28.0,
onPressed: (context) {
final viewBloc = context.read<ViewBloc>();
final view = viewBloc.state.view;
final title = view.name;
showMobileBottomSheet(
context,
showHeader: true,
title: title,
showDragHandle: true,
showCloseButton: true,
useRootNavigator: true,
backgroundColor: Theme.of(context).colorScheme.surface,
builder: (sheetContext) {
return AddNewPageWidgetBottomSheet(
view: view,
onAction: (layout) {
Navigator.of(sheetContext).pop();
viewBloc.add(
ViewEvent.createView(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout,
section: spaceType!.toViewSectionPB,
),
);
},
);
},
);
},
);
case MobilePaneActionType.more:
return MobileSlideActionButton(
backgroundColor: const Color(0xE5515563),
svg: FlowySvgs.three_dots_s,
size: 24.0,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10),
),
onPressed: (context) {
final viewBloc = context.read<ViewBloc>();
final favoriteBloc = context.read<FavoriteBloc>();
final recentViewsBloc = context.read<RecentViewsBloc?>();
showMobileBottomSheet(
context,
showDragHandle: true,
showDivider: false,
backgroundColor: Theme.of(context).colorScheme.background,
useRootNavigator: true,
backgroundColor: Theme.of(context).colorScheme.surface,
builder: (context) {
return MultiBlocProvider(
providers: [
BlocProvider.value(value: viewBloc),
BlocProvider.value(value: favoriteBloc),
if (recentViewsBloc != null)
BlocProvider.value(value: recentViewsBloc),
],
child: BlocBuilder<ViewBloc, ViewState>(
builder: (context, state) {
return MobileViewItemBottomSheet(
view: viewBloc.state.view,
actions: _buildActions(state.view, cardType: cardType),
);
},
),
@@ -130,70 +76,19 @@ enum MobilePaneActionType {
);
}
}
List<MobileViewItemBottomSheetBodyAction> _buildActions(
ViewPB view, {
MobilePageCardType? cardType,
}) {
final isFavorite = view.isFavorite;
if (cardType != null) {
switch (cardType) {
case MobilePageCardType.recent:
return [
isFavorite
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
: MobileViewItemBottomSheetBodyAction.addToFavorites,
MobileViewItemBottomSheetBodyAction.divider,
if (view.layout != ViewLayoutPB.Chat)
MobileViewItemBottomSheetBodyAction.duplicate,
MobileViewItemBottomSheetBodyAction.divider,
MobileViewItemBottomSheetBodyAction.removeFromRecent,
];
case MobilePageCardType.favorite:
return [
isFavorite
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
: MobileViewItemBottomSheetBodyAction.addToFavorites,
MobileViewItemBottomSheetBodyAction.divider,
MobileViewItemBottomSheetBodyAction.duplicate,
];
}
}
return [
isFavorite
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
: MobileViewItemBottomSheetBodyAction.addToFavorites,
MobileViewItemBottomSheetBodyAction.divider,
MobileViewItemBottomSheetBodyAction.rename,
if (view.layout != ViewLayoutPB.Chat)
MobileViewItemBottomSheetBodyAction.duplicate,
MobileViewItemBottomSheetBodyAction.divider,
MobileViewItemBottomSheetBodyAction.delete,
];
}
}
ActionPane buildEndActionPane(
BuildContext context,
List<MobilePaneActionType> actions, {
bool needSpace = true,
MobilePageCardType? cardType,
FolderSpaceType? spaceType,
}) {
List<MobilePaneActionType> actions,
) {
return ActionPane(
motion: const ScrollMotion(),
extentRatio: actions.length / 5,
children: [
if (needSpace) const HSpace(20),
...actions.map(
(action) => action.actionButton(
context,
spaceType: spaceType,
cardType: cardType,
),
),
],
children: actions
.map(
(action) => action.actionButton(context),
)
.toList(),
);
}
@@ -1,6 +1,6 @@
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_buttons.dart';
import 'package:appflowy/plugins/base/drag_handler.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder;
import 'package:flutter/material.dart';
extension BottomSheetPaddingExtension on BuildContext {
@@ -1,28 +0,0 @@
import 'package:appflowy/mobile/presentation/base/mobile_view_page.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
class MobileChatScreen extends StatelessWidget {
const MobileChatScreen({
super.key,
required this.id,
this.title,
});
/// view id
final String id;
final String? title;
static const routeName = '/chat';
static const viewId = 'id';
static const viewTitle = 'title';
@override
Widget build(BuildContext context) {
return MobileViewPage(
id: id,
title: title,
viewLayout: ViewLayoutPB.Chat,
);
}
}
@@ -1,4 +1,4 @@
export 'mobile_board_screen.dart';
export 'mobile_board_page.dart';
export 'mobile_board_content.dart';
export 'widgets/mobile_hidden_groups_column.dart';
export 'widgets/mobile_board_trailing.dart';
@@ -3,118 +3,38 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/board/board.dart';
import 'package:appflowy/mobile/presentation/database/board/widgets/group_card_header.dart';
import 'package:appflowy/mobile/presentation/database/card/card.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_type_extension.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_style_maps/mobile_board_card_cell_style.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
class MobileBoardPage extends StatefulWidget {
const MobileBoardPage({
class MobileBoardContent extends StatefulWidget {
const MobileBoardContent({
super.key,
required this.view,
required this.databaseController,
this.onEditStateChanged,
});
final ViewPB view;
final DatabaseController databaseController;
/// Called when edit state changed
final VoidCallback? onEditStateChanged;
@override
State<MobileBoardPage> createState() => _MobileBoardPageState();
State<MobileBoardContent> createState() => _MobileBoardContentState();
}
class _MobileBoardPageState extends State<MobileBoardPage> {
late final ValueNotifier<DidCreateRowResult?> _didCreateRow;
@override
void initState() {
super.initState();
_didCreateRow = ValueNotifier(null)..addListener(_handleDidCreateRow);
}
@override
void dispose() {
_didCreateRow
..removeListener(_handleDidCreateRow)
..dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider<BoardBloc>(
create: (_) => BoardBloc(
databaseController: widget.databaseController,
didCreateRow: _didCreateRow,
)..add(const BoardEvent.initial()),
child: BlocBuilder<BoardBloc, BoardState>(
builder: (context, state) => state.maybeMap(
loading: (_) => const Center(
child: CircularProgressIndicator.adaptive(),
),
error: (err) => FlowyMobileStateContainer.error(
emoji: '🛸',
title: LocaleKeys.board_mobile_failedToLoad.tr(),
errorMsg: err.toString(),
),
ready: (data) => const _BoardContent(),
orElse: () => const SizedBox.shrink(),
),
),
);
}
void _handleDidCreateRow() {
if (_didCreateRow.value != null) {
final result = _didCreateRow.value!;
switch (result.action) {
case DidCreateRowAction.openAsPage:
context.push(
MobileRowDetailPage.routeName,
extra: {
MobileRowDetailPage.argRowId: result.rowMeta.id,
MobileRowDetailPage.argDatabaseController:
widget.databaseController,
},
);
break;
default:
break;
}
}
}
}
class _BoardContent extends StatefulWidget {
const _BoardContent();
@override
State<_BoardContent> createState() => _BoardContentState();
}
class _BoardContentState extends State<_BoardContent> {
class _MobileBoardContentState extends State<MobileBoardContent> {
late final ScrollController scrollController;
late final AppFlowyBoardScrollController scrollManager;
@override
void initState() {
super.initState();
// mobile may not need this
// scroll to bottom when add a new card
scrollManager = AppFlowyBoardScrollController();
scrollController = ScrollController();
}
@@ -137,48 +57,54 @@ class _BoardContentState extends State<_BoardContent> {
cardMargin: const EdgeInsets.all(4),
);
return BlocBuilder<BoardBloc, BoardState>(
builder: (context, state) {
return state.maybeMap(
orElse: () => const SizedBox.shrink(),
ready: (state) {
final showCreateGroupButton = context
.read<BoardBloc>()
.groupingFieldType
?.canCreateNewGroup ??
false;
final showHiddenGroups = state.hiddenGroups.isNotEmpty;
return AppFlowyBoard(
scrollController: scrollController,
controller: context.read<BoardBloc>().boardController,
groupConstraints:
BoxConstraints.tightFor(width: screenWidth * 0.7),
config: config,
leading: showHiddenGroups
? MobileHiddenGroupsColumn(
padding: config.groupHeaderPadding,
)
: const HSpace(16),
trailing: showCreateGroupButton
? const MobileBoardTrailing()
: const HSpace(16),
headerBuilder: (_, groupData) => BlocProvider<BoardBloc>.value(
value: context.read<BoardBloc>(),
child: GroupCardHeader(
groupData: groupData,
),
),
footerBuilder: _buildFooter,
cardBuilder: (_, column, columnItem) => _buildCard(
context: context,
afGroupData: column,
afGroupItem: columnItem,
cardMargin: config.cardMargin,
),
);
return BlocListener<BoardBloc, BoardState>(
listenWhen: (previous, current) =>
previous.recentAddedRowMeta != current.recentAddedRowMeta,
listener: (context, state) {
context.push(
MobileRowDetailPage.routeName,
extra: {
MobileRowDetailPage.argRowId: state.recentAddedRowMeta!.id,
MobileRowDetailPage.argDatabaseController:
context.read<BoardBloc>().databaseController,
},
);
},
child: BlocBuilder<BoardBloc, BoardState>(
builder: (context, state) {
final showCreateGroupButton =
context.read<BoardBloc>().groupingFieldType.canCreateNewGroup;
final showHiddenGroups = state.hiddenGroups.isNotEmpty;
return AppFlowyBoard(
boardScrollController: scrollManager,
scrollController: scrollController,
controller: context.read<BoardBloc>().boardController,
groupConstraints: BoxConstraints.tightFor(width: screenWidth * 0.7),
config: config,
leading: showHiddenGroups
? MobileHiddenGroupsColumn(
padding: config.groupHeaderPadding,
)
: const HSpace(16),
trailing: showCreateGroupButton
? const MobileBoardTrailing()
: const HSpace(16),
headerBuilder: (_, groupData) => BlocProvider<BoardBloc>.value(
value: context.read<BoardBloc>(),
child: GroupCardHeader(
groupData: groupData,
),
),
footerBuilder: _buildFooter,
cardBuilder: (_, column, columnItem) => _buildCard(
context: context,
afGroupData: column,
afGroupItem: columnItem,
cardMargin: config.cardMargin,
),
);
},
),
);
}
@@ -203,14 +129,9 @@ class _BoardContentState extends State<_BoardContent> {
color: style.colorScheme.onSurface,
),
),
onPressed: () => context.read<BoardBloc>().add(
BoardEvent.createRow(
columnData.id,
OrderObjectPositionTypePB.End,
null,
null,
),
),
onPressed: () => context
.read<BoardBloc>()
.add(BoardEvent.createBottomRow(columnData.id)),
),
);
}
@@ -225,9 +146,16 @@ class _BoardContentState extends State<_BoardContent> {
final groupItem = afGroupItem as GroupItem;
final groupData = afGroupData.customData as GroupData;
final rowMeta = groupItem.row;
final rowCache = boardBloc.getRowCache();
/// Return placeholder widget if the rowCache is null.
if (rowCache == null) return SizedBox.shrink(key: ObjectKey(groupItem));
final viewId = boardBloc.viewId;
final cellBuilder =
CardCellBuilder(databaseController: boardBloc.databaseController);
final isEditing = boardBloc.state.isEditingRow &&
boardBloc.state.editingRow?.row.id == groupItem.row.id;
final groupItemId = groupItem.row.id + groupData.group.groupId;
@@ -238,12 +166,12 @@ class _BoardContentState extends State<_BoardContent> {
child: RowCard(
fieldController: boardBloc.fieldController,
rowMeta: rowMeta,
viewId: boardBloc.viewId,
rowCache: boardBloc.rowCache,
viewId: viewId,
rowCache: rowCache,
groupingFieldId: groupItem.fieldInfo.id,
isEditing: false,
isEditing: isEditing,
cellBuilder: cellBuilder,
onTap: (context) {
openCard: (context) {
context.push(
MobileRowDetailPage.routeName,
extra: {
@@ -253,8 +181,10 @@ class _BoardContentState extends State<_BoardContent> {
},
);
},
onStartEditing: () {},
onEndEditing: () {},
onStartEditing: () => boardBloc
.add(BoardEvent.startEditingRow(groupData.group, groupItem.row)),
onEndEditing: () =>
boardBloc.add(BoardEvent.endEditingRow(groupItem.row.id)),
styleConfiguration: RowCardStyleConfiguration(
cellStyleMap: mobileBoardCardCellStyleMap(context),
showAccessory: false,
@@ -266,7 +196,7 @@ class _BoardContentState extends State<_BoardContent> {
BoxDecoration _makeBoxDecoration(BuildContext context) {
final themeMode = context.read<AppearanceSettingsCubit>().state.themeMode;
return BoxDecoration(
color: AFThemeExtension.of(context).background,
color: Theme.of(context).colorScheme.background,
borderRadius: const BorderRadius.all(Radius.circular(8)),
border: themeMode == ThemeMode.light
? Border.fromBorderSide(
@@ -1,14 +1,16 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
import 'package:appflowy/plugins/database/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
@@ -71,12 +73,8 @@ class _GroupCardHeaderState extends State<GroupCardHeader> {
);
}
final isEditing = state.maybeMap(
ready: (value) => value.editingHeaderId == widget.groupData.id,
orElse: () => false,
);
if (isEditing) {
if (state.isEditingHeader &&
state.editingHeaderId == widget.groupData.id) {
title = TextField(
controller: _controller,
autofocus: true,
@@ -137,7 +135,7 @@ class _GroupCardHeaderState extends State<GroupCardHeader> {
icon: FlowySvgs.hide_s,
onTap: () {
context.read<BoardBloc>().add(
BoardEvent.setGroupVisibility(
BoardEvent.toggleGroupVisibility(
widget.groupData.customData.group
as GroupPB,
false,
@@ -156,16 +154,9 @@ class _GroupCardHeaderState extends State<GroupCardHeader> {
color: Theme.of(context).colorScheme.onSurface,
),
splashRadius: 5,
onPressed: () {
context.read<BoardBloc>().add(
BoardEvent.createRow(
widget.groupData.id,
OrderObjectPositionTypePB.Start,
null,
null,
),
);
},
onPressed: () => context.read<BoardBloc>().add(
BoardEvent.createHeaderRow(widget.groupData.id),
),
),
],
),
@@ -60,7 +60,7 @@ class _MobileBoardTrailingState extends State<MobileBoardTrailing> {
child: IconButton(
icon: Icon(
Icons.close,
color: style.colorScheme.onSurface,
color: style.colorScheme.onBackground,
),
onPressed: () =>
setState(() => _textController.clear()),
@@ -86,7 +86,7 @@ class _MobileBoardTrailingState extends State<MobileBoardTrailing> {
child: Text(
LocaleKeys.button_cancel.tr(),
style: style.textTheme.titleSmall?.copyWith(
color: style.colorScheme.onSurface,
color: style.colorScheme.onBackground,
),
),
onPressed: () => setState(() => isEditing = false),
@@ -96,7 +96,7 @@ class _MobileBoardTrailingState extends State<MobileBoardTrailing> {
LocaleKeys.button_add.tr(),
style: style.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
color: style.colorScheme.onSurface,
color: style.colorScheme.onBackground,
),
),
onPressed: () {
@@ -117,14 +117,14 @@ class _MobileBoardTrailingState extends State<MobileBoardTrailing> {
)
: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
foregroundColor: style.colorScheme.onSurface,
foregroundColor: style.colorScheme.onBackground,
backgroundColor: style.colorScheme.secondary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
).copyWith(
overlayColor:
WidgetStateProperty.all(Theme.of(context).hoverColor),
MaterialStateProperty.all(Theme.of(context).hoverColor),
),
icon: const Icon(Icons.add),
label: Text(
@@ -9,7 +9,6 @@ import 'package:appflowy/plugins/database/widgets/cell/card_cell_skeleton/text_c
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -24,10 +23,7 @@ class MobileHiddenGroupsColumn extends StatelessWidget {
Widget build(BuildContext context) {
final databaseController = context.read<BoardBloc>().databaseController;
return BlocSelector<BoardBloc, BoardState, BoardLayoutSettingPB?>(
selector: (state) => state.maybeMap(
orElse: () => null,
ready: (value) => value.layoutSettings,
),
selector: (state) => state.layoutSettings,
builder: (context, layoutSettings) {
if (layoutSettings == null) {
return const SizedBox.shrink();
@@ -109,36 +105,29 @@ class MobileHiddenGroupList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<BoardBloc, BoardState>(
builder: (_, state) {
return state.maybeMap(
orElse: () => const SizedBox.shrink(),
ready: (state) {
return ReorderableListView.builder(
itemCount: state.hiddenGroups.length,
itemBuilder: (_, index) => MobileHiddenGroup(
key: ValueKey(state.hiddenGroups[index].groupId),
group: state.hiddenGroups[index],
index: index,
),
proxyDecorator: (child, index, animation) => BlocProvider.value(
value: context.read<BoardBloc>(),
child: Material(color: Colors.transparent, child: child),
),
physics: const ClampingScrollPhysics(),
onReorder: (oldIndex, newIndex) {
if (oldIndex < newIndex) {
newIndex--;
}
final fromGroupId = state.hiddenGroups[oldIndex].groupId;
final toGroupId = state.hiddenGroups[newIndex].groupId;
context
.read<BoardBloc>()
.add(BoardEvent.reorderGroup(fromGroupId, toGroupId));
},
);
},
);
},
builder: (_, state) => ReorderableListView.builder(
itemCount: state.hiddenGroups.length,
itemBuilder: (_, index) => MobileHiddenGroup(
key: ValueKey(state.hiddenGroups[index].groupId),
group: state.hiddenGroups[index],
index: index,
),
proxyDecorator: (child, index, animation) => BlocProvider.value(
value: context.read<BoardBloc>(),
child: Material(color: Colors.transparent, child: child),
),
physics: const ClampingScrollPhysics(),
onReorder: (oldIndex, newIndex) {
if (oldIndex < newIndex) {
newIndex--;
}
final fromGroupId = state.hiddenGroups[oldIndex].groupId;
final toGroupId = state.hiddenGroups[newIndex].groupId;
context
.read<BoardBloc>()
.add(BoardEvent.reorderGroup(fromGroupId, toGroupId));
},
),
);
}
}
@@ -159,77 +148,92 @@ class MobileHiddenGroup extends StatelessWidget {
final primaryField = databaseController.fieldController.fieldInfos
.firstWhereOrNull((element) => element.isPrimary)!;
final cells = group.rows.map(
(item) {
final cellContext =
databaseController.rowCache.loadCells(item).firstWhere(
(cellContext) => cellContext.fieldId == primaryField.id,
);
return BlocBuilder<BoardBloc, BoardState>(
builder: (context, state) {
final group = state.hiddenGroups.firstWhereOrNull(
(g) => g.groupId == this.group.groupId,
);
if (group == null) {
return const SizedBox.shrink();
}
return TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.bodyMedium,
foregroundColor: AFThemeExtension.of(context).onBackground,
visualDensity: VisualDensity.compact,
),
child: CardCellBuilder(
databaseController: context.read<BoardBloc>().databaseController,
).build(
cellContext: cellContext,
styleMap: {FieldType.RichText: _titleCellStyle(context)},
hasNotes: !item.isDocumentEmpty,
),
onPressed: () {
context.push(
MobileRowDetailPage.routeName,
extra: {
MobileRowDetailPage.argRowId: item.id,
MobileRowDetailPage.argDatabaseController:
final cells = group.rows.map(
(item) {
final cellContext =
databaseController.rowCache.loadCells(item).firstWhere(
(cellContext) => cellContext.fieldId == primaryField.id,
);
return TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.bodyMedium,
foregroundColor: Theme.of(context).colorScheme.onBackground,
visualDensity: VisualDensity.compact,
),
child: CardCellBuilder(
databaseController:
context.read<BoardBloc>().databaseController,
).build(
cellContext: cellContext,
styleMap: {FieldType.RichText: _titleCellStyle(context)},
hasNotes: !item.isDocumentEmpty,
),
onPressed: () {
context.push(
MobileRowDetailPage.routeName,
extra: {
MobileRowDetailPage.argRowId: item.id,
MobileRowDetailPage.argDatabaseController:
context.read<BoardBloc>().databaseController,
},
);
},
);
},
).toList();
return ExpansionTile(
tilePadding: EdgeInsets.zero,
childrenPadding: EdgeInsets.zero,
title: Row(
children: [
Expanded(
child: Text(
context.read<BoardBloc>().generateGroupNameFromGroup(group),
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
GestureDetector(
child: const Padding(
padding: EdgeInsets.all(4),
child: FlowySvg(
FlowySvgs.hide_m,
size: Size.square(20),
),
),
onTap: () => showFlowyMobileConfirmDialog(
context,
title: FlowyText(LocaleKeys.board_mobile_showGroup.tr()),
content: FlowyText(
LocaleKeys.board_mobile_showGroupContent.tr(),
),
actionButtonTitle: LocaleKeys.button_yes.tr(),
actionButtonColor: Theme.of(context).colorScheme.primary,
onActionButtonPressed: () => context.read<BoardBloc>().add(
BoardEvent.toggleGroupVisibility(
group,
true,
),
),
),
),
],
),
children: cells,
);
},
).toList();
return ExpansionTile(
tilePadding: EdgeInsets.zero,
childrenPadding: EdgeInsets.zero,
title: Row(
children: [
Expanded(
child: Text(
context.read<BoardBloc>().generateGroupNameFromGroup(group),
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
GestureDetector(
child: const Padding(
padding: EdgeInsets.all(4),
child: FlowySvg(
FlowySvgs.hide_m,
size: Size.square(20),
),
),
onTap: () => showFlowyMobileConfirmDialog(
context,
title: FlowyText(LocaleKeys.board_mobile_showGroup.tr()),
content: FlowyText(
LocaleKeys.board_mobile_showGroupContent.tr(),
),
actionButtonTitle: LocaleKeys.button_yes.tr(),
actionButtonColor: Theme.of(context).colorScheme.primary,
onActionButtonPressed: () => context
.read<BoardBloc>()
.add(BoardEvent.setGroupVisibility(group, true)),
),
),
],
),
children: cells,
);
}
@@ -20,7 +20,6 @@ import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'
import 'package:appflowy/plugins/database/widgets/row/row_property.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -132,7 +131,7 @@ class _MobileRowDetailPageState extends State<MobileRowDetailPage> {
void _showCardActions(BuildContext context) {
showMobileBottomSheet(
context,
backgroundColor: AFThemeExtension.of(context).background,
backgroundColor: Theme.of(context).colorScheme.background,
showDragHandle: true,
builder: (_) => Column(
mainAxisSize: MainAxisSize.min,
@@ -140,7 +139,7 @@ class _MobileRowDetailPageState extends State<MobileRowDetailPage> {
MobileQuickActionButton(
onTap: () =>
_performAction(viewId, _bloc.state.currentRowId, false),
icon: FlowySvgs.duplicate_s,
icon: FlowySvgs.copy_s,
text: LocaleKeys.button_duplicate.tr(),
),
const Divider(height: 8.5, thickness: 0.5),
@@ -148,7 +147,7 @@ class _MobileRowDetailPageState extends State<MobileRowDetailPage> {
onTap: () => _performAction(viewId, _bloc.state.currentRowId, true),
text: LocaleKeys.button_delete.tr(),
textColor: Theme.of(context).colorScheme.error,
icon: FlowySvgs.trash_s,
icon: FlowySvgs.m_delete_m,
iconColor: Theme.of(context).colorScheme.error,
),
const Divider(height: 8.5, thickness: 0.5),
@@ -163,7 +162,7 @@ class _MobileRowDetailPageState extends State<MobileRowDetailPage> {
}
deleteRow
? RowBackendService.deleteRows(viewId, [rowId])
? RowBackendService.deleteRow(viewId, rowId)
: RowBackendService.duplicateRow(viewId, rowId);
context
@@ -2,7 +2,6 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/field/mobile_field_bottom_sheets.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -20,23 +19,20 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
minHeight: GridSize.headerHeight,
),
constraints: const BoxConstraints(minWidth: double.infinity),
child: TextButton.icon(
style: Theme.of(context).textButtonTheme.style?.copyWith(
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
overlayColor: WidgetStateProperty.all<Color>(
overlayColor: MaterialStateProperty.all<Color>(
Theme.of(context).hoverColor,
),
alignment: AlignmentDirectional.centerStart,
splashFactory: NoSplash.splashFactory,
padding: const WidgetStatePropertyAll(
padding: const MaterialStatePropertyAll(
EdgeInsets.symmetric(vertical: 14, horizontal: 6),
),
),
@@ -1,5 +1,5 @@
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy/plugins/database/widgets/card/card_bloc.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_style_maps/mobile_board_card_cell_style.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
@@ -16,7 +16,7 @@ class MobileCardContent extends StatelessWidget {
final RowMetaPB rowMeta;
final CardCellBuilder cellBuilder;
final List<CellMeta> cells;
final List<CellContext> cells;
final RowCardStyleConfiguration styleConfiguration;
@override
@@ -26,9 +26,9 @@ class MobileCardContent extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: cells.map(
(cellMeta) {
(cellContext) {
return cellBuilder.build(
cellContext: cellMeta.cellContext(),
cellContext: cellContext,
styleMap: mobileBoardCardCellStyleMap(context),
hasNotes: !rowMeta.isDocumentEmpty,
);
@@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/type_option_menu_item.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
@@ -9,7 +7,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.da
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'mobile_create_field_screen.dart';
@@ -29,7 +27,6 @@ const mobileSupportedFieldTypes = [
FieldType.CreatedTime,
FieldType.Checkbox,
FieldType.Checklist,
// FieldType.Time,
];
Future<FieldType?> showFieldTypeGridBottomSheet(
@@ -43,7 +40,7 @@ Future<FieldType?> showFieldTypeGridBottomSheet(
showCloseButton: true,
elevation: 20,
title: title,
backgroundColor: AFThemeExtension.of(context).background,
backgroundColor: Theme.of(context).colorScheme.background,
enableDraggableScrollable: true,
builder: (context) {
final typeOptionMenuItemValue = mobileSupportedFieldTypes
@@ -119,7 +119,6 @@ class FieldOptionValues {
case FieldType.RichText:
case FieldType.URL:
case FieldType.Checkbox:
case FieldType.Time:
return null;
case FieldType.Number:
return NumberTypeOptionPB(
@@ -5,8 +5,8 @@ import 'package:appflowy/mobile/presentation/database/field/mobile_field_bottom_
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
import 'package:appflowy/plugins/database/application/field/field_editor_bloc.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/domain/field_backend_service.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/widgets/setting/field_visibility_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -438,7 +438,7 @@ class _SortDetailContent extends StatelessWidget {
color: Theme.of(context).colorScheme.surface,
),
splashFactory: NoSplash.splashFactory,
overlayColor: const WidgetStatePropertyAll(
overlayColor: const MaterialStatePropertyAll(
Colors.transparent,
),
onTap: (index) {
@@ -11,7 +11,6 @@ import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -184,7 +183,7 @@ class MobileDatabaseViewListButton extends StatelessWidget {
showMobileBottomSheet(
context,
showDragHandle: true,
backgroundColor: AFThemeExtension.of(context).background,
backgroundColor: Theme.of(context).colorScheme.background,
builder: (_) {
return BlocProvider<ViewBloc>(
create: (_) =>
@@ -107,9 +107,9 @@ enum _Action {
FlowySvgData get icon {
return switch (this) {
edit => FlowySvgs.view_item_rename_s,
duplicate => FlowySvgs.duplicate_s,
delete => FlowySvgs.trash_s,
edit => FlowySvgs.edit_s,
duplicate => FlowySvgs.copy_s,
delete => FlowySvgs.delete_s,
};
}
@@ -234,6 +234,7 @@ class DatabaseViewSettingTile extends StatelessWidget {
showHeader: true,
showBackButton: true,
title: LocaleKeys.grid_settings_properties.tr(),
showDivider: true,
builder: (_) {
return BlocProvider.value(
value: context.read<ViewBloc>(),
@@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder.dart';
@@ -8,7 +10,6 @@ import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
@@ -16,15 +17,14 @@ class MobileFavoritePageFolder extends StatelessWidget {
const MobileFavoritePageFolder({
super.key,
required this.userProfile,
required this.workspaceId,
});
final UserProfilePB userProfile;
final String workspaceId;
@override
Widget build(BuildContext context) {
final workspaceId =
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return MultiBlocProvider(
providers: [
BlocProvider(
@@ -67,8 +67,7 @@ class MobileFavoritePageFolder extends StatelessWidget {
MobileFavoriteFolder(
showHeader: false,
forceExpanded: true,
views:
favoriteState.views.map((e) => e.item).toList(),
views: favoriteState.views,
),
const VSpace(100.0),
],
@@ -64,6 +64,8 @@ class MobileFavoriteScreen extends StatelessWidget {
builder: (context, state) {
return MobileFavoritePage(
userProfile: userProfile,
workspaceId: state.currentWorkspace?.workspaceId ??
workspaceSetting.workspaceId,
);
},
),
@@ -79,9 +81,11 @@ class MobileFavoritePage extends StatelessWidget {
const MobileFavoritePage({
super.key,
required this.userProfile,
required this.workspaceId,
});
final UserProfilePB userProfile;
final String workspaceId;
@override
Widget build(BuildContext context) {
@@ -104,6 +108,7 @@ class MobileFavoritePage extends StatelessWidget {
Expanded(
child: MobileFavoritePageFolder(
userProfile: userProfile,
workspaceId: workspaceId,
),
),
],
@@ -1,133 +0,0 @@
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/home/shared/empty_placeholder.dart';
import 'package:appflowy/mobile/presentation/home/shared/mobile_page_card.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/application/user/prelude.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MobileFavoriteSpace extends StatefulWidget {
const MobileFavoriteSpace({
super.key,
required this.userProfile,
});
final UserProfilePB userProfile;
@override
State<MobileFavoriteSpace> createState() => _MobileFavoriteSpaceState();
}
class _MobileFavoriteSpaceState extends State<MobileFavoriteSpace>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
final workspaceId =
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return MultiBlocProvider(
providers: [
BlocProvider(
create: (_) => SidebarSectionsBloc()
..add(
SidebarSectionsEvent.initial(widget.userProfile, workspaceId),
),
),
BlocProvider(
create: (_) => FavoriteBloc()..add(const FavoriteEvent.initial()),
),
],
child: BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
listener: (context, state) =>
context.read<FavoriteBloc>().add(const FavoriteEvent.initial()),
child: MultiBlocListener(
listeners: [
BlocListener<SidebarSectionsBloc, SidebarSectionsState>(
listenWhen: (p, c) =>
p.lastCreatedRootView?.id != c.lastCreatedRootView?.id,
listener: (context, state) =>
context.pushView(state.lastCreatedRootView!),
),
],
child: Builder(
builder: (context) {
final favoriteState = context.watch<FavoriteBloc>().state;
if (favoriteState.isLoading) {
return const SizedBox.shrink();
}
if (favoriteState.views.isEmpty) {
return const EmptySpacePlaceholder(
type: MobilePageCardType.favorite,
);
}
return _FavoriteViews(
favoriteViews: favoriteState.views.reversed.toList(),
);
},
),
),
),
);
}
}
class _FavoriteViews extends StatelessWidget {
const _FavoriteViews({
required this.favoriteViews,
});
final List<SectionViewPB> favoriteViews;
@override
Widget build(BuildContext context) {
final borderColor = Theme.of(context).isLightMode
? const Color(0xFFE9E9EC)
: const Color(0x1AFFFFFF);
return Scrollbar(
child: ListView.separated(
key: const PageStorageKey('favorite_views_page_storage_key'),
padding: EdgeInsets.only(
left: HomeSpaceViewSizes.mHorizontalPadding,
right: HomeSpaceViewSizes.mHorizontalPadding,
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final view = favoriteViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
),
),
child: MobileViewPage(
key: ValueKey(view.item.id),
view: view.item,
timestamp: view.timestamp,
type: MobilePageCardType.favorite,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: favoriteViews.length,
),
);
}
}
@@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart';
import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder_header.dart';
@@ -5,7 +7,6 @@ import 'package:appflowy/mobile/presentation/page_item/mobile_view_item.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MobileFavoriteFolder extends StatelessWidget {
@@ -27,7 +28,7 @@ class MobileFavoriteFolder extends StatelessWidget {
}
return BlocProvider<FolderBloc>(
create: (context) => FolderBloc(type: FolderSpaceType.favorite)
create: (context) => FolderBloc(type: FolderCategoryType.favorite)
..add(
const FolderEvent.initial(),
),
@@ -54,25 +55,21 @@ class MobileFavoriteFolder extends StatelessWidget {
...views.map(
(view) => MobileViewItem(
key: ValueKey(
'${FolderSpaceType.favorite.name} ${view.id}',
'${FolderCategoryType.favorite.name} ${view.id}',
),
spaceType: FolderSpaceType.favorite,
categoryType: FolderCategoryType.favorite,
isDraggable: false,
isFirstChild: view.id == views.first.id,
isFeedback: false,
view: view,
level: 0,
onSelected: context.pushView,
endActionPane: (context) => buildEndActionPane(
context,
[
view.isFavorite
? MobilePaneActionType.removeFromFavorites
: MobilePaneActionType.addToFavorites,
MobilePaneActionType.more,
],
spaceType: FolderSpaceType.favorite,
),
endActionPane: (context) => buildEndActionPane(context, [
view.isFavorite
? MobilePaneActionType.removeFromFavorites
: MobilePaneActionType.addToFavorites,
MobilePaneActionType.more,
]),
),
),
],
@@ -1,47 +0,0 @@
import 'package:appflowy/mobile/presentation/home/mobile_folders.dart';
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MobileHomeSpace extends StatefulWidget {
const MobileHomeSpace({super.key, required this.userProfile});
final UserProfilePB userProfile;
@override
State<MobileHomeSpace> createState() => _MobileHomeSpaceState();
}
class _MobileHomeSpaceState extends State<MobileHomeSpace>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
final workspaceId =
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return Scrollbar(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
left: HomeSpaceViewSizes.mHorizontalPadding,
right: HomeSpaceViewSizes.mHorizontalPadding,
top: HomeSpaceViewSizes.mVerticalPadding,
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
child: MobileFolders(
user: widget.userProfile,
workspaceId: workspaceId,
showFavorite: false,
),
),
),
);
}
}
Loaded 100 of 1416 files, more files were not shown because too many files have changed in this diff. Show more