mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-07 14:12:20 +00:00
parent
89c4629ec2
commit
155817a0f1
@ -58,11 +58,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
find.text(LocaleKeys.menuAppHeader_defaultNewPageName.tr()),
|
find.text(LocaleKeys.menuAppHeader_defaultNewPageName.tr()),
|
||||||
findsNWidgets(3),
|
findsNWidgets(3),
|
||||||
@ -77,12 +72,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -101,11 +90,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -154,11 +138,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -212,11 +191,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -253,11 +227,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -303,11 +272,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -346,11 +310,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu(true);
|
await tester.insertSubPageFromSlashMenu(true);
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -394,11 +353,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
expect(find.byType(SubPageBlockComponent), findsOneWidget);
|
expect(find.byType(SubPageBlockComponent), findsOneWidget);
|
||||||
@ -421,12 +375,6 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(name: 'SubPageBlock');
|
await tester.createNewPageWithNameUnderParent(name: 'SubPageBlock');
|
||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu();
|
await tester.insertSubPageFromSlashMenu();
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
await tester.renamePageWithSecondary(_defaultPageName, 'Child page');
|
||||||
expect(find.text('Child page'), findsNWidgets(2));
|
expect(find.text('Child page'), findsNWidgets(2));
|
||||||
|
|
||||||
@ -447,11 +395,6 @@ void main() {
|
|||||||
|
|
||||||
await tester.insertSubPageFromSlashMenu(true);
|
await tester.insertSubPageFromSlashMenu(true);
|
||||||
|
|
||||||
await tester.expandOrCollapsePage(
|
|
||||||
pageName: 'SubPageBlock',
|
|
||||||
layout: ViewLayoutPB.Document,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.byType(SubPageBlockComponent), findsOneWidget);
|
expect(find.byType(SubPageBlockComponent), findsOneWidget);
|
||||||
|
|
||||||
final beforeNode = tester.editor.getNodeAtPath([1]);
|
final beforeNode = tester.editor.getNodeAtPath([1]);
|
||||||
@ -532,6 +475,11 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
await tester.openPage(firstPage);
|
await tester.openPage(firstPage);
|
||||||
|
|
||||||
|
await tester.expandOrCollapsePage(
|
||||||
|
pageName: firstPage,
|
||||||
|
layout: ViewLayoutPB.Document,
|
||||||
|
);
|
||||||
|
|
||||||
/// check if there is a icon in document
|
/// check if there is a icon in document
|
||||||
final iconWidget = find.byWidgetPredicate((w) {
|
final iconWidget = find.byWidgetPredicate((w) {
|
||||||
if (w is! RawEmojiIconWidget) return false;
|
if (w is! RawEmojiIconWidget) return false;
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.dart';
|
||||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_folder.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_folder.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
@ -44,5 +48,82 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(isExpanded(type: FolderSpaceType.private), true);
|
expect(isExpanded(type: FolderSpaceType.private), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Expanding with subpage', (tester) async {
|
||||||
|
await tester.initializeAppFlowy();
|
||||||
|
await tester.tapAnonymousSignInButton();
|
||||||
|
const page1 = 'SubPageBloc', page2 = '$page1 2';
|
||||||
|
await tester.createNewPageWithNameUnderParent(name: page1);
|
||||||
|
await tester.createNewPageWithNameUnderParent(
|
||||||
|
name: page2,
|
||||||
|
parentName: page1,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.expandOrCollapsePage(
|
||||||
|
pageName: gettingStarted,
|
||||||
|
layout: ViewLayoutPB.Document,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tapNewPageButton();
|
||||||
|
|
||||||
|
await tester.editor.tapLineOfEditorAt(0);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
await tester.editor.showSlashMenu();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
final slashMenu = find
|
||||||
|
.ancestor(
|
||||||
|
of: find.byType(SelectionMenuItemWidget),
|
||||||
|
matching: find.byWidgetPredicate(
|
||||||
|
(widget) => widget is Scrollable,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.first;
|
||||||
|
final slashMenuItem = find.text(
|
||||||
|
LocaleKeys.document_slashMenu_name_linkedDoc.tr(),
|
||||||
|
);
|
||||||
|
await tester.scrollUntilVisible(
|
||||||
|
slashMenuItem,
|
||||||
|
100,
|
||||||
|
scrollable: slashMenu,
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
);
|
||||||
|
|
||||||
|
final menuItemFinder = find.byWidgetPredicate(
|
||||||
|
(w) =>
|
||||||
|
w is SelectionMenuItemWidget &&
|
||||||
|
w.item.name == LocaleKeys.document_slashMenu_name_linkedDoc.tr(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final menuItem =
|
||||||
|
menuItemFinder.evaluate().first.widget as SelectionMenuItemWidget;
|
||||||
|
|
||||||
|
/// tapSlashMenuItemWithName is not working, so invoke this function directly
|
||||||
|
menuItem.item.handler(
|
||||||
|
menuItem.editorState,
|
||||||
|
menuItem.menuService,
|
||||||
|
menuItemFinder.evaluate().first,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final actionHandler = find.byType(InlineActionsHandler);
|
||||||
|
final subPage = find.descendant(
|
||||||
|
of: actionHandler,
|
||||||
|
matching: find.text(page2, findRichText: true),
|
||||||
|
);
|
||||||
|
await tester.tapButton(subPage);
|
||||||
|
|
||||||
|
final subpageBlock = find.descendant(
|
||||||
|
of: find.byType(AppFlowyEditor),
|
||||||
|
matching: find.text(page2, findRichText: true),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.text(page2, findRichText: true), findsOneWidget);
|
||||||
|
await tester.tapButton(subpageBlock);
|
||||||
|
|
||||||
|
/// one is in SectionFolder, another one is in CoverTitle
|
||||||
|
/// the last one is in FlowyNavigation
|
||||||
|
expect(find.text(page2, findRichText: true), findsNWidgets(3));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:appflowy/env/cloud_env.dart';
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
import 'package:appflowy/startup/tasks/feature_flag_task.dart';
|
import 'package:appflowy/startup/tasks/feature_flag_task.dart';
|
||||||
|
import 'package:appflowy/util/expand_views.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
import 'package:appflowy_backend/appflowy_backend.dart';
|
import 'package:appflowy_backend/appflowy_backend.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
@ -182,6 +183,7 @@ Future<void> initGetIt(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
getIt.registerSingleton<PluginSandbox>(PluginSandbox());
|
getIt.registerSingleton<PluginSandbox>(PluginSandbox());
|
||||||
|
getIt.registerSingleton<ViewExpanderRegistry>(ViewExpanderRegistry());
|
||||||
|
|
||||||
await DependencyResolver.resolve(getIt, mode);
|
await DependencyResolver.resolve(getIt, mode);
|
||||||
}
|
}
|
||||||
@ -207,6 +209,7 @@ abstract class LaunchTask {
|
|||||||
LaunchTaskType get type => LaunchTaskType.dataProcessing;
|
LaunchTaskType get type => LaunchTaskType.dataProcessing;
|
||||||
|
|
||||||
Future<void> initialize(LaunchContext context);
|
Future<void> initialize(LaunchContext context);
|
||||||
|
|
||||||
Future<void> dispose();
|
Future<void> dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +251,9 @@ enum IntegrationMode {
|
|||||||
|
|
||||||
// test mode
|
// test mode
|
||||||
bool get isTest => isUnitTest || isIntegrationTest;
|
bool get isTest => isUnitTest || isIntegrationTest;
|
||||||
|
|
||||||
bool get isUnitTest => this == IntegrationMode.unitTest;
|
bool get isUnitTest => this == IntegrationMode.unitTest;
|
||||||
|
|
||||||
bool get isIntegrationTest => this == IntegrationMode.integrationTest;
|
bool get isIntegrationTest => this == IntegrationMode.integrationTest;
|
||||||
|
|
||||||
// release mode
|
// release mode
|
||||||
|
|||||||
40
frontend/appflowy_flutter/lib/util/expand_views.dart
Normal file
40
frontend/appflowy_flutter/lib/util/expand_views.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
class ViewExpanderRegistry {
|
||||||
|
/// the key is view id
|
||||||
|
final Map<String, Set<ViewExpander>> _viewExpanders = {};
|
||||||
|
|
||||||
|
bool isViewExpanded(String id) => getExpander(id)?.isViewExpanded ?? false;
|
||||||
|
|
||||||
|
void register(String id, ViewExpander expander) {
|
||||||
|
final expanders = _viewExpanders[id] ?? {};
|
||||||
|
expanders.add(expander);
|
||||||
|
_viewExpanders[id] = expanders;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister(String id, ViewExpander expander) {
|
||||||
|
final expanders = _viewExpanders[id] ?? {};
|
||||||
|
expanders.remove(expander);
|
||||||
|
if (expanders.isEmpty) {
|
||||||
|
_viewExpanders.remove(id);
|
||||||
|
} else {
|
||||||
|
_viewExpanders[id] = expanders;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewExpander? getExpander(String id) {
|
||||||
|
final expanders = _viewExpanders[id] ?? {};
|
||||||
|
return expanders.isEmpty ? null : expanders.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewExpander {
|
||||||
|
ViewExpander(this._isExpandedCallback, this._expandCallback);
|
||||||
|
|
||||||
|
final ValueGetter<bool> _isExpandedCallback;
|
||||||
|
final VoidCallback _expandCallback;
|
||||||
|
|
||||||
|
bool get isViewExpanded => _isExpandedCallback.call();
|
||||||
|
|
||||||
|
void expand() => _expandCallback.call();
|
||||||
|
}
|
||||||
@ -1,11 +1,19 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:appflowy/core/config/kv.dart';
|
||||||
|
import 'package:appflowy/core/config/kv_keys.dart';
|
||||||
import 'package:appflowy/plugins/blank/blank.dart';
|
import 'package:appflowy/plugins/blank/blank.dart';
|
||||||
import 'package:appflowy/plugins/util.dart';
|
import 'package:appflowy/plugins/util.dart';
|
||||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
import 'package:appflowy/startup/plugin/plugin.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/util/expand_views.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
|
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/home_stack.dart';
|
import 'package:appflowy/workspace/presentation/home/home_stack.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
|
import 'package:appflowy_result/appflowy_result.dart';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
@ -75,6 +83,7 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_setLatestOpenView(view);
|
_setLatestOpenView(view);
|
||||||
|
if (view != null) _expandAncestors(view);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeOtherTabs: (String pluginId) {
|
closeOtherTabs: (String pluginId) {
|
||||||
@ -213,6 +222,32 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _expandAncestors(ViewPB view) async {
|
||||||
|
final viewExpanderRegistry = getIt.get<ViewExpanderRegistry>();
|
||||||
|
if (viewExpanderRegistry.isViewExpanded(view.parentViewId)) return;
|
||||||
|
final value = await getIt<KeyValueStorage>().get(KVKeys.expandedViews);
|
||||||
|
try {
|
||||||
|
final Map expandedViews = value == null ? {} : jsonDecode(value);
|
||||||
|
final List<String> ancestors =
|
||||||
|
await ViewBackendService.getViewAncestors(view.id)
|
||||||
|
.fold((s) => s.items.map((e) => e.id).toList(), (f) => []);
|
||||||
|
ViewExpander? viewExpander;
|
||||||
|
for (final id in ancestors) {
|
||||||
|
expandedViews[id] = true;
|
||||||
|
final expander = viewExpanderRegistry.getExpander(id);
|
||||||
|
if (expander == null) continue;
|
||||||
|
if (!expander.isViewExpanded && viewExpander == null) {
|
||||||
|
viewExpander = expander;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await getIt<KeyValueStorage>()
|
||||||
|
.set(KVKeys.expandedViews, jsonEncode(expandedViews));
|
||||||
|
viewExpander?.expand();
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('expandAncestors error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int _adjustCurrentIndex({
|
int _adjustCurrentIndex({
|
||||||
required int currentIndex,
|
required int currentIndex,
|
||||||
required int tabIndex,
|
required int tabIndex,
|
||||||
@ -250,26 +285,37 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
|
|||||||
@freezed
|
@freezed
|
||||||
class TabsEvent with _$TabsEvent {
|
class TabsEvent with _$TabsEvent {
|
||||||
const factory TabsEvent.moveTab() = _MoveTab;
|
const factory TabsEvent.moveTab() = _MoveTab;
|
||||||
|
|
||||||
const factory TabsEvent.closeTab(String pluginId) = _CloseTab;
|
const factory TabsEvent.closeTab(String pluginId) = _CloseTab;
|
||||||
|
|
||||||
const factory TabsEvent.closeOtherTabs(String pluginId) = _CloseOtherTabs;
|
const factory TabsEvent.closeOtherTabs(String pluginId) = _CloseOtherTabs;
|
||||||
|
|
||||||
const factory TabsEvent.closeCurrentTab() = _CloseCurrentTab;
|
const factory TabsEvent.closeCurrentTab() = _CloseCurrentTab;
|
||||||
|
|
||||||
const factory TabsEvent.selectTab(int index) = _SelectTab;
|
const factory TabsEvent.selectTab(int index) = _SelectTab;
|
||||||
|
|
||||||
const factory TabsEvent.togglePin(String pluginId) = _TogglePin;
|
const factory TabsEvent.togglePin(String pluginId) = _TogglePin;
|
||||||
|
|
||||||
const factory TabsEvent.openTab({
|
const factory TabsEvent.openTab({
|
||||||
required Plugin plugin,
|
required Plugin plugin,
|
||||||
required ViewPB view,
|
required ViewPB view,
|
||||||
}) = _OpenTab;
|
}) = _OpenTab;
|
||||||
|
|
||||||
const factory TabsEvent.openPlugin({
|
const factory TabsEvent.openPlugin({
|
||||||
required Plugin plugin,
|
required Plugin plugin,
|
||||||
ViewPB? view,
|
ViewPB? view,
|
||||||
@Default(true) bool setLatest,
|
@Default(true) bool setLatest,
|
||||||
}) = _OpenPlugin;
|
}) = _OpenPlugin;
|
||||||
|
|
||||||
const factory TabsEvent.openSecondaryPlugin({
|
const factory TabsEvent.openSecondaryPlugin({
|
||||||
required Plugin plugin,
|
required Plugin plugin,
|
||||||
ViewPB? view,
|
ViewPB? view,
|
||||||
}) = _OpenSecondaryPlugin;
|
}) = _OpenSecondaryPlugin;
|
||||||
|
|
||||||
const factory TabsEvent.closeSecondaryPlugin() = _CloseSecondaryPlugin;
|
const factory TabsEvent.closeSecondaryPlugin() = _CloseSecondaryPlugin;
|
||||||
|
|
||||||
const factory TabsEvent.expandSecondaryPlugin() = _ExpandSecondaryPlugin;
|
const factory TabsEvent.expandSecondaryPlugin() = _ExpandSecondaryPlugin;
|
||||||
|
|
||||||
const factory TabsEvent.switchWorkspace(String workspaceId) =
|
const factory TabsEvent.switchWorkspace(String workspaceId) =
|
||||||
_SwitchWorkspace;
|
_SwitchWorkspace;
|
||||||
}
|
}
|
||||||
@ -282,8 +328,11 @@ class TabsState {
|
|||||||
|
|
||||||
final int currentIndex;
|
final int currentIndex;
|
||||||
final List<PageManager> _pageManagers;
|
final List<PageManager> _pageManagers;
|
||||||
|
|
||||||
int get pages => _pageManagers.length;
|
int get pages => _pageManagers.length;
|
||||||
|
|
||||||
PageManager get currentPageManager => _pageManagers[currentIndex];
|
PageManager get currentPageManager => _pageManagers[currentIndex];
|
||||||
|
|
||||||
List<PageManager> get pageManagers => _pageManagers;
|
List<PageManager> get pageManagers => _pageManagers;
|
||||||
|
|
||||||
bool get isAllPinned => _pageManagers.every((pm) => pm.isPinned);
|
bool get isAllPinned => _pageManagers.every((pm) => pm.isPinned);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:appflowy/core/config/kv_keys.dart';
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
|
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/util/expand_views.dart';
|
||||||
import 'package:appflowy/workspace/application/favorite/favorite_listener.dart';
|
import 'package:appflowy/workspace/application/favorite/favorite_listener.dart';
|
||||||
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
|
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||||
@ -24,12 +25,22 @@ import 'package:protobuf/protobuf.dart';
|
|||||||
part 'view_bloc.freezed.dart';
|
part 'view_bloc.freezed.dart';
|
||||||
|
|
||||||
class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
||||||
ViewBloc({required this.view, this.shouldLoadChildViews = true})
|
ViewBloc({
|
||||||
: viewBackendSvc = ViewBackendService(),
|
required this.view,
|
||||||
|
this.shouldLoadChildViews = true,
|
||||||
|
this.engagedInExpanding = false,
|
||||||
|
}) : viewBackendSvc = ViewBackendService(),
|
||||||
listener = ViewListener(viewId: view.id),
|
listener = ViewListener(viewId: view.id),
|
||||||
favoriteListener = FavoriteListener(),
|
favoriteListener = FavoriteListener(),
|
||||||
super(ViewState.init(view)) {
|
super(ViewState.init(view)) {
|
||||||
_dispatch();
|
_dispatch();
|
||||||
|
if (engagedInExpanding) {
|
||||||
|
expander = ViewExpander(
|
||||||
|
() => state.isExpanded,
|
||||||
|
() => add(const ViewEvent.setIsExpanded(true)),
|
||||||
|
);
|
||||||
|
getIt<ViewExpanderRegistry>().register(view.id, expander);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -37,11 +48,16 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
|||||||
final ViewListener listener;
|
final ViewListener listener;
|
||||||
final FavoriteListener favoriteListener;
|
final FavoriteListener favoriteListener;
|
||||||
final bool shouldLoadChildViews;
|
final bool shouldLoadChildViews;
|
||||||
|
final bool engagedInExpanding;
|
||||||
|
late ViewExpander expander;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
await listener.stop();
|
await listener.stop();
|
||||||
await favoriteListener.stop();
|
await favoriteListener.stop();
|
||||||
|
if (engagedInExpanding) {
|
||||||
|
getIt<ViewExpanderRegistry>().unregister(view.id, expander);
|
||||||
|
}
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,6 +103,7 @@ class _SectionFolderState extends State<SectionFolder> {
|
|||||||
(view) => ViewItem(
|
(view) => ViewItem(
|
||||||
key: ValueKey('${widget.spaceType.name} ${view.id}'),
|
key: ValueKey('${widget.spaceType.name} ${view.id}'),
|
||||||
spaceType: widget.spaceType,
|
spaceType: widget.spaceType,
|
||||||
|
engagedInExpanding: true,
|
||||||
isFirstChild: view.id == widget.views.first.id,
|
isFirstChild: view.id == widget.views.first.id,
|
||||||
view: view,
|
view: view,
|
||||||
level: 0,
|
level: 0,
|
||||||
|
|||||||
@ -69,6 +69,7 @@ class ViewItem extends StatelessWidget {
|
|||||||
this.extendBuilder,
|
this.extendBuilder,
|
||||||
this.disableSelectedStatus,
|
this.disableSelectedStatus,
|
||||||
this.shouldIgnoreView,
|
this.shouldIgnoreView,
|
||||||
|
this.engagedInExpanding = false,
|
||||||
this.enableRightClickContext = false,
|
this.enableRightClickContext = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -136,12 +137,17 @@ class ViewItem extends StatelessWidget {
|
|||||||
///
|
///
|
||||||
final bool enableRightClickContext;
|
final bool enableRightClickContext;
|
||||||
|
|
||||||
|
/// to record the ViewBlock which is expanded or collapsed
|
||||||
|
final bool engagedInExpanding;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) =>
|
create: (_) => ViewBloc(
|
||||||
ViewBloc(view: view, shouldLoadChildViews: shouldLoadChildViews)
|
view: view,
|
||||||
..add(const ViewEvent.initial()),
|
shouldLoadChildViews: shouldLoadChildViews,
|
||||||
|
engagedInExpanding: engagedInExpanding,
|
||||||
|
)..add(const ViewEvent.initial()),
|
||||||
child: BlocConsumer<ViewBloc, ViewState>(
|
child: BlocConsumer<ViewBloc, ViewState>(
|
||||||
listenWhen: (p, c) =>
|
listenWhen: (p, c) =>
|
||||||
c.lastCreatedView != null &&
|
c.lastCreatedView != null &&
|
||||||
@ -183,6 +189,7 @@ class ViewItem extends StatelessWidget {
|
|||||||
isExpandedNotifier: isExpandedNotifier,
|
isExpandedNotifier: isExpandedNotifier,
|
||||||
extendBuilder: extendBuilder,
|
extendBuilder: extendBuilder,
|
||||||
shouldIgnoreView: shouldIgnoreView,
|
shouldIgnoreView: shouldIgnoreView,
|
||||||
|
engagedInExpanding: engagedInExpanding,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (shouldIgnoreView?.call(view) == IgnoreViewType.disable) {
|
if (shouldIgnoreView?.call(view) == IgnoreViewType.disable) {
|
||||||
@ -235,6 +242,7 @@ class InnerViewItem extends StatefulWidget {
|
|||||||
this.isExpandedNotifier,
|
this.isExpandedNotifier,
|
||||||
required this.extendBuilder,
|
required this.extendBuilder,
|
||||||
this.disableSelectedStatus,
|
this.disableSelectedStatus,
|
||||||
|
this.engagedInExpanding = false,
|
||||||
required this.shouldIgnoreView,
|
required this.shouldIgnoreView,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -270,6 +278,7 @@ class InnerViewItem extends StatefulWidget {
|
|||||||
final PropertyValueNotifier<bool>? isExpandedNotifier;
|
final PropertyValueNotifier<bool>? isExpandedNotifier;
|
||||||
final List<Widget> Function(ViewPB view)? extendBuilder;
|
final List<Widget> Function(ViewPB view)? extendBuilder;
|
||||||
final IgnoreViewType Function(ViewPB view)? shouldIgnoreView;
|
final IgnoreViewType Function(ViewPB view)? shouldIgnoreView;
|
||||||
|
final bool engagedInExpanding;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<InnerViewItem> createState() => _InnerViewItemState();
|
State<InnerViewItem> createState() => _InnerViewItemState();
|
||||||
@ -345,6 +354,7 @@ class _InnerViewItemState extends State<InnerViewItem> {
|
|||||||
rightIconsBuilder: widget.rightIconsBuilder,
|
rightIconsBuilder: widget.rightIconsBuilder,
|
||||||
extendBuilder: widget.extendBuilder,
|
extendBuilder: widget.extendBuilder,
|
||||||
shouldIgnoreView: widget.shouldIgnoreView,
|
shouldIgnoreView: widget.shouldIgnoreView,
|
||||||
|
engagedInExpanding: widget.engagedInExpanding,
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user