Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09f5317768 | ||
|
|
b2f0c4f109 | ||
|
|
da5b369aec | ||
|
|
a92f3d30c2 | ||
|
|
5c96a2c5cb | ||
|
|
31798959c7 | ||
|
|
5479d3ec6e | ||
|
|
5777830730 | ||
|
|
79ea485a27 | ||
|
|
f0d8eee8a0 | ||
|
|
83b18c4825 | ||
|
|
429892aefc | ||
|
|
d56de308e1 | ||
|
|
3171712380 | ||
|
|
47d321b8c2 | ||
|
|
9536cde789 | ||
|
|
3e32fac876 | ||
|
|
81594fa796 | ||
|
|
db6767f61e | ||
|
|
5ceb132b0b | ||
|
|
587de161f6 |
No files matched your search
@@ -0,0 +1,73 @@
|
||||
name: Deploy Web (Test)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build/test
|
||||
- main
|
||||
env:
|
||||
NODE_VERSION: "18.16.0"
|
||||
PNPM_VERSION: "8.5.0"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.WEB_TEST_SSH_PRIVATE_KEY }}
|
||||
REMOTE_HOST: ${{ secrets.WEB_TEST_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.WEB_TEST_REMOTE_USER }}
|
||||
SSL_CERTIFICATE: ${{ secrets.WEB_TEST_SSL_CERTIFICATE }}
|
||||
SSL_CERTIFICATE_KEY: ${{ secrets.WEB_TEST_SSL_CERTIFICATE_KEY }}
|
||||
ENV_FILE: test.env
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
- name: setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
- name: Node_modules cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: frontend/appflowy_web_app/node_modules
|
||||
key: node-modules-${{ runner.os }}
|
||||
- name: install frontend dependencies
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
pnpm install
|
||||
- name: copy env file
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
cp ${{ env.ENV_FILE }} .env
|
||||
- name: test and lint
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
pnpm run lint
|
||||
- name: build
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
pnpm run build
|
||||
- name: generate SSL certificate
|
||||
run: |
|
||||
echo "${{ env.SSL_CERTIFICATE }}" > nginx-signed.crt
|
||||
echo "${{ env.SSL_CERTIFICATE_KEY }}" > nginx-signed.key
|
||||
- name: Deploy to EC2
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
with:
|
||||
SSH_PRIVATE_KEY: ${{ env.SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rlgoDzvc -i"
|
||||
SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key"
|
||||
REMOTE_HOST: ${{ env.REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ env.REMOTE_USER }}
|
||||
EXCLUDE: "frontend/appflowy_web_app/dist/, frontend/appflowy_web_app/node_modules/"
|
||||
SCRIPT_AFTER: |
|
||||
docker build -t appflowy-web-app .
|
||||
docker rm -f appflowy-web-app || true
|
||||
docker run -d -p 80:80 -p 443:443 --name appflowy-web-app appflowy-web-app
|
||||
@@ -86,6 +86,7 @@ jobs:
|
||||
model: 'iPhone 15'
|
||||
shutdown_after_job: false
|
||||
|
||||
- name: Run integration tests
|
||||
working-directory: frontend/appflowy_flutter
|
||||
run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
|
||||
# enable it again if the 12 mins timeout is fixed
|
||||
# - name: Run integration tests
|
||||
# working-directory: frontend/appflowy_flutter
|
||||
# run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
|
||||
@@ -47,6 +47,7 @@ jobs:
|
||||
with:
|
||||
path: frontend/appflowy_web_app/node_modules
|
||||
key: node-modules-${{ runner.os }}
|
||||
|
||||
- name: install frontend dependencies
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
@@ -55,7 +56,19 @@ jobs:
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
pnpm run lint
|
||||
- name: build
|
||||
- name: build and analyze
|
||||
working-directory: frontend/appflowy_web_app
|
||||
run: |
|
||||
pnpm run build
|
||||
pnpm run analyze >> analyze-size.txt
|
||||
- name: Upload analyze-size.txt
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: analyze-size.txt
|
||||
path: frontend/appflowy_web_app/analyze-size.txt
|
||||
retention-days: 30
|
||||
- name: Upload stats.html
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: stats.html
|
||||
path: frontend/appflowy_web_app/dist/stats.html
|
||||
retention-days: 30
|
||||
+7
-2
@@ -1,9 +1,14 @@
|
||||
# Release Notes
|
||||
## Version 0.5.4 - 04/08/2024
|
||||
### New Features
|
||||
- TBD
|
||||
- Introduced support for displaying a synchronization indicator within documents and databases to enhance user awareness of data sync status
|
||||
- Revamped the select option cell editor in database
|
||||
- Improved translations for Spanish, German, Kurdish, and Vietnamese
|
||||
- Supported Android 6 and newer versions
|
||||
### Bug Fixes
|
||||
- TBD
|
||||
- Resolved an issue where twelve-hour time formats were not being parsed correctly in databases
|
||||
- Fixed a bug affecting the user interface of the single select option filter
|
||||
- Fixed various minor UI issues
|
||||
|
||||
## Version 0.5.3 - 03/21/2024
|
||||
### New Features
|
||||
|
||||
+9
-27
@@ -4,6 +4,7 @@ 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/openai/widgets/loading.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';
|
||||
@@ -51,33 +52,23 @@ void main() {
|
||||
await tester.expectToSeeHomePageWithGetStartedPage();
|
||||
|
||||
const name = 'AppFlowy.IO';
|
||||
// the workspace will be opened after created
|
||||
await tester.createCollaborativeWorkspace(name);
|
||||
|
||||
// see the success message
|
||||
var success = find.text(LocaleKeys.workspace_createSuccess.tr());
|
||||
expect(success, findsOneWidget);
|
||||
await tester.pumpUntilNotFound(success);
|
||||
final loading = find.byType(Loading);
|
||||
await tester.pumpUntilNotFound(loading);
|
||||
|
||||
// check the create result
|
||||
Finder success;
|
||||
|
||||
// delete the newly created workspace
|
||||
await tester.openCollaborativeWorkspaceMenu();
|
||||
var items = find.byType(WorkspaceMenuItem);
|
||||
final Finder items = find.byType(WorkspaceMenuItem);
|
||||
expect(items, findsNWidgets(2));
|
||||
expect(
|
||||
tester.widget<WorkspaceMenuItem>(items.last).workspace.name,
|
||||
name,
|
||||
);
|
||||
|
||||
// open the newly created workspace
|
||||
await tester.tapButton(items.last, milliseconds: 1000);
|
||||
success = find.text(LocaleKeys.workspace_openSuccess.tr());
|
||||
await tester.pumpUntilFound(success);
|
||||
expect(success, findsOneWidget);
|
||||
await tester.pumpUntilNotFound(success);
|
||||
|
||||
await tester.closeCollaborativeWorkspaceMenu();
|
||||
|
||||
// delete the newly created workspace
|
||||
await tester.openCollaborativeWorkspaceMenu();
|
||||
final secondWorkspace = find.byType(WorkspaceMenuItem).last;
|
||||
await tester.hoverOnWidget(
|
||||
secondWorkspace,
|
||||
@@ -97,20 +88,11 @@ void main() {
|
||||
await tester.tapButton(find.text(LocaleKeys.button_ok.tr()));
|
||||
// delete success
|
||||
success = find.text(LocaleKeys.workspace_createSuccess.tr());
|
||||
await tester.pumpUntilFound(success);
|
||||
expect(success, findsOneWidget);
|
||||
await tester.pumpUntilNotFound(success);
|
||||
},
|
||||
);
|
||||
|
||||
// check the result
|
||||
await tester.openCollaborativeWorkspaceMenu();
|
||||
items = find.byType(WorkspaceMenuItem);
|
||||
expect(items, findsOneWidget);
|
||||
expect(
|
||||
tester.widget<WorkspaceMenuItem>(items.last).workspace.name != name,
|
||||
true,
|
||||
);
|
||||
await tester.closeCollaborativeWorkspaceMenu();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -180,7 +180,11 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
buttons: buttons,
|
||||
warnIfMissed: warnIfMissed,
|
||||
);
|
||||
await pumpAndSettle(Duration(milliseconds: milliseconds));
|
||||
await pumpAndSettle(
|
||||
Duration(milliseconds: milliseconds),
|
||||
EnginePhase.sendSemanticsUpdate,
|
||||
const Duration(seconds: 5),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> tapButtonWithName(
|
||||
|
||||
@@ -528,7 +528,7 @@ extension CommonOperations on WidgetTester {
|
||||
final workspace = find.byType(SidebarWorkspace);
|
||||
expect(workspace, findsOneWidget);
|
||||
// click it
|
||||
await tapButton(workspace);
|
||||
await tapButton(workspace, milliseconds: 2000);
|
||||
}
|
||||
|
||||
Future<void> closeCollaborativeWorkspaceMenu() async {
|
||||
@@ -560,7 +560,6 @@ extension CommonOperations on WidgetTester {
|
||||
|
||||
// input the workspace name
|
||||
await enterText(find.byType(TextField), name);
|
||||
await pumpAndSettle();
|
||||
|
||||
await tapButtonWithName(LocaleKeys.button_ok.tr());
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ class AppFlowyConfiguration {
|
||||
required this.custom_app_path,
|
||||
required this.origin_app_path,
|
||||
required this.device_id,
|
||||
required this.platform,
|
||||
required this.authenticator_type,
|
||||
required this.supabase_config,
|
||||
required this.appflowy_cloud_config,
|
||||
@@ -25,6 +26,7 @@ class AppFlowyConfiguration {
|
||||
final String custom_app_path;
|
||||
final String origin_app_path;
|
||||
final String device_id;
|
||||
final String platform;
|
||||
final int authenticator_type;
|
||||
final SupabaseConfiguration supabase_config;
|
||||
final AppFlowyCloudConfiguration appflowy_cloud_config;
|
||||
|
||||
@@ -69,7 +69,7 @@ class MobileFolders extends StatelessWidget {
|
||||
...isCollaborativeWorkspace
|
||||
? [
|
||||
MobileSectionFolder(
|
||||
title: LocaleKeys.sideBar_public.tr(),
|
||||
title: LocaleKeys.sideBar_workspace.tr(),
|
||||
categoryType: FolderCategoryType.public,
|
||||
views: state.section.publicViews,
|
||||
),
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ import 'dart:io';
|
||||
|
||||
import 'package:appflowy/mobile/application/mobile_router.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_listener.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_listener.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/shared/appflowy_network_image.dart';
|
||||
import 'package:appflowy/workspace/application/view/prelude.dart';
|
||||
|
||||
+2
@@ -31,6 +31,7 @@ class MobileWorkspaceMenu extends StatelessWidget {
|
||||
final workspace = workspaces[i];
|
||||
children.add(
|
||||
_WorkspaceMenuItem(
|
||||
key: ValueKey(workspace.workspaceId),
|
||||
userProfile: userProfile,
|
||||
workspace: workspace,
|
||||
showTopBorder: i == 0,
|
||||
@@ -47,6 +48,7 @@ class MobileWorkspaceMenu extends StatelessWidget {
|
||||
|
||||
class _WorkspaceMenuItem extends StatelessWidget {
|
||||
const _WorkspaceMenuItem({
|
||||
super.key,
|
||||
required this.userProfile,
|
||||
required this.workspace,
|
||||
required this.showTopBorder,
|
||||
|
||||
+3
-3
@@ -30,9 +30,9 @@ class DatabaseSyncBloc extends Bloc<DatabaseSyncEvent, DatabaseSyncBlocState> {
|
||||
.then((value) => value.fold((s) => s, (f) => null));
|
||||
emit(
|
||||
state.copyWith(
|
||||
shouldShowIndicator:
|
||||
userProfile?.authenticator != AuthenticatorPB.Local &&
|
||||
databaseId != null,
|
||||
shouldShowIndicator: userProfile?.authenticator ==
|
||||
AuthenticatorPB.AppFlowyCloud &&
|
||||
databaseId != null,
|
||||
),
|
||||
);
|
||||
if (databaseId != null) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/grid/application/row/row_document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
|
||||
import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart';
|
||||
@@ -10,6 +8,7 @@ import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class RowDocument extends StatelessWidget {
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
// This file is "main.dart"
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'doc_awareness_metadata.freezed.dart';
|
||||
part 'doc_awareness_metadata.g.dart';
|
||||
part 'document_awareness_metadata.freezed.dart';
|
||||
part 'document_awareness_metadata.g.dart';
|
||||
|
||||
@freezed
|
||||
class DocumentAwarenessMetadata with _$DocumentAwarenessMetadata {
|
||||
+40
-10
@@ -1,12 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/plugins/document/application/doc_awareness_metadata.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_collab_adapter.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_listener.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_service.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_sync_state_listener.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_collab_adapter.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_listener.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_service.dart';
|
||||
import 'package:appflowy/plugins/document/application/editor_transaction_adapter.dart';
|
||||
import 'package:appflowy/plugins/trash/application/trash_service.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
@@ -16,7 +16,9 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:appflowy/util/color_generator/color_generator.dart';
|
||||
import 'package:appflowy/util/color_to_hex_string.dart';
|
||||
import 'package:appflowy/util/debounce.dart';
|
||||
import 'package:appflowy/util/throttle.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
@@ -35,7 +37,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'doc_bloc.freezed.dart';
|
||||
part 'document_bloc.freezed.dart';
|
||||
|
||||
class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
DocumentBloc({
|
||||
@@ -66,7 +68,12 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
StreamSubscription? _transactionSubscription;
|
||||
|
||||
final _updateSelectionDebounce = Debounce();
|
||||
final _syncDocDebounce = Debounce();
|
||||
final _syncThrottle = Throttler(duration: const Duration(milliseconds: 500));
|
||||
|
||||
// The conflict handle logic is not fully implemented yet
|
||||
// use the syncTimer to force to reload the document state when the conflict happens.
|
||||
Timer? _syncTimer;
|
||||
bool _shouldSync = false;
|
||||
|
||||
bool get isLocalMode {
|
||||
final userProfilePB = state.userProfilePB;
|
||||
@@ -81,6 +88,8 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
await _viewListener.stop();
|
||||
await _transactionSubscription?.cancel();
|
||||
await _documentService.closeDocument(view: view);
|
||||
_syncTimer?.cancel();
|
||||
_syncTimer = null;
|
||||
state.editorState?.service.keyboardService?.closeKeyboard();
|
||||
state.editorState?.dispose();
|
||||
return super.close();
|
||||
@@ -92,6 +101,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
_resetSyncTimer();
|
||||
final result = await _fetchDocumentState();
|
||||
_onViewChanged();
|
||||
_onDocumentChanged();
|
||||
@@ -155,7 +165,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
/// subscribe to the document content change
|
||||
void _onDocumentChanged() {
|
||||
_documentListener.start(
|
||||
onDocEventUpdate: _debounceSyncDoc,
|
||||
onDocEventUpdate: _throttleSyncDoc,
|
||||
onDocAwarenessUpdate: _onAwarenessStatesUpdate,
|
||||
);
|
||||
|
||||
@@ -168,6 +178,19 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
);
|
||||
}
|
||||
|
||||
void _resetSyncTimer() {
|
||||
_syncTimer?.cancel();
|
||||
_syncTimer = null;
|
||||
_syncTimer = Timer.periodic(const Duration(seconds: 10), (_) {
|
||||
if (!_shouldSync) {
|
||||
return;
|
||||
}
|
||||
Log.debug('auto sync document');
|
||||
// unawaited(_documentCollabAdapter.forceReload());
|
||||
_shouldSync = false;
|
||||
});
|
||||
}
|
||||
|
||||
/// Fetch document
|
||||
Future<FlowyResult<EditorState?, FlowyError>> _fetchDocumentState() async {
|
||||
final result = await _documentService.openDocument(viewId: view.id);
|
||||
@@ -207,6 +230,10 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
// ignore: invalid_use_of_visible_for_testing_member
|
||||
emit(state.copyWith(isDocumentEmpty: editorState.document.isEmpty));
|
||||
}
|
||||
|
||||
// reset the sync timer
|
||||
_shouldSync = true;
|
||||
_resetSyncTimer();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -267,7 +294,9 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
return;
|
||||
}
|
||||
|
||||
unawaited(_documentCollabAdapter.syncV3(docEvent));
|
||||
unawaited(_documentCollabAdapter.syncV3(docEvent: docEvent));
|
||||
|
||||
_resetSyncTimer();
|
||||
}
|
||||
|
||||
Future<void> _onAwarenessStatesUpdate(
|
||||
@@ -290,8 +319,9 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
_updateSelectionDebounce.call(_onSelectionUpdate);
|
||||
}
|
||||
|
||||
void _debounceSyncDoc(DocEventPB docEvent) {
|
||||
_syncDocDebounce.call(() {
|
||||
void _throttleSyncDoc(DocEventPB docEvent) {
|
||||
_shouldSync = true;
|
||||
_syncThrottle.call(() {
|
||||
_onDocumentStateUpdate(docEvent);
|
||||
});
|
||||
}
|
||||
+38
-4
@@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/plugins/document/application/doc_awareness_metadata.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
|
||||
import 'package:appflowy/plugins/document/application/prelude.dart';
|
||||
import 'package:appflowy/shared/list_extension.dart';
|
||||
@@ -68,7 +68,7 @@ class DocumentCollabAdapter {
|
||||
/// Sync version 3
|
||||
///
|
||||
/// Diff the local document with the remote document and apply the changes
|
||||
Future<void> syncV3(DocEventPB docEvent) async {
|
||||
Future<void> syncV3({DocEventPB? docEvent}) async {
|
||||
final result = await _service.getDocument(viewId: docId);
|
||||
final document = result.fold((s) => s.toDocument(), (f) => null);
|
||||
if (document == null) {
|
||||
@@ -77,17 +77,51 @@ class DocumentCollabAdapter {
|
||||
|
||||
final ops = diffNodes(editorState.document.root, document.root);
|
||||
if (ops.isEmpty) {
|
||||
debugPrint('[collab] received empty ops');
|
||||
Log.info('Doc diff, no changes');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('[collab] received ops: $ops');
|
||||
// Use for debugging, DO NOT REMOVE
|
||||
// prettyPrintJson(ops.map((op) => op.toJson()).toList());
|
||||
|
||||
final transaction = editorState.transaction;
|
||||
for (final op in ops) {
|
||||
transaction.add(op);
|
||||
}
|
||||
await editorState.apply(transaction, isRemote: true);
|
||||
|
||||
// Use for debugging, DO NOT REMOVE
|
||||
// assert(() {
|
||||
// final local = editorState.document.root.toJson();
|
||||
// final remote = document.root.toJson();
|
||||
// if (!const DeepCollectionEquality().equals(local, remote)) {
|
||||
// Log.error('Invalid diff status');
|
||||
// Log.error('Local: $local');
|
||||
// Log.error('Remote: $remote');
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }());
|
||||
}
|
||||
|
||||
Future<void> forceReload() async {
|
||||
final result = await _service.getDocument(viewId: docId);
|
||||
final document = result.fold((s) => s.toDocument(), (f) => null);
|
||||
if (document == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final beforeSelection = editorState.selection;
|
||||
|
||||
final clear = editorState.transaction;
|
||||
clear.deleteNodes(editorState.document.root.children);
|
||||
await editorState.apply(clear, isRemote: true);
|
||||
|
||||
final insert = editorState.transaction;
|
||||
insert.insertNodes([0], document.root.children);
|
||||
await editorState.apply(insert, isRemote: true);
|
||||
|
||||
editorState.selection = beforeSelection;
|
||||
}
|
||||
|
||||
Future<void> _syncUpdated(
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/plugins/document/application/doc_awareness_metadata.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_listener.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_listener.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/startup/tasks/device_info_task.dart';
|
||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
@@ -13,7 +13,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'doc_collaborators_bloc.freezed.dart';
|
||||
part 'document_collaborators_bloc.freezed.dart';
|
||||
|
||||
bool _filterCurrentUser = false;
|
||||
|
||||
@@ -32,7 +32,7 @@ class DocumentCollaboratorsBloc
|
||||
emit(
|
||||
state.copyWith(
|
||||
shouldShowIndicator:
|
||||
userProfile?.authenticator != AuthenticatorPB.Local,
|
||||
userProfile?.authenticator == AuthenticatorPB.AppFlowyCloud,
|
||||
),
|
||||
);
|
||||
final deviceId = ApplicationInfo.deviceId;
|
||||
File renamed without changes.
File renamed without changes.
+15
-14
@@ -8,10 +8,11 @@ import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'share_bloc.freezed.dart';
|
||||
part 'document_share_bloc.freezed.dart';
|
||||
|
||||
class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
|
||||
DocShareBloc({required this.view}) : super(const DocShareState.initial()) {
|
||||
class DocumentShareBloc extends Bloc<DocumentShareEvent, DocumentShareState> {
|
||||
DocumentShareBloc({required this.view})
|
||||
: super(const DocumentShareState.initial()) {
|
||||
on<ShareMarkdown>(_onShareMarkdown);
|
||||
}
|
||||
|
||||
@@ -19,14 +20,14 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
|
||||
|
||||
Future<void> _onShareMarkdown(
|
||||
ShareMarkdown event,
|
||||
Emitter<DocShareState> emit,
|
||||
Emitter<DocumentShareState> emit,
|
||||
) async {
|
||||
emit(const DocShareState.loading());
|
||||
emit(const DocumentShareState.loading());
|
||||
|
||||
final documentExporter = DocumentExporter(view);
|
||||
final result = await documentExporter.export(DocumentExportType.markdown);
|
||||
emit(
|
||||
DocShareState.finish(
|
||||
DocumentShareState.finish(
|
||||
result.fold(
|
||||
(markdown) =>
|
||||
FlowyResult.success(_saveMarkdownToPath(markdown, event.path)),
|
||||
@@ -45,17 +46,17 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DocShareEvent with _$DocShareEvent {
|
||||
const factory DocShareEvent.shareMarkdown(String path) = ShareMarkdown;
|
||||
const factory DocShareEvent.shareText() = ShareText;
|
||||
const factory DocShareEvent.shareLink() = ShareLink;
|
||||
class DocumentShareEvent with _$DocumentShareEvent {
|
||||
const factory DocumentShareEvent.shareMarkdown(String path) = ShareMarkdown;
|
||||
const factory DocumentShareEvent.shareText() = ShareText;
|
||||
const factory DocumentShareEvent.shareLink() = ShareLink;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DocShareState with _$DocShareState {
|
||||
const factory DocShareState.initial() = _Initial;
|
||||
const factory DocShareState.loading() = _Loading;
|
||||
const factory DocShareState.finish(
|
||||
class DocumentShareState with _$DocumentShareState {
|
||||
const factory DocumentShareState.initial() = _Initial;
|
||||
const factory DocumentShareState.loading() = _Loading;
|
||||
const factory DocumentShareState.finish(
|
||||
FlowyResult<ExportDataPB, FlowyError> successOrFail,
|
||||
) = _Finish;
|
||||
}
|
||||
+2
-2
@@ -11,7 +11,7 @@ import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'doc_sync_bloc.freezed.dart';
|
||||
part 'document_sync_bloc.freezed.dart';
|
||||
|
||||
class DocumentSyncBloc extends Bloc<DocumentSyncEvent, DocumentSyncBlocState> {
|
||||
DocumentSyncBloc({
|
||||
@@ -31,7 +31,7 @@ class DocumentSyncBloc extends Bloc<DocumentSyncEvent, DocumentSyncBlocState> {
|
||||
emit(
|
||||
state.copyWith(
|
||||
shouldShowIndicator:
|
||||
userProfile?.authenticator != AuthenticatorPB.Local,
|
||||
userProfile?.authenticator == AuthenticatorPB.AppFlowyCloud,
|
||||
),
|
||||
);
|
||||
_syncStateListener.start(
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/plugins/document/application/doc_service.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart'
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export 'doc_bloc.dart';
|
||||
export 'doc_service.dart';
|
||||
export 'share_bloc.dart';
|
||||
export 'document_bloc.dart';
|
||||
export 'document_service.dart';
|
||||
export 'document_share_bloc.dart';
|
||||
@@ -145,7 +145,7 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
|
||||
? [
|
||||
DocumentCollaborators(
|
||||
key: ValueKey('collaborators_${view.id}'),
|
||||
width: 100,
|
||||
width: 150,
|
||||
height: 32,
|
||||
view: view,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/banner.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_notification.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
|
||||
@@ -39,17 +39,12 @@ class _DocumentPageState extends State<DocumentPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// The appflowy editor use Intl as localization, set the default language as fallback.
|
||||
Intl.defaultLocale = 'en_US';
|
||||
|
||||
EditorNotification.addListener(_onEditorNotification);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
EditorNotification.removeListener(_onEditorNotification);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
+6
-17
@@ -13,6 +13,7 @@ class CollaboratorAvatarStack extends StatelessWidget {
|
||||
this.borderWidth,
|
||||
this.borderColor,
|
||||
this.backgroundColor,
|
||||
required this.plusWidgetBuilder,
|
||||
});
|
||||
|
||||
final List<Widget> avatars;
|
||||
@@ -31,13 +32,16 @@ class CollaboratorAvatarStack extends StatelessWidget {
|
||||
|
||||
final Color? backgroundColor;
|
||||
|
||||
final Widget Function(int value, BorderSide border) plusWidgetBuilder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = this.settings ??
|
||||
RestrictedPositions(
|
||||
maxCoverage: 0.3,
|
||||
minCoverage: 0.1,
|
||||
minCoverage: 0.2,
|
||||
align: StackAlign.right,
|
||||
laying: StackLaying.first,
|
||||
);
|
||||
|
||||
final border = BorderSide(
|
||||
@@ -45,27 +49,12 @@ class CollaboratorAvatarStack extends StatelessWidget {
|
||||
width: borderWidth ?? 2.0,
|
||||
);
|
||||
|
||||
Widget textInfoWidgetBuilder(surplus) => BorderedCircleAvatar(
|
||||
border: border,
|
||||
backgroundColor: backgroundColor,
|
||||
child: FittedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'+$surplus',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final infoWidgetBuilder = this.infoWidgetBuilder ?? textInfoWidgetBuilder;
|
||||
|
||||
return SizedBox(
|
||||
height: height,
|
||||
width: width,
|
||||
child: WidgetStack(
|
||||
positions: settings,
|
||||
buildInfoWidget: infoWidgetBuilder,
|
||||
buildInfoWidget: (value) => plusWidgetBuilder(value, border),
|
||||
stackedWidgets: avatars
|
||||
.map(
|
||||
(avatar) => CircleAvatar(
|
||||
|
||||
+26
-3
@@ -1,7 +1,8 @@
|
||||
import 'package:appflowy/plugins/document/application/doc_collaborators_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_collaborators_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/collaborator_avater_stack.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:avatar_stack/avatar_stack.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -41,8 +42,30 @@ class DocumentCollaborators extends StatelessWidget {
|
||||
height: height,
|
||||
width: width,
|
||||
borderWidth: 1.0,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
plusWidgetBuilder: (value, border) {
|
||||
final lastXCollaborators = collaborators.sublist(
|
||||
collaborators.length - value,
|
||||
);
|
||||
return BorderedCircleAvatar(
|
||||
border: border,
|
||||
backgroundColor: Theme.of(context).hoverColor,
|
||||
child: FittedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: FlowyTooltip(
|
||||
message: lastXCollaborators
|
||||
.map((e) => e.userName)
|
||||
.join('\n'),
|
||||
child: FlowyText(
|
||||
'+$value',
|
||||
fontSize: fontSize,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
avatars: collaborators
|
||||
.map(
|
||||
(c) => FlowyTooltip(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/align_toolbar_item/custom_text_align_command.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/background_color/theme_background_color.dart';
|
||||
|
||||
+5
-3
@@ -1,5 +1,7 @@
|
||||
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/material.dart';
|
||||
|
||||
final List<CommandShortcutEvent> customTextAlignCommands = [
|
||||
@@ -19,7 +21,7 @@ final List<CommandShortcutEvent> customTextAlignCommands = [
|
||||
final CommandShortcutEvent customTextLeftAlignCommand = CommandShortcutEvent(
|
||||
key: 'Align text to the left',
|
||||
command: 'ctrl+shift+l',
|
||||
getDescription: () => 'Align text to the left',
|
||||
getDescription: LocaleKeys.settings_shortcuts_commands_textAlignLeft.tr,
|
||||
handler: (editorState) => _textAlignHandler(editorState, leftAlignmentKey),
|
||||
);
|
||||
|
||||
@@ -34,7 +36,7 @@ final CommandShortcutEvent customTextLeftAlignCommand = CommandShortcutEvent(
|
||||
final CommandShortcutEvent customTextCenterAlignCommand = CommandShortcutEvent(
|
||||
key: 'Align text to the center',
|
||||
command: 'ctrl+shift+e',
|
||||
getDescription: () => 'Align text to the center',
|
||||
getDescription: LocaleKeys.settings_shortcuts_commands_textAlignCenter.tr,
|
||||
handler: (editorState) => _textAlignHandler(editorState, centerAlignmentKey),
|
||||
);
|
||||
|
||||
@@ -49,7 +51,7 @@ final CommandShortcutEvent customTextCenterAlignCommand = CommandShortcutEvent(
|
||||
final CommandShortcutEvent customTextRightAlignCommand = CommandShortcutEvent(
|
||||
key: 'Align text to the right',
|
||||
command: 'ctrl+shift+r',
|
||||
getDescription: () => 'Align text to the right',
|
||||
getDescription: LocaleKeys.settings_shortcuts_commands_textAlignRight.tr,
|
||||
handler: (editorState) => _textAlignHandler(editorState, rightAlignmentKey),
|
||||
);
|
||||
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart' show LocaleKeys;
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart'
|
||||
show StringTranslateExtension;
|
||||
import 'package:easy_localization/easy_localization.dart' hide TextDirection;
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@@ -49,7 +52,7 @@ Node calloutNode({
|
||||
|
||||
// defining the callout block menu item in selection menu
|
||||
SelectionMenuItem calloutItem = SelectionMenuItem.node(
|
||||
getName: () => LocaleKeys.document_plugins_callout.tr(),
|
||||
getName: LocaleKeys.document_plugins_callout.tr,
|
||||
iconData: Icons.note,
|
||||
keywords: [CalloutBlockKeys.type],
|
||||
nodeBuilder: (editorState, context) =>
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ Node codeBlockNode({
|
||||
|
||||
// defining the callout block menu item for selection
|
||||
SelectionMenuItem codeBlockItem = SelectionMenuItem.node(
|
||||
getName: () => LocaleKeys.document_selectionMenu_codeBlock.tr(),
|
||||
getName: LocaleKeys.document_selectionMenu_codeBlock.tr,
|
||||
iconData: Icons.abc,
|
||||
keywords: ['code', 'codeblock'],
|
||||
nodeBuilder: (editorState, _) => codeBlockNode(),
|
||||
|
||||
+10
-5
@@ -1,5 +1,7 @@
|
||||
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/material.dart';
|
||||
|
||||
final List<CharacterShortcutEvent> codeBlockCharacterEvents = [
|
||||
@@ -59,7 +61,8 @@ final CommandShortcutEvent insertNewParagraphNextToCodeBlockCommand =
|
||||
CommandShortcutEvent(
|
||||
key: 'insert a new paragraph next to the code block',
|
||||
command: 'shift+enter',
|
||||
getDescription: () => 'Insert a new paragraph next to the code block',
|
||||
getDescription:
|
||||
LocaleKeys.settings_shortcuts_commands_codeBlockNewParagraph.tr,
|
||||
handler: _insertNewParagraphNextToCodeBlockCommandHandler,
|
||||
);
|
||||
|
||||
@@ -72,7 +75,8 @@ final CommandShortcutEvent tabToInsertSpacesInCodeBlockCommand =
|
||||
CommandShortcutEvent(
|
||||
key: 'tab to insert two spaces at the line start in code block',
|
||||
command: 'tab',
|
||||
getDescription: () => 'Insert two spaces at the line start in code block',
|
||||
getDescription:
|
||||
LocaleKeys.settings_shortcuts_commands_codeBlockAddTwoSpaces.tr,
|
||||
handler: _tabToInsertSpacesInCodeBlockCommandHandler,
|
||||
);
|
||||
|
||||
@@ -85,7 +89,8 @@ final CommandShortcutEvent tabToDeleteSpacesInCodeBlockCommand =
|
||||
CommandShortcutEvent(
|
||||
key: 'shift + tab to delete two spaces at the line start in code block',
|
||||
command: 'shift+tab',
|
||||
getDescription: () => 'Delete two spaces at the line start in code block',
|
||||
getDescription:
|
||||
LocaleKeys.settings_shortcuts_commands_codeBlockDeleteTwoSpaces.tr,
|
||||
handler: _tabToDeleteSpacesInCodeBlockCommandHandler,
|
||||
);
|
||||
|
||||
@@ -98,7 +103,7 @@ final CommandShortcutEvent selectAllInCodeBlockCommand = CommandShortcutEvent(
|
||||
key: 'ctrl + a to select all content inside a code block',
|
||||
command: 'ctrl+a',
|
||||
macOSCommand: 'meta+a',
|
||||
getDescription: () => 'Select all content inside a code block',
|
||||
getDescription: LocaleKeys.settings_shortcuts_commands_codeBlockSelectAll.tr,
|
||||
handler: _selectAllInCodeBlockCommandHandler,
|
||||
);
|
||||
|
||||
@@ -111,7 +116,7 @@ final CommandShortcutEvent pasteInCodeblock = CommandShortcutEvent(
|
||||
key: 'paste in codeblock',
|
||||
command: 'ctrl+v',
|
||||
macOSCommand: 'cmd+v',
|
||||
getDescription: () => 'Paste text in codeblock',
|
||||
getDescription: LocaleKeys.settings_shortcuts_commands_codeBlockPasteText.tr,
|
||||
handler: _pasteInCodeBlock,
|
||||
);
|
||||
|
||||
|
||||
+3
-3
@@ -6,15 +6,15 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
final List<List<ContextMenuItem>> customContextMenuItems = [
|
||||
[
|
||||
ContextMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_contextMenu_copy.tr(),
|
||||
getName: LocaleKeys.document_plugins_contextMenu_copy.tr,
|
||||
onPressed: (editorState) => customCopyCommand.execute(editorState),
|
||||
),
|
||||
ContextMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_contextMenu_paste.tr(),
|
||||
getName: LocaleKeys.document_plugins_contextMenu_paste.tr,
|
||||
onPressed: (editorState) => customPasteCommand.execute(editorState),
|
||||
),
|
||||
ContextMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_contextMenu_cut.tr(),
|
||||
getName: LocaleKeys.document_plugins_contextMenu_cut.tr,
|
||||
onPressed: (editorState) => customCutCommand.execute(editorState),
|
||||
),
|
||||
],
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@ import 'package:flutter/material.dart';
|
||||
/// - mobile
|
||||
///
|
||||
final CommandShortcutEvent customCopyCommand = CommandShortcutEvent(
|
||||
key: 'copy the selected content (with formatting)',
|
||||
getDescription: () => 'copy the selected content (with formatting)',
|
||||
key: 'copy the selected content',
|
||||
getDescription: () => AppFlowyEditorL10n.current.cmdCopySelection,
|
||||
command: 'ctrl+c',
|
||||
macOSCommand: 'cmd+c',
|
||||
handler: _copyCommandHandler,
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ import 'package:flutter/material.dart';
|
||||
/// - mobile
|
||||
///
|
||||
final CommandShortcutEvent customCutCommand = CommandShortcutEvent(
|
||||
key: 'cut the selected content (with formatting)',
|
||||
getDescription: () => 'cut the selected content (with formatting)',
|
||||
key: 'cut the selected content',
|
||||
getDescription: () => AppFlowyEditorL10n.current.cmdCutSelection,
|
||||
command: 'ctrl+x',
|
||||
macOSCommand: 'cmd+x',
|
||||
handler: _cutCommandHandler,
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ import 'package:string_validator/string_validator.dart';
|
||||
/// - mobile
|
||||
///
|
||||
final CommandShortcutEvent customPasteCommand = CommandShortcutEvent(
|
||||
key: 'paste the content (with formatting)',
|
||||
getDescription: () => 'paste the content (with formatting)',
|
||||
key: 'paste the content',
|
||||
getDescription: () => AppFlowyEditorL10n.current.cmdPasteContent,
|
||||
command: 'ctrl+v',
|
||||
macOSCommand: 'cmd+v',
|
||||
handler: _pasteCommandHandler,
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
|
||||
|
||||
+4
-5
@@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/insert_page_command.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||
@@ -10,7 +10,7 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
SelectionMenuItem inlineGridMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
|
||||
getName: LocaleKeys.document_slashMenu_grid_createANewGrid.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.grid_s,
|
||||
isSelected: onSelected,
|
||||
@@ -31,7 +31,7 @@ SelectionMenuItem inlineGridMenuItem(DocumentBloc documentBloc) =>
|
||||
|
||||
SelectionMenuItem inlineBoardMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
|
||||
getName: LocaleKeys.document_slashMenu_board_createANewBoard.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.board_s,
|
||||
isSelected: onSelected,
|
||||
@@ -52,8 +52,7 @@ SelectionMenuItem inlineBoardMenuItem(DocumentBloc documentBloc) =>
|
||||
|
||||
SelectionMenuItem inlineCalendarMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
getName: () =>
|
||||
LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr(),
|
||||
getName: LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.date_s,
|
||||
isSelected: onSelected,
|
||||
|
||||
+4
-4
@@ -9,7 +9,7 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
// Document Reference
|
||||
|
||||
SelectionMenuItem referencedDocumentMenuItem = SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_referencedDocument.tr(),
|
||||
getName: LocaleKeys.document_plugins_referencedDocument.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.document_s,
|
||||
isSelected: onSelected,
|
||||
@@ -23,7 +23,7 @@ SelectionMenuItem referencedDocumentMenuItem = SelectionMenuItem(
|
||||
// Database References
|
||||
|
||||
SelectionMenuItem referencedGridMenuItem = SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_referencedGrid.tr(),
|
||||
getName: LocaleKeys.document_plugins_referencedGrid.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.grid_s,
|
||||
isSelected: onSelected,
|
||||
@@ -35,7 +35,7 @@ SelectionMenuItem referencedGridMenuItem = SelectionMenuItem(
|
||||
);
|
||||
|
||||
SelectionMenuItem referencedBoardMenuItem = SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_referencedBoard.tr(),
|
||||
getName: LocaleKeys.document_plugins_referencedBoard.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.board_s,
|
||||
isSelected: onSelected,
|
||||
@@ -47,7 +47,7 @@ SelectionMenuItem referencedBoardMenuItem = SelectionMenuItem(
|
||||
);
|
||||
|
||||
SelectionMenuItem referencedCalendarMenuItem = SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_referencedCalendar.tr(),
|
||||
getName: LocaleKeys.document_plugins_referencedCalendar.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
data: FlowySvgs.date_s,
|
||||
isSelected: onSelected,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ Node mathEquationNode({
|
||||
|
||||
// defining the callout block menu item for selection
|
||||
SelectionMenuItem mathEquationItem = SelectionMenuItem.node(
|
||||
getName: () => LocaleKeys.document_plugins_mathEquation_name.tr(),
|
||||
getName: LocaleKeys.document_plugins_mathEquation_name.tr,
|
||||
iconData: Icons.text_fields_rounded,
|
||||
keywords: ['tex, latex, katex', 'math equation', 'formula'],
|
||||
nodeBuilder: (editorState, _) => mathEquationNode(),
|
||||
|
||||
+4
-5
@@ -1,11 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/base/drag_handler.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
||||
import 'package:appflowy/user/application/reminder/reminder_extension.dart';
|
||||
@@ -27,6 +25,7 @@ import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:nanoid/non_secure.dart';
|
||||
|
||||
@@ -258,11 +257,11 @@ class _MentionDateBlockState extends State<MentionDateBlock> {
|
||||
}
|
||||
|
||||
DateTime _parseTime(String timeStr, UserTimeFormatPB timeFormat) {
|
||||
final twelveHourFormat = DateFormat('HH:mm a');
|
||||
final twelveHourFormat = DateFormat('hh:mm a');
|
||||
final twentyFourHourFormat = DateFormat('HH:mm');
|
||||
|
||||
try {
|
||||
if (timeFormat == TimeFormatPB.TwelveHour) {
|
||||
if (timeFormat == UserTimeFormatPB.TwelveHour) {
|
||||
return twelveHourFormat.parseStrict(timeStr);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
SelectionMenuItem dateMenuItem = SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_date.tr(),
|
||||
getName: LocaleKeys.document_plugins_insertDate.tr,
|
||||
icon: (_, isSelected, style) => FlowySvg(
|
||||
FlowySvgs.date_s,
|
||||
color: isSelected
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ Node autoCompletionNode({
|
||||
}
|
||||
|
||||
SelectionMenuItem autoGeneratorMenuItem = SelectionMenuItem.node(
|
||||
getName: () => LocaleKeys.document_plugins_autoGeneratorMenuItemName.tr(),
|
||||
getName: LocaleKeys.document_plugins_autoGeneratorMenuItemName.tr,
|
||||
iconData: Icons.generating_tokens,
|
||||
keywords: ['ai', 'openai' 'writer', 'autogenerator'],
|
||||
nodeBuilder: (editorState, _) {
|
||||
|
||||
+7
-2
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
||||
class Loading {
|
||||
Loading(this.context);
|
||||
|
||||
late BuildContext loadingContext;
|
||||
BuildContext? loadingContext;
|
||||
final BuildContext context;
|
||||
|
||||
Future<void> start() async => showDialog<void>(
|
||||
@@ -24,7 +24,12 @@ class Loading {
|
||||
},
|
||||
);
|
||||
|
||||
Future<void> stop() async => Navigator.of(loadingContext).pop();
|
||||
Future<void> stop() async {
|
||||
if (loadingContext != null) {
|
||||
Navigator.of(loadingContext!).pop();
|
||||
loadingContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BarrierDialog {
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class OutlineBlockKeys {
|
||||
|
||||
// defining the callout block menu item for selection
|
||||
SelectionMenuItem outlineItem = SelectionMenuItem.node(
|
||||
getName: () => LocaleKeys.document_selectionMenu_outline.tr(),
|
||||
getName: LocaleKeys.document_selectionMenu_outline.tr,
|
||||
iconData: Icons.list_alt,
|
||||
keywords: ['outline', 'table of contents'],
|
||||
nodeBuilder: (editorState, _) => outlineBlockNode(),
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ Node toggleListBlockNode({
|
||||
|
||||
// defining the toggle list block menu item
|
||||
SelectionMenuItem toggleListBlockItem = SelectionMenuItem.node(
|
||||
getName: () => LocaleKeys.document_plugins_toggleList.tr(),
|
||||
getName: LocaleKeys.document_plugins_toggleList.tr,
|
||||
iconData: Icons.arrow_right,
|
||||
keywords: ['collapsed list', 'toggle list', 'list'],
|
||||
nodeBuilder: (editorState, _) => toggleListBlockNode(),
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ CharacterShortcutEvent insertChildNodeInsideToggleList = CharacterShortcutEvent(
|
||||
// toggle the todo list
|
||||
final CommandShortcutEvent toggleToggleListCommand = CommandShortcutEvent(
|
||||
key: 'toggle the toggle list',
|
||||
getDescription: () => 'Toggle the toggle list',
|
||||
getDescription: () => AppFlowyEditorL10n.current.cmdToggleTodoList,
|
||||
command: 'ctrl+enter',
|
||||
macOSCommand: 'cmd+enter',
|
||||
handler: _toggleToggleListCommandHandler,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/application/share_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_share_bloc.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/util/string_extension.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||
@@ -14,6 +12,7 @@ import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/file_picker/file_picker_service.dart';
|
||||
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DocumentShareButton extends StatelessWidget {
|
||||
@@ -27,8 +26,8 @@ class DocumentShareButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<DocShareBloc>(param1: view),
|
||||
child: BlocListener<DocShareBloc, DocShareState>(
|
||||
create: (context) => getIt<DocumentShareBloc>(param1: view),
|
||||
child: BlocListener<DocumentShareBloc, DocumentShareState>(
|
||||
listener: (context, state) {
|
||||
state.mapOrNull(
|
||||
finish: (state) {
|
||||
@@ -39,7 +38,7 @@ class DocumentShareButton extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
},
|
||||
child: BlocBuilder<DocShareBloc, DocShareState>(
|
||||
child: BlocBuilder<DocumentShareBloc, DocumentShareState>(
|
||||
builder: (context, state) => ConstrainedBox(
|
||||
constraints: const BoxConstraints.expand(
|
||||
height: 30,
|
||||
@@ -102,7 +101,7 @@ class ShareActionListState extends State<ShareActionList> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final docShareBloc = context.read<DocShareBloc>();
|
||||
final docShareBloc = context.read<DocumentShareBloc>();
|
||||
return PopoverActionList<ShareActionWrapper>(
|
||||
direction: PopoverDirection.bottomWithCenterAligned,
|
||||
offset: const Offset(0, 8),
|
||||
@@ -126,7 +125,7 @@ class ShareActionListState extends State<ShareActionList> {
|
||||
fileName: '${name.toFileName()}.md',
|
||||
);
|
||||
if (exportPath != null) {
|
||||
docShareBloc.add(DocShareEvent.shareMarkdown(exportPath));
|
||||
docShareBloc.add(DocumentShareEvent.shareMarkdown(exportPath));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/date/date_service.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/string_extension.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||
@@ -14,6 +12,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:nanoid/nanoid.dart';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/application/sync/database_sync_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_sync_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_sync_bloc.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:appflowy/core/config/kv.dart';
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
typedef FeatureFlagMap = Map<FeatureFlag, bool>;
|
||||
|
||||
@@ -83,14 +84,18 @@ enum FeatureFlag {
|
||||
bool get isOn {
|
||||
// release this feature in version 0.5.4
|
||||
if ([
|
||||
FeatureFlag.collaborativeWorkspace,
|
||||
FeatureFlag.membersSettings,
|
||||
// FeatureFlag.collaborativeWorkspace,
|
||||
// FeatureFlag.membersSettings,
|
||||
FeatureFlag.syncDatabase,
|
||||
FeatureFlag.syncDocument,
|
||||
].contains(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (kReleaseMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_values.containsKey(this)) {
|
||||
return _values[this]!;
|
||||
}
|
||||
|
||||
@@ -189,8 +189,8 @@ void _resolveHomeDeps(GetIt getIt) {
|
||||
);
|
||||
|
||||
// share
|
||||
getIt.registerFactoryParam<DocShareBloc, ViewPB, void>(
|
||||
(view, _) => DocShareBloc(view: view),
|
||||
getIt.registerFactoryParam<DocumentShareBloc, ViewPB, void>(
|
||||
(view, _) => DocumentShareBloc(view: view),
|
||||
);
|
||||
|
||||
getIt.registerSingleton<NotificationActionBloc>(NotificationActionBloc());
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:appflowy/env/backend_env.dart';
|
||||
import 'package:appflowy/env/cloud_env.dart';
|
||||
import 'package:appflowy/user/application/auth/device_id.dart';
|
||||
import 'package:appflowy_backend/appflowy_backend.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
@@ -28,6 +29,7 @@ class InitRustSDKTask extends LaunchTask {
|
||||
final dir = customApplicationPath ?? applicationPath;
|
||||
final deviceId = await getDeviceId();
|
||||
|
||||
debugPrint('application path: ${applicationPath.path}');
|
||||
// Pass the environment variables to the Rust SDK
|
||||
final env = _makeAppFlowyConfiguration(
|
||||
root.path,
|
||||
@@ -59,6 +61,7 @@ AppFlowyConfiguration _makeAppFlowyConfiguration(
|
||||
custom_app_path: customAppPath,
|
||||
origin_app_path: originAppPath,
|
||||
device_id: deviceId,
|
||||
platform: Platform.operatingSystem,
|
||||
authenticator_type: env.authenticatorType.value,
|
||||
supabase_config: env.supabaseConfig,
|
||||
appflowy_cloud_config: env.appflowyCloudConfig,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Debounce {
|
||||
Debounce({
|
||||
this.duration = const Duration(milliseconds: 1000),
|
||||
@@ -10,8 +8,9 @@ class Debounce {
|
||||
final Duration duration;
|
||||
Timer? _timer;
|
||||
|
||||
void call(VoidCallback action) {
|
||||
void call(Function action) {
|
||||
dispose();
|
||||
|
||||
_timer = Timer(duration, () {
|
||||
action();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'dart:async';
|
||||
|
||||
class Throttler {
|
||||
Throttler({
|
||||
this.duration = const Duration(milliseconds: 1000),
|
||||
});
|
||||
|
||||
final Duration duration;
|
||||
Timer? _timer;
|
||||
|
||||
void call(Function callback) {
|
||||
if (_timer?.isActive ?? false) return;
|
||||
|
||||
_timer = Timer(duration, () {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||
import 'package:appflowy/workspace/application/workspace/workspace_sections_listener.dart';
|
||||
import 'package:appflowy/workspace/application/workspace/workspace_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
@@ -152,6 +156,37 @@ class SidebarSectionsBloc
|
||||
},
|
||||
);
|
||||
},
|
||||
reload: (userProfile, workspaceId) async {
|
||||
_initial(userProfile, workspaceId);
|
||||
final sectionViews = await _getSectionViews();
|
||||
if (sectionViews != null) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
section: sectionViews,
|
||||
),
|
||||
);
|
||||
// try to open the fist view in public section or private section
|
||||
if (sectionViews.publicViews.isNotEmpty) {
|
||||
getIt<TabsBloc>().add(
|
||||
TabsEvent.openPlugin(
|
||||
plugin: sectionViews.publicViews.first.plugin(),
|
||||
),
|
||||
);
|
||||
} else if (sectionViews.privateViews.isNotEmpty) {
|
||||
getIt<TabsBloc>().add(
|
||||
TabsEvent.openPlugin(
|
||||
plugin: sectionViews.privateViews.first.plugin(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
getIt<TabsBloc>().add(
|
||||
TabsEvent.openPlugin(
|
||||
plugin: makePlugin(pluginType: PluginType.blank),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -245,6 +280,10 @@ class SidebarSectionsEvent with _$SidebarSectionsEvent {
|
||||
const factory SidebarSectionsEvent.receiveSectionViewsUpdate(
|
||||
SectionViewsPB sectionViews,
|
||||
) = _ReceiveSectionViewsUpdate;
|
||||
const factory SidebarSectionsEvent.reload(
|
||||
UserProfilePB userProfile,
|
||||
String workspaceId,
|
||||
) = _Reload;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
+5
@@ -10,6 +10,8 @@ import 'package:appflowy/workspace/application/settings/appearance/base_appearan
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/date_time.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart'
|
||||
show AppFlowyEditorLocalizations;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -193,6 +195,9 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
Log.warn('Catch error in setLocale: $e}');
|
||||
});
|
||||
|
||||
// Sync the app's locale with the editor (initialization and update)
|
||||
AppFlowyEditorLocalizations.load(newLocale);
|
||||
|
||||
if (state.locale != newLocale) {
|
||||
_appearanceSettings.locale.languageCode = newLocale.languageCode;
|
||||
_appearanceSettings.locale.countryCode = newLocale.countryCode ?? "";
|
||||
|
||||
+2
@@ -39,8 +39,10 @@ class ShortcutsCubit extends Cubit<ShortcutsState> {
|
||||
commandShortcutEvents,
|
||||
customizeShortcuts,
|
||||
);
|
||||
|
||||
//sort the shortcuts
|
||||
commandShortcutEvents.sort((a, b) => a.key.compareTo(b.key));
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ShortcutsStatus.success,
|
||||
|
||||
@@ -40,7 +40,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
final currentWorkspace = result.$1;
|
||||
final workspaces = result.$2;
|
||||
final isCollabWorkspaceOn =
|
||||
userProfile.authenticator != AuthenticatorPB.Local &&
|
||||
userProfile.authenticator == AuthenticatorPB.AppFlowyCloud &&
|
||||
FeatureFlag.collaborativeWorkspace.isOn;
|
||||
if (currentWorkspace != null && result.$3 == true) {
|
||||
final result = await _userService
|
||||
@@ -71,6 +71,15 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
);
|
||||
},
|
||||
createWorkspace: (name) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
actionResult: const UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.create,
|
||||
isLoading: true,
|
||||
result: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
final result = await _userService.createUserWorkspace(name);
|
||||
final workspaces = result.fold(
|
||||
(s) => [...state.workspaces, s],
|
||||
@@ -81,6 +90,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
workspaces: workspaces,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.create,
|
||||
isLoading: false,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
@@ -91,6 +101,15 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
});
|
||||
},
|
||||
deleteWorkspace: (workspaceId) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
actionResult: const UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.delete,
|
||||
isLoading: true,
|
||||
result: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
final remoteWorkspaces = await _fetchWorkspaces().then(
|
||||
(value) => value.$2,
|
||||
);
|
||||
@@ -108,6 +127,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.delete,
|
||||
result: result,
|
||||
isLoading: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -134,11 +154,21 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.delete,
|
||||
result: result,
|
||||
isLoading: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
openWorkspace: (workspaceId) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
actionResult: const UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.open,
|
||||
isLoading: true,
|
||||
result: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
final result = await _userService.openWorkspace(workspaceId);
|
||||
final currentWorkspace = result.fold(
|
||||
(s) => state.workspaces.firstWhereOrNull(
|
||||
@@ -157,6 +187,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
currentWorkspace: currentWorkspace,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.open,
|
||||
isLoading: false,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
@@ -188,6 +219,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
currentWorkspace: currentWorkspace,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.rename,
|
||||
isLoading: false,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
@@ -221,6 +253,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
currentWorkspace: currentWorkspace,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.updateIcon,
|
||||
isLoading: false,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
@@ -245,6 +278,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
workspaces: workspaces,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.leave,
|
||||
isLoading: false,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
@@ -253,7 +287,11 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
updateWorkspaces: (workspaces) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
workspaces: workspaces.items,
|
||||
workspaces: workspaces.items
|
||||
..sort(
|
||||
(a, b) =>
|
||||
a.createdAtTimestamp.compareTo(b.createdAtTimestamp),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -359,11 +397,13 @@ enum UserWorkspaceActionType {
|
||||
class UserWorkspaceActionResult {
|
||||
const UserWorkspaceActionResult({
|
||||
required this.actionType,
|
||||
required this.isLoading,
|
||||
required this.result,
|
||||
});
|
||||
|
||||
final UserWorkspaceActionType actionType;
|
||||
final FlowyResult<void, FlowyError> result;
|
||||
final bool isLoading;
|
||||
final FlowyResult<void, FlowyError>? result;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -6,11 +6,8 @@ import 'package:appflowy/plugins/database/grid/presentation/mobile_grid_page.dar
|
||||
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
|
||||
import 'package:appflowy/plugins/document/document.dart';
|
||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum FlowyPlugin {
|
||||
@@ -84,29 +81,6 @@ extension ViewExtension on ViewPB {
|
||||
};
|
||||
|
||||
FlowySvgData get iconData => layout.icon;
|
||||
|
||||
Future<List<ViewPB>> getAncestors({
|
||||
bool includeSelf = false,
|
||||
bool includeRoot = false,
|
||||
}) async {
|
||||
final ancestors = <ViewPB>[];
|
||||
if (includeSelf) {
|
||||
final self = await ViewBackendService.getView(id);
|
||||
ancestors.add(self.fold((s) => s, (e) => this));
|
||||
}
|
||||
FlowyResult<ViewPB, FlowyError> parent =
|
||||
await ViewBackendService.getView(parentViewId);
|
||||
while (parent.isSuccess) {
|
||||
// parent is not null
|
||||
final view = parent.fold((s) => s, (e) => null);
|
||||
if (view == null || (!includeRoot && view.parentViewId.isEmpty)) {
|
||||
break;
|
||||
}
|
||||
ancestors.add(view);
|
||||
parent = await ViewBackendService.getView(view.parentViewId);
|
||||
}
|
||||
return ancestors.reversed.toList();
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewLayoutExtension on ViewLayoutPB {
|
||||
|
||||
@@ -260,12 +260,19 @@ class ViewBackendService {
|
||||
}
|
||||
|
||||
static Future<FlowyResult<ViewPB, FlowyError>> getView(
|
||||
String viewID,
|
||||
String viewId,
|
||||
) async {
|
||||
final payload = ViewIdPB.create()..value = viewID;
|
||||
final payload = ViewIdPB.create()..value = viewId;
|
||||
return FolderEventGetView(payload).send();
|
||||
}
|
||||
|
||||
static Future<FlowyResult<RepeatedViewPB, FlowyError>> getViewAncestors(
|
||||
String viewId,
|
||||
) async {
|
||||
final payload = ViewIdPB.create()..value = viewId;
|
||||
return FolderEventGetViewAncestors(payload).send();
|
||||
}
|
||||
|
||||
Future<FlowyResult<ViewPB, FlowyError>> getChildView({
|
||||
required String parentViewId,
|
||||
required String childViewId,
|
||||
|
||||
+16
-16
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/prelude.dart';
|
||||
@@ -106,21 +105,22 @@ class HomeSideBar extends StatelessWidget {
|
||||
),
|
||||
BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
|
||||
listener: (context, state) {
|
||||
context.read<TabsBloc>().add(
|
||||
TabsEvent.openPlugin(
|
||||
plugin: makePlugin(pluginType: PluginType.blank),
|
||||
),
|
||||
);
|
||||
context.read<SidebarSectionsBloc>().add(
|
||||
SidebarSectionsEvent.initial(
|
||||
userProfile,
|
||||
state.currentWorkspace?.workspaceId ??
|
||||
workspaceSetting.workspaceId,
|
||||
),
|
||||
);
|
||||
context.read<FavoriteBloc>().add(
|
||||
const FavoriteEvent.fetchFavorites(),
|
||||
);
|
||||
final actionType = state.actionResult?.actionType;
|
||||
|
||||
if (actionType == UserWorkspaceActionType.create ||
|
||||
actionType == UserWorkspaceActionType.delete ||
|
||||
actionType == UserWorkspaceActionType.open) {
|
||||
context.read<SidebarSectionsBloc>().add(
|
||||
SidebarSectionsEvent.reload(
|
||||
userProfile,
|
||||
state.currentWorkspace?.workspaceId ??
|
||||
workspaceSetting.workspaceId,
|
||||
),
|
||||
);
|
||||
context.read<FavoriteBloc>().add(
|
||||
const FavoriteEvent.fetchFavorites(),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
+3
-3
@@ -103,10 +103,10 @@ class PublicSectionFolder extends SectionFolder {
|
||||
super.key,
|
||||
required super.views,
|
||||
}) : super(
|
||||
title: LocaleKeys.sideBar_public.tr(),
|
||||
title: LocaleKeys.sideBar_workspace.tr(),
|
||||
categoryType: FolderCategoryType.public,
|
||||
expandButtonTooltip: LocaleKeys.sideBar_clickToHidePublic.tr(),
|
||||
addButtonTooltip: LocaleKeys.sideBar_addAPageToPublic.tr(),
|
||||
expandButtonTooltip: LocaleKeys.sideBar_clickToHideWorkspace.tr(),
|
||||
addButtonTooltip: LocaleKeys.sideBar_addAPageToWorkspace.tr(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+27
-3
@@ -1,5 +1,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/openai/widgets/loading.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_setting.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
|
||||
@@ -16,7 +17,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SidebarWorkspace extends StatelessWidget {
|
||||
class SidebarWorkspace extends StatefulWidget {
|
||||
const SidebarWorkspace({
|
||||
super.key,
|
||||
required this.userProfile,
|
||||
@@ -24,9 +25,18 @@ class SidebarWorkspace extends StatelessWidget {
|
||||
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
@override
|
||||
State<SidebarWorkspace> createState() => _SidebarWorkspaceState();
|
||||
}
|
||||
|
||||
class _SidebarWorkspaceState extends State<SidebarWorkspace> {
|
||||
Loading? loadingIndicator;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
||||
listenWhen: (previous, current) =>
|
||||
previous.actionResult != current.actionResult,
|
||||
listener: _showResultDialog,
|
||||
builder: (context, state) {
|
||||
final currentWorkspace = state.currentWorkspace;
|
||||
@@ -37,11 +47,11 @@ class SidebarWorkspace extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: SidebarSwitchWorkspaceButton(
|
||||
userProfile: userProfile,
|
||||
userProfile: widget.userProfile,
|
||||
currentWorkspace: currentWorkspace,
|
||||
),
|
||||
),
|
||||
UserSettingButton(userProfile: userProfile),
|
||||
UserSettingButton(userProfile: widget.userProfile),
|
||||
const HSpace(4),
|
||||
const NotificationButton(),
|
||||
],
|
||||
@@ -58,6 +68,19 @@ class SidebarWorkspace extends StatelessWidget {
|
||||
|
||||
final actionType = actionResult.actionType;
|
||||
final result = actionResult.result;
|
||||
final isLoading = actionResult.isLoading;
|
||||
|
||||
if (isLoading) {
|
||||
loadingIndicator ??= Loading(context)..start();
|
||||
return;
|
||||
} else {
|
||||
loadingIndicator?.stop();
|
||||
loadingIndicator = null;
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.onFailure((f) {
|
||||
Log.error(
|
||||
@@ -193,6 +216,7 @@ class _SidebarSwitchWorkspaceButtonState
|
||||
child: FlowyText.medium(
|
||||
widget.currentWorkspace.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
withTooltip: true,
|
||||
),
|
||||
),
|
||||
const FlowySvg(FlowySvgs.drop_menu_show_m),
|
||||
|
||||
-1
@@ -110,7 +110,6 @@ class _WorkspaceMoreActionWrapper extends CustomActionCell {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (_) => NavigatorOkCancelDialog(
|
||||
title: LocaleKeys.workspace_leaveCurrentWorkspace.tr(),
|
||||
message: LocaleKeys.workspace_leaveCurrentWorkspacePrompt.tr(),
|
||||
onOkPressed: () {
|
||||
workspaceBloc.add(
|
||||
|
||||
+14
-7
@@ -9,6 +9,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/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:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
@@ -136,8 +137,10 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
PopoverContainer.of(context).closeAll();
|
||||
}
|
||||
},
|
||||
margin:
|
||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 12,
|
||||
),
|
||||
iconPadding: 10.0,
|
||||
leftIconSize: const Size.square(32),
|
||||
leftIcon: const SizedBox.square(
|
||||
@@ -146,12 +149,12 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
rightIcon: const HSpace(42.0),
|
||||
text: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FlowyText.medium(
|
||||
workspace.name,
|
||||
fontSize: 14.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
withTooltip: true,
|
||||
),
|
||||
FlowyText(
|
||||
state.isLoading
|
||||
@@ -171,10 +174,14 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
left: 8,
|
||||
child: SizedBox.square(
|
||||
dimension: 32,
|
||||
child: WorkspaceIcon(
|
||||
workspace: workspace,
|
||||
iconSize: 26,
|
||||
enableEdit: true,
|
||||
child: FlowyTooltip(
|
||||
message:
|
||||
LocaleKeys.document_plugins_cover_changeIcon.tr(),
|
||||
child: WorkspaceIcon(
|
||||
workspace: workspace,
|
||||
iconSize: 26,
|
||||
enableEdit: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -62,6 +62,7 @@ class SettingsDialog extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: SettingsMenu(
|
||||
userProfile: user,
|
||||
changeSelectedPage: (index) {
|
||||
context
|
||||
.read<SettingsDialogBloc>()
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
SelectionMenuItem emojiMenuItem = SelectionMenuItem(
|
||||
getName: () => LocaleKeys.document_plugins_emoji.tr(),
|
||||
getName: LocaleKeys.document_plugins_emoji.tr,
|
||||
icon: (editorState, onSelected, style) => SelectableIconWidget(
|
||||
icon: Icons.emoji_emotions_outlined,
|
||||
isSelected: onSelected,
|
||||
|
||||
+8
-7
@@ -117,13 +117,14 @@ class CloudTypeSwitcher extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final isDevelopMode = integrationMode().isDevelop;
|
||||
// Only show the appflowyCloudDevelop in develop mode
|
||||
final values = AuthenticatorType.values
|
||||
.where(
|
||||
(element) =>
|
||||
isDevelopMode ||
|
||||
element != AuthenticatorType.appflowyCloudDevelop,
|
||||
)
|
||||
.toList();
|
||||
final values = AuthenticatorType.values.where((element) {
|
||||
// Supabase will going to be removed in the future
|
||||
if (element == AuthenticatorType.supabase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isDevelopMode || element != AuthenticatorType.appflowyCloudDevelop;
|
||||
}).toList();
|
||||
return PlatformExtension.isDesktopOrWeb
|
||||
? AppFlowyPopover(
|
||||
direction: PopoverDirection.bottomWithRightAligned,
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ class ShortcutsListTile extends StatelessWidget {
|
||||
Expanded(
|
||||
child: FlowyText.medium(
|
||||
key: Key(shortcutEvent.key),
|
||||
shortcutEvent.key.capitalize(),
|
||||
shortcutEvent.description!.capitalize(),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
|
||||
+5
-1
@@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -12,10 +13,12 @@ class SettingsMenu extends StatelessWidget {
|
||||
super.key,
|
||||
required this.changeSelectedPage,
|
||||
required this.currentPage,
|
||||
required this.userProfile,
|
||||
});
|
||||
|
||||
final Function changeSelectedPage;
|
||||
final SettingsPage currentPage;
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -72,7 +75,8 @@ class SettingsMenu extends StatelessWidget {
|
||||
icon: Icons.cut,
|
||||
changeSelectedPage: changeSelectedPage,
|
||||
),
|
||||
if (FeatureFlag.membersSettings.isOn)
|
||||
if (FeatureFlag.membersSettings.isOn &&
|
||||
userProfile.authenticator == AuthenticatorPB.AppFlowyCloud)
|
||||
SettingsMenuElement(
|
||||
page: SettingsPage.member,
|
||||
selectedPage: currentPage,
|
||||
|
||||
+80
-73
@@ -174,85 +174,92 @@ class _AppFlowyDatePickerState extends State<AppFlowyDatePicker> {
|
||||
}
|
||||
|
||||
Widget buildDesktopPicker() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 18.0, bottom: 12.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
StartTextField(
|
||||
includeTime: widget.includeTime,
|
||||
timeFormat: widget.timeFormat,
|
||||
timeHintText: widget.timeHintText,
|
||||
parseEndTimeError: widget.parseEndTimeError,
|
||||
parseTimeError: widget.parseTimeError,
|
||||
timeStr: widget.timeStr,
|
||||
popoverMutex: widget.popoverMutex,
|
||||
onSubmitted: widget.onStartTimeSubmitted,
|
||||
),
|
||||
EndTextField(
|
||||
includeTime: widget.includeTime,
|
||||
timeFormat: widget.timeFormat,
|
||||
isRange: widget.isRange,
|
||||
endTimeStr: widget.endTimeStr,
|
||||
popoverMutex: widget.popoverMutex,
|
||||
onSubmitted: widget.onEndTimeSubmitted,
|
||||
),
|
||||
DatePicker(
|
||||
isRange: widget.isRange,
|
||||
onDaySelected: (selectedDay, focusedDay) {
|
||||
widget.onDaySelected?.call(selectedDay, focusedDay);
|
||||
|
||||
if (widget.rebuildOnDaySelected) {
|
||||
setState(() => _selectedDay = selectedDay);
|
||||
}
|
||||
},
|
||||
onRangeSelected: widget.onRangeSelected,
|
||||
selectedDay:
|
||||
widget.rebuildOnDaySelected ? _selectedDay : widget.selectedDay,
|
||||
firstDay: widget.firstDay,
|
||||
lastDay: widget.lastDay,
|
||||
startDay: widget.startDay,
|
||||
endDay: widget.endDay,
|
||||
onCalendarCreated: widget.onCalendarCreated,
|
||||
onPageChanged: widget.onPageChanged,
|
||||
),
|
||||
const TypeOptionSeparator(spacing: 12.0),
|
||||
if (widget.enableRanges && widget.onIsRangeChanged != null) ...[
|
||||
EndTimeButton(
|
||||
// GestureDetector is a workaround to stop popover from closing
|
||||
// when clicking on the date picker.
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 18.0, bottom: 12.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
StartTextField(
|
||||
includeTime: widget.includeTime,
|
||||
timeFormat: widget.timeFormat,
|
||||
timeHintText: widget.timeHintText,
|
||||
parseEndTimeError: widget.parseEndTimeError,
|
||||
parseTimeError: widget.parseTimeError,
|
||||
timeStr: widget.timeStr,
|
||||
popoverMutex: widget.popoverMutex,
|
||||
onSubmitted: widget.onStartTimeSubmitted,
|
||||
),
|
||||
EndTextField(
|
||||
includeTime: widget.includeTime,
|
||||
timeFormat: widget.timeFormat,
|
||||
isRange: widget.isRange,
|
||||
onChanged: widget.onIsRangeChanged!,
|
||||
endTimeStr: widget.endTimeStr,
|
||||
popoverMutex: widget.popoverMutex,
|
||||
onSubmitted: widget.onEndTimeSubmitted,
|
||||
),
|
||||
const VSpace(4.0),
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: IncludeTimeButton(
|
||||
value: widget.includeTime,
|
||||
onChanged: widget.onIncludeTimeChanged,
|
||||
DatePicker(
|
||||
isRange: widget.isRange,
|
||||
onDaySelected: (selectedDay, focusedDay) {
|
||||
widget.onDaySelected?.call(selectedDay, focusedDay);
|
||||
|
||||
if (widget.rebuildOnDaySelected) {
|
||||
setState(() => _selectedDay = selectedDay);
|
||||
}
|
||||
},
|
||||
onRangeSelected: widget.onRangeSelected,
|
||||
selectedDay: widget.rebuildOnDaySelected
|
||||
? _selectedDay
|
||||
: widget.selectedDay,
|
||||
firstDay: widget.firstDay,
|
||||
lastDay: widget.lastDay,
|
||||
startDay: widget.startDay,
|
||||
endDay: widget.endDay,
|
||||
onCalendarCreated: widget.onCalendarCreated,
|
||||
onPageChanged: widget.onPageChanged,
|
||||
),
|
||||
const TypeOptionSeparator(spacing: 12.0),
|
||||
if (widget.enableRanges && widget.onIsRangeChanged != null) ...[
|
||||
EndTimeButton(
|
||||
isRange: widget.isRange,
|
||||
onChanged: widget.onIsRangeChanged!,
|
||||
),
|
||||
const VSpace(4.0),
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: IncludeTimeButton(
|
||||
value: widget.includeTime,
|
||||
onChanged: widget.onIncludeTimeChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
const _GroupSeparator(),
|
||||
ReminderSelector(
|
||||
mutex: widget.popoverMutex,
|
||||
hasTime: widget.includeTime,
|
||||
timeFormat: widget.timeFormat,
|
||||
selectedOption: _selectedReminderOption,
|
||||
onOptionSelected: (option) {
|
||||
setState(() => _selectedReminderOption = option);
|
||||
widget.onReminderSelected?.call(option);
|
||||
},
|
||||
),
|
||||
if (widget.options?.isNotEmpty ?? false) ...[
|
||||
const _GroupSeparator(),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.options!.length,
|
||||
separatorBuilder: (_, __) => const _GroupSeparator(),
|
||||
itemBuilder: (_, index) =>
|
||||
_renderGroupOptions(widget.options![index].options),
|
||||
ReminderSelector(
|
||||
mutex: widget.popoverMutex,
|
||||
hasTime: widget.includeTime,
|
||||
timeFormat: widget.timeFormat,
|
||||
selectedOption: _selectedReminderOption,
|
||||
onOptionSelected: (option) {
|
||||
setState(() => _selectedReminderOption = option);
|
||||
widget.onReminderSelected?.call(option);
|
||||
},
|
||||
),
|
||||
if (widget.options?.isNotEmpty ?? false) ...[
|
||||
const _GroupSeparator(),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.options!.length,
|
||||
separatorBuilder: (_, __) => const _GroupSeparator(),
|
||||
itemBuilder: (_, index) =>
|
||||
_renderGroupOptions(widget.options![index].options),
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
+33
-2
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pbenum.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text_field.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
const _maxLengthTwelveHour = 8;
|
||||
const _maxLengthTwentyFourHour = 5;
|
||||
@@ -55,6 +56,13 @@ class _TimeTextFieldState extends State<TimeTextField> {
|
||||
text = widget.endTimeStr!;
|
||||
}
|
||||
|
||||
if (widget.timeFormat == TimeFormatPB.TwelveHour) {
|
||||
final twentyFourHourFormat = DateFormat('HH:mm');
|
||||
final twelveHourFormat = DateFormat('hh:mm a');
|
||||
final date = twentyFourHourFormat.parse(text);
|
||||
text = twelveHourFormat.format(date);
|
||||
}
|
||||
|
||||
_focusNode.addListener(_focusNodeListener);
|
||||
widget.popoverMutex?.listenOnPopoverChanged(_popoverListener);
|
||||
}
|
||||
@@ -86,6 +94,7 @@ class _TimeTextFieldState extends State<TimeTextField> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: FlowyTextField(
|
||||
text: text,
|
||||
keyboardType: TextInputType.datetime,
|
||||
focusNode: _focusNode,
|
||||
autoFocus: false,
|
||||
controller: _textController,
|
||||
@@ -97,7 +106,16 @@ class _TimeTextFieldState extends State<TimeTextField> {
|
||||
? _maxLengthTwelveHour
|
||||
: _maxLengthTwentyFourHour,
|
||||
showCounter: false,
|
||||
inputFormatters: [TimeInputFormatter(widget.timeFormat)],
|
||||
inputFormatters: [
|
||||
if (widget.timeFormat == TimeFormatPB.TwelveHour) ...[
|
||||
// Allow for AM/PM if time format is 12-hour
|
||||
FilteringTextInputFormatter.allow(RegExp('[0-9:aApPmM ]')),
|
||||
] else ...[
|
||||
// Default allow for hh:mm format
|
||||
FilteringTextInputFormatter.allow(RegExp('[0-9:]')),
|
||||
],
|
||||
TimeInputFormatter(widget.timeFormat),
|
||||
],
|
||||
onSubmitted: widget.onSubmitted,
|
||||
),
|
||||
);
|
||||
@@ -134,7 +152,20 @@ class TimeInputFormatter extends TextInputFormatter {
|
||||
return _formatText(newText, spacePosition, ' ');
|
||||
}
|
||||
|
||||
return newValue;
|
||||
if (timeFormat == TimeFormatPB.TwentyFourHour &&
|
||||
newValue.text.length == 5) {
|
||||
final prefix = newValue.text.substring(0, 3);
|
||||
final suffix = newValue.text.length > 5 ? newValue.text.substring(6) : '';
|
||||
|
||||
final minutes = int.tryParse(newValue.text.substring(3, 5));
|
||||
if (minutes == null || minutes <= 0) {
|
||||
return newValue.copyWith(text: '${prefix}00$suffix'.toUpperCase());
|
||||
} else if (minutes > 59) {
|
||||
return newValue.copyWith(text: '${prefix}59$suffix'.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
return newValue.copyWith(text: newText.toUpperCase());
|
||||
}
|
||||
|
||||
TextEditingValue _formatText(String text, int index, String separator) {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
|
||||
import 'package:appflowy/startup/tasks/app_window_size_manager.dart';
|
||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/rename_view_popover.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
// workspaces / ... / view_title
|
||||
@@ -115,9 +116,8 @@ class _ViewTitleBarState extends State<ViewTitleBar> {
|
||||
}
|
||||
|
||||
void _reloadAncestors() {
|
||||
ancestors = widget.view.getAncestors(
|
||||
includeSelf: true,
|
||||
);
|
||||
ancestors = ViewBackendService.getViewAncestors(widget.view.id)
|
||||
.fold((s) => s.items, (f) => []);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
export 'package:async/async.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:appflowy_backend/rust_stream.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'dart:ffi';
|
||||
import 'ffi.dart' as ffi;
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'dart:isolate';
|
||||
import 'dart:io';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
enum ExceptionType {
|
||||
AppearanceSettingsIsEmpty,
|
||||
@@ -27,10 +32,15 @@ class FlowySDK {
|
||||
Future<void> dispose() async {}
|
||||
|
||||
Future<void> init(String configuration) async {
|
||||
final port = RustStreamReceiver.shared.port;
|
||||
ffi.set_stream_port(port);
|
||||
ffi.set_stream_port(RustStreamReceiver.shared.port);
|
||||
ffi.store_dart_post_cobject(NativeApi.postCObject);
|
||||
|
||||
// On iOS, VSCode can't print logs from Rust, so we need to use a different method to print logs.
|
||||
// So we use a shared port to receive logs from Rust and print them using the logger. In release mode, we don't print logs.
|
||||
if (Platform.isIOS && kDebugMode) {
|
||||
ffi.set_log_stream_port(RustLogStreamReceiver.logShared.port);
|
||||
}
|
||||
|
||||
// final completer = Completer<Uint8List>();
|
||||
// // Create a SendPort that accepts only one message.
|
||||
// final sendPort = singleCompletePort(completer);
|
||||
@@ -42,3 +52,44 @@ class FlowySDK {
|
||||
// return completer.future;
|
||||
}
|
||||
}
|
||||
|
||||
class RustLogStreamReceiver {
|
||||
static RustLogStreamReceiver logShared = RustLogStreamReceiver._internal();
|
||||
late RawReceivePort _ffiPort;
|
||||
late StreamController<Uint8List> _streamController;
|
||||
late StreamSubscription<Uint8List> _subscription;
|
||||
int get port => _ffiPort.sendPort.nativePort;
|
||||
late Logger _logger;
|
||||
|
||||
RustLogStreamReceiver._internal() {
|
||||
_ffiPort = RawReceivePort();
|
||||
_streamController = StreamController();
|
||||
_ffiPort.handler = _streamController.add;
|
||||
_logger = Logger(
|
||||
printer: PrettyPrinter(
|
||||
methodCount: 0, // number of method calls to be displayed
|
||||
errorMethodCount: 8, // number of method calls if stacktrace is provided
|
||||
lineLength: 120, // width of the output
|
||||
colors: false, // Colorful log messages
|
||||
printEmojis: false, // Print an emoji for each log message
|
||||
printTime: false, // Should each log print contain a timestamp
|
||||
),
|
||||
level: kDebugMode ? Level.trace : Level.info,
|
||||
);
|
||||
|
||||
_subscription = _streamController.stream.listen((data) {
|
||||
String decodedString = utf8.decode(data);
|
||||
_logger.i(decodedString);
|
||||
});
|
||||
}
|
||||
|
||||
factory RustLogStreamReceiver() {
|
||||
return logShared;
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _streamController.close();
|
||||
await _subscription.cancel();
|
||||
_ffiPort.close();
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,22 @@ typedef _set_stream_port_Dart = int Function(
|
||||
int port,
|
||||
);
|
||||
|
||||
/// C function `set log stream port`.
|
||||
int set_log_stream_port(int port) {
|
||||
return _set_log_stream_port(port);
|
||||
}
|
||||
|
||||
final _set_log_stream_port_Dart _set_log_stream_port = _dart_ffi_lib
|
||||
.lookupFunction<_set_log_stream_port_C, _set_log_stream_port_Dart>(
|
||||
'set_log_stream_port');
|
||||
|
||||
typedef _set_log_stream_port_C = Int32 Function(
|
||||
Int64 port,
|
||||
);
|
||||
typedef _set_log_stream_port_Dart = int Function(
|
||||
int port,
|
||||
);
|
||||
|
||||
/// C function `link_me_please`.
|
||||
void link_me_please() {
|
||||
_link_me_please();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// ignore: import_of_legacy_library_into_null_safe
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart' as ffi;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:isolate';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
|
||||
import 'protobuf/flowy-notification/subject.pb.dart';
|
||||
|
||||
@@ -11,6 +11,8 @@ const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
|
||||
|
||||
int32_t set_stream_port(int64_t port);
|
||||
|
||||
int32_t set_log_stream_port(int64_t port);
|
||||
|
||||
void link_me_please(void);
|
||||
|
||||
void rust_log(int64_t level, const char *data);
|
||||
|
||||
@@ -15,6 +15,7 @@ class FlowyText extends StatelessWidget {
|
||||
final String? fontFamily;
|
||||
final List<String>? fallbackFontFamily;
|
||||
final double? lineHeight;
|
||||
final bool withTooltip;
|
||||
|
||||
const FlowyText(
|
||||
this.text, {
|
||||
@@ -30,6 +31,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.fontFamily,
|
||||
this.fallbackFontFamily,
|
||||
this.lineHeight,
|
||||
this.withTooltip = false,
|
||||
});
|
||||
|
||||
FlowyText.small(
|
||||
@@ -44,6 +46,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.fontFamily,
|
||||
this.fallbackFontFamily,
|
||||
this.lineHeight,
|
||||
this.withTooltip = false,
|
||||
}) : fontWeight = FontWeight.w400,
|
||||
fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12;
|
||||
|
||||
@@ -60,6 +63,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.fontFamily,
|
||||
this.fallbackFontFamily,
|
||||
this.lineHeight,
|
||||
this.withTooltip = false,
|
||||
}) : fontWeight = FontWeight.w400;
|
||||
|
||||
const FlowyText.medium(
|
||||
@@ -75,6 +79,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.fontFamily,
|
||||
this.fallbackFontFamily,
|
||||
this.lineHeight,
|
||||
this.withTooltip = false,
|
||||
}) : fontWeight = FontWeight.w500;
|
||||
|
||||
const FlowyText.semibold(
|
||||
@@ -90,6 +95,7 @@ class FlowyText extends StatelessWidget {
|
||||
this.fontFamily,
|
||||
this.fallbackFontFamily,
|
||||
this.lineHeight,
|
||||
this.withTooltip = false,
|
||||
}) : fontWeight = FontWeight.w600;
|
||||
|
||||
// Some emojis are not supported on Linux and Android, fallback to noto color emoji
|
||||
@@ -104,14 +110,17 @@ class FlowyText extends StatelessWidget {
|
||||
this.decoration,
|
||||
this.selectable = false,
|
||||
this.lineHeight,
|
||||
this.withTooltip = false,
|
||||
}) : fontWeight = FontWeight.w400,
|
||||
fontFamily = 'noto color emoji',
|
||||
fallbackFontFamily = null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget child;
|
||||
|
||||
if (selectable) {
|
||||
return SelectableText(
|
||||
child = SelectableText(
|
||||
text,
|
||||
maxLines: maxLines,
|
||||
textAlign: textAlign,
|
||||
@@ -126,7 +135,7 @@ class FlowyText extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Text(
|
||||
child = Text(
|
||||
text,
|
||||
maxLines: maxLines,
|
||||
textAlign: textAlign,
|
||||
@@ -142,5 +151,14 @@ class FlowyText extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (withTooltip) {
|
||||
child = Tooltip(
|
||||
message: text,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flowy_infra/size.dart';
|
||||
|
||||
class FlowyTextField extends StatefulWidget {
|
||||
final String? hintText;
|
||||
final String? text;
|
||||
@@ -31,6 +32,7 @@ class FlowyTextField extends StatefulWidget {
|
||||
final TextStyle? hintStyle;
|
||||
final InputDecoration? decoration;
|
||||
final TextAlignVertical? textAlignVertical;
|
||||
final TextInputAction? textInputAction;
|
||||
final TextInputType? keyboardType;
|
||||
final List<TextInputFormatter>? inputFormatters;
|
||||
|
||||
@@ -62,6 +64,7 @@ class FlowyTextField extends StatefulWidget {
|
||||
this.hintStyle,
|
||||
this.decoration,
|
||||
this.textAlignVertical,
|
||||
this.textInputAction,
|
||||
this.keyboardType = TextInputType.multiline,
|
||||
this.inputFormatters,
|
||||
});
|
||||
|
||||
@@ -53,8 +53,8 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: b927ec0
|
||||
resolved-ref: b927ec0685c870c731c5b6d9688a031d0cd31e76
|
||||
ref: "6d12761"
|
||||
resolved-ref: "6d127619294060999522be904a3e72a59dc270ca"
|
||||
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
|
||||
source: git
|
||||
version: "2.3.3"
|
||||
|
||||
@@ -169,7 +169,7 @@ dependency_overrides:
|
||||
appflowy_editor:
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
||||
ref: "b927ec0"
|
||||
ref: "6d12761"
|
||||
|
||||
sheet:
|
||||
git:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/home/home_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
|
||||
+34
-130
@@ -156,7 +156,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -712,7 +712,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@@ -733,7 +733,6 @@ dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"gotrue",
|
||||
"gotrue-entity",
|
||||
"governor",
|
||||
"mime",
|
||||
"parking_lot 0.12.1",
|
||||
"prost",
|
||||
@@ -752,14 +751,13 @@ dependencies = [
|
||||
"url",
|
||||
"uuid",
|
||||
"wasm-bindgen-futures",
|
||||
"workspace-template",
|
||||
"yrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@@ -833,7 +831,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -857,7 +855,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -887,7 +885,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@@ -906,7 +904,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -921,7 +919,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -959,7 +957,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@@ -998,7 +996,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -1023,7 +1021,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -1037,7 +1035,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@@ -1096,9 +1094,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.16.2"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
|
||||
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
@@ -1107,12 +1105,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cookie_store"
|
||||
version = "0.16.2"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa"
|
||||
checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"idna 0.2.3",
|
||||
"idna 0.3.0",
|
||||
"log",
|
||||
"publicsuffix",
|
||||
"serde",
|
||||
@@ -1371,7 +1369,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@@ -2352,12 +2350,6 @@ version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
@@ -2687,7 +2679,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@@ -2704,7 +2696,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@@ -2715,24 +2707,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "governor"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dashmap",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"no-std-compat",
|
||||
"nonzero_ext",
|
||||
"parking_lot 0.12.1",
|
||||
"quanta",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.15.5"
|
||||
@@ -3027,17 +3001,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
@@ -3155,7 +3118,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@@ -3399,6 +3362,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
@@ -3519,15 +3483,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macroific"
|
||||
version = "1.3.1"
|
||||
@@ -3788,12 +3743,6 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "no-std-compat"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.14"
|
||||
@@ -3810,12 +3759,6 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nonzero_ext"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.4.1"
|
||||
@@ -4759,22 +4702,6 @@ dependencies = [
|
||||
"psl-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quanta"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"libc",
|
||||
"mach2",
|
||||
"once_cell",
|
||||
"raw-cpuid",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.28.2"
|
||||
@@ -4891,15 +4818,6 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "10.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.5.2"
|
||||
@@ -5013,9 +4931,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.23"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
@@ -5044,6 +4962,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
@@ -5599,7 +5518,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@@ -5865,6 +5784,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.30.5"
|
||||
@@ -7050,9 +6975,9 @@ checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
|
||||
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
@@ -7584,27 +7509,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "workspace-template"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-document",
|
||||
"collab-entity",
|
||||
"collab-folder",
|
||||
"getrandom 0.2.10",
|
||||
"indexmap 2.1.0",
|
||||
"nanoid",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.24.6"
|
||||
|
||||
@@ -87,7 +87,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4df32f6d3b53bec5e3715f5abfe4fb9079021b" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@@ -97,10 +97,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
@@ -9,19 +9,19 @@ pub fn read_env() {
|
||||
dotenv().ok();
|
||||
|
||||
let env = if cfg!(debug_assertions) {
|
||||
include_str!("../env.development")
|
||||
include_str!("../env.development")
|
||||
} else {
|
||||
include_str!("../env.production")
|
||||
include_str!("../env.production")
|
||||
};
|
||||
|
||||
for line in env.lines() {
|
||||
if let Some((key, value)) = line.split_once('=') {
|
||||
// Check if the environment variable is not already set in the system
|
||||
let current_value = std::env::var(key).unwrap_or_default();
|
||||
if current_value.is_empty() {
|
||||
std::env::set_var(key, value);
|
||||
}
|
||||
if let Some((key, value)) = line.split_once('=') {
|
||||
// Check if the environment variable is not already set in the system
|
||||
let current_value = std::env::var(key).unwrap_or_default();
|
||||
if current_value.is_empty() {
|
||||
std::env::set_var(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,12 @@ pub fn init_flowy_core() -> AppFlowyCore {
|
||||
let config_json = include_str!("../tauri.conf.json");
|
||||
let config: tauri_utils::config::Config = serde_json::from_str(config_json).unwrap();
|
||||
|
||||
let app_version = config.package.version.clone().map(|v| v.to_string()).unwrap_or_else(|| "0.0.0".to_string());
|
||||
let app_version = config
|
||||
.package
|
||||
.version
|
||||
.clone()
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| "0.0.0".to_string());
|
||||
let mut data_path = tauri::api::path::app_local_data_dir(&config).unwrap();
|
||||
if cfg!(debug_assertions) {
|
||||
data_path.push("data_dev");
|
||||
@@ -49,11 +54,12 @@ pub fn init_flowy_core() -> AppFlowyCore {
|
||||
custom_application_path,
|
||||
application_path,
|
||||
device_id,
|
||||
"tauri".to_string(),
|
||||
DEFAULT_NAME.to_string(),
|
||||
)
|
||||
.log_filter("trace", vec!["appflowy_tauri".to_string()]);
|
||||
|
||||
let runtime = Arc::new(AFPluginRuntime::new().unwrap());
|
||||
let cloned_runtime = runtime.clone();
|
||||
runtime.block_on(async move { AppFlowyCore::new(config, cloned_runtime).await })
|
||||
runtime.block_on(async move { AppFlowyCore::new(config, cloned_runtime, None).await })
|
||||
}
|
||||
+37
-143
@@ -215,7 +215,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -378,9 +378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.4.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f"
|
||||
checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -541,7 +541,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@@ -562,7 +562,6 @@ dependencies = [
|
||||
"getrandom 0.2.12",
|
||||
"gotrue",
|
||||
"gotrue-entity",
|
||||
"governor",
|
||||
"mime",
|
||||
"parking_lot 0.12.1",
|
||||
"prost",
|
||||
@@ -587,7 +586,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@@ -631,7 +630,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -655,7 +654,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@@ -674,7 +673,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -689,7 +688,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -727,7 +726,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@@ -765,7 +764,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -790,7 +789,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -804,7 +803,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@@ -851,9 +850,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.16.2"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
|
||||
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
@@ -862,12 +861,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cookie_store"
|
||||
version = "0.16.2"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa"
|
||||
checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"idna 0.2.3",
|
||||
"idna 0.3.0",
|
||||
"log",
|
||||
"publicsuffix",
|
||||
"serde",
|
||||
@@ -956,7 +955,7 @@ dependencies = [
|
||||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa",
|
||||
"phf 0.11.2",
|
||||
"phf 0.8.0",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@@ -1001,7 +1000,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@@ -1629,12 +1628,6 @@ version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
@@ -1769,7 +1762,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@@ -1786,7 +1779,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@@ -1797,24 +1790,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "governor"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"dashmap",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"no-std-compat",
|
||||
"nonzero_ext",
|
||||
"parking_lot 0.12.1",
|
||||
"quanta",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.24"
|
||||
@@ -2022,17 +1997,6 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
@@ -2116,7 +2080,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@@ -2342,15 +2306,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macroific"
|
||||
version = "1.3.1"
|
||||
@@ -2412,12 +2367,6 @@ dependencies = [
|
||||
"tendril",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.7.0"
|
||||
@@ -2517,12 +2466,6 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "no-std-compat"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -2533,12 +2476,6 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nonzero_ext"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.4"
|
||||
@@ -2569,16 +2506,6 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
@@ -2836,7 +2763,7 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_macros 0.8.0",
|
||||
"phf_macros",
|
||||
"phf_shared 0.8.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
@@ -2856,7 +2783,6 @@ version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_macros 0.11.2",
|
||||
"phf_shared 0.11.2",
|
||||
]
|
||||
|
||||
@@ -2924,19 +2850,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||
dependencies = [
|
||||
"phf_generator 0.11.2",
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.8.0"
|
||||
@@ -3247,22 +3160,6 @@ dependencies = [
|
||||
"psl-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quanta"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"libc",
|
||||
"mach2",
|
||||
"once_cell",
|
||||
"raw-cpuid",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
@@ -3353,15 +3250,6 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "10.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
@@ -3417,9 +3305,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.23"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
@@ -3448,6 +3336,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
@@ -3816,7 +3705,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@@ -4009,6 +3898,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
@@ -4190,7 +4085,6 @@ dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
@@ -4738,9 +4632,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
|
||||
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
@@ -5073,4 +4967,4 @@ dependencies = [
|
||||
[[patch.unused]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
|
||||
@@ -55,7 +55,7 @@ codegen-units = 1
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4df32f6d3b53bec5e3715f5abfe4fb9079021b" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@@ -65,10 +65,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
|
||||
@@ -14,7 +14,7 @@ flowy-user-pub = { workspace = true }
|
||||
strum_macros = "0.25.2"
|
||||
tracing.workspace = true
|
||||
lib-infra = { workspace = true }
|
||||
collab = { workspace = true, features = ["async-plugin"] }
|
||||
collab = { workspace = true }
|
||||
collab-entity.workspace = true
|
||||
collab-user.workspace = true
|
||||
collab-integrate = { workspace = true }
|
||||
|
||||
@@ -30,7 +30,7 @@ flowy-error = { workspace = true, features = ["impl_from_dispatch_error", "web_t
|
||||
flowy-document = { workspace = true, features = ["web_ts"] }
|
||||
flowy-folder = { workspace = true, features = ["web_ts"] }
|
||||
lib-infra = { workspace = true }
|
||||
collab = { workspace = true, features = ["async-plugin"] }
|
||||
collab = { workspace = true }
|
||||
web-sys = "0.3"
|
||||
wasm-bindgen-futures.workspace = true
|
||||
uuid.workspace = true
|
||||
|
||||
@@ -3,4 +3,5 @@ dist/
|
||||
src-tauri/
|
||||
.eslintrc.cjs
|
||||
tsconfig.json
|
||||
**/backend/**
|
||||
**/backend/**
|
||||
vite.config.ts
|
||||
@@ -3,4 +3,5 @@ dist/
|
||||
src-tauri/
|
||||
.eslintrc.cjs
|
||||
tsconfig.json
|
||||
src/application/services/tauri-services/
|
||||
src/application/services/tauri-services/
|
||||
vite.config.ts
|
||||
@@ -0,0 +1,23 @@
|
||||
FROM node:latest
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y nginx
|
||||
|
||||
RUN addgroup --system nginx && \
|
||||
adduser --system --no-create-home --disabled-login --ingroup nginx nginx
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
COPY nginx-signed.crt /etc/ssl/certs/nginx-signed.crt
|
||||
COPY nginx-signed.key /etc/ssl/private/nginx-signed.key
|
||||
|
||||
RUN chown -R nginx:nginx /etc/ssl/certs/nginx-signed.crt /etc/ssl/private/nginx-signed.key
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -194,6 +194,77 @@ Don't modify the theme file in `frontend/appflowy_web_app/src/styles/variables`
|
||||
}
|
||||
```
|
||||
|
||||
### 📦 Deployment
|
||||
|
||||
Use the AppFlowy CI/CD pipeline to deploy the application to the test and production environments.
|
||||
|
||||
- Push the changes to the main branch
|
||||
- Deploy Test Environment
|
||||
- Automatically, the test environment will be deployed if merged to the main branch or build/test branch
|
||||
- Deploy Production Environment
|
||||
- Navigate to the Actions tab
|
||||
- Click on the workflow and select the Run workflow
|
||||
- Enter the options
|
||||
- Click on the Run workflow button
|
||||
|
||||
#### 📦 Deployment (Self-Hosted)
|
||||
|
||||
##### Pre-requisites
|
||||
|
||||
Please ensure you have learned about:
|
||||
|
||||
- [Deploy Web application on AWS Cloud using EC2 Instance](https://www.youtube.com/watch?v=gWVIIU1ev0Y)
|
||||
- [How to Install and Use Rsync Command](https://operavps.com/docs/install-rsync-command-in-linux/)
|
||||
- [How to Use ssh-keygen to Generate a New SSH Key?](https://www.ssh.com/academy/ssh/keygen)
|
||||
- [Linux post-installation steps for Docker Engine](https://docs.docker.com/engine/install/linux-postinstall/)
|
||||
- [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
||||
|
||||
And then follow the steps below:
|
||||
|
||||
1. Ensure you have the following installed on your server:
|
||||
- Docker: [Install Docker](https://docs.docker.com/engine/install/)
|
||||
- Rsync: [Install Rsync](https://operavps.com/docs/install-rsync-command-in-linux/)
|
||||
|
||||
2. Create a new user for deploy, and generate an SSH key for the user
|
||||
|
||||
```bash
|
||||
sudo adduser appflowy(or any name)
|
||||
sudo su - appflowy
|
||||
mkdir ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
ssh-keygen -t rsa
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
# add the user to the docker group, to run docker commands without sudo
|
||||
sudo usermod -aG docker ${USER}
|
||||
```
|
||||
- visit the `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub` to get the private and public key respectively
|
||||
- add the public key to the `~/.ssh/authorized_keys` file
|
||||
- ensure the private key is kept safe
|
||||
- exit and login back to the server with the new
|
||||
user: `ssh -i your-existing-key.pem ec2-user@your-instance-public-dns`
|
||||
|
||||
3. Clone the AppFlowy repository
|
||||
|
||||
4. Set the following secrets in your
|
||||
repository, have to
|
||||
know [Using secrets in GitHub Actions](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions)
|
||||
|
||||
> Note: Test Environment: prefix the secret with `WEB_TEST_` and Production Environment: prefix the secret with `WEB_`
|
||||
|
||||
> for example, `WEB_TEST_SSH_PRIVATE_KEY` and `WEB_SSH_PRIVATE_KEY`
|
||||
|
||||
- `SSH_PRIVATE_KEY`: The private key generated in step 2: cat ~/.ssh/id_rsa
|
||||
- `REMOTE_HOST`: The host of the server: `your-instance-public-dns` or `your-instance-ip`
|
||||
- `REMOTE_USER`: The user created in step 2: `appflowy`
|
||||
- `SSL_CERTIFICATE`: The SSL certificate for the
|
||||
server - [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
||||
- `SSL_CERTIFICATE_KEY`: The SSL certificate key for the
|
||||
server - [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
||||
|
||||
5. Run the deployment workflow to deploy the application(production or test environment)
|
||||
|
||||
> Note: the test server will **automatically** deploy if merged to the main branch or build/test branch
|
||||
|
||||
### 🧪 Testing
|
||||
|
||||
> To be Continued...
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
AF_WS_URL=wss://beta.appflowy.cloud/ws/v1
|
||||
AF_BASE_URL=https://beta.appflowy.cloud
|
||||
AF_GOTRUE_URL=https://beta.appflowy.cloud/gotrue
|
||||
@@ -0,0 +1,78 @@
|
||||
# nginx.conf
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
gzip on;
|
||||
|
||||
gzip_static on;
|
||||
|
||||
gzip_http_version 1.0;
|
||||
|
||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/wasm;
|
||||
|
||||
# Existing server block for HTTP
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
#server_name appflowy.com *.appflowy.com;
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Additional server block for HTTPS
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name localhost;
|
||||
#server_name appflowy.com *.appflowy.com;
|
||||
|
||||
ssl_certificate /etc/ssl/certs/nginx-signed.crt;
|
||||
ssl_certificate_key /etc/ssl/private/nginx-signed.key;
|
||||
|
||||
ssl_session_cache shared:SSL:1m;
|
||||
ssl_session_timeout 5m;
|
||||
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
location = /404.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@
|
||||
"tauri:dev": "tauri dev",
|
||||
"css:variables": "node style-dictionary/config.cjs",
|
||||
"sync:i18n": "node scripts/i18n.cjs",
|
||||
"link:client-api": "rm -rf node_modules/.vite && node scripts/create-symlink.cjs"
|
||||
"link:client-api": "rm -rf node_modules/.vite && node scripts/create-symlink.cjs",
|
||||
"analyze": "ANALYZE_MODE=true vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appflowyinc/client-api-wasm": "^0.0.2",
|
||||
@@ -117,6 +118,7 @@
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "2.8.4",
|
||||
"prettier-plugin-tailwindcss": "^0.2.2",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"style-dictionary": "^3.9.2",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"ts-jest": "^29.1.1",
|
||||
@@ -125,7 +127,10 @@
|
||||
"typescript": "4.9.5",
|
||||
"uuid": "^9.0.0",
|
||||
"vite": "^5.2.0",
|
||||
"vite-plugin-compression2": "^1.0.0",
|
||||
"vite-plugin-importer": "^0.2.5",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"vite-plugin-terminal": "^1.2.0"
|
||||
"vite-plugin-terminal": "^1.2.0",
|
||||
"vite-plugin-total-bundle-size": "^1.0.7"
|
||||
}
|
||||
}
|
||||
Loaded 100 of 168 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user