mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat:IInline math equation (#2949)
This commit is contained in:
parent
4c17298432
commit
ff9b3c56c5
2
.github/workflows/flutter_ci.yaml
vendored
2
.github/workflows/flutter_ci.yaml
vendored
@ -134,6 +134,6 @@ jobs:
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
os: ${{ matrix.os }}
|
||||
attempt_limit: 5
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
||||
|
||||
|
37
.github/workflows/integration_test.yml
vendored
37
.github/workflows/integration_test.yml
vendored
@ -29,25 +29,31 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
build:
|
||||
if: github.event.pull_request.draft != true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
flutter_profile: development-linux-x86_64
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: windows-latest
|
||||
flutter_profile: development-windows-x86
|
||||
target: x86_64-pc-windows-msvc
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "stable-2022-04-07"
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
id: rust_toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
profile: minimal
|
||||
|
||||
@ -64,6 +70,7 @@ jobs:
|
||||
prefix-key: ${{ matrix.os }}
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
cache-all-crates: true
|
||||
|
||||
- uses: davidB/rust-cargo-make@v1
|
||||
with:
|
||||
@ -87,30 +94,24 @@ jobs:
|
||||
cargo make appflowy-flutter-deps-tools
|
||||
shell: bash
|
||||
|
||||
- name: Config Flutter
|
||||
- name: Enable Flutter Desktop
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
flutter config --enable-linux-desktop
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
flutter config --enable-macos-desktop
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
git config --system core.longpaths true
|
||||
flutter config --enable-windows-desktop
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Build Test lib
|
||||
- name: Build AppFlowy
|
||||
working-directory: frontend
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
cargo make --profile development-linux-x86_64 appflowy-dev
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
cargo make --profile development-mac-x86_64 appflowy-dev
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
cargo make --profile development-windows-x86 appflowy-dev
|
||||
fi
|
||||
shell: bash
|
||||
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
|
||||
|
||||
- name: Run AppFlowy tests
|
||||
- name: Run Flutter integration tests
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
@ -135,5 +136,5 @@ jobs:
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
os: ${{ matrix.os }}
|
||||
attempt_limit: 5
|
||||
attempt_limit: 20
|
||||
attempt_delay: 10000
|
1
frontend/appflowy_flutter/assets/images/editor/math.svg
Normal file
1
frontend/appflowy_flutter/assets/images/editor/math.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" style="width: 16px; height: 16px; display: block; fill: inherit; flex-shrink: 0; backface-visibility: hidden;" width="30" height="30" ><path d="M6.04883 27.3232C7.24219 27.3232 7.86426 26.4854 8.20703 25.3936L13.9834 6.79492H27.5039C28.2275 6.79492 28.7227 6.35059 28.7227 5.65234C28.7227 4.97949 28.2275 4.53516 27.5039 4.53516H13.958C12.6631 4.53516 12.0791 5.01758 11.7363 6.13477L6.18848 24.3525H5.97266L3.58594 15.9355C3.38281 15.2373 3.00195 14.9072 2.40527 14.9072C1.73242 14.9072 1.2373 15.3896 1.2373 16.0117C1.2373 16.2656 1.30078 16.4941 1.35156 16.6846L4.04297 25.5332C4.36035 26.5615 4.93164 27.3232 6.04883 27.3232ZM16.3955 24.7334C16.8652 24.7334 17.1064 24.5684 17.4619 24.0732L20.4707 19.8203H20.5215L23.5049 24.0732C23.873 24.5684 24.1143 24.7334 24.5713 24.7334C25.2061 24.7334 25.6758 24.3018 25.6758 23.7051C25.6758 23.4258 25.6123 23.1973 25.4219 22.9561L21.9307 18.208L25.4473 13.4346C25.6377 13.168 25.7139 12.9395 25.7139 12.6855C25.7139 12.127 25.2568 11.6953 24.6475 11.6953C24.2031 11.6953 23.9365 11.8477 23.6064 12.3174L20.7246 16.5957H20.6611L17.6904 12.3047C17.373 11.8477 17.0938 11.6953 16.624 11.6953C16.0146 11.6953 15.5068 12.165 15.5068 12.7363C15.5068 13.0537 15.583 13.2568 15.8115 13.5488L19.1504 18.1445L15.6084 23.0322C15.418 23.2861 15.3672 23.4639 15.3672 23.7559C15.3672 24.3018 15.8115 24.7334 16.3955 24.7334Z" fill="#2F3030"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -426,6 +426,7 @@
|
||||
"smartEditCouldNotFetchKey": "Could not fetch OpenAI key",
|
||||
"smartEditDisabled": "Connect OpenAI in Settings",
|
||||
"discardResponse": "Do you want to discard the AI responses?",
|
||||
"createInlineMathEquation": "Create equation",
|
||||
"cover": {
|
||||
"changeCover": "Change Cover",
|
||||
"colors": "Colors",
|
||||
|
@ -107,7 +107,7 @@ void main() {
|
||||
|
||||
// Make sure that the event is edited
|
||||
tester.assertNumberOfEventsInCalendar(1, title: 'hello world');
|
||||
tester.assertNumberofEventsOnSpecificDay(2, DateTime.now());
|
||||
tester.assertNumberOfEventsOnSpecificDay(2, DateTime.now());
|
||||
|
||||
// Click on the event
|
||||
await tester.openCalendarEvent(index: 1);
|
||||
@ -119,7 +119,7 @@ void main() {
|
||||
|
||||
// Check that there are 2 events
|
||||
tester.assertNumberOfEventsInCalendar(2, title: 'hello world');
|
||||
tester.assertNumberofEventsOnSpecificDay(3, DateTime.now());
|
||||
tester.assertNumberOfEventsOnSpecificDay(3, DateTime.now());
|
||||
|
||||
// Delete an event
|
||||
await tester.openCalendarEvent(index: 1);
|
||||
@ -127,7 +127,7 @@ void main() {
|
||||
|
||||
// Check that there is 1 event
|
||||
tester.assertNumberOfEventsInCalendar(1, title: 'hello world');
|
||||
tester.assertNumberofEventsOnSpecificDay(2, DateTime.now());
|
||||
tester.assertNumberOfEventsOnSpecificDay(2, DateTime.now());
|
||||
});
|
||||
|
||||
testWidgets('rescheduling events', (tester) async {
|
||||
@ -150,7 +150,7 @@ void main() {
|
||||
// Make sure that the event has been rescheduled to the new date
|
||||
final sameDayNextWeek = firstOfThisMonth.add(const Duration(days: 7));
|
||||
tester.assertNumberOfEventsInCalendar(1);
|
||||
tester.assertNumberofEventsOnSpecificDay(1, sameDayNextWeek);
|
||||
tester.assertNumberOfEventsOnSpecificDay(1, sameDayNextWeek);
|
||||
|
||||
// Delete the event
|
||||
await tester.openCalendarEvent(index: 0, date: sameDayNextWeek);
|
||||
@ -162,7 +162,7 @@ void main() {
|
||||
await tester.dismissRowDetailPage();
|
||||
|
||||
// Make sure that the event is today
|
||||
tester.assertNumberofEventsOnSpecificDay(1, today);
|
||||
tester.assertNumberOfEventsOnSpecificDay(1, today);
|
||||
|
||||
// Click on the event
|
||||
await tester.openCalendarEvent(index: 0);
|
||||
@ -183,7 +183,7 @@ void main() {
|
||||
|
||||
// Make sure that the event is edited
|
||||
tester.assertNumberOfEventsInCalendar(1);
|
||||
tester.assertNumberofEventsOnSpecificDay(1, newDate);
|
||||
tester.assertNumberOfEventsOnSpecificDay(1, newDate);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -172,9 +172,10 @@ void main() {
|
||||
// Focus on the editor
|
||||
final textBlock = find.byType(TextBlockComponentWidget);
|
||||
await tester.tapAt(tester.getCenter(textBlock));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Input some text
|
||||
const inputText = 'Hello world';
|
||||
const inputText = 'Hello World';
|
||||
await tester.ime.insertText(inputText);
|
||||
expect(
|
||||
find.textContaining(inputText, findRichText: true),
|
||||
|
@ -10,6 +10,8 @@ void main() {
|
||||
group('database', () {
|
||||
testWidgets('import v0.2.0 database data', (tester) async {
|
||||
await tester.openV020database();
|
||||
// wait the database data is loaded
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
|
||||
// check the text cell
|
||||
final textCells = <String>['A', 'B', 'C', 'D', 'E', '', '', '', '', ''];
|
||||
|
@ -9,7 +9,7 @@ import '../util/util.dart';
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('document', () {
|
||||
group('create and delete the document', () {
|
||||
testWidgets('create a new document when launching app in first time',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
@ -0,0 +1,22 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'document_create_and_delete_test.dart'
|
||||
as document_create_and_delete_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_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 'edit_document_test.dart' as document_edit_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Document integration tests
|
||||
document_create_and_delete_test.main();
|
||||
document_edit_test.main();
|
||||
document_with_database_test.main();
|
||||
document_with_inline_page_test.main();
|
||||
document_with_inline_math_equation_test.main();
|
||||
document_with_cover_image_test.main();
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../util/ime.dart';
|
||||
import '../util/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('inline math equation in document', () {
|
||||
testWidgets('insert an inline math equation', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
// create a new document
|
||||
await tester.createNewPageWithName(
|
||||
ViewLayoutPB.Document,
|
||||
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
);
|
||||
|
||||
// tap the first line of the document
|
||||
await tester.editor.tapLineOfEditorAt(0);
|
||||
// insert a inline page
|
||||
const formula = 'E = MC ^ 2';
|
||||
await tester.ime.insertText(formula);
|
||||
await tester.editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0, endOffset: formula.length),
|
||||
);
|
||||
|
||||
// tap the inline math equation button
|
||||
final inlineMathEquationButton = find.byTooltip(
|
||||
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
);
|
||||
await tester.tapButton(inlineMathEquationButton);
|
||||
|
||||
// expect to see the math equation block
|
||||
final inlineMathEquation = find.byType(InlineMathEquation);
|
||||
expect(inlineMathEquation, findsOneWidget);
|
||||
|
||||
// tap it and update the content
|
||||
await tester.tapButton(inlineMathEquation);
|
||||
final textFormField = find.descendant(
|
||||
of: find.byType(MathInputTextField),
|
||||
matching: find.byType(TextFormField),
|
||||
);
|
||||
const newFormula = 'E = MC ^ 3';
|
||||
await tester.enterText(textFormField, newFormula);
|
||||
await tester.tapButton(
|
||||
find.descendant(
|
||||
of: find.byType(MathInputTextField),
|
||||
matching: find.byType(FlowyButton),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
});
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
@ -1,23 +1,19 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'switch_folder_test.dart' as switch_folder_test;
|
||||
import 'document/document_test.dart' as document_test;
|
||||
import 'document/cover_image_test.dart' as cover_image_test;
|
||||
import 'share_markdown_test.dart' as share_markdown_test;
|
||||
import 'import_files_test.dart' as import_files_test;
|
||||
import 'document/document_with_database_test.dart'
|
||||
as document_with_database_test;
|
||||
import 'document/edit_document_test.dart' as edit_document_test;
|
||||
import 'database_calendar_test.dart' as database_calendar_test;
|
||||
import 'database_cell_test.dart' as database_cell_test;
|
||||
import 'database_field_test.dart' as database_field_test;
|
||||
import 'database_share_test.dart' as database_share_test;
|
||||
import 'database_filter_test.dart' as database_filter_test;
|
||||
import 'database_row_page_test.dart' as database_row_page_test;
|
||||
import 'database_row_test.dart' as database_row_test;
|
||||
import 'database_setting_test.dart' as database_setting_test;
|
||||
import 'database_filter_test.dart' as database_filter_test;
|
||||
import 'database_view_test.dart' as database_view_test;
|
||||
import 'database_calendar_test.dart' as database_calendar_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;
|
||||
import 'document/document_test_runner.dart' as document_test_runner;
|
||||
import 'import_files_test.dart' as import_files_test;
|
||||
import 'share_markdown_test.dart' as share_markdown_test;
|
||||
import 'switch_folder_test.dart' as switch_folder_test;
|
||||
|
||||
/// The main task runner for all integration tests in AppFlowy.
|
||||
///
|
||||
@ -33,10 +29,7 @@ void main() {
|
||||
import_files_test.main();
|
||||
|
||||
// Document integration tests
|
||||
cover_image_test.main();
|
||||
document_test.main();
|
||||
document_with_database_test.main();
|
||||
edit_document_test.main();
|
||||
document_test_runner.startTesting();
|
||||
|
||||
// Database integration tests
|
||||
database_cell_test.main();
|
||||
|
@ -10,6 +10,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class FlowyTestContext {
|
||||
FlowyTestContext({
|
||||
@ -23,7 +24,10 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
Future<FlowyTestContext> initializeAppFlowy({
|
||||
// use to append after the application data directory
|
||||
String? pathExtension,
|
||||
Size windowsSize = const Size(1600, 1200),
|
||||
}) async {
|
||||
binding.setSurfaceSize(windowsSize);
|
||||
|
||||
mockHotKeyManagerHandlers();
|
||||
final directory = await mockApplicationDataStorage(
|
||||
pathExtension: pathExtension,
|
||||
@ -60,7 +64,7 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
final dir = await getTemporaryDirectory();
|
||||
|
||||
// Use a random uuid to avoid conflict.
|
||||
String path = '${dir.path}/appflowy_integration_test/${uuid()}';
|
||||
String path = p.join(dir.path, 'appflowy_integration_test', uuid());
|
||||
if (pathExtension != null && pathExtension.isNotEmpty) {
|
||||
path = '$path/$pathExtension';
|
||||
}
|
||||
@ -78,7 +82,7 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
Finder finder, {
|
||||
int? pointer,
|
||||
int buttons = kPrimaryButton,
|
||||
bool warnIfMissed = true,
|
||||
bool warnIfMissed = false,
|
||||
int milliseconds = 500,
|
||||
}) async {
|
||||
await tap(
|
||||
@ -123,6 +127,18 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
return;
|
||||
}
|
||||
|
||||
Future<void> doubleTapAt(
|
||||
Offset location, {
|
||||
int? pointer,
|
||||
int buttons = kPrimaryButton,
|
||||
int milliseconds = 500,
|
||||
}) async {
|
||||
await tapAt(location, pointer: pointer, buttons: buttons);
|
||||
await pump(kDoubleTapMinTime);
|
||||
await tapAt(location, pointer: pointer, buttons: buttons);
|
||||
await pumpAndSettle(Duration(milliseconds: milliseconds));
|
||||
}
|
||||
|
||||
Future<void> doubleTapButton(
|
||||
Finder finder, {
|
||||
int? pointer,
|
||||
@ -130,20 +146,22 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
bool warnIfMissed = true,
|
||||
int milliseconds = 500,
|
||||
}) async {
|
||||
await tapButton(
|
||||
await tap(
|
||||
finder,
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
warnIfMissed: warnIfMissed,
|
||||
milliseconds: kDoubleTapMinTime.inMilliseconds,
|
||||
);
|
||||
await tapButton(
|
||||
|
||||
await pump(kDoubleTapMinTime);
|
||||
|
||||
await tap(
|
||||
finder,
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
pointer: pointer,
|
||||
warnIfMissed: warnIfMissed,
|
||||
milliseconds: milliseconds,
|
||||
);
|
||||
await pumpAndSettle(Duration(milliseconds: milliseconds));
|
||||
}
|
||||
|
||||
Future<void> wait(int milliseconds) async {
|
||||
|
@ -453,8 +453,15 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
}
|
||||
|
||||
Future<void> dismissRowDetailPage() async {
|
||||
await sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
// use tap empty area instead of clicking ESC to dismiss the row detail page
|
||||
// sometimes, the ESC key is not working.
|
||||
await simulateKeyEvent(LogicalKeyboardKey.escape);
|
||||
await pumpAndSettle();
|
||||
final findRowDetailPage = find.byType(RowDetailPage);
|
||||
if (findRowDetailPage.evaluate().isNotEmpty) {
|
||||
await tapAt(const Offset(0, 0));
|
||||
await pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> editTitleInRowDetailPage(String title) async {
|
||||
@ -1031,7 +1038,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
expect(findEvents, findsNWidgets(number));
|
||||
}
|
||||
|
||||
void assertNumberofEventsOnSpecificDay(
|
||||
void assertNumberOfEventsOnSpecificDay(
|
||||
int number,
|
||||
DateTime date, {
|
||||
String? title,
|
||||
@ -1058,8 +1065,8 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
final todayCell = find.byWidgetPredicate(
|
||||
(widget) => widget is CalendarDayCard && isSameDay(date, widget.date),
|
||||
);
|
||||
|
||||
await doubleTapButton(todayCell);
|
||||
final location = getTopLeft(todayCell).translate(10, 10);
|
||||
await doubleTapAt(location);
|
||||
}
|
||||
|
||||
Future<void> openCalendarEvent({required index, DateTime? date}) async {
|
||||
|
@ -165,4 +165,14 @@ class EditorOperations {
|
||||
);
|
||||
await tester.tapButton(atMenuItem);
|
||||
}
|
||||
|
||||
/// Update the editor's selection
|
||||
Future<void> updateSelection(Selection selection) async {
|
||||
final editorState = getCurrentEditorState();
|
||||
editorState.updateSelectionWithReason(
|
||||
selection,
|
||||
reason: SelectionUpdateReason.uiEvent,
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 200));
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,10 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
quoteItem,
|
||||
bulletedListItem,
|
||||
numberedListItem,
|
||||
inlineMathEquationItem,
|
||||
linkItem,
|
||||
textColorItem,
|
||||
highlightColorItem,
|
||||
buildTextColorItem(),
|
||||
buildHighlightColorItem(),
|
||||
];
|
||||
|
||||
late final List<SelectionMenuItem> slashMenuItems;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/emoji_picker/emoji_picker.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
@ -43,20 +43,6 @@ enum CoverType {
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentHeaderNodeWidgetBuilder implements NodeWidgetBuilder {
|
||||
@override
|
||||
Widget build(NodeWidgetContext<Node> context) {
|
||||
return DocumentHeaderNodeWidget(
|
||||
key: context.node.key,
|
||||
node: context.node,
|
||||
editorState: context.editorState,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
NodeValidator<Node> get nodeValidator => (_) => true;
|
||||
}
|
||||
|
||||
class DocumentHeaderNodeWidget extends StatefulWidget {
|
||||
const DocumentHeaderNodeWidget({
|
||||
required this.node,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/emoji_picker/emoji_picker.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
|
@ -0,0 +1,173 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.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:flowy_infra_ui/style_widget/text_input.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_math_fork/flutter_math.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class InlineMathEquationKeys {
|
||||
const InlineMathEquationKeys._();
|
||||
|
||||
static const formula = 'formula';
|
||||
}
|
||||
|
||||
class InlineMathEquation extends StatefulWidget {
|
||||
const InlineMathEquation({
|
||||
super.key,
|
||||
required this.formula,
|
||||
required this.node,
|
||||
required this.index,
|
||||
this.textStyle,
|
||||
});
|
||||
|
||||
final Node node;
|
||||
final int index;
|
||||
final String formula;
|
||||
final TextStyle? textStyle;
|
||||
|
||||
@override
|
||||
State<InlineMathEquation> createState() => _InlineMathEquationState();
|
||||
}
|
||||
|
||||
class _InlineMathEquationState extends State<InlineMathEquation> {
|
||||
final popoverController = PopoverController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return _IgnoreParentPointer(
|
||||
child: AppFlowyPopover(
|
||||
controller: popoverController,
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
popupBuilder: (_) {
|
||||
return MathInputTextField(
|
||||
initialText: widget.formula,
|
||||
onSubmit: (value) async {
|
||||
popoverController.close();
|
||||
if (value == widget.formula) {
|
||||
return;
|
||||
}
|
||||
final editorState = context.read<EditorState>();
|
||||
final transaction = editorState.transaction
|
||||
..formatText(widget.node, widget.index, 1, {
|
||||
InlineMathEquationKeys.formula: value,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
},
|
||||
);
|
||||
},
|
||||
offset: const Offset(0, 10),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const HSpace(2),
|
||||
Math.tex(
|
||||
widget.formula,
|
||||
options: MathOptions(
|
||||
style: MathStyle.text,
|
||||
mathFontOptions: const FontOptions(
|
||||
fontShape: FontStyle.italic,
|
||||
),
|
||||
fontSize: 14.0,
|
||||
color: widget.textStyle?.color ??
|
||||
theme.colorScheme.onBackground,
|
||||
),
|
||||
),
|
||||
const HSpace(2),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MathInputTextField extends StatefulWidget {
|
||||
const MathInputTextField({
|
||||
super.key,
|
||||
required this.initialText,
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
final String initialText;
|
||||
final void Function(String value) onSubmit;
|
||||
|
||||
@override
|
||||
State<MathInputTextField> createState() => _MathInputTextFieldState();
|
||||
}
|
||||
|
||||
class _MathInputTextFieldState extends State<MathInputTextField> {
|
||||
late final TextEditingController textEditingController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
textEditingController = TextEditingController(
|
||||
text: widget.initialText,
|
||||
);
|
||||
textEditingController.selection = TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: widget.initialText.length,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 240,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: FlowyFormTextInput(
|
||||
autoFocus: true,
|
||||
textAlign: TextAlign.left,
|
||||
controller: textEditingController,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
horizontal: 4.0,
|
||||
),
|
||||
onEditingComplete: () =>
|
||||
widget.onSubmit(textEditingController.text),
|
||||
),
|
||||
),
|
||||
const HSpace(4.0),
|
||||
FlowyButton(
|
||||
text: FlowyText(LocaleKeys.button_Done.tr()),
|
||||
useIntrinsicWidth: true,
|
||||
onTap: () => widget.onSubmit(textEditingController.text),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _IgnoreParentPointer extends StatelessWidget {
|
||||
const _IgnoreParentPointer({
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {},
|
||||
onTapDown: (_) {},
|
||||
onDoubleTap: () {},
|
||||
onLongPress: () {},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
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:flowy_infra/image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final ToolbarItem inlineMathEquationItem = ToolbarItem(
|
||||
id: 'editor.inline_math_equation',
|
||||
group: 2,
|
||||
isActive: onlyShowInSingleSelectionAndTextType,
|
||||
builder: (context, editorState) {
|
||||
final selection = editorState.selection!;
|
||||
final nodes = editorState.getNodesInSelection(selection);
|
||||
final isHighlight = nodes.allSatisfyInSelection(selection, (delta) {
|
||||
return delta.everyAttributes(
|
||||
(attributes) => attributes[InlineMathEquationKeys.formula] != null,
|
||||
);
|
||||
});
|
||||
return IconItemWidget(
|
||||
iconBuilder: (_) => svgWidget(
|
||||
'editor/math',
|
||||
size: const Size.square(16),
|
||||
color: Colors.white,
|
||||
),
|
||||
isHighlight: isHighlight,
|
||||
tooltip: LocaleKeys.document_plugins_createInlineMathEquation.tr(),
|
||||
onPressed: () async {
|
||||
final selection = editorState.selection;
|
||||
if (selection == null || selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
final text = editorState.getTextInSelection(selection).join();
|
||||
final transaction = editorState.transaction
|
||||
..replaceText(
|
||||
node,
|
||||
selection.startIndex,
|
||||
selection.length,
|
||||
'\$',
|
||||
attributes: {
|
||||
InlineMathEquationKeys.formula: text,
|
||||
},
|
||||
);
|
||||
await editorState.apply(transaction);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
@ -24,8 +24,6 @@ class MentionBlockKeys {
|
||||
static const mention = 'mention';
|
||||
static const type = 'type'; // MentionType, String
|
||||
static const pageId = 'page_id';
|
||||
static const pageType = 'page_type';
|
||||
static const pageName = 'page_name';
|
||||
}
|
||||
|
||||
class InlinePageReferenceService {
|
||||
|
@ -1,22 +1,24 @@
|
||||
export 'actions/block_action_list.dart';
|
||||
export 'actions/option_action.dart';
|
||||
export 'callout/callout_block_component.dart';
|
||||
export 'code_block/code_block_component.dart';
|
||||
export 'code_block/code_block_shortcut_event.dart';
|
||||
export 'header/cover_editor_bloc.dart';
|
||||
export 'header/document_header_node_widget.dart';
|
||||
export 'header/custom_cover_picker.dart';
|
||||
export 'emoji_picker/emoji_menu_item.dart';
|
||||
export 'extensions/flowy_tint_extension.dart';
|
||||
export 'database/database_view_block_component.dart';
|
||||
export 'database/inline_database_menu_item.dart';
|
||||
export 'database/referenced_database_menu_item.dart';
|
||||
export 'database/database_view_block_component.dart';
|
||||
export 'emoji_picker/emoji_menu_item.dart';
|
||||
export 'extensions/flowy_tint_extension.dart';
|
||||
export 'header/cover_editor_bloc.dart';
|
||||
export 'header/custom_cover_picker.dart';
|
||||
export 'header/document_header_node_widget.dart';
|
||||
export 'image/image_menu.dart';
|
||||
export 'image/image_selection_menu.dart';
|
||||
export 'inline_math_equation/inline_math_equation.dart';
|
||||
export 'inline_math_equation/inline_math_equation_toolbar_item.dart';
|
||||
export 'math_equation/math_equation_block_component.dart';
|
||||
export 'openai/widgets/auto_completion_node_widget.dart';
|
||||
export 'openai/widgets/smart_edit_node_widget.dart';
|
||||
export 'openai/widgets/smart_edit_toolbar_item.dart';
|
||||
export 'outline/outline_block_component.dart';
|
||||
export 'toggle/toggle_block_component.dart';
|
||||
export 'toggle/toggle_block_shortcut_event.dart';
|
||||
export 'outline/outline_block_component.dart';
|
||||
export 'image/image_menu.dart';
|
||||
export 'image/image_selection_menu.dart';
|
||||
export 'actions/option_action.dart';
|
||||
export 'actions/block_action_list.dart';
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/inline_math_equation/inline_math_equation.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/inline_page/inline_page_reference.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg, Log;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@ -173,13 +174,17 @@ class EditorStyleCustomizer {
|
||||
}
|
||||
|
||||
InlineSpan customizeAttributeDecorator(
|
||||
TextInsert textInsert,
|
||||
Node node,
|
||||
int index,
|
||||
TextInsert text,
|
||||
TextSpan textSpan,
|
||||
) {
|
||||
final attributes = textInsert.attributes;
|
||||
final attributes = text.attributes;
|
||||
if (attributes == null) {
|
||||
return textSpan;
|
||||
}
|
||||
|
||||
// customize the inline mention block, like inline page
|
||||
final mention = attributes[MentionBlockKeys.mention] as Map?;
|
||||
if (mention != null) {
|
||||
final type = mention[MentionBlockKeys.type];
|
||||
@ -193,6 +198,21 @@ class EditorStyleCustomizer {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// customize the inline math equation block
|
||||
final formula = attributes[InlineMathEquationKeys.formula] as String?;
|
||||
if (formula != null) {
|
||||
return WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: InlineMathEquation(
|
||||
node: node,
|
||||
index: index,
|
||||
formula: formula,
|
||||
textStyle: style().textStyleConfiguration.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return textSpan;
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,9 @@ class FlowyRunner {
|
||||
final launcher = getIt<AppLauncher>();
|
||||
launcher.addTasks(
|
||||
[
|
||||
// handle platform errors.
|
||||
const PlatformErrorCatcherTask(),
|
||||
// this task should be first task, for handling platform errors.
|
||||
// don't catch errors in test mode
|
||||
if (!mode.isUnitTest) const PlatformErrorCatcherTask(),
|
||||
// localization
|
||||
const InitLocalizationTask(),
|
||||
// init the app window
|
||||
|
@ -19,17 +19,14 @@ class InitAppWindowTask extends LaunchTask with WindowListener {
|
||||
@override
|
||||
Future<void> initialize(LaunchContext context) async {
|
||||
// Don't initialize on mobile or web.
|
||||
if (!defaultTargetPlatform.isDesktop) {
|
||||
if (!defaultTargetPlatform.isDesktop || context.env.isIntegrationTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
await windowManager.ensureInitialized();
|
||||
windowManager.addListener(this);
|
||||
|
||||
Size windowSize = await WindowSizeManager().getSize();
|
||||
if (context.env.isIntegrationTest) {
|
||||
windowSize = const Size(1600, 1200);
|
||||
}
|
||||
final windowSize = await WindowSizeManager().getSize();
|
||||
|
||||
final windowOptions = WindowOptions(
|
||||
size: windowSize,
|
||||
|
@ -96,7 +96,7 @@ class SplashScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
Future<void> _registerIfNeeded() async {
|
||||
final result = await UserEventCheckUser().send();
|
||||
final result = await UserEventGetUserProfile().send();
|
||||
if (!result.isLeft()) {
|
||||
await getIt<AuthService>().signUpAsGuest();
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ class MockApplicationDataStorage extends ApplicationDataStorage {
|
||||
final path = initialPath;
|
||||
if (path != null) {
|
||||
initialPath = null;
|
||||
await super.setPath(path);
|
||||
return Future.value(path);
|
||||
}
|
||||
return super.getPath();
|
||||
|
@ -5,16 +5,23 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
///
|
||||
/// Get the hover color from ThemeData
|
||||
class FlowySvg extends StatelessWidget {
|
||||
const FlowySvg({super.key, this.size, required this.name});
|
||||
const FlowySvg({
|
||||
super.key,
|
||||
required this.name,
|
||||
this.size,
|
||||
this.color,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final Size? size;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return svgWidget(
|
||||
name,
|
||||
size: size,
|
||||
color: Theme.of(context).iconTheme.color,
|
||||
color: color ?? Theme.of(context).iconTheme.color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -53,11 +53,11 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "572a174"
|
||||
resolved-ref: "572a174892267e2f78f9c3d7f1fe4ca71c9be0db"
|
||||
ref: c5b5e64
|
||||
resolved-ref: c5b5e641fe11ae634f02db112e71f40a119e9c44
|
||||
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
|
||||
source: git
|
||||
version: "1.0.4"
|
||||
version: "1.1.0"
|
||||
appflowy_popover:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -46,7 +46,7 @@ dependencies:
|
||||
appflowy_editor:
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
||||
ref: 572a174
|
||||
ref: c5b5e64
|
||||
appflowy_popover:
|
||||
path: packages/appflowy_popover
|
||||
|
||||
|
@ -7,7 +7,7 @@ mod init;
|
||||
mod notification;
|
||||
mod request;
|
||||
|
||||
use flowy_notification::register_notification_sender;
|
||||
use flowy_notification::{register_notification_sender, unregister_all_notification_sender};
|
||||
use init::*;
|
||||
use notification::*;
|
||||
use request::*;
|
||||
@ -22,6 +22,8 @@ fn main() {
|
||||
.on_menu_event(|_menu| {})
|
||||
.on_page_load(|window, _payload| {
|
||||
let app_handler = window.app_handle();
|
||||
// Make sure hot reload won't register the notification sender twice
|
||||
unregister_all_notification_sender();
|
||||
register_notification_sender(TSNotificationSender::new(app_handler.clone()));
|
||||
// tauri::async_runtime::spawn(async move {});
|
||||
window.listen_global(AF_EVENT, move |event| {
|
||||
|
10
frontend/rust-lib/Cargo.lock
generated
10
frontend/rust-lib/Cargo.lock
generated
@ -85,6 +85,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -896,6 +897,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -913,6 +915,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -930,6 +933,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -956,6 +960,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -967,6 +972,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -985,6 +991,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1004,6 +1011,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1023,6 +1031,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1056,6 +1065,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2134c0#2134c0f27b8a9f3077e25ae928f2420c926506cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
|
@ -6,7 +6,7 @@ use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use flowy_core::*;
|
||||
use flowy_notification::register_notification_sender;
|
||||
use flowy_notification::{register_notification_sender, unregister_all_notification_sender};
|
||||
use lib_dispatch::prelude::ToBytes;
|
||||
use lib_dispatch::prelude::*;
|
||||
|
||||
@ -90,6 +90,8 @@ pub extern "C" fn sync_event(input: *const u8, len: usize) -> *const u8 {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_stream_port(port: i64) -> i32 {
|
||||
// Make sure hot reload won't register the notification sender twice
|
||||
unregister_all_notification_sender();
|
||||
register_notification_sender(DartNotificationSender::new(port));
|
||||
0
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ lazy_static! {
|
||||
static ref NOTIFICATION_SENDER: RwLock<Vec<Box<dyn NotificationSender>>> = RwLock::new(vec![]);
|
||||
}
|
||||
|
||||
/// Register a notification sender. The sender will be alive until the process exits.
|
||||
/// Flutter integration test or Tauri hot reload might cause register multiple times.
|
||||
/// So before register a new sender, you might need to unregister the old one. Currently,
|
||||
/// Just remove all senders by calling `unregister_all_notification_sender`.
|
||||
pub fn register_notification_sender<T: NotificationSender>(sender: T) {
|
||||
let box_sender = Box::new(sender);
|
||||
match NOTIFICATION_SENDER.write() {
|
||||
@ -22,6 +26,13 @@ pub fn register_notification_sender<T: NotificationSender>(sender: T) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unregister_all_notification_sender() {
|
||||
match NOTIFICATION_SENDER.write() {
|
||||
Ok(mut write_guard) => write_guard.clear(),
|
||||
Err(err) => tracing::error!("Failed to remove all notification senders: {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NotificationSender: Send + Sync + 'static {
|
||||
fn send_subject(&self, subject: SubscribeObject) -> Result<(), String>;
|
||||
}
|
||||
|
11
frontend/scripts/code_generation/freezed/generate_freezed.sh
Normal file → Executable file
11
frontend/scripts/code_generation/freezed/generate_freezed.sh
Normal file → Executable file
@ -10,12 +10,14 @@ cd ../../../appflowy_flutter
|
||||
|
||||
# Navigate to the appflowy_flutter directory and generate files
|
||||
echo "Generating files for appflowy_flutter"
|
||||
flutter clean >/dev/null 2>&1 && flutter packages pub get >/dev/null 2>&1 && dart run build_runner clean && dart run build_runner build -d
|
||||
# flutter clean >/dev/null 2>&1 && flutter packages pub get >/dev/null 2>&1 && dart run build_runner clean &&
|
||||
flutter packages pub get >/dev/null 2>&1
|
||||
dart run build_runner build -d
|
||||
echo "Done generating files for appflowy_flutter"
|
||||
|
||||
echo "Generating files for packages"
|
||||
cd packages
|
||||
for d in */ ; do
|
||||
for d in */; do
|
||||
# Navigate into the subdirectory
|
||||
cd "$d"
|
||||
|
||||
@ -23,7 +25,8 @@ for d in */ ; do
|
||||
if [ -f "pubspec.yaml" ]; then
|
||||
echo "Generating freezed files in $d..."
|
||||
echo "Please wait while we clean the project and fetch the dependencies."
|
||||
flutter clean >/dev/null 2>&1 && flutter packages pub get >/dev/null 2>&1 && dart run build_runner clean && dart run build_runner build -d
|
||||
flutter packages pub get >/dev/null 2>&1
|
||||
dart run build_runner build -d
|
||||
echo "Done running build command in $d"
|
||||
else
|
||||
echo "No pubspec.yaml found in $d, it can\'t be a Dart project. Skipping."
|
||||
@ -34,4 +37,4 @@ for d in */ ; do
|
||||
done
|
||||
|
||||
# Return to the original directory
|
||||
cd "$original_dir"
|
||||
cd "$original_dir"
|
||||
|
0
frontend/scripts/code_generation/generate.sh
Normal file → Executable file
0
frontend/scripts/code_generation/generate.sh
Normal file → Executable file
@ -10,8 +10,6 @@ cd /d "%~dp0"
|
||||
|
||||
cd ..\..\..\appflowy_flutter
|
||||
|
||||
call flutter clean
|
||||
|
||||
call flutter packages pub get
|
||||
|
||||
echo Specifying source directory for AppFlowy Localizations.
|
||||
|
2
frontend/scripts/code_generation/language_files/generate_language_files.sh
Normal file → Executable file
2
frontend/scripts/code_generation/language_files/generate_language_files.sh
Normal file → Executable file
@ -10,8 +10,6 @@ cd "$(dirname "$0")"
|
||||
# Navigate to the project root
|
||||
cd ../../../appflowy_flutter
|
||||
|
||||
flutter clean
|
||||
|
||||
flutter packages pub get
|
||||
|
||||
echo "Specifying source directory for AppFlowy Localizations."
|
||||
|
@ -167,7 +167,6 @@ script = [
|
||||
[tasks.flutter-build]
|
||||
script = ["""
|
||||
cd appflowy_flutter/
|
||||
flutter clean
|
||||
flutter pub get
|
||||
flutter build ${TARGET_OS} --${BUILD_FLAG}
|
||||
"""]
|
||||
@ -176,7 +175,6 @@ script_runner = "@shell"
|
||||
[tasks.flutter-build.windows]
|
||||
script = ["""
|
||||
cd appflowy_flutter
|
||||
exec cmd.exe /c flutter clean
|
||||
exec cmd.exe /c flutter pub get
|
||||
exec cmd.exe /c flutter build ${TARGET_OS} --${BUILD_FLAG} --build-name=${APP_VERSION}
|
||||
"""]
|
||||
@ -186,16 +184,15 @@ script_runner = "@duckscript"
|
||||
script_runner = "@shell"
|
||||
script = [
|
||||
"""
|
||||
chmod +x scripts/code_generation/generate.sh
|
||||
""",
|
||||
"scripts/code_generation/generate.sh"
|
||||
sh scripts/code_generation/generate.sh
|
||||
"""
|
||||
]
|
||||
|
||||
[tasks.code_generation.windows]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
"""
|
||||
exec "scripts/code_generation/generate.cmd"
|
||||
exec scripts/code_generation/generate.cmd
|
||||
""",
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user