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 'package:appflowy/generated/locale_keys.g.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:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@ -75,7 +75,7 @@ void main() {
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(HomeMenu), findsOneWidget);
|
||||
expect(find.byType(HomeSideBar), findsOneWidget);
|
||||
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
@ -89,7 +89,7 @@ void main() {
|
||||
|
||||
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 'board/board_test_runner.dart' as board_test_runner;
|
||||
import 'tabs_test.dart' as tabs_test;
|
||||
import 'hotkeys_test.dart' as hotkeys_test;
|
||||
|
||||
/// The main task runner for all integration tests in AppFlowy.
|
||||
///
|
||||
@ -55,6 +56,9 @@ void main() {
|
||||
// Tabs
|
||||
tabs_test.main();
|
||||
|
||||
// Others
|
||||
hotkeys_test.main();
|
||||
|
||||
// board_test.main();
|
||||
// empty_document_test.main();
|
||||
// smart_menu_test.main();
|
||||
|
@ -1,7 +1,7 @@
|
||||
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/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:flowy_infra/theme_extension.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/presentation/router.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-user/user_profile.pb.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'dart:collection';
|
||||
|
||||
import 'package:appflowy/startup/startup.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:appflowy_backend/log.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/workspace/application/view/view_ext.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:bloc/bloc.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/startup/startup.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:flowy_infra/file_picker/file_picker_service.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
@ -1,5 +1,5 @@
|
||||
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/personal_folder.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/startup.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:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
|
@ -1,7 +1,8 @@
|
||||
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/sidebar/import/import_panel.dart';
|
||||
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.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/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/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/view_action_type.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
|
||||
|
Loading…
Reference in New Issue
Block a user