Compare commits

..
Author SHA1 Message Date
Kilu a7a40aebda feat: open editing 2024-10-28 14:39:40 +08:00
473 changed files with 5253 additions and 10893 deletions

No files matched your search

+89 -28
View File
@@ -28,7 +28,7 @@ env:
FLUTTER_VERSION: "3.22.2"
RUST_TOOLCHAIN: "1.80.1"
CARGO_MAKE_VERSION: "0.37.18"
CLOUD_VERSION: 0.6.54-amd64
CLOUD_VERSION: 0.6.50
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -40,7 +40,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest]
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
@@ -74,7 +74,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [windows-latest]
os: [ windows-latest ]
include:
- os: windows-latest
flutter_profile: development-windows-x86
@@ -101,7 +101,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [macos-latest]
os: [ macos-latest ]
include:
- os: macos-latest
flutter_profile: development-mac-x86_64
@@ -123,12 +123,12 @@ jobs:
flutter_profile: ${{ matrix.flutter_profile }}
unit_test:
needs: [prepare-linux]
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
@@ -217,11 +217,11 @@ jobs:
shell: bash
cloud_integration_test:
needs: [prepare-linux]
needs: [ prepare-linux ]
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
@@ -262,20 +262,9 @@ jobs:
else
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Restarting with the correct version..."
# Remove all containers if any exist
if [ "$(docker ps -aq)" ]; then
docker rm -f $(docker ps -aq)
else
echo "No containers to remove."
fi
# Remove all volumes if any exist
if [ "$(docker volume ls -q)" ]; then
docker volume rm $(docker volume ls -q)
else
echo "No volumes to remove."
fi
echo "AppFlowy-Cloud is running with an incorrect version. Pulling the correct version..."
docker rm -f $(docker ps -aq)
docker volume rm $(docker volume ls -q)
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
@@ -339,14 +328,14 @@ jobs:
flutter test integration_test/desktop/cloud/cloud_runner.dart -d Linux --coverage
shell: bash
integration_test:
needs: [prepare-linux]
# split the integration tests into different machines to minimize the time
integration_test_1:
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
test_number: [1, 2, 3, 4, 5, 6, 7, 8]
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
target: "x86_64-unknown-linux-gnu"
@@ -355,10 +344,82 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Flutter Integration Test ${{ matrix.test_number }}
- name: Flutter Integration Test 1
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_${{ matrix.test_number }}.dart
test_path: integration_test/desktop_runner_1.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
integration_test_2:
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
target: "x86_64-unknown-linux-gnu"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Flutter Integration Test 2
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_2.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
integration_test_3:
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
target: "x86_64-unknown-linux-gnu"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Flutter Integration Test 3
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_3.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
integration_test_4:
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
target: "x86_64-unknown-linux-gnu"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Flutter Integration Test 4
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_4.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
+1 -1
View File
@@ -22,7 +22,7 @@ on:
env:
FLUTTER_VERSION: "3.22.0"
RUST_TOOLCHAIN: "1.80.1"
CLOUD_VERSION: 0.6.51
CLOUD_VERSION: 0.6.50
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+5 -15
View File
@@ -20,7 +20,7 @@ on:
env:
CARGO_TERM_COLOR: always
CLOUD_VERSION: 0.6.51-amd64
CLOUD_VERSION: 0.6.50
RUST_TOOLCHAIN: "1.77.2"
jobs:
@@ -62,6 +62,8 @@ jobs:
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Pulling the correct version..."
docker rm -f $(docker ps -aq)
docker volume rm $(docker volume ls -q)
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
@@ -147,20 +149,8 @@ jobs:
APPFLOWY_HISTORY_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_WORKER_VERSION: ${{ env.CLOUD_VERSION }}
run: |
# Remove all containers if any exist
if [ "$(docker ps -aq)" ]; then
docker rm -f $(docker ps -aq)
else
echo "No containers to remove."
fi
# Remove all volumes if any exist
if [ "$(docker volume ls -q)" ]; then
docker volume rm $(docker volume ls -q)
else
echo "No volumes to remove."
fi
docker rm -f $(docker ps -aq)
docker volume rm $(docker volume ls -q)
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
+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.7.3"
APPFLOWY_VERSION = "0.7.2"
FLUTTER_DESKTOP_FEATURES = "dart"
PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0"
@@ -6,7 +6,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:time/time.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
@@ -15,31 +14,6 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board row test', () {
testWidgets('edit item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.ancestor(
matching: find.byType(RowCard),
of: find.text(name),
);
await tester.hoverOnWidget(
card1,
onHover: () async {
final editCard = find.byType(EditCardAccessory);
await tester.tapButton(editCard);
},
);
await tester.showKeyboard(card1);
tester.testTextInput.enterText("");
await tester.pump(300.milliseconds);
tester.testTextInput.enterText("a");
await tester.pump(300.milliseconds);
expect(find.text('a'), findsOneWidget);
});
testWidgets('delete item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -1,157 +0,0 @@
// ignore_for_file: unused_import
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/plugins/shared/share/constants.dart';
import 'package:appflowy/plugins/shared/share/publish_tab.dart';
import 'package:appflowy/plugins/shared/share/share_menu.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/shared/patterns/common_patterns.dart';
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/workspace/_sidebar_workspace_icon.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.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/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../../shared/constants.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../../shared/workspace.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Publish:', () {
testWidgets('publish document', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
final publishButton = find.byType(PublishButton);
final unpublishButton = find.byType(UnPublishButton);
await tester.tapButton(publishButton);
// expect to see unpublish, visit site and manage all sites button
expect(unpublishButton, findsOneWidget);
expect(find.text(LocaleKeys.shareAction_visitSite.tr()), findsOneWidget);
// unpublish the document
await tester.tapButton(unpublishButton);
// expect to see publish button
expect(publishButton, findsOneWidget);
});
testWidgets('rename path name', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
final publishButton = find.byType(PublishButton);
await tester.tapButton(publishButton);
// rename the path name
final inputField = find.descendant(
of: find.byType(ShareMenu),
matching: find.byType(TextField),
);
// rename with invalid name
await tester.tap(inputField);
await tester.enterText(inputField, '&&&&????');
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
await tester.pumpAndSettle();
// expect to see the toast with error message
final errorToast1 = find.text(
LocaleKeys.settings_sites_error_publishNameContainsInvalidCharacters
.tr(),
);
await tester.pumpUntilFound(errorToast1);
await tester.pumpUntilNotFound(errorToast1);
// rename with long name
await tester.tap(inputField);
await tester.enterText(inputField, 'long-path-name' * 200);
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
await tester.pumpAndSettle();
// expect to see the toast with error message
final errorToast2 = find.text(
LocaleKeys.settings_sites_error_publishNameTooLong.tr(),
);
await tester.pumpUntilFound(errorToast2);
await tester.pumpUntilNotFound(errorToast2);
await tester.tap(inputField);
// input the new path name
await tester.enterText(inputField, 'new-path-name');
// click save button
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
await tester.pumpAndSettle();
// expect to see the toast with success message
final successToast = find.text(
LocaleKeys.settings_sites_success_updatePathNameSuccess.tr(),
);
await tester.pumpUntilFound(successToast);
await tester.pumpUntilNotFound(successToast);
// click the copy link button
await tester.tapButton(
find.byWidgetPredicate(
(widget) =>
widget is FlowySvg &&
widget.svg.path == FlowySvgs.m_toolbar_link_m.path,
),
);
await tester.pumpAndSettle();
// check the clipboard has the link
final content = await Clipboard.getData(Clipboard.kTextPlain);
expect(
content?.text?.contains('new-path-name'),
isTrue,
);
});
});
}
@@ -3,12 +3,10 @@ import 'package:integration_test/integration_test.dart';
import 'document_copy_link_to_block_test.dart'
as document_copy_link_to_block_test;
import 'document_option_actions_test.dart' as document_option_actions_test;
import 'document_publish_test.dart' as document_publish_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
document_option_actions_test.main();
document_copy_link_to_block_test.main();
document_publish_test.main();
}
@@ -6,7 +6,6 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_p
import 'package:appflowy/plugins/shared/share/constants.dart';
import 'package:appflowy/plugins/shared/share/share_menu.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/shared/patterns/common_patterns.dart';
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';
@@ -62,11 +61,11 @@ void main() {
final plainText = clipboardContent.plainText;
expect(
plainText,
matches(appflowySharePageLinkPattern),
startsWith(ShareConstants.shareBaseUrl),
);
final shareValues = plainText!
.replaceAll('https://${ShareConstants.shareBaseUrl}/', '')
.replaceAll('${ShareConstants.shareBaseUrl}/', '')
.split('/');
final workspaceId = shareValues[0];
expect(workspaceId, isNotEmpty);
@@ -4,10 +4,8 @@ import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/plugins/shared/share/publish_tab.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
@@ -17,13 +15,6 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sid
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/pages/settings_workspace_view.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_item.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_more_action.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/home_page_menu.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/published_page/published_view_item.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/published_page/published_view_more_action.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/published_page/published_view_settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_list_tile.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
@@ -36,7 +27,6 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../../shared/constants.dart';
import '../../../shared/database_test_op.dart';
import '../../../shared/dir.dart';
import '../../../shared/emoji.dart';
@@ -103,266 +93,4 @@ void main() {
},
);
});
group('sites settings:', () {
testWidgets(
'manage published page, set it as homepage, remove the homepage',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
await tester.tapButton(find.byType(PublishButton));
// click empty area to close the publish menu
await tester.tapAt(Offset.zero);
await tester.pumpAndSettle();
// check if the page is published in sites page
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.sites);
// wait the backend return the sites data
await tester.wait(1000);
// check if the page is published in sites page
final pageItem = find.byWidgetPredicate(
(widget) =>
widget is PublishedViewItem &&
widget.publishInfoView.view.name == pageName,
);
expect(pageItem, findsOneWidget);
// comment it out because it's not allowed to update the namespace in free plan
// // set it to homepage
// await tester.tapButton(
// find.textContaining(
// LocaleKeys.settings_sites_selectHomePage.tr(),
// ),
// );
// await tester.tapButton(
// find.descendant(
// of: find.byType(SelectHomePageMenu),
// matching: find.text(pageName),
// ),
// );
// await tester.pumpAndSettle();
// // check if the page is set to homepage
// final homePageItem = find.descendant(
// of: find.byType(DomainItem),
// matching: find.text(pageName),
// );
// expect(homePageItem, findsOneWidget);
// // remove the homepage
// await tester.tapButton(find.byType(DomainMoreAction));
// await tester.tapButton(
// find.text(LocaleKeys.settings_sites_removeHomepage.tr()),
// );
// await tester.pumpAndSettle();
// // check if the page is removed from homepage
// expect(homePageItem, findsNothing);
});
testWidgets('update namespace', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// check if the page is published in sites page
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.sites);
// wait the backend return the sites data
await tester.wait(1000);
// update the domain
final domainMoreAction = find.byType(DomainMoreAction);
await tester.tapButton(domainMoreAction);
final updateNamespaceButton = find.text(
LocaleKeys.settings_sites_updateNamespace.tr(),
);
await tester.pumpUntilFound(updateNamespaceButton);
// click the update namespace button
await tester.tapButton(updateNamespaceButton);
// comment it out because it's not allowed to update the namespace in free plan
// expect to see the dialog
// await tester.updateNamespace('&&&???');
// // need to upgrade to pro plan to update the namespace
// final errorToast = find.text(
// LocaleKeys.settings_sites_error_proPlanLimitation.tr(),
// );
// await tester.pumpUntilFound(errorToast);
// expect(errorToast, findsOneWidget);
// await tester.pumpUntilNotFound(errorToast);
// comment it out because it's not allowed to update the namespace in free plan
// // short namespace
// await tester.updateNamespace('a');
// // expect to see the toast with error message
// final errorToast2 = find.text(
// LocaleKeys.settings_sites_error_namespaceTooShort.tr(),
// );
// await tester.pumpUntilFound(errorToast2);
// expect(errorToast2, findsOneWidget);
// await tester.pumpUntilNotFound(errorToast2);
// // valid namespace
// await tester.updateNamespace('AppFlowy');
// // expect to see the toast with success message
// final successToast = find.text(
// LocaleKeys.settings_sites_success_namespaceUpdated.tr(),
// );
// await tester.pumpUntilFound(successToast);
// expect(successToast, findsOneWidget);
});
testWidgets('''
More actions for published page:
1. visit site
2. copy link
3. settings
4. unpublish
5. custom url
''', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
await tester.tapButton(find.byType(PublishButton));
// click empty area to close the publish menu
await tester.tapAt(Offset.zero);
await tester.pumpAndSettle();
// check if the page is published in sites page
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.sites);
// wait the backend return the sites data
await tester.wait(1000);
// check if the page is published in sites page
final pageItem = find.byWidgetPredicate(
(widget) =>
widget is PublishedViewItem &&
widget.publishInfoView.view.name == pageName,
);
expect(pageItem, findsOneWidget);
final copyLinkItem = find.text(LocaleKeys.shareAction_copyLink.tr());
final customUrlItem = find.text(LocaleKeys.settings_sites_customUrl.tr());
final unpublishItem = find.text(LocaleKeys.shareAction_unPublish.tr());
// custom url
final publishMoreAction = find.byType(PublishedViewMoreAction);
// click the copy link button
{
await tester.tapButton(publishMoreAction);
await tester.pumpAndSettle();
await tester.pumpUntilFound(copyLinkItem);
await tester.tapButton(copyLinkItem);
await tester.pumpAndSettle();
await tester.pumpUntilNotFound(copyLinkItem);
final clipboardContent = await getIt<ClipboardService>().getData();
final plainText = clipboardContent.plainText;
expect(
plainText,
contains(pageName),
);
}
// custom url
{
await tester.tapButton(publishMoreAction);
await tester.pumpAndSettle();
await tester.pumpUntilFound(customUrlItem);
await tester.tapButton(customUrlItem);
await tester.pumpAndSettle();
await tester.pumpUntilNotFound(customUrlItem);
// see the custom url dialog
final customUrlDialog = find.byType(PublishedViewSettingsDialog);
expect(customUrlDialog, findsOneWidget);
// rename the custom url
final textField = find.descendant(
of: customUrlDialog,
matching: find.byType(TextField),
);
await tester.enterText(textField, 'hello-world');
await tester.pumpAndSettle();
// click the save button
final saveButton = find.descendant(
of: customUrlDialog,
matching: find.text(LocaleKeys.button_save.tr()),
);
await tester.tapButton(saveButton);
await tester.pumpAndSettle();
// expect to see the toast with success message
final successToast = find.text(
LocaleKeys.settings_sites_success_updatePathNameSuccess.tr(),
);
await tester.pumpUntilFound(successToast);
expect(successToast, findsOneWidget);
}
// unpublish
{
await tester.tapButton(publishMoreAction);
await tester.pumpAndSettle();
await tester.pumpUntilFound(unpublishItem);
await tester.tapButton(unpublishItem);
await tester.pumpAndSettle();
await tester.pumpUntilNotFound(unpublishItem);
// expect to see the toast with success message
final successToast = find.text(
LocaleKeys.publish_unpublishSuccessfully.tr(),
);
await tester.pumpUntilFound(successToast);
expect(successToast, findsOneWidget);
await tester.pumpUntilNotFound(successToast);
// check if the page is unpublished in sites page
expect(pageItem, findsNothing);
}
});
});
}
@@ -211,7 +211,8 @@ void main() {
await tester.toggleIncludeTime();
// Select a date
DateTime now = DateTime.now();
final now = DateTime.now();
final expected = DateTime(now.year, now.month, now.day);
await tester.selectDay(content: now.day);
await tester.dismissCellEditor();
@@ -219,13 +220,13 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y').format(now),
content: DateFormat('MMM dd, y').format(expected),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
// Toggle include time
now = DateTime.now();
// When toggling include time, the time value is from the previous existing date time, not the current time
await tester.toggleIncludeTime();
await tester.dismissCellEditor();
@@ -233,7 +234,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y HH:mm').format(now),
content: DateFormat('MMM dd, y HH:mm').format(expected),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -248,7 +249,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('dd/MM/y HH:mm').format(now),
content: DateFormat('dd/MM/y HH:mm').format(expected),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -263,7 +264,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('dd/MM/y hh:mm a').format(now),
content: DateFormat('dd/MM/y hh:mm a').format(expected),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -292,6 +292,7 @@ void main() {
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.toggleIncludeTime();
final now = DateTime.now();
final expected = DateTime(now.year, now.month, now.day);
await tester.selectDay(content: now.day);
await tester.dismissCellEditor();
@@ -299,7 +300,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y HH:mm').format(now),
content: DateFormat('MMM dd, y HH:mm').format(expected),
);
// open editor and change date & time format
@@ -313,7 +314,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('dd/MM/y hh:mm a').format(now),
content: DateFormat('dd/MM/y hh:mm a').format(expected),
);
});
@@ -540,6 +541,7 @@ void main() {
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.toggleIncludeTime();
final now = DateTime.now();
final expected = DateTime(now.year, now.month, now.day);
await tester.selectDay(content: now.day);
await tester.dismissCellEditor();
@@ -547,7 +549,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y HH:mm').format(now),
content: DateFormat('MMM dd, y HH:mm').format(expected),
);
await tester.changeFieldTypeOfFieldWithName(
@@ -557,7 +559,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.RichText,
content: DateFormat('MMM dd, y HH:mm').format(now),
content: DateFormat('MMM dd, y HH:mm').format(expected),
cellIndex: 1,
);
@@ -581,7 +583,7 @@ void main() {
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y').format(now),
content: DateFormat('MMM dd, y').format(expected),
);
tester.assertCellContent(
rowIndex: 1,
@@ -68,7 +68,10 @@ void main() {
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect one file
expect(find.byType(RenderMedia), findsOneWidget);
@@ -81,7 +84,9 @@ void main() {
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect two files
@@ -133,7 +138,10 @@ void main() {
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
@@ -184,7 +192,10 @@ void main() {
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
@@ -218,7 +229,7 @@ void main() {
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
testWidgets('show file names', (tester) async {
testWidgets('hide file names', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -260,7 +271,10 @@ void main() {
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
@@ -268,28 +282,28 @@ void main() {
await tester.dismissCellEditor();
await tester.pumpAndSettle();
// Open first row in row detail view then toggle show file names
// Open first row in row detail view then toggle hide file names
await tester.openFirstRowDetailPage();
await tester.pumpAndSettle();
// Expect file names to not be shown (hidden)
expect(find.text('sample.jpeg'), findsNothing);
expect(find.text('sample.gif'), findsNothing);
await tester.tapGridFieldWithNameInRowDetailPage('Type');
await tester.pumpAndSettle();
// Toggle show file names
await tester.tap(find.byType(Toggle));
await tester.pumpAndSettle();
// Expect file names to be shown
expect(find.text('sample.jpeg'), findsOneWidget);
expect(find.text('sample.gif'), findsOneWidget);
await tester.tapGridFieldWithNameInRowDetailPage('Type');
await tester.pumpAndSettle();
// Toggle hide file names
await tester.tap(find.byType(Toggle));
await tester.pumpAndSettle();
await tester.dismissRowDetailPage();
await tester.pumpAndSettle();
// Expect file names to be hidden
expect(find.text('sample.jpeg'), findsNothing);
expect(find.text('sample.gif'), findsNothing);
// Remove the temp files
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
@@ -62,7 +62,9 @@ void main() {
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
// Expect one file
expect(find.byType(RenderMedia), findsOneWidget);
@@ -1,20 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'database_cell_test.dart' as database_cell_test;
import 'database_field_settings_test.dart' as database_field_settings_test;
import 'database_field_test.dart' as database_field_test;
import 'database_row_page_test.dart' as database_row_page_test;
import 'database_setting_test.dart' as database_setting_test;
import 'database_share_test.dart' as database_share_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
database_cell_test.main();
database_field_test.main();
database_field_settings_test.main();
database_share_test.main();
database_row_page_test.main();
database_setting_test.main();
// DON'T add more tests here.
}
@@ -1,22 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'database_calendar_test.dart' as database_calendar_test;
import 'database_filter_test.dart' as database_filter_test;
import 'database_media_test.dart' as database_media_test;
import 'database_row_cover_test.dart' as database_row_cover_test;
import 'database_share_test.dart' as database_share_test;
import 'database_sort_test.dart' as database_sort_test;
import 'database_view_test.dart' as database_view_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
database_filter_test.main();
database_sort_test.main();
database_view_test.main();
database_calendar_test.main();
database_media_test.main();
database_row_cover_test.main();
database_share_test.main();
// DON'T add more tests here.
}
@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
@@ -50,6 +51,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
// Delete from editor
await tester.editor.updateSelection(
@@ -123,6 +125,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
// Cut from editor
await tester.editor.updateSelection(
@@ -148,6 +151,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
// Cut again
await tester.editor.updateSelection(
@@ -191,6 +195,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
});
testWidgets(
'Cut+paste in same docuemnt and then paste again in same document',
@@ -209,6 +214,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
// Cut from editor
await tester.editor.updateSelection(
@@ -234,6 +240,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
// Paste again
await tester.simulateKeyEvent(
@@ -245,6 +252,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsNWidgets(2));
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsNWidgets(2));
expect(find.text('$_createdPageName (copy)'), findsNWidgets(2));
});
@@ -263,6 +271,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
final headingText = LocaleKeys.document_slashMenu_name_heading1.tr();
final paragraphText = LocaleKeys.document_slashMenu_name_text.tr();
@@ -274,6 +283,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
// Turn into paragraph
await tester.editor.openTurnIntoMenu([0]);
@@ -282,6 +292,7 @@ void main() {
expect(find.text(_createdPageName), findsNWidgets(2));
expect(find.byType(MentionSubPageBlock), findsOneWidget);
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsOneWidget);
});
testWidgets('Duplicate a block containing two sub page mentions',
@@ -320,6 +331,7 @@ void main() {
expect(find.text(_createdPageName), findsOneWidget);
expect(find.text("$_createdPageName (copy)"), findsOneWidget);
expect(find.byType(MentionSubPageBlock), findsNWidgets(2));
expect(find.byFlowySvg(FlowySvgs.child_page_s), findsNWidgets(2));
// Duplicate node from block action menu
await tester.editor.hoverAndClickOptionMenuButton([0]);
@@ -1,6 +1,5 @@
import 'dart:io';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -74,7 +73,10 @@ void main() {
);
await tester.pumpAndSettle();
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor.hoverAndClickOptionMenuButton([0]);
@@ -97,7 +99,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor.hoverAndClickOptionAddButton([0], false);
@@ -150,7 +155,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor.hoverAndClickOptionAddButton([0], false);
@@ -208,7 +216,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor
@@ -249,7 +260,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor
@@ -299,7 +313,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor.hoverAndClickOptionMenuButton([0]);
@@ -309,11 +326,6 @@ void main() {
expect(find.text('Child page'), findsNothing);
expect(find.byType(SubPageBlockComponent), findsNothing);
// Since there is no selection active in editor before deleting Node,
// we need to give focus back to the editor
await tester.editor
.updateSelection(Selection.collapsed(Position(path: [0])));
await tester.simulateKeyEvent(
LogicalKeyboardKey.keyZ,
isControlPressed: Platform.isLinux || Platform.isWindows,
@@ -342,7 +354,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
// Delete
@@ -390,16 +405,15 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
expect(find.byType(SubPageBlockComponent), findsOneWidget);
await tester.hoverOnPageName(
'Child page',
onHover: () async {
await tester.tapDeletePageButton();
},
);
await tester.hoverOnPageName('Child page');
await tester.tapDeletePageButton();
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Child page'), findsNothing);
@@ -418,7 +432,10 @@ void main() {
layout: ViewLayoutPB.Document,
);
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
await tester.hoverOnPageName(_defaultPageName);
await tester.renamePage('Child page');
await tester.pumpAndSettle();
expect(find.text('Child page'), findsNWidgets(2));
await tester.editor.hoverAndClickOptionMenuButton([0]);
@@ -456,49 +473,6 @@ void main() {
expect(afterNode.type, beforeNode.type);
expect(find.byType(SubPageBlockComponent), findsOneWidget);
});
testWidgets('turn into page', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(name: 'SubPageBlock');
final editorState = tester.editor.getCurrentEditorState();
// Insert nested list
final transaction = editorState.transaction;
transaction.insertNode(
[0],
bulletedListNode(
text: 'Parent',
children: [
bulletedListNode(text: 'Child 1'),
bulletedListNode(text: 'Child 2'),
],
),
);
await editorState.apply(transaction);
await tester.pumpAndSettle();
expect(find.byType(SubPageBlockComponent), findsNothing);
await tester.editor.hoverAndClickOptionMenuButton([0]);
await tester.tapButtonWithName(
LocaleKeys.document_plugins_optionAction_turnInto.tr(),
);
await tester.pumpAndSettle();
await tester.tap(find.text(LocaleKeys.editor_page.tr()));
await tester.pumpAndSettle();
expect(find.byType(SubPageBlockComponent), findsOneWidget);
await tester.expandOrCollapsePage(
pageName: 'SubPageBlock',
layout: ViewLayoutPB.Document,
);
expect(find.text('Parent'), findsNWidgets(2));
});
});
}
@@ -524,16 +498,4 @@ extension _SubPageTestHelper on WidgetTester {
await pumpUntilFound(find.byType(SubPageBlockComponent));
}
Future<void> renamePageWithSecondary(
String currentName,
String newName,
) async {
await hoverOnPageName(currentName, onHover: () async => pumpAndSettle());
await rightClickOnPageName(currentName);
await tapButtonWithName(ViewMoreActionType.rename.name);
await enterText(find.byType(TextFormField), newName);
await tapOKButton();
await pumpAndSettle();
}
}
@@ -1,12 +1,26 @@
import 'package:integration_test/integration_test.dart';
import 'document_alignment_test.dart' as document_alignment_test;
import 'document_codeblock_paste_test.dart' as document_codeblock_paste_test;
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_inline_page_reference_test.dart'
as document_inline_page_reference_test;
import 'document_more_actions_test.dart' as document_more_actions_test;
import 'document_shortcuts_test.dart' as document_shortcuts_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;
import 'document_with_file_test.dart' as document_with_file_test;
import 'document_with_image_block_test.dart' as document_with_image_block_test;
import 'document_with_inline_math_equation_test.dart'
as document_with_inline_math_equation_test;
import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
import 'document_with_multi_image_block_test.dart'
as document_with_multi_image_block_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;
void main() {
@@ -19,5 +33,17 @@ void main() {
document_with_inline_page_test.main();
document_with_inline_math_equation_test.main();
document_with_cover_image_test.main();
// Don't add new tests here.
document_with_outline_block.main();
document_with_toggle_list_test.main();
document_copy_and_paste_test.main();
document_codeblock_paste_test.main();
document_alignment_test.main();
document_text_direction_test.main();
document_with_image_block_test.main();
document_with_multi_image_block_test.main();
document_inline_page_reference_test.main();
document_more_actions_test.main();
document_with_file_test.main();
document_shortcuts_test.main();
// Don't add new tests here. Add them to document_test_runner_2.dart
}
@@ -9,18 +9,18 @@ import 'document_with_date_reminder_test.dart'
as document_with_date_reminder_test;
import 'document_with_toggle_heading_block_test.dart'
as document_with_toggle_heading_block_test;
import 'document_sub_page_test.dart' as document_sub_page_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Document integration tests
document_title_test.main();
// Disable subPage test temporarily, enable it in version 0.7.2
// document_sub_page_test.main();
document_app_lifecycle_test.main();
document_with_date_reminder_test.main();
document_deletion_test.main();
document_option_action_test.main();
document_inline_sub_page_test.main();
document_with_toggle_heading_block_test.main();
document_sub_page_test.main();
}
@@ -1,22 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'document_alignment_test.dart' as document_alignment_test;
import 'document_codeblock_paste_test.dart' as document_codeblock_paste_test;
import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
import 'document_text_direction_test.dart' as document_text_direction_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;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Document integration tests
document_with_outline_block.main();
document_with_toggle_list_test.main();
document_copy_and_paste_test.main();
document_codeblock_paste_test.main();
document_alignment_test.main();
document_text_direction_test.main();
// Don't add new tests here.
}
@@ -1,25 +0,0 @@
import 'package:integration_test/integration_test.dart';
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_shortcuts_test.dart' as document_shortcuts_test;
import 'document_with_file_test.dart' as document_with_file_test;
import 'document_with_image_block_test.dart' as document_with_image_block_test;
import 'document_with_multi_image_block_test.dart'
as document_with_multi_image_block_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Document integration tests
document_with_image_block_test.main();
document_with_multi_image_block_test.main();
document_inline_page_reference_test.main();
document_more_actions_test.main();
document_with_file_test.main();
document_shortcuts_test.main();
// Disable subPage test temporarily, enable it in version 0.7.2
// document_sub_page_test.main();
}
@@ -2,7 +2,6 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_date_block.dart';
import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/desktop_date_picker.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -33,6 +32,7 @@ void main() {
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_dateOrReminder.tr(),
offset: 100,
);
final dateTimeSettings = DateTimeSettingsPB(
@@ -56,13 +56,11 @@ void main() {
await tester.pumpAndSettle();
// add time 11:12
final textField = find
.descendant(
of: find.byType(DesktopAppFlowyDatePicker),
matching: find.byType(TextField),
)
.last;
await tester.pumpUntilFound(textField);
final currentTime = DateFormat('HH:mm').format(DateTime.now());
final textField = find.byWidgetPredicate(
(widget) =>
widget is TextField && widget.controller!.text == currentTime,
);
await tester.enterText(textField, "11:12");
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
@@ -86,6 +84,7 @@ void main() {
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_dateOrReminder.tr(),
offset: 100,
);
final dateTimeSettings = DateTimeSettingsPB(
@@ -47,7 +47,9 @@ void main() {
mockPickFilePaths(paths: [filePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
await tester.tapFileUploadHint();
await tester.tap(
find.text(LocaleKeys.document_plugins_file_fileUploadHint.tr()),
);
await tester.pumpAndSettle();
expect(find.byType(FileUploadMenu), findsNothing);
@@ -6,6 +6,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/image_render.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/layouts/image_browser_layout.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/multi_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/multi_image_placeholder.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/upload_image_menu/upload_image_menu.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/upload_image_menu/widgets/embed_image_url_widget.dart';
@@ -169,6 +169,7 @@ Future<void> insertOutlineInDocument(WidgetTester tester) async {
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_outline.tr(),
offset: 100,
);
await tester.pumpAndSettle();
}
@@ -1,8 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.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';
@@ -62,50 +60,6 @@ void main() {
findsNWidgets(6),
);
});
testWidgets('insert toggle heading and convert it to heading',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(
name: 'toggle heading block test',
);
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText('# > $_heading1\n');
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.ime.insertText('item 1');
await tester.pumpAndSettle();
await tester.editor.updateSelection(
Selection(
start: Position(path: [0]),
end: Position(path: [0], offset: _heading1.length),
),
);
await tester.tapButton(find.byType(HeadingPopup));
await tester.pumpAndSettle();
expect(
find.byType(HeadingButton),
findsNWidgets(3),
);
// tap the H1 button
await tester.tapButton(find.byType(HeadingButton).at(0));
await tester.pumpAndSettle();
final editorState = tester.editor.getCurrentEditorState();
final node1 = editorState.document.nodeAtPath([0])!;
expect(node1.type, HeadingBlockKeys.type);
expect(node1.attributes[HeadingBlockKeys.level], 1);
final node2 = editorState.document.nodeAtPath([1])!;
expect(node2.type, ParagraphBlockKeys.type);
expect(node2.delta!.toPlainText(), 'item 1');
});
});
}
@@ -122,7 +76,7 @@ Future<void> _insertToggleHeadingBlockInDocument(
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
name,
offset: 150,
offset: 100,
);
await tester.pumpAndSettle();
}
@@ -1,19 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'grid_edit_row_test.dart' as grid_edit_row_test_runner;
import 'grid_filter_and_sort_test.dart' as grid_filter_and_sort_test_runner;
import 'grid_reopen_test.dart' as grid_reopen_test_runner;
import 'grid_reorder_row_test.dart' as grid_reorder_row_test_runner;
import 'grid_row_test.dart' as grid_row_test_runner;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
grid_reopen_test_runner.main();
grid_row_test_runner.main();
grid_reorder_row_test_runner.main();
grid_filter_and_sort_test_runner.main();
grid_edit_row_test_runner.main();
// grid_calculations_test_runner.main();
// DON'T add more tests here.
}
@@ -19,13 +19,8 @@ void main() {
await tester.tapAnonymousSignInButton();
// Right click on the view item and change icon
await tester.hoverOnWidget(
find.byType(ViewItem),
onHover: () async {
await tester.tap(find.byType(ViewItem), buttons: kSecondaryButton);
await tester.pumpAndSettle();
},
);
await tester.tap(find.byType(ViewItem), buttons: kSecondaryButton);
await tester.pumpAndSettle();
// Change icon
final changeIconButton =
@@ -11,7 +11,7 @@ void main() {
testWidgets('empty test', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.wait(500);
await tester.wait(1000);
});
});
}
@@ -1,23 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'emoji_shortcut_test.dart' as emoji_shortcut_test;
import 'hotkeys_test.dart' as hotkeys_test;
import 'import_files_test.dart' as import_files_test;
import 'share_markdown_test.dart' as share_markdown_test;
import 'tabs_test.dart' as tabs_test;
import 'zoom_in_out_test.dart' as zoom_in_out_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
hotkeys_test.main();
emoji_shortcut_test.main();
hotkeys_test.main();
emoji_shortcut_test.main();
share_markdown_test.main();
import_files_test.main();
tabs_test.main();
zoom_in_out_test.main();
// DON'T add more tests here.
}
@@ -1,6 +1,7 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/document/document_test_runner_1.dart' as document_test_runner_1;
import 'desktop/document/document_test_runner_1.dart' as document_test_runner;
import 'desktop/uncategorized/empty_test.dart' as first_test;
import 'desktop/uncategorized/switch_folder_test.dart' as switch_folder_test;
Future<void> main() async {
@@ -10,7 +11,11 @@ Future<void> main() async {
Future<void> runIntegration1OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
first_test.main();
switch_folder_test.main();
document_test_runner_1.main();
document_test_runner.main();
// DON'T add more tests here.
}
@@ -1,7 +1,18 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/database/database_test_runner_1.dart' as database_test_runner_1;
import 'desktop/first_test/first_test.dart' as first_test;
import 'desktop/database/database_calendar_test.dart' as database_calendar_test;
import 'desktop/database/database_cell_test.dart' as database_cell_test;
import 'desktop/database/database_field_settings_test.dart'
as database_field_settings_test;
import 'desktop/database/database_field_test.dart' as database_field_test;
import 'desktop/database/database_filter_test.dart' as database_filter_test;
import 'desktop/database/database_media_test.dart' as database_media_test;
import 'desktop/database/database_row_page_test.dart' as database_row_page_test;
import 'desktop/database/database_setting_test.dart' as database_setting_test;
import 'desktop/database/database_share_test.dart' as database_share_test;
import 'desktop/database/database_sort_test.dart' as database_sort_test;
import 'desktop/database/database_view_test.dart' as database_view_test;
import 'desktop/uncategorized/empty_test.dart' as first_test;
Future<void> main() async {
await runIntegration2OnDesktop();
@@ -10,8 +21,20 @@ Future<void> main() async {
Future<void> runIntegration2OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
first_test.main();
database_test_runner_1.main();
database_cell_test.main();
database_field_test.main();
database_field_settings_test.main();
database_share_test.main();
database_row_page_test.main();
database_setting_test.main();
database_filter_test.main();
database_sort_test.main();
database_view_test.main();
database_calendar_test.main();
database_media_test.main();
// DON'T add more tests here. This is the second test runner for desktop.
}
@@ -1,8 +1,24 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/board/board_test_runner.dart' as board_test_runner;
import 'desktop/first_test/first_test.dart' as first_test;
import 'desktop/grid/grid_test_runner_1.dart' as grid_test_runner_1;
import 'desktop/database/database_row_cover_test.dart'
as database_row_cover_test;
import 'desktop/grid/grid_edit_row_test.dart' as grid_edit_row_test_runner;
import 'desktop/grid/grid_filter_and_sort_test.dart'
as grid_filter_and_sort_test_runner;
import 'desktop/grid/grid_reopen_test.dart' as grid_reopen_test_runner;
import 'desktop/grid/grid_reorder_row_test.dart'
as grid_reorder_row_test_runner;
import 'desktop/grid/grid_row_test.dart' as grid_create_row_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/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;
import 'desktop/uncategorized/import_files_test.dart' as import_files_test;
import 'desktop/uncategorized/share_markdown_test.dart' as share_markdown_test;
import 'desktop/uncategorized/tabs_test.dart' as tabs_test;
import 'desktop/uncategorized/zoom_in_out_test.dart' as zoom_in_out_test;
Future<void> main() async {
await runIntegration3OnDesktop();
@@ -11,9 +27,26 @@ Future<void> main() async {
Future<void> runIntegration3OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
first_test.main();
hotkeys_test.main();
emoji_shortcut_test.main();
hotkeys_test.main();
emoji_shortcut_test.main();
settings_test_runner.main();
share_markdown_test.main();
import_files_test.main();
sidebar_test_runner.main();
board_test_runner.main();
grid_test_runner_1.main();
// DON'T add more tests here.
tabs_test.main();
database_row_cover_test.main();
grid_reopen_test_runner.main();
grid_create_row_test_runner.main();
grid_reorder_row_test_runner.main();
grid_filter_and_sort_test_runner.main();
grid_edit_row_test_runner.main();
zoom_in_out_test.main();
// DON'T add more tests here. Add them to desktop_runner_4.dart
}
@@ -1,7 +1,7 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/document/document_test_runner_2.dart' as document_test_runner_2;
import 'desktop/first_test/first_test.dart' as first_test;
import 'desktop/uncategorized/empty_test.dart' as first_test;
Future<void> main() async {
await runIntegration4OnDesktop();
@@ -10,8 +10,8 @@ Future<void> main() async {
Future<void> runIntegration4OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
first_test.main();
document_test_runner_2.main();
// DON'T add more tests here.
}
@@ -1,17 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/database/database_test_runner_2.dart' as database_test_runner_2;
import 'desktop/first_test/first_test.dart' as first_test;
Future<void> main() async {
await runIntegration5OnDesktop();
}
Future<void> runIntegration5OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
first_test.main();
database_test_runner_2.main();
// DON'T add more tests here.
}
@@ -1,22 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/first_test/first_test.dart' as first_test;
import 'desktop/settings/settings_runner.dart' as settings_test_runner;
import 'desktop/sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
import 'desktop/uncategorized/uncategorized_test_runner_1.dart'
as uncategorized_test_runner_1;
Future<void> main() async {
await runIntegration6OnDesktop();
}
Future<void> runIntegration6OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
first_test.main();
settings_test_runner.main();
sidebar_test_runner.main();
uncategorized_test_runner_1.main();
// DON'T add more tests here.
}
@@ -1,17 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/document/document_test_runner_3.dart' as document_test_runner_3;
import 'desktop/first_test/first_test.dart' as first_test;
Future<void> main() async {
await runIntegration7OnDesktop();
}
Future<void> runIntegration7OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
first_test.main();
document_test_runner_3.main();
// DON'T add more tests here.
}
@@ -1,17 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'desktop/document/document_test_runner_4.dart' as document_test_runner_4;
import 'desktop/first_test/first_test.dart' as first_test;
Future<void> main() async {
await runIntegration8OnDesktop();
}
Future<void> runIntegration8OnDesktop() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
first_test.main();
document_test_runner_4.main();
// DON'T add more tests here.
}
@@ -4,10 +4,6 @@ import 'desktop_runner_1.dart';
import 'desktop_runner_2.dart';
import 'desktop_runner_3.dart';
import 'desktop_runner_4.dart';
import 'desktop_runner_5.dart';
import 'desktop_runner_6.dart';
import 'desktop_runner_7.dart';
import 'desktop_runner_8.dart';
import 'mobile_runner.dart';
/// The main task runner for all integration tests in AppFlowy.
@@ -23,10 +19,6 @@ Future<void> main() async {
await runIntegration2OnDesktop();
await runIntegration3OnDesktop();
await runIntegration4OnDesktop();
await runIntegration5OnDesktop();
await runIntegration6OnDesktop();
await runIntegration7OnDesktop();
await runIntegration8OnDesktop();
} else if (Platform.isIOS || Platform.isAndroid) {
await runIntegrationOnMobile();
} else {
@@ -192,13 +192,8 @@ extension CommonOperations on WidgetTester {
ViewLayoutPB layout = ViewLayoutPB.Document,
}) async {
final page = findPageName(name, layout: layout);
await hoverOnPageName(
name,
onHover: () async {
await tap(page, buttons: kSecondaryMouseButton);
await pumpAndSettle();
},
);
await tap(page, buttons: kSecondaryMouseButton);
await pumpAndSettle();
}
/// open the page with given name.
@@ -316,15 +311,6 @@ extension CommonOperations on WidgetTester {
await tapButton(shareButton);
}
// open the share menu and then click the publish tab
Future<void> openPublishMenu() async {
await tapShareButton();
final publishButton = find.textContaining(
LocaleKeys.shareAction_publishTab.tr(),
);
await tapButton(publishButton);
}
/// Tap the export markdown button
///
/// Must call [tapShareButton] first.
@@ -775,18 +761,6 @@ extension CommonOperations on WidgetTester {
await tap(button);
await pump();
}
Future<void> tapFileUploadHint() async {
final finder = find.byWidgetPredicate(
(w) =>
w is RichText &&
w.text.toPlainText().contains(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
),
);
await tap(finder);
await pumpAndSettle(const Duration(seconds: 2));
}
}
extension SettingsFinder on CommonFinders {
@@ -596,10 +596,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
final banner = find.byType(RowBanner);
expect(banner, findsOneWidget);
await startGesture(
getCenter(banner) + const Offset(0, -10),
kind: PointerDeviceKind.mouse,
);
await startGesture(getCenter(banner), kind: PointerDeviceKind.mouse);
await pumpAndSettle();
}
@@ -611,6 +608,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButtonWithName(
LocaleKeys.document_plugins_cover_addCover.tr(),
);
await pumpAndSettle();
}
Future<void> openEmojiPicker() async =>
@@ -4,13 +4,11 @@ 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/settings/pages/account/account_user_profile.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_workspace_view.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.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/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'base.dart';
@@ -118,20 +116,4 @@ extension AppFlowySettings on WidgetTester {
await tapAt(Offset.zero);
await pumpAndSettle();
}
Future<void> updateNamespace(String namespace) async {
final dialog = find.byType(DomainSettingsDialog);
expect(dialog, findsOneWidget);
// input the new namespace
await enterText(
find.descendant(
of: dialog,
matching: find.byType(TextField),
),
namespace,
);
await tapButton(find.text(LocaleKeys.button_save.tr()));
await pumpAndSettle();
}
}
@@ -20,7 +20,6 @@ extension MobileRouter on BuildContext {
bool addInRecent = true,
bool showMoreButton = true,
String? fixedTitle,
String? blockId,
}) async {
// set the current view before pushing the new view
getIt<MenuSharedState>().latestOpenView = view;
@@ -33,9 +32,6 @@ extension MobileRouter on BuildContext {
if (fixedTitle != null) {
queryParameters[MobileDocumentScreen.viewFixedTitle] = fixedTitle;
}
if (blockId != null) {
queryParameters[MobileDocumentScreen.viewBlockId] = blockId;
}
}
final uri = Uri(
@@ -61,7 +61,6 @@ class NotificationReminderBloc
reminderContent: node.delta?.toPlainText() ?? '',
nodes: [node],
status: NotificationReminderStatus.loaded,
blockId: reminder.meta[ReminderMetaKeys.blockId],
),
);
}
@@ -206,7 +205,6 @@ class NotificationReminderState with _$NotificationReminderState {
@Default(NotificationReminderStatus.initial)
NotificationReminderStatus status,
@Default([]) List<Node> nodes,
String? blockId,
ViewPB? view,
}) = _NotificationReminderState;
@@ -30,7 +30,6 @@ class MobileViewPage extends StatefulWidget {
this.arguments,
this.fixedTitle,
this.showMoreButton = true,
this.blockId,
});
/// view id
@@ -39,7 +38,6 @@ class MobileViewPage extends StatefulWidget {
final String? title;
final Map<String, dynamic>? arguments;
final bool showMoreButton;
final String? blockId;
// only used in row page
final String? fixedTitle;
@@ -65,7 +63,6 @@ class _MobileViewPageState extends State<MobileViewPage> {
@override
void dispose() {
_appBarOpacity.dispose();
_scrollNotificationObserver?.removeListener(_onScrollNotification);
_scrollNotificationObserver = null;
super.dispose();
@@ -180,7 +177,6 @@ class _MobileViewPageState extends State<MobileViewPage> {
context: PluginContext(userProfile: state.userProfilePB),
data: {
MobileDocumentScreen.viewFixedTitle: widget.fixedTitle,
MobileDocumentScreen.viewBlockId: widget.blockId,
},
);
},
@@ -1,96 +0,0 @@
import 'package:appflowy/plugins/database/application/cell/bloc/media_cell_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/file/file_util.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/file/mobile_file_upload_menu.dart';
import 'package:appflowy/util/xfile_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/file_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/media_entities.pbenum.dart';
import 'package:cross_file/cross_file.dart';
import 'package:flutter/widgets.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
class MobileMediaUploadSheetContent extends StatelessWidget {
const MobileMediaUploadSheetContent({super.key, required this.dialogContext});
final BuildContext dialogContext;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(top: 12),
constraints: const BoxConstraints(
maxHeight: 340,
minHeight: 80,
),
child: MobileFileUploadMenu(
onInsertLocalFile: (files) async {
dialogContext.pop();
await insertLocalFiles(
context,
files,
userProfile: context.read<MediaCellBloc>().state.userProfile,
documentId: context.read<MediaCellBloc>().rowId,
onUploadSuccess: (file, path, isLocalMode) {
final mediaCellBloc = context.read<MediaCellBloc>();
if (mediaCellBloc.isClosed) {
return;
}
mediaCellBloc.add(
MediaCellEvent.addFile(
url: path,
name: file.name,
uploadType: isLocalMode
? FileUploadTypePB.LocalFile
: FileUploadTypePB.CloudFile,
fileType: file.fileType.toMediaFileTypePB(),
),
);
},
);
},
onInsertNetworkFile: (url) async => _onInsertNetworkFile(
url,
dialogContext,
context,
),
),
);
}
Future<void> _onInsertNetworkFile(
String url,
BuildContext dialogContext,
BuildContext context,
) async {
dialogContext.pop();
if (url.isEmpty) return;
final uri = Uri.tryParse(url);
if (uri == null) {
return;
}
final fakeFile = XFile(uri.path);
MediaFileTypePB fileType = fakeFile.fileType.toMediaFileTypePB();
fileType =
fileType == MediaFileTypePB.Other ? MediaFileTypePB.Link : fileType;
String name = uri.pathSegments.isNotEmpty ? uri.pathSegments.last : "";
if (name.isEmpty && uri.pathSegments.length > 1) {
name = uri.pathSegments[uri.pathSegments.length - 2];
} else if (name.isEmpty) {
name = uri.host;
}
context.read<MediaCellBloc>().add(
MediaCellEvent.addFile(
url: url,
name: name,
uploadType: FileUploadTypePB.NetworkFile,
fileType: fileType,
),
);
}
}
@@ -143,7 +143,6 @@ Future<T?> showMobileBottomSheet<T>(
) ??
Expanded(
child: Scrollbar(
controller: scrollController,
child: SingleChildScrollView(
controller: scrollController,
child: child,
@@ -11,7 +11,6 @@ class OptionTextField extends StatelessWidget {
const OptionTextField({
super.key,
required this.controller,
this.autoFocus = false,
required this.isPrimary,
required this.fieldType,
required this.onTextChanged,
@@ -19,7 +18,6 @@ class OptionTextField extends StatelessWidget {
});
final TextEditingController controller;
final bool autoFocus;
final bool isPrimary;
final FieldType fieldType;
final void Function(String value) onTextChanged;
@@ -29,7 +27,6 @@ class OptionTextField extends StatelessWidget {
Widget build(BuildContext context) {
return FlowyOptionTile.textField(
controller: controller,
autofocus: autoFocus,
textFieldPadding: const EdgeInsets.symmetric(horizontal: 12.0),
onTextChanged: onTextChanged,
leftIcon: GestureDetector(
@@ -5,7 +5,7 @@ import 'package:appflowy/plugins/database/application/cell/bloc/date_cell_editor
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/mobile_date_picker.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/mobile_appflowy_date_picker.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/mobile_date_header.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -93,19 +93,11 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
onRangeSelected: (start, end) {
dateCellBloc.add(DateCellEditorEvent.updateDateRange(start, end));
},
onIsRangeChanged: (value, dateTime, endDateTime) {
dateCellBloc.add(
DateCellEditorEvent.setIsRange(value, dateTime, endDateTime),
);
onIsRangeChanged: (value) {
dateCellBloc.add(DateCellEditorEvent.setIsRange(value));
},
onIncludeTimeChanged: (value, dateTime, endDateTime) {
dateCellBloc.add(
DateCellEditorEvent.setIncludeTime(
value,
dateTime,
endDateTime,
),
);
onIncludeTimeChanged: (value) {
dateCellBloc.add(DateCellEditorEvent.setIncludeTime(value));
},
onClearDate: () {
dateCellBloc.add(const DateCellEditorEvent.clearDate());
@@ -21,15 +21,15 @@ import 'mobile_quick_field_editor.dart';
const mobileSupportedFieldTypes = [
FieldType.RichText,
FieldType.Number,
FieldType.URL,
FieldType.SingleSelect,
FieldType.MultiSelect,
FieldType.DateTime,
FieldType.Media,
FieldType.URL,
FieldType.Checkbox,
FieldType.Checklist,
FieldType.LastEditedTime,
FieldType.CreatedTime,
FieldType.Checkbox,
FieldType.Checklist,
FieldType.Media,
// FieldType.Time,
];
@@ -224,7 +224,6 @@ class _MobileFieldEditorState extends State<MobileFieldEditor> {
const _Divider(),
OptionTextField(
controller: controller,
autoFocus: widget.mode == FieldOptionMode.add,
fieldType: values.type,
isPrimary: widget.isPrimary,
onTextChanged: (value) {
@@ -9,7 +9,6 @@ class MobileDocumentScreen extends StatelessWidget {
this.title,
this.showMoreButton = true,
this.fixedTitle,
this.blockId,
});
/// view id
@@ -17,14 +16,12 @@ class MobileDocumentScreen extends StatelessWidget {
final String? title;
final bool showMoreButton;
final String? fixedTitle;
final String? blockId;
static const routeName = '/docs';
static const viewId = 'id';
static const viewTitle = 'title';
static const viewShowMoreButton = 'show_more_button';
static const viewFixedTitle = 'fixed_title';
static const viewBlockId = 'block_id';
@override
Widget build(BuildContext context) {
@@ -34,7 +31,6 @@ class MobileDocumentScreen extends StatelessWidget {
viewLayout: ViewLayoutPB.Document,
showMoreButton: showMoreButton,
fixedTitle: fixedTitle,
blockId: blockId,
);
}
}
@@ -138,9 +138,11 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
if (tabController == null) {
return;
}
context
.read<SpaceOrderBloc>()
.add(SpaceOrderEvent.open(tabController!.index));
context.read<SpaceOrderBloc>().add(
SpaceOrderEvent.open(
tabController!.index,
),
);
}
List<Widget> _buildTabs(SpaceOrderState state) {
@@ -172,9 +174,13 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
}
// quick create new page when clicking the add button in navigation bar
void _createNewDocument() => _createNewPage(ViewLayoutPB.Document);
void _createNewDocument() {
_createNewPage(ViewLayoutPB.Document);
}
void _createNewAIChat() => _createNewPage(ViewLayoutPB.Chat);
void _createNewAIChat() {
_createNewPage(ViewLayoutPB.Chat);
}
void _createNewPage(ViewLayoutPB layout) {
if (context.read<SpaceBloc>().state.spaces.isNotEmpty) {
@@ -200,7 +206,8 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
final workspaceId =
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId;
if (workspaceId == null) {
return Log.error('Workspace ID is null');
Log.error('Workspace ID is null');
return;
}
context
.read<UserWorkspaceBloc>()
@@ -28,8 +28,8 @@ class MobileNotificationsScreen extends StatefulWidget {
class _MobileNotificationsScreenState extends State<MobileNotificationsScreen>
with SingleTickerProviderStateMixin {
final ReminderBloc reminderBloc = getIt<ReminderBloc>();
late final TabController controller = TabController(length: 2, vsync: this);
final ReminderBloc _reminderBloc = getIt<ReminderBloc>();
late final TabController _controller = TabController(length: 2, vsync: this);
@override
Widget build(BuildContext context) {
@@ -39,7 +39,7 @@ class _MobileNotificationsScreenState extends State<MobileNotificationsScreen>
create: (context) =>
UserProfileBloc()..add(const UserProfileEvent.started()),
),
BlocProvider<ReminderBloc>.value(value: reminderBloc),
BlocProvider<ReminderBloc>.value(value: _reminderBloc),
BlocProvider<NotificationFilterBloc>(
create: (_) => NotificationFilterBloc(),
),
@@ -54,8 +54,8 @@ class _MobileNotificationsScreenState extends State<MobileNotificationsScreen>
_NotificationScreenContent(
workspaceSetting: workspaceSetting,
userProfile: userProfile,
controller: controller,
reminderBloc: reminderBloc,
controller: _controller,
reminderBloc: _reminderBloc,
),
);
},
@@ -124,6 +124,7 @@ class _NotificationScreenContent extends StatelessWidget {
reminderBloc: reminderBloc,
views: sectionState.section.publicViews,
onAction: _onAction,
onDelete: _onDelete,
onReadChanged: _onReadChanged,
actionBar: InboxActionBar(
hasUnreads: state.hasUnreads,
@@ -160,6 +161,9 @@ class _NotificationScreenContent extends StatelessWidget {
),
);
void _onDelete(ReminderPB reminder) =>
reminderBloc.add(ReminderEvent.remove(reminderId: reminder.id));
void _onReadChanged(ReminderPB reminder, bool isRead) => reminderBloc.add(
ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)),
);
@@ -61,11 +61,15 @@ class _MobileNotificationsScreenV2State
);
}
void _onRefresh() => getIt<ReminderBloc>().add(const ReminderEvent.refresh());
void _onRefresh() {
getIt<ReminderBloc>().add(const ReminderEvent.refresh());
}
}
class MobileNotificationsTab extends StatefulWidget {
const MobileNotificationsTab({super.key});
const MobileNotificationsTab({
super.key,
});
@override
State<MobileNotificationsTab> createState() => _MobileNotificationsTabState();
@@ -84,12 +88,17 @@ class _MobileNotificationsTabState extends State<MobileNotificationsTab>
@override
void initState() {
super.initState();
tabController = TabController(length: 3, vsync: this);
tabController = TabController(
length: 3,
vsync: this,
);
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@@ -21,12 +21,6 @@ class _MobileNotificationTabBarState extends State<MobileNotificationTabBar> {
widget.controller.addListener(_updateState);
}
@override
void dispose() {
widget.controller.removeListener(_updateState);
super.dispose();
}
void _updateState() => setState(() {});
@override
@@ -64,15 +64,11 @@ class NotificationItem extends StatelessWidget {
child: child,
onTapUp: () async {
final view = state.view;
final blockId = state.blockId;
if (view == null) {
return;
}
await context.pushView(
view,
blockId: blockId,
);
await context.pushView(view);
if (!reminder.isRead && context.mounted) {
context.read<ReminderBloc>().add(
@@ -98,7 +98,12 @@ class AIChatPagePluginWidgetBuilder extends PluginWidgetBuilder
required bool shrinkWrap,
Map<String, dynamic>? data,
}) {
notifier.isDeleted.addListener(_onDeleted);
notifier.isDeleted.addListener(() {
final deletedView = notifier.isDeleted.value;
if (deletedView != null && deletedView.hasIndex()) {
deletedViewIndex = deletedView.index;
}
});
if (context.userProfile == null) {
Log.error("User profile is null when opening AI Chat plugin");
@@ -117,13 +122,6 @@ class AIChatPagePluginWidgetBuilder extends PluginWidgetBuilder
);
}
void _onDeleted() {
final deletedView = notifier.isDeleted.value;
if (deletedView != null && deletedView.hasIndex()) {
deletedViewIndex = deletedView.index;
}
}
@override
List<NavigationItem> get navigationItems => [this];
@@ -86,7 +86,9 @@ class _ChatInputState extends State<ChatInput> {
},
);
_inputFocusNode.addListener(_updateState);
_inputFocusNode.addListener(() {
setState(() {});
});
_inputActionControl = ChatInputActionControl(
chatId: widget.chatId,
@@ -99,15 +101,12 @@ class _ChatInputState extends State<ChatInput> {
@override
void dispose() {
_inputFocusNode.removeListener(_updateState);
_inputFocusNode.dispose();
_textController.dispose();
_inputActionControl.dispose();
super.dispose();
}
void _updateState() => setState(() {});
@override
Widget build(BuildContext context) {
return Padding(
@@ -137,11 +137,11 @@ class DateCellEditorBloc
}
await _updateDateData(date: start, endDate: end);
},
setIncludeTime: (includeTime, dateTime, endDateTime) async {
await _updateIncludeTime(includeTime, dateTime, endDateTime);
setIncludeTime: (includeTime) async {
await _updateIncludeTime(includeTime);
},
setIsRange: (isRange, dateTime, endDateTime) async {
await _updateIsRange(isRange, dateTime, endDateTime);
setIsRange: (isRange) async {
await _updateIsRange(isRange);
},
setDateFormat: (DateFormatPB dateFormat) async {
await _updateTypeOption(emit, dateFormat: dateFormat);
@@ -209,11 +209,10 @@ class DateCellEditorBloc
result.onFailure(Log.error);
}
Future<void> _updateIsRange(
bool isRange,
DateTime? dateTime,
DateTime? endDateTime,
) async {
Future<void> _updateIsRange(bool isRange) async {
final dateTime = state.dateTime == null ? DateTime.now().withoutTime : null;
final endDateTime = dateTime;
final result = await _dateCellBackendService.update(
date: dateTime,
endDate: endDateTime,
@@ -222,11 +221,9 @@ class DateCellEditorBloc
result.onFailure(Log.error);
}
Future<void> _updateIncludeTime(
bool includeTime,
DateTime? dateTime,
DateTime? endDateTime,
) async {
Future<void> _updateIncludeTime(bool includeTime) async {
final dateTime = state.dateTime ?? DateTime.now().withoutTime;
final endDateTime = state.isRange ? state.endDateTime ?? dateTime : null;
final result = await _dateCellBackendService.update(
date: dateTime,
endDate: endDateTime,
@@ -323,17 +320,10 @@ class DateCellEditorEvent with _$DateCellEditorEvent {
DateTime end,
) = _UpdateDateRange;
const factory DateCellEditorEvent.setIncludeTime(
bool includeTime,
DateTime? dateTime,
DateTime? endDateTime,
) = _IncludeTime;
const factory DateCellEditorEvent.setIncludeTime(bool includeTime) =
_IncludeTime;
const factory DateCellEditorEvent.setIsRange(
bool isRange,
DateTime? dateTime,
DateTime? endDateTime,
) = _SetIsRange;
const factory DateCellEditorEvent.setIsRange(bool isRange) = _SetIsRange;
const factory DateCellEditorEvent.setReminderOption(ReminderOption option) =
_SetReminderOption;
@@ -3,14 +3,12 @@ import 'dart:async';
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/application/field/type_option/type_option_data_parser.dart';
import 'package:appflowy/plugins/database/application/row/row_service.dart';
import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/file_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/media_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -26,10 +24,7 @@ class MediaCellBloc extends Bloc<MediaCellEvent, MediaCellState> {
_startListening();
}
late final RowBackendService _rowService =
RowBackendService(viewId: cellController.viewId);
final MediaCellController cellController;
void Function()? _onCellChangedFn;
String get databaseId => cellController.viewId;
@@ -115,6 +110,10 @@ class MediaCellBloc extends Bloc<MediaCellEvent, MediaCellState> {
},
reorderFiles: (from, to) async {
final files = List<MediaFilePB>.from(state.files);
if (from < to) {
to--;
}
files.insert(to, files.removeAt(from));
// We emit the new state first to update the UI
@@ -154,10 +153,6 @@ class MediaCellBloc extends Bloc<MediaCellEvent, MediaCellState> {
toggleShowAllFiles: () {
emit(state.copyWith(showAllFiles: !state.showAllFiles));
},
setCover: (cover) => _rowService.updateMeta(
rowId: cellController.rowId,
cover: cover,
),
);
},
);
@@ -219,8 +214,6 @@ class MediaCellEvent with _$MediaCellEvent {
}) = _RenameFile;
const factory MediaCellEvent.toggleShowAllFiles() = _ToggleShowAllFiles;
const factory MediaCellEvent.setCover(RowCoverPB cover) = _SetCover;
}
@freezed
@@ -230,7 +223,7 @@ class MediaCellState with _$MediaCellState {
required String fieldName,
@Default([]) List<MediaFilePB> files,
@Default(false) showAllFiles,
@Default(true) hideFileNames,
@Default(false) hideFileNames,
}) = _MediaCellState;
factory MediaCellState.initial(MediaCellController cellController) {
@@ -132,24 +132,6 @@ class DatabaseController {
}
}
void removeListener({
DatabaseCallbacks? onDatabaseChanged,
DatabaseLayoutSettingCallbacks? onLayoutSettingsChanged,
GroupCallbacks? onGroupChanged,
}) {
if (onDatabaseChanged != null) {
_databaseCallbacks.remove(onDatabaseChanged);
}
if (onLayoutSettingsChanged != null) {
_layoutCallbacks.remove(onLayoutSettingsChanged);
}
if (onGroupChanged != null) {
_groupCallbacks.remove(onGroupChanged);
}
}
Future<FlowyResult<void, FlowyError>> open() async {
return _databaseViewBackendSvc.openDatabase().then((result) {
return result.fold(
@@ -40,7 +40,6 @@ class BoardActionsCubit extends Cubit<BoardActionsState> {
}
void startCreateBottomRow(String groupId) {
emit(const BoardActionsState.setFocus(groupedRowIds: []));
emit(BoardActionsState.startCreateBottomRow(groupId: groupId));
emit(const BoardActionsState.initial());
}
@@ -55,10 +55,6 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
FieldController get fieldController => databaseController.fieldController;
String get viewId => databaseController.viewId;
DatabaseCallbacks? _databaseCallbacks;
DatabaseLayoutSettingCallbacks? _layoutSettingsCallback;
GroupCallbacks? _groupCallbacks;
void _initBoardController(AppFlowyBoardController? controller) {
boardController = controller ??
AppFlowyBoardController(
@@ -334,17 +330,6 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
for (final controller in groupControllers.values) {
await controller.dispose();
}
databaseController.removeListener(
onDatabaseChanged: _databaseCallbacks,
onLayoutSettingsChanged: _layoutSettingsCallback,
onGroupChanged: _groupCallbacks,
);
_databaseCallbacks = null;
_layoutSettingsCallback = null;
_groupCallbacks = null;
boardController.dispose();
return super.close();
}
@@ -395,7 +380,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
RowCache get rowCache => databaseController.rowCache;
void _startListening() {
_layoutSettingsCallback = DatabaseLayoutSettingCallbacks(
final onLayoutSettingsChanged = DatabaseLayoutSettingCallbacks(
onLayoutSettingsChanged: (layoutSettings) {
if (isClosed) {
return;
@@ -418,7 +403,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
add(BoardEvent.didUpdateLayoutSettings(layoutSettings.board));
},
);
_groupCallbacks = GroupCallbacks(
final onGroupChanged = GroupCallbacks(
onGroupByField: (groups) {
if (isClosed) {
return;
@@ -497,7 +482,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
add(BoardEvent.didReceiveGroups(groupList));
},
);
_databaseCallbacks = DatabaseCallbacks(
final onDatabaseChanged = DatabaseCallbacks(
onRowsCreated: (rows) {
for (final row in rows) {
if (!isClosed && row.isHiddenInView) {
@@ -508,9 +493,9 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
);
databaseController.addListener(
onDatabaseChanged: _databaseCallbacks,
onLayoutSettingsChanged: _layoutSettingsCallback,
onGroupChanged: _groupCallbacks,
onDatabaseChanged: onDatabaseChanged,
onLayoutSettingsChanged: onLayoutSettingsChanged,
onGroupChanged: onGroupChanged,
);
}
@@ -534,9 +534,7 @@ class _BoardColumnFooterState extends State<BoardColumnFooter> {
color: Theme.of(context).hintColor,
),
onTap: () {
context
.read<BoardActionsCubit>()
.startCreateBottomRow(widget.columnData.id);
setState(() => _isCreating = true);
},
),
),
@@ -8,6 +8,7 @@ import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -51,7 +51,17 @@ class _EditableColumnHeaderState extends State<EditableColumnHeader> {
}
return KeyEventResult.ignored;
},
)..addListener(onFocusChanged);
)..addListener(() {
if (!focusNode.hasFocus) {
widget.isEditing.value = false;
widget.onSubmitted(textController.text);
} else {
textController.selection = TextSelection(
baseOffset: 0,
extentOffset: textController.text.length,
);
}
});
}
@override
@@ -64,25 +74,11 @@ class _EditableColumnHeaderState extends State<EditableColumnHeader> {
@override
void dispose() {
focusNode
..removeListener(onFocusChanged)
..dispose();
focusNode.dispose();
textController.dispose();
super.dispose();
}
void onFocusChanged() {
if (!focusNode.hasFocus) {
widget.isEditing.value = false;
widget.onSubmitted(textController.text);
} else {
textController.selection = TextSelection(
baseOffset: 0,
extentOffset: textController.text.length,
);
}
}
@override
Widget build(BuildContext context) {
return Row(
@@ -16,6 +16,7 @@ import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_skeleton/text_card_cell.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -37,20 +37,6 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
UserProfilePB? _userProfile;
UserProfilePB? get userProfile => _userProfile;
DatabaseCallbacks? _databaseCallbacks;
DatabaseLayoutSettingCallbacks? _layoutSettingCallbacks;
@override
Future<void> close() async {
databaseController.removeListener(
onDatabaseChanged: _databaseCallbacks,
onLayoutSettingsChanged: _layoutSettingCallbacks,
);
_databaseCallbacks = null;
_layoutSettingCallbacks = null;
await super.close();
}
void _dispatch() {
on<CalendarEvent>(
(event, emit) async {
@@ -314,7 +300,7 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
}
void _startListening() {
_databaseCallbacks = DatabaseCallbacks(
final onDatabaseChanged = DatabaseCallbacks(
onDatabaseChanged: (database) {
if (isClosed) return;
},
@@ -389,13 +375,13 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
},
);
_layoutSettingCallbacks = DatabaseLayoutSettingCallbacks(
final onLayoutSettingsChanged = DatabaseLayoutSettingCallbacks(
onLayoutSettingsChanged: _didReceiveLayoutSetting,
);
databaseController.addListener(
onDatabaseChanged: _databaseCallbacks,
onLayoutSettingsChanged: _layoutSettingCallbacks,
onDatabaseChanged: onDatabaseChanged,
onLayoutSettingsChanged: onLayoutSettingsChanged,
);
}
@@ -29,15 +29,6 @@ class UnscheduleEventsBloc
CellMemCache get cellCache => databaseController.rowCache.cellCache;
RowCache get rowCache => databaseController.rowCache;
DatabaseCallbacks? _databaseCallbacks;
@override
Future<void> close() async {
databaseController.removeListener(onDatabaseChanged: _databaseCallbacks);
_databaseCallbacks = null;
await super.close();
}
void _dispatch() {
on<UnscheduleEventsEvent>(
(event, emit) async {
@@ -112,7 +103,7 @@ class UnscheduleEventsBloc
}
void _startListening() {
_databaseCallbacks = DatabaseCallbacks(
final onDatabaseChanged = DatabaseCallbacks(
onRowsCreated: (rows) async {
if (isClosed) {
return;
@@ -144,7 +135,7 @@ class UnscheduleEventsBloc
},
);
databaseController.addListener(onDatabaseChanged: _databaseCallbacks);
databaseController.addListener(onDatabaseChanged: onDatabaseChanged);
}
}
@@ -242,7 +242,6 @@ class NewEventButton extends StatelessWidget {
hoverColor: AFThemeExtension.of(context).lightGreyHover,
width: 22,
tooltipText: LocaleKeys.calendar_newEventButtonTooltip.tr(),
radius: Corners.s6Border,
decoration: BoxDecoration(
border: Border.fromBorderSide(
BorderSide(
@@ -252,7 +251,7 @@ class NewEventButton extends StatelessWidget {
width: 0.5,
),
),
borderRadius: Corners.s6Border,
borderRadius: Corners.s5Border,
boxShadow: [
BoxShadow(
spreadRadius: -2,
@@ -9,6 +9,7 @@ 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/calendar_card_cell_style.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -13,6 +13,7 @@ import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/te
import 'package:appflowy/plugins/database/widgets/row/accessory/cell_accessory.dart';
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -15,6 +15,7 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:calendar_view/calendar_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
@@ -436,6 +437,7 @@ class _UnscheduledEventsButtonState extends State<UnscheduledEventsButton> {
),
side: BorderSide(color: Theme.of(context).dividerColor),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
visualDensity: VisualDensity.compact,
),
onPressed: () {
if (state.unscheduleEvents.isNotEmpty) {
@@ -8,6 +8,7 @@ import 'package:appflowy/plugins/database/calendar/application/calendar_setting_
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -80,8 +80,12 @@ class FilterEditorBloc extends Bloc<FilterEditorEvent, FilterEditorState> {
};
fieldController.addListener(
onFilters: _onFilterFn,
onReceiveFields: _onFieldFn,
onFilters: (filters) {
_onFilterFn?.call(filters);
},
onReceiveFields: (fields) {
_onFieldFn?.call(fields);
},
);
}
@@ -32,15 +32,6 @@ class GridBloc extends Bloc<GridEvent, GridState> {
UserProfilePB? _userProfile;
UserProfilePB? get userProfile => _userProfile;
DatabaseCallbacks? _databaseCallbacks;
@override
Future<void> close() async {
databaseController.removeListener(onDatabaseChanged: _databaseCallbacks);
_databaseCallbacks = null;
await super.close();
}
void _dispatch() {
on<GridEvent>(
(event, emit) async {
@@ -129,7 +120,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
RowCache get rowCache => databaseController.rowCache;
void _startListening() {
_databaseCallbacks = DatabaseCallbacks(
final onDatabaseChanged = DatabaseCallbacks(
onNumOfRowsChanged: (rowInfos, _, reason) {
if (!isClosed) {
add(GridEvent.didLoadRows(rowInfos, reason));
@@ -166,7 +157,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
}
},
);
databaseController.addListener(onDatabaseChanged: _databaseCallbacks);
databaseController.addListener(onDatabaseChanged: onDatabaseChanged);
}
Future<void> _openGrid(Emitter<GridState> emit) async {
@@ -20,12 +20,6 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
final String viewId;
final FieldController fieldController;
@override
Future<void> close() async {
fieldController.removeListener(onFieldsListener: _onReceiveFields);
await super.close();
}
void _dispatch() {
on<GridHeaderEvent>(
(event, emit) async {
@@ -88,13 +82,11 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
void _startListening() {
fieldController.addListener(
onReceiveFields: _onReceiveFields,
onReceiveFields: (fields) =>
add(GridHeaderEvent.didReceiveFieldUpdate(fields)),
listenWhen: () => !isClosed,
);
}
void _onReceiveFields(List<FieldInfo> fields) =>
add(GridHeaderEvent.didReceiveFieldUpdate(fields));
}
@freezed
@@ -24,15 +24,6 @@ class MobileRowDetailBloc
UserProfilePB? _userProfile;
UserProfilePB? get userProfile => _userProfile;
DatabaseCallbacks? _databaseCallbacks;
@override
Future<void> close() async {
databaseController.removeListener(onDatabaseChanged: _databaseCallbacks);
_databaseCallbacks = null;
await super.close();
}
void _dispatch() {
on<MobileRowDetailEvent>(
(event, emit) {
@@ -76,7 +67,7 @@ class MobileRowDetailBloc
}
void _startListening() {
_databaseCallbacks = DatabaseCallbacks(
final onDatabaseChanged = DatabaseCallbacks(
onNumOfRowsChanged: (rowInfos, _, reason) {
if (!isClosed) {
add(MobileRowDetailEvent.didLoadRows(rowInfos));
@@ -92,7 +83,7 @@ class MobileRowDetailBloc
}
},
);
databaseController.addListener(onDatabaseChanged: _databaseCallbacks);
databaseController.addListener(onDatabaseChanged: onDatabaseChanged);
}
}
@@ -70,13 +70,14 @@ class RowBloc extends Bloc<RowEvent, RowState> {
);
}
void _startListening() =>
_rowController.addListener(onRowChanged: _onRowChanged);
void _onRowChanged(List<CellContext> cells, ChangedReason reason) {
if (!isClosed) {
add(RowEvent.didReceiveCells(cells, reason));
}
void _startListening() {
_rowController.addListener(
onRowChanged: (cells, reason) {
if (!isClosed) {
add(RowEvent.didReceiveCells(cells, reason));
}
},
);
}
void _init() {
@@ -10,6 +10,7 @@ import 'package:appflowy/shared/patterns/common_patterns.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/calculation_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/number_entities.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -4,6 +4,7 @@ import 'package:appflowy/plugins/database/application/field/filter_entities.dart
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_filter.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -3,6 +3,7 @@ import 'package:appflowy/plugins/database/application/field/filter_entities.dart
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_filter.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -6,7 +6,8 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/desktop_date_picker.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/appflowy_date_picker.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -198,7 +199,7 @@ class _DateFilterEditorState extends State<DateFilterEditor> {
child: SingleFilterBlocSelector<DateTimeFilter>(
filterId: widget.filterId,
builder: (context, filter, field) {
return DesktopAppFlowyDatePicker(
return AppFlowyDatePicker(
isRange: isRange,
includeTime: false,
dateFormat: DateFormatPB.Friendly,
@@ -5,6 +5,7 @@ import 'package:appflowy/plugins/database/application/field/filter_entities.dart
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -1,6 +1,7 @@
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/application/field/filter_entities.dart';
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -5,6 +5,7 @@ import 'package:appflowy/plugins/database/application/field/filter_entities.dart
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -5,6 +5,7 @@ import 'package:appflowy/plugins/database/application/field/filter_entities.dart
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -1,6 +1,7 @@
import 'package:appflowy/plugins/database/application/field/filter_entities.dart';
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/text.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -2,6 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -9,6 +9,7 @@ import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/widgets/field/field_editor.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
@@ -6,6 +6,7 @@ import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -12,6 +12,7 @@ import 'package:appflowy/plugins/database/application/row/row_service.dart';
import 'package:appflowy/plugins/database/grid/application/row/row_bloc.dart';
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_builder.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -10,6 +10,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -4,6 +4,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
import 'package:appflowy/plugins/database/application/field/sort_entities.dart';
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -1,6 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/filter/filter_editor_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
@@ -39,6 +40,7 @@ class _FilterButtonState extends State<FilterButton> {
LocaleKeys.grid_settings_filter.tr(),
fontColor: textColor,
fontSize: FontSizes.s12,
fontWeight: FontWeight.w400,
fillColor: Colors.transparent,
hoverColor: AFThemeExtension.of(context).lightGreyHover,
padding: GridSize.toolbarSettingButtonInsets,
@@ -1,6 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
@@ -36,6 +37,7 @@ class _SortButtonState extends State<SortButton> {
LocaleKeys.grid_settings_sort.tr(),
fontColor: textColor,
fontSize: FontSizes.s12,
fontWeight: FontWeight.w400,
fillColor: Colors.transparent,
hoverColor: AFThemeExtension.of(context).lightGreyHover,
padding: GridSize.toolbarSettingButtonInsets,
@@ -3,6 +3,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/widgets/database_layout_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
@@ -6,6 +6,7 @@ import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
@@ -46,15 +47,16 @@ class TabBarHeader extends StatelessWidget {
const Expanded(
child: DatabaseTabBar(),
),
Flexible(
child: BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(
builder: (context, state) {
return Padding(
BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(
builder: (context, state) {
return SizedBox(
width: 200,
child: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: pageSettingBarFromState(context, state),
);
},
),
),
);
},
),
],
),
@@ -219,9 +221,7 @@ class TabBarItemButton extends StatelessWidget {
color: color,
),
text: FlowyText(
view.name.isEmpty
? LocaleKeys.document_title_placeholder.tr()
: view.name,
view.name,
lineHeight: 1.0,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
@@ -1,6 +1,4 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
@@ -107,9 +105,7 @@ class _DatabaseViewSelectorButton extends StatelessWidget {
const HSpace(6),
Flexible(
child: FlowyText.medium(
tabBar.view.name.isEmpty
? LocaleKeys.document_title_placeholder.tr()
: tabBar.view.name,
tabBar.view.name,
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
Loaded 100 of 473 files, more files were not shown because too many files have changed in this diff. Show more