mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: remove the unused code
This commit is contained in:
parent
7a6c829187
commit
d0a343ee36
@ -1,7 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -75,7 +75,7 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(HomeMenu), findsOneWidget);
|
expect(find.byType(HomeSideBar), findsOneWidget);
|
||||||
|
|
||||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||||
[
|
[
|
||||||
@ -89,7 +89,7 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(HomeMenu), findsNothing);
|
expect(find.byType(HomeSideBar), findsNothing);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import 'switch_folder_test.dart' as switch_folder_test;
|
|||||||
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
|
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
|
||||||
import 'board/board_test_runner.dart' as board_test_runner;
|
import 'board/board_test_runner.dart' as board_test_runner;
|
||||||
import 'tabs_test.dart' as tabs_test;
|
import 'tabs_test.dart' as tabs_test;
|
||||||
|
import 'hotkeys_test.dart' as hotkeys_test;
|
||||||
|
|
||||||
/// The main task runner for all integration tests in AppFlowy.
|
/// The main task runner for all integration tests in AppFlowy.
|
||||||
///
|
///
|
||||||
@ -55,6 +56,9 @@ void main() {
|
|||||||
// Tabs
|
// Tabs
|
||||||
tabs_test.main();
|
tabs_test.main();
|
||||||
|
|
||||||
|
// Others
|
||||||
|
hotkeys_test.main();
|
||||||
|
|
||||||
// board_test.main();
|
// board_test.main();
|
||||||
// empty_document_test.main();
|
// empty_document_test.main();
|
||||||
// smart_menu_test.main();
|
// smart_menu_test.main();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
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/workspace/application/tabs/tabs_bloc.dart';
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
|
@ -26,7 +26,7 @@ import 'package:appflowy/workspace/application/settings/prelude.dart';
|
|||||||
import 'package:appflowy/user/application/prelude.dart';
|
import 'package:appflowy/user/application/prelude.dart';
|
||||||
import 'package:appflowy/user/presentation/router.dart';
|
import 'package:appflowy/user/presentation/router.dart';
|
||||||
import 'package:appflowy/plugins/trash/application/prelude.dart';
|
import 'package:appflowy/plugins/trash/application/prelude.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
@ -2,7 +2,7 @@ import 'dart:collection';
|
|||||||
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/view/prelude.dart';
|
import 'package:appflowy/workspace/application/view/prelude.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:expandable/expandable.dart';
|
import 'package:expandable/expandable.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||||
|
@ -3,7 +3,7 @@ import 'package:appflowy/startup/plugin/plugin.dart';
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
import 'package:appflowy/workspace/application/view/view_ext.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.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flowy_infra/image.dart';
|
|
||||||
import 'package:flowy_infra/size.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/extension.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
|
|
||||||
class NewAppButton extends StatelessWidget {
|
|
||||||
final Function(String)? press;
|
|
||||||
|
|
||||||
const NewAppButton({this.press, Key? key}) : super(key: key);
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final child = FlowyTextButton(
|
|
||||||
LocaleKeys.newPageText.tr(),
|
|
||||||
fillColor: Colors.transparent,
|
|
||||||
hoverColor: Colors.transparent,
|
|
||||||
fontColor: Theme.of(context).colorScheme.tertiary,
|
|
||||||
onPressed: () async => await _showCreateAppDialog(context),
|
|
||||||
heading: Container(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: Theme.of(context).colorScheme.surface,
|
|
||||||
),
|
|
||||||
child: svgWidget("home/new_app"),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: Insets.l, vertical: 20),
|
|
||||||
);
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
height: HomeSizes.menuAddButtonHeight,
|
|
||||||
child: child,
|
|
||||||
).topBorder(color: Theme.of(context).dividerColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showCreateAppDialog(BuildContext context) async {
|
|
||||||
return NavigatorTextFieldDialog(
|
|
||||||
title: LocaleKeys.newPageText.tr(),
|
|
||||||
value: "",
|
|
||||||
confirm: (newValue) {
|
|
||||||
if (newValue.isNotEmpty && press != null) {
|
|
||||||
press!(newValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
).show(context);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
import 'package:appflowy/plugins/document/document.dart';
|
|
||||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/app/header/import/import_panel.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/app/header/import/import_type.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
|
||||||
import 'package:flowy_infra/image.dart';
|
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
|
|
||||||
class AddButton extends StatelessWidget {
|
|
||||||
final String parentViewId;
|
|
||||||
final Function(
|
|
||||||
PluginBuilder,
|
|
||||||
String? name,
|
|
||||||
List<int>? initialDataBytes,
|
|
||||||
bool openAfterCreated,
|
|
||||||
) onSelected;
|
|
||||||
|
|
||||||
const AddButton({
|
|
||||||
required this.parentViewId,
|
|
||||||
Key? key,
|
|
||||||
required this.onSelected,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final List<PopoverAction> actions = [];
|
|
||||||
|
|
||||||
// Plugins
|
|
||||||
actions.addAll(
|
|
||||||
pluginBuilders()
|
|
||||||
.map(
|
|
||||||
(pluginBuilder) =>
|
|
||||||
AddButtonActionWrapper(pluginBuilder: pluginBuilder),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Import
|
|
||||||
actions.addAll(
|
|
||||||
getIt<PluginSandbox>()
|
|
||||||
.builders
|
|
||||||
.whereType<DocumentPluginBuilder>()
|
|
||||||
.map(
|
|
||||||
(pluginBuilder) =>
|
|
||||||
ImportActionWrapper(pluginBuilder: pluginBuilder),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return PopoverActionList<PopoverAction>(
|
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
|
||||||
actions: actions,
|
|
||||||
offset: const Offset(0, 8),
|
|
||||||
buildChild: (controller) {
|
|
||||||
return SizedBox(
|
|
||||||
width: 22,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => controller.show(),
|
|
||||||
child: FlowyHover(
|
|
||||||
style: HoverStyle(
|
|
||||||
hoverColor: AFThemeExtension.of(context).greySelect,
|
|
||||||
),
|
|
||||||
builder: (context, onHover) => const FlowySvg(
|
|
||||||
name: 'home/add',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onSelected: (action, controller) {
|
|
||||||
if (action is AddButtonActionWrapper) {
|
|
||||||
onSelected(action.pluginBuilder, null, null, true);
|
|
||||||
}
|
|
||||||
if (action is ImportActionWrapper) {
|
|
||||||
showImportPanel(
|
|
||||||
parentViewId,
|
|
||||||
context,
|
|
||||||
(type, name, initialDataBytes) {
|
|
||||||
if (initialDataBytes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (type) {
|
|
||||||
case ImportType.historyDocument:
|
|
||||||
case ImportType.historyDatabase:
|
|
||||||
case ImportType.databaseCSV:
|
|
||||||
case ImportType.databaseRawData:
|
|
||||||
onSelected(
|
|
||||||
action.pluginBuilder,
|
|
||||||
name,
|
|
||||||
initialDataBytes,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case ImportType.markdownOrText:
|
|
||||||
onSelected(
|
|
||||||
action.pluginBuilder,
|
|
||||||
name,
|
|
||||||
initialDataBytes,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
controller.close();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AddButtonActionWrapper extends ActionCell {
|
|
||||||
final PluginBuilder pluginBuilder;
|
|
||||||
|
|
||||||
AddButtonActionWrapper({required this.pluginBuilder});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget? leftIcon(Color iconColor) => FlowySvg(name: pluginBuilder.menuIcon);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => pluginBuilder.menuName;
|
|
||||||
|
|
||||||
PluginType get pluginType => pluginBuilder.pluginType;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImportActionWrapper extends ActionCell {
|
|
||||||
final DocumentPluginBuilder pluginBuilder;
|
|
||||||
|
|
||||||
ImportActionWrapper({
|
|
||||||
required this.pluginBuilder,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget? leftIcon(Color iconColor) => const FlowySvg(
|
|
||||||
name: 'editor/import',
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => LocaleKeys.moreAction_import.tr();
|
|
||||||
}
|
|
@ -1,205 +0,0 @@
|
|||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:expandable/expandable.dart';
|
|
||||||
import 'package:flowy_infra/icon_data.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/app/app_bloc.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
import 'package:flowy_infra/image.dart';
|
|
||||||
|
|
||||||
import '../menu_app.dart';
|
|
||||||
import 'add_button.dart';
|
|
||||||
|
|
||||||
class MenuAppHeader extends StatelessWidget {
|
|
||||||
final ViewPB parentView;
|
|
||||||
const MenuAppHeader(
|
|
||||||
this.parentView, {
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
height: MenuAppSizes.headerHeight,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
_renderExpandedIcon(context),
|
|
||||||
// HSpace(MenuAppSizes.iconPadding),
|
|
||||||
_renderTitle(context),
|
|
||||||
_renderCreateViewButton(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderExpandedIcon(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
width: MenuAppSizes.headerHeight,
|
|
||||||
height: MenuAppSizes.headerHeight,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
ExpandableController.of(
|
|
||||||
context,
|
|
||||||
rebuildOnChange: false,
|
|
||||||
required: true,
|
|
||||||
)?.toggle();
|
|
||||||
},
|
|
||||||
child: ExpandableIcon(
|
|
||||||
theme: ExpandableThemeData(
|
|
||||||
expandIcon: FlowyIconData.drop_down_show,
|
|
||||||
collapseIcon: FlowyIconData.drop_down_hide,
|
|
||||||
iconColor: Theme.of(context).colorScheme.tertiary,
|
|
||||||
iconSize: MenuAppSizes.iconSize,
|
|
||||||
iconPadding: const EdgeInsets.fromLTRB(0, 0, 10, 0),
|
|
||||||
hasIcon: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderTitle(BuildContext context) {
|
|
||||||
return Expanded(
|
|
||||||
child: BlocListener<AppBloc, AppState>(
|
|
||||||
listenWhen: (p, c) =>
|
|
||||||
(p.latestCreatedView == null && c.latestCreatedView != null),
|
|
||||||
listener: (context, state) {
|
|
||||||
final expandableController = ExpandableController.of(
|
|
||||||
context,
|
|
||||||
rebuildOnChange: false,
|
|
||||||
required: true,
|
|
||||||
)!;
|
|
||||||
if (!expandableController.expanded) {
|
|
||||||
expandableController.toggle();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: AppActionList(
|
|
||||||
onSelected: (action) {
|
|
||||||
switch (action) {
|
|
||||||
case AppDisclosureAction.rename:
|
|
||||||
NavigatorTextFieldDialog(
|
|
||||||
title: LocaleKeys.menuAppHeader_renameDialog.tr(),
|
|
||||||
autoSelectAllText: true,
|
|
||||||
value: context.read<AppBloc>().state.view.name,
|
|
||||||
confirm: (newValue) {
|
|
||||||
context.read<AppBloc>().add(AppEvent.rename(newValue));
|
|
||||||
},
|
|
||||||
).show(context);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case AppDisclosureAction.delete:
|
|
||||||
context.read<AppBloc>().add(const AppEvent.delete());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderCreateViewButton(BuildContext context) {
|
|
||||||
return Tooltip(
|
|
||||||
message: LocaleKeys.menuAppHeader_addPageTooltip.tr(),
|
|
||||||
child: AddButton(
|
|
||||||
parentViewId: parentView.id,
|
|
||||||
onSelected: (pluginBuilder, name, initialDataBytes, openAfterCreated) {
|
|
||||||
context.read<AppBloc>().add(
|
|
||||||
AppEvent.createView(
|
|
||||||
name ?? LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
|
||||||
pluginBuilder.layoutType!,
|
|
||||||
initialDataBytes: initialDataBytes,
|
|
||||||
openAfterCreated: openAfterCreated,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).padding(right: MenuAppSizes.headerPadding),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AppDisclosureAction {
|
|
||||||
rename,
|
|
||||||
delete,
|
|
||||||
}
|
|
||||||
|
|
||||||
extension AppDisclosureExtension on AppDisclosureAction {
|
|
||||||
String get name {
|
|
||||||
switch (this) {
|
|
||||||
case AppDisclosureAction.rename:
|
|
||||||
return LocaleKeys.disclosureAction_rename.tr();
|
|
||||||
case AppDisclosureAction.delete:
|
|
||||||
return LocaleKeys.disclosureAction_delete.tr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget icon(Color iconColor) {
|
|
||||||
switch (this) {
|
|
||||||
case AppDisclosureAction.rename:
|
|
||||||
return const FlowySvg(name: 'editor/edit');
|
|
||||||
case AppDisclosureAction.delete:
|
|
||||||
return const FlowySvg(name: 'editor/delete');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppActionList extends StatelessWidget {
|
|
||||||
final Function(AppDisclosureAction) onSelected;
|
|
||||||
const AppActionList({
|
|
||||||
required this.onSelected,
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return PopoverActionList<DisclosureActionWrapper>(
|
|
||||||
direction: PopoverDirection.bottomWithCenterAligned,
|
|
||||||
actions: AppDisclosureAction.values
|
|
||||||
.map((action) => DisclosureActionWrapper(action))
|
|
||||||
.toList(),
|
|
||||||
buildChild: (controller) {
|
|
||||||
return GestureDetector(
|
|
||||||
behavior: HitTestBehavior.opaque,
|
|
||||||
onTap: () => ExpandableController.of(
|
|
||||||
context,
|
|
||||||
rebuildOnChange: false,
|
|
||||||
required: true,
|
|
||||||
)?.toggle(),
|
|
||||||
onSecondaryTap: () {
|
|
||||||
controller.show();
|
|
||||||
},
|
|
||||||
child: BlocSelector<AppBloc, AppState, ViewPB>(
|
|
||||||
selector: (state) => state.view,
|
|
||||||
builder: (context, app) => FlowyText.medium(
|
|
||||||
app.name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
color: Theme.of(context).colorScheme.tertiary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onSelected: (action, controller) {
|
|
||||||
onSelected(action.inner);
|
|
||||||
controller.close();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisclosureActionWrapper extends ActionCell {
|
|
||||||
final AppDisclosureAction inner;
|
|
||||||
|
|
||||||
DisclosureActionWrapper(this.inner);
|
|
||||||
@override
|
|
||||||
Widget? leftIcon(Color iconColor) => inner.icon(iconColor);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => inner.name;
|
|
||||||
}
|
|
@ -1,121 +0,0 @@
|
|||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|
||||||
import 'package:expandable/expandable.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/workspace/application/app/app_bloc.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'section/section.dart';
|
|
||||||
|
|
||||||
class MenuApp extends StatefulWidget {
|
|
||||||
final ViewPB view;
|
|
||||||
const MenuApp(this.view, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MenuApp> createState() => _MenuAppState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MenuAppState extends State<MenuApp> {
|
|
||||||
late ViewDataContext viewDataContext;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
viewDataContext = ViewDataContext(viewId: widget.view.id);
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MultiBlocProvider(
|
|
||||||
providers: [
|
|
||||||
BlocProvider<AppBloc>(
|
|
||||||
create: (context) {
|
|
||||||
final appBloc = AppBloc(view: widget.view);
|
|
||||||
appBloc.add(const AppEvent.initial());
|
|
||||||
return appBloc;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: MultiBlocListener(
|
|
||||||
listeners: [
|
|
||||||
BlocListener<AppBloc, AppState>(
|
|
||||||
listenWhen: (p, c) => p.latestCreatedView != c.latestCreatedView,
|
|
||||||
listener: (context, state) {
|
|
||||||
if (state.latestCreatedView != null) {
|
|
||||||
getIt<MenuSharedState>().latestOpenView =
|
|
||||||
state.latestCreatedView;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
BlocListener<AppBloc, AppState>(
|
|
||||||
listener: (context, state) => viewDataContext.views = state.views,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: BlocBuilder<AppBloc, AppState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return ChangeNotifierProvider.value(
|
|
||||||
value: viewDataContext,
|
|
||||||
child: Consumer<ViewDataContext>(
|
|
||||||
builder: (context, viewDataContext, _) {
|
|
||||||
return expandableWrapper(context, viewDataContext);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpandableNotifier expandableWrapper(
|
|
||||||
BuildContext context,
|
|
||||||
ViewDataContext viewDataContext,
|
|
||||||
) {
|
|
||||||
return ExpandableNotifier(
|
|
||||||
controller: viewDataContext.expandController,
|
|
||||||
child: ScrollOnExpand(
|
|
||||||
scrollOnExpand: false,
|
|
||||||
scrollOnCollapse: false,
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
ExpandablePanel(
|
|
||||||
theme: const ExpandableThemeData(
|
|
||||||
headerAlignment: ExpandablePanelHeaderAlignment.center,
|
|
||||||
tapBodyToExpand: false,
|
|
||||||
tapBodyToCollapse: false,
|
|
||||||
tapHeaderToExpand: false,
|
|
||||||
iconPadding: EdgeInsets.zero,
|
|
||||||
hasIcon: false,
|
|
||||||
),
|
|
||||||
header: MenuAppHeader(widget.view),
|
|
||||||
expanded: ViewSection(appViewData: viewDataContext),
|
|
||||||
collapsed: const SizedBox(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(covariant MenuApp oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
viewDataContext.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MenuAppSizes {
|
|
||||||
static double iconSize = 16;
|
|
||||||
static double headerHeight = 26;
|
|
||||||
static double headerPadding = 6;
|
|
||||||
static double iconPadding = 6;
|
|
||||||
static double appVPadding = 14;
|
|
||||||
static double scale = 1;
|
|
||||||
static double get expandedPadding => iconSize * scale + headerPadding;
|
|
||||||
}
|
|
@ -1,243 +0,0 @@
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
import 'package:flowy_infra/image.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
|
||||||
|
|
||||||
class ViewSectionItem extends StatelessWidget {
|
|
||||||
final bool isSelected;
|
|
||||||
final ViewPB view;
|
|
||||||
final void Function(ViewPB) onSelected;
|
|
||||||
|
|
||||||
const ViewSectionItem({
|
|
||||||
Key? key,
|
|
||||||
required this.view,
|
|
||||||
required this.isSelected,
|
|
||||||
required this.onSelected,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MultiBlocProvider(
|
|
||||||
providers: [
|
|
||||||
BlocProvider(
|
|
||||||
create: (ctx) => getIt<ViewBloc>(param1: view)
|
|
||||||
..add(
|
|
||||||
const ViewEvent.initial(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: BlocBuilder<ViewBloc, ViewState>(
|
|
||||||
builder: (blocContext, state) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => onSelected(blocContext.read<ViewBloc>().state.view),
|
|
||||||
child: FlowyHover(
|
|
||||||
style: HoverStyle(
|
|
||||||
hoverColor: Theme.of(context).colorScheme.secondary,
|
|
||||||
),
|
|
||||||
// If current state.isEditing is true, the hover should not
|
|
||||||
// rebuild when onEnter/onExit events happened.
|
|
||||||
buildWhenOnHover: () => !state.isEditing,
|
|
||||||
builder: (_, onHover) => _render(
|
|
||||||
blocContext,
|
|
||||||
onHover,
|
|
||||||
state,
|
|
||||||
),
|
|
||||||
isSelected: () => state.isEditing || isSelected,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _render(
|
|
||||||
BuildContext blocContext,
|
|
||||||
bool onHover,
|
|
||||||
ViewState state,
|
|
||||||
) {
|
|
||||||
final List<Widget> children = [
|
|
||||||
SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: state.view.renderThumbnail(),
|
|
||||||
),
|
|
||||||
const HSpace(2),
|
|
||||||
Expanded(
|
|
||||||
child: FlowyText.regular(
|
|
||||||
state.view.name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (onHover || state.isEditing) {
|
|
||||||
children.add(
|
|
||||||
ViewDisclosureButton(
|
|
||||||
state: state,
|
|
||||||
onEdit: (isEdit) =>
|
|
||||||
blocContext.read<ViewBloc>().add(ViewEvent.setIsEditing(isEdit)),
|
|
||||||
onAction: (action) {
|
|
||||||
switch (action) {
|
|
||||||
case ViewDisclosureAction.rename:
|
|
||||||
NavigatorTextFieldDialog(
|
|
||||||
title: LocaleKeys.disclosureAction_rename.tr(),
|
|
||||||
autoSelectAllText: true,
|
|
||||||
value: blocContext.read<ViewBloc>().state.view.name,
|
|
||||||
confirm: (newValue) {
|
|
||||||
blocContext
|
|
||||||
.read<ViewBloc>()
|
|
||||||
.add(ViewEvent.rename(newValue));
|
|
||||||
},
|
|
||||||
).show(blocContext);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ViewDisclosureAction.delete:
|
|
||||||
blocContext.read<ViewBloc>().add(const ViewEvent.delete());
|
|
||||||
break;
|
|
||||||
case ViewDisclosureAction.duplicate:
|
|
||||||
blocContext.read<ViewBloc>().add(const ViewEvent.duplicate());
|
|
||||||
break;
|
|
||||||
case ViewDisclosureAction.favorite:
|
|
||||||
blocContext
|
|
||||||
.read<FavoriteBloc>()
|
|
||||||
.add(FavoriteEvent.toggle(view));
|
|
||||||
break;
|
|
||||||
case ViewDisclosureAction.openInNewTab:
|
|
||||||
blocContext.read<TabsBloc>().openTab(state.view);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
height: 26,
|
|
||||||
child: Row(children: children).padding(
|
|
||||||
left: MenuAppSizes.expandedPadding,
|
|
||||||
right: MenuAppSizes.headerPadding,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ViewDisclosureAction {
|
|
||||||
rename,
|
|
||||||
delete,
|
|
||||||
duplicate,
|
|
||||||
favorite,
|
|
||||||
openInNewTab,
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ViewDisclosureExtension on ViewDisclosureAction {
|
|
||||||
String name({ViewState? state}) {
|
|
||||||
switch (this) {
|
|
||||||
case ViewDisclosureAction.rename:
|
|
||||||
return LocaleKeys.disclosureAction_rename.tr();
|
|
||||||
case ViewDisclosureAction.delete:
|
|
||||||
return LocaleKeys.disclosureAction_delete.tr();
|
|
||||||
case ViewDisclosureAction.duplicate:
|
|
||||||
return LocaleKeys.disclosureAction_duplicate.tr();
|
|
||||||
case ViewDisclosureAction.favorite:
|
|
||||||
return state!.view.isFavorite
|
|
||||||
? LocaleKeys.disclosureAction_unfavorite.tr()
|
|
||||||
: LocaleKeys.disclosureAction_favorite.tr();
|
|
||||||
case ViewDisclosureAction.openInNewTab:
|
|
||||||
return LocaleKeys.disclosureAction_openNewTab.tr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget icon(Color iconColor, {ViewState? state}) {
|
|
||||||
switch (this) {
|
|
||||||
case ViewDisclosureAction.rename:
|
|
||||||
return const FlowySvg(name: 'editor/edit');
|
|
||||||
case ViewDisclosureAction.delete:
|
|
||||||
return const FlowySvg(name: 'editor/delete');
|
|
||||||
case ViewDisclosureAction.duplicate:
|
|
||||||
return const FlowySvg(name: 'editor/copy');
|
|
||||||
case ViewDisclosureAction.favorite:
|
|
||||||
return state!.view.isFavorite
|
|
||||||
? const FlowySvg(name: 'home/favorite')
|
|
||||||
: const FlowySvg(name: 'home/unfavorite');
|
|
||||||
case ViewDisclosureAction.openInNewTab:
|
|
||||||
return const FlowySvg(name: 'grid/expander');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewDisclosureButton extends StatelessWidget {
|
|
||||||
final Function(bool) onEdit;
|
|
||||||
final Function(ViewDisclosureAction) onAction;
|
|
||||||
final ViewState state;
|
|
||||||
const ViewDisclosureButton({
|
|
||||||
required this.onEdit,
|
|
||||||
required this.onAction,
|
|
||||||
required this.state,
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return PopoverActionList<ViewDisclosureActionWrapper>(
|
|
||||||
direction: PopoverDirection.bottomWithCenterAligned,
|
|
||||||
actions: ViewDisclosureAction.values
|
|
||||||
.map((action) => ViewDisclosureActionWrapper(action, state))
|
|
||||||
.toList(),
|
|
||||||
buildChild: (controller) {
|
|
||||||
return FlowyIconButton(
|
|
||||||
hoverColor: Colors.transparent,
|
|
||||||
iconPadding: const EdgeInsets.all(5),
|
|
||||||
width: 26,
|
|
||||||
icon: svgWidget(
|
|
||||||
"editor/details",
|
|
||||||
color: Theme.of(context).iconTheme.color,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
onEdit(true);
|
|
||||||
controller.show();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onSelected: (action, controller) {
|
|
||||||
onEdit(false);
|
|
||||||
onAction(action.inner);
|
|
||||||
controller.close();
|
|
||||||
},
|
|
||||||
onClosed: () {
|
|
||||||
onEdit(false);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewDisclosureActionWrapper extends ActionCell {
|
|
||||||
final ViewDisclosureAction inner;
|
|
||||||
final ViewState? state;
|
|
||||||
|
|
||||||
ViewDisclosureActionWrapper(this.inner, [this.state]);
|
|
||||||
@override
|
|
||||||
Widget? leftIcon(Color iconColor) => inner.icon(iconColor, state: state);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => inner.name(state: state);
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/workspace/application/app/app_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/menu/menu_view_section_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/app/section/item.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:reorderables/reorderables.dart';
|
|
||||||
|
|
||||||
class ViewSection extends StatelessWidget {
|
|
||||||
final ViewDataContext appViewData;
|
|
||||||
const ViewSection({Key? key, required this.appViewData}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocProvider(
|
|
||||||
create: (context) {
|
|
||||||
final bloc = ViewSectionBloc(appViewData: appViewData);
|
|
||||||
bloc.add(const ViewSectionEvent.initial());
|
|
||||||
return bloc;
|
|
||||||
},
|
|
||||||
child: BlocListener<ViewSectionBloc, ViewSectionState>(
|
|
||||||
listenWhen: (p, c) => p.selectedView != c.selectedView,
|
|
||||||
listener: (context, state) {
|
|
||||||
if (state.selectedView != null) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
getIt<TabsBloc>().add(
|
|
||||||
TabsEvent.openPlugin(
|
|
||||||
plugin: state.selectedView!.plugin(listenOnViewChanged: true),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: BlocBuilder<ViewSectionBloc, ViewSectionState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return _reorderableColumn(context, state);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReorderableColumn _reorderableColumn(
|
|
||||||
BuildContext context,
|
|
||||||
ViewSectionState state,
|
|
||||||
) {
|
|
||||||
final children = state.views.map((view) {
|
|
||||||
final isSelected = _isViewSelected(state, view.id);
|
|
||||||
return ViewSectionItem(
|
|
||||||
view: view,
|
|
||||||
key: ValueKey('$view.hashCode/$isSelected'),
|
|
||||||
isSelected: isSelected,
|
|
||||||
onSelected: (view) => getIt<MenuSharedState>().latestOpenView = view,
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
return ReorderableColumn(
|
|
||||||
needsLongPressDraggable: false,
|
|
||||||
onReorder: (oldIndex, index) {
|
|
||||||
context
|
|
||||||
.read<ViewSectionBloc>()
|
|
||||||
.add(ViewSectionEvent.moveView(oldIndex, index));
|
|
||||||
},
|
|
||||||
ignorePrimaryScrollController: true,
|
|
||||||
buildDraggableFeedback: (context, constraints, child) => ConstrainedBox(
|
|
||||||
constraints: constraints,
|
|
||||||
child: Material(color: Colors.transparent, child: child),
|
|
||||||
),
|
|
||||||
children: children,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isViewSelected(ViewSectionState state, String viewId) {
|
|
||||||
return state.selectedView?.id == viewId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,289 +0,0 @@
|
|||||||
import 'dart:io' show Platform;
|
|
||||||
|
|
||||||
import 'package:appflowy/core/frameless_window.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
import 'package:appflowy/plugins/trash/menu.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/application/menu/menu_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/workspace.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
|
|
||||||
show UserProfilePB;
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:expandable/expandable.dart';
|
|
||||||
import 'package:flowy_infra/image.dart';
|
|
||||||
import 'package:flowy_infra/size.dart';
|
|
||||||
import 'package:flowy_infra/time/duration.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
|
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
|
|
||||||
import '../navigation.dart';
|
|
||||||
import 'app/create_button.dart';
|
|
||||||
import 'app/menu_app.dart';
|
|
||||||
import 'app/section/item.dart';
|
|
||||||
import 'menu_user.dart';
|
|
||||||
|
|
||||||
export './app/header/header.dart';
|
|
||||||
export './app/menu_app.dart';
|
|
||||||
|
|
||||||
class HomeMenu extends StatelessWidget {
|
|
||||||
final UserProfilePB user;
|
|
||||||
final WorkspaceSettingPB workspaceSetting;
|
|
||||||
|
|
||||||
const HomeMenu({
|
|
||||||
Key? key,
|
|
||||||
required this.user,
|
|
||||||
required this.workspaceSetting,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MultiBlocProvider(
|
|
||||||
providers: [
|
|
||||||
BlocProvider<MenuBloc>(
|
|
||||||
create: (context) => MenuBloc(
|
|
||||||
user: user,
|
|
||||||
workspace: workspaceSetting.workspace,
|
|
||||||
)..add(const MenuEvent.initial()),
|
|
||||||
),
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) =>
|
|
||||||
getIt<FavoriteBloc>()..add(const FavoriteEvent.initial()),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
child: BlocBuilder<MenuBloc, MenuState>(
|
|
||||||
builder: (context, state) => _renderBody(context),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderBody(BuildContext context) {
|
|
||||||
// nested column: https://siddharthmolleti.com/flutter-box-constraints-nested-column-s-row-s-3dfacada7361
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
|
||||||
border:
|
|
||||||
Border(right: BorderSide(color: Theme.of(context).dividerColor)),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const MenuTopBar(),
|
|
||||||
const VSpace(10),
|
|
||||||
_renderApps(context),
|
|
||||||
],
|
|
||||||
).padding(horizontal: Insets.l),
|
|
||||||
),
|
|
||||||
const VSpace(20),
|
|
||||||
const MenuTrash(),
|
|
||||||
const VSpace(20),
|
|
||||||
_renderNewAppButton(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderFavorites(BuildContext context) {
|
|
||||||
return BlocBuilder<FavoriteBloc, FavoriteState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return state.views.isNotEmpty
|
|
||||||
? ExpandableTheme(
|
|
||||||
data: ExpandableThemeData(
|
|
||||||
useInkWell: true,
|
|
||||||
animationDuration: Durations.medium,
|
|
||||||
),
|
|
||||||
child: ExpandablePanel(
|
|
||||||
theme: const ExpandableThemeData(
|
|
||||||
headerAlignment: ExpandablePanelHeaderAlignment.center,
|
|
||||||
tapBodyToExpand: false,
|
|
||||||
tapBodyToCollapse: false,
|
|
||||||
tapHeaderToExpand: false,
|
|
||||||
iconPadding: EdgeInsets.zero,
|
|
||||||
hasIcon: false,
|
|
||||||
),
|
|
||||||
// header: const FavoriteHeader(),
|
|
||||||
expanded: ScrollConfiguration(
|
|
||||||
behavior:
|
|
||||||
const ScrollBehavior().copyWith(scrollbars: false),
|
|
||||||
child: Column(
|
|
||||||
children: state.views
|
|
||||||
.map(
|
|
||||||
(e) => ViewSectionItem(
|
|
||||||
key: ValueKey(e.id),
|
|
||||||
isSelected: false,
|
|
||||||
onSelected: (view) => getIt<MenuSharedState>()
|
|
||||||
.latestOpenView = view,
|
|
||||||
view: e,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
collapsed: const SizedBox.shrink(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderApps(BuildContext context) {
|
|
||||||
return ExpandableTheme(
|
|
||||||
data: ExpandableThemeData(
|
|
||||||
useInkWell: true,
|
|
||||||
animationDuration: Durations.medium,
|
|
||||||
),
|
|
||||||
child: Expanded(
|
|
||||||
child: ScrollConfiguration(
|
|
||||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
|
||||||
child: BlocSelector<MenuBloc, MenuState, List<Widget>>(
|
|
||||||
selector: (state) => state.views
|
|
||||||
.map((app) => MenuApp(app, key: ValueKey(app.id)))
|
|
||||||
.toList(),
|
|
||||||
builder: (context, menuItems) {
|
|
||||||
return ReorderableListView.builder(
|
|
||||||
itemCount: menuItems.length,
|
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
header: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: MenuAppSizes.appVPadding,
|
|
||||||
),
|
|
||||||
child: MenuUser(user),
|
|
||||||
),
|
|
||||||
_renderFavorites(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onReorder: (oldIndex, newIndex) {
|
|
||||||
// Moving item1 from index 0 to index 1
|
|
||||||
// expect: oldIndex: 0, newIndex: 1
|
|
||||||
// receive: oldIndex: 0, newIndex: 2
|
|
||||||
// Workaround: if newIndex > oldIndex, we just minus one
|
|
||||||
final int index =
|
|
||||||
newIndex > oldIndex ? newIndex - 1 : newIndex;
|
|
||||||
context
|
|
||||||
.read<MenuBloc>()
|
|
||||||
.add(MenuEvent.moveApp(oldIndex, index));
|
|
||||||
},
|
|
||||||
physics: StyledScrollPhysics(),
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
return ReorderableDragStartListener(
|
|
||||||
key: ValueKey(menuItems[index].key),
|
|
||||||
index: index,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: MenuAppSizes.appVPadding / 2,
|
|
||||||
),
|
|
||||||
child: menuItems[index],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
proxyDecorator: (child, index, animation) =>
|
|
||||||
Material(color: Colors.transparent, child: child),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderNewAppButton(BuildContext context) {
|
|
||||||
return NewAppButton(
|
|
||||||
press: (appName) =>
|
|
||||||
context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MenuSharedState {
|
|
||||||
final ValueNotifier<ViewPB?> _latestOpenView = ValueNotifier<ViewPB?>(null);
|
|
||||||
|
|
||||||
MenuSharedState({ViewPB? view}) {
|
|
||||||
_latestOpenView.value = view;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewPB? get latestOpenView => _latestOpenView.value;
|
|
||||||
ValueNotifier<ViewPB?> get notifier => _latestOpenView;
|
|
||||||
|
|
||||||
set latestOpenView(ViewPB? view) {
|
|
||||||
if (_latestOpenView.value?.id != view?.id) {
|
|
||||||
_latestOpenView.value = view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VoidCallback addLatestViewListener(void Function(ViewPB?) callback) {
|
|
||||||
listener() {
|
|
||||||
callback(_latestOpenView.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
_latestOpenView.addListener(listener);
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeLatestViewListener(VoidCallback listener) {
|
|
||||||
_latestOpenView.removeListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MenuTopBar extends StatelessWidget {
|
|
||||||
const MenuTopBar({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
Widget renderIcon(BuildContext context) {
|
|
||||||
if (Platform.isMacOS) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
return (Theme.of(context).brightness == Brightness.dark
|
|
||||||
? svgWidget("flowy_logo_dark_mode", size: const Size(92, 17))
|
|
||||||
: svgWidget("flowy_logo_with_text", size: const Size(92, 17)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<MenuBloc, MenuState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return SizedBox(
|
|
||||||
height: HomeSizes.topBarHeight,
|
|
||||||
child: MoveWindowDetector(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
renderIcon(context),
|
|
||||||
const Spacer(),
|
|
||||||
Tooltip(
|
|
||||||
richMessage: sidebarTooltipTextSpan(
|
|
||||||
context,
|
|
||||||
LocaleKeys.sideBar_closeSidebar.tr(),
|
|
||||||
),
|
|
||||||
child: FlowyIconButton(
|
|
||||||
width: 28,
|
|
||||||
hoverColor: Colors.transparent,
|
|
||||||
onPressed: () => context
|
|
||||||
.read<HomeSettingBloc>()
|
|
||||||
.add(const HomeSettingEvent.collapseMenu()),
|
|
||||||
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
|
||||||
icon: svgWidget(
|
|
||||||
"home/hide_menu",
|
|
||||||
color: Theme.of(context).iconTheme.color,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,32 @@
|
|||||||
|
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MenuSharedState {
|
||||||
|
final ValueNotifier<ViewPB?> _latestOpenView = ValueNotifier<ViewPB?>(null);
|
||||||
|
|
||||||
|
MenuSharedState({ViewPB? view}) {
|
||||||
|
_latestOpenView.value = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewPB? get latestOpenView => _latestOpenView.value;
|
||||||
|
ValueNotifier<ViewPB?> get notifier => _latestOpenView;
|
||||||
|
|
||||||
|
set latestOpenView(ViewPB? view) {
|
||||||
|
if (_latestOpenView.value?.id != view?.id) {
|
||||||
|
_latestOpenView.value = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VoidCallback addLatestViewListener(void Function(ViewPB?) callback) {
|
||||||
|
listener() {
|
||||||
|
callback(_latestOpenView.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_latestOpenView.addListener(listener);
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeLatestViewListener(VoidCallback listener) {
|
||||||
|
_latestOpenView.removeListener(listener);
|
||||||
|
}
|
||||||
|
}
|
@ -1,147 +0,0 @@
|
|||||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
|
||||||
import 'package:appflowy/startup/entry_point.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
|
||||||
import 'package:appflowy/util/color_generator/color_generator.dart';
|
|
||||||
import 'package:appflowy/workspace/application/menu/menu_user_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
|
|
||||||
import 'package:flowy_infra/image.dart';
|
|
||||||
import 'package:flowy_infra/size.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
|
|
||||||
show UserProfilePB;
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
|
|
||||||
class MenuUser extends StatelessWidget {
|
|
||||||
final UserProfilePB user;
|
|
||||||
MenuUser(this.user, {Key? key}) : super(key: ValueKey(user.id));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocProvider<MenuUserBloc>(
|
|
||||||
create: (context) =>
|
|
||||||
getIt<MenuUserBloc>(param1: user)..add(const MenuUserEvent.initial()),
|
|
||||||
child: BlocBuilder<MenuUserBloc, MenuUserState>(
|
|
||||||
builder: (context, state) => Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
_renderAvatar(context),
|
|
||||||
const HSpace(10),
|
|
||||||
Expanded(
|
|
||||||
child: _renderUserName(context),
|
|
||||||
),
|
|
||||||
_renderSettingsButton(context),
|
|
||||||
//ToDo: when the user is allowed to create another workspace,
|
|
||||||
//we get the below block back
|
|
||||||
//_renderDropButton(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderAvatar(BuildContext context) {
|
|
||||||
String iconUrl = context.read<MenuUserBloc>().state.userProfile.iconUrl;
|
|
||||||
if (iconUrl.isEmpty) {
|
|
||||||
iconUrl = defaultUserAvatar;
|
|
||||||
final String name =
|
|
||||||
userName(context.read<MenuUserBloc>().state.userProfile);
|
|
||||||
final Color color = ColorGenerator().generateColorFromString(name);
|
|
||||||
const initialsCount = 2;
|
|
||||||
// Taking the first letters of the name components and limiting to 2 elements
|
|
||||||
final nameInitials = name
|
|
||||||
.split(' ')
|
|
||||||
.where((element) => element.isNotEmpty)
|
|
||||||
.take(initialsCount)
|
|
||||||
.map((element) => element[0].toUpperCase())
|
|
||||||
.join('');
|
|
||||||
return Container(
|
|
||||||
width: 28,
|
|
||||||
height: 28,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: color,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: FlowyText.semibold(
|
|
||||||
nameInitials,
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: nameInitials.length == initialsCount ? 12 : 14,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return SizedBox(
|
|
||||||
width: 25,
|
|
||||||
height: 25,
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: Corners.s5Border,
|
|
||||||
child: CircleAvatar(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
child: svgWidget('emoji/$iconUrl'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderUserName(BuildContext context) {
|
|
||||||
final String name =
|
|
||||||
userName(context.read<MenuUserBloc>().state.userProfile);
|
|
||||||
return FlowyText.medium(
|
|
||||||
name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
color: Theme.of(context).colorScheme.tertiary,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _renderSettingsButton(BuildContext context) {
|
|
||||||
final userProfile = context.read<MenuUserBloc>().state.userProfile;
|
|
||||||
return Tooltip(
|
|
||||||
message: LocaleKeys.settings_menu_open.tr(),
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (dialogContext) {
|
|
||||||
return BlocProvider<DocumentAppearanceCubit>.value(
|
|
||||||
value: BlocProvider.of<DocumentAppearanceCubit>(context),
|
|
||||||
child: SettingsDialog(
|
|
||||||
userProfile,
|
|
||||||
didLogout: () async {
|
|
||||||
Navigator.of(dialogContext).pop();
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
await FlowyRunner.run(
|
|
||||||
FlowyApp(),
|
|
||||||
integrationEnv(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
dismissDialog: () => Navigator.of(context).pop(),
|
|
||||||
didOpenUser: () {},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: SizedBox.square(
|
|
||||||
dimension: 20,
|
|
||||||
child: svgWidget(
|
|
||||||
"home/settings",
|
|
||||||
color: Theme.of(context).colorScheme.tertiary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the user name, if the user name is empty, return the default user name.
|
|
||||||
String userName(UserProfilePB userProfile) {
|
|
||||||
String name = userProfile.name;
|
|
||||||
if (name.isEmpty) {
|
|
||||||
name = LocaleKeys.defaultUsername.tr();
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,8 @@ import 'package:appflowy/plugins/document/application/document_data_pb_extension
|
|||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/migration/editor_migration.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/migration/editor_migration.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/share/import_service.dart';
|
import 'package:appflowy/workspace/application/settings/share/import_service.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/app/header/import/import_type.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/import/import_type.dart';
|
||||||
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
||||||
import 'package:flowy_infra/file_picker/file_picker_service.dart';
|
import 'package:flowy_infra/file_picker/file_picker_service.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/favorite_folder.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/favorite_folder.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
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/workspace/application/tabs/tabs_bloc.dart';
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import 'package:appflowy/plugins/document/document.dart';
|
import 'package:appflowy/plugins/document/document.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/workspace/presentation/home/menu/app/header/import/import_panel.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/import/import_panel.dart';
|
||||||
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
|
@ -5,7 +5,7 @@ import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
|||||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user