|
@@ -1,31 +1,47 @@
|
|
-import 'package:app_flowy/workspace/presentation/widgets/menu/widget/app/menu_app.dart';
|
|
|
|
|
|
+import 'package:dartz/dartz.dart' as dartz;
|
|
|
|
+import 'package:flowy_infra/image.dart';
|
|
import 'package:flowy_infra/theme.dart';
|
|
import 'package:flowy_infra/theme.dart';
|
|
|
|
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
|
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
|
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
-import 'package:app_flowy/workspace/domain/image.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:styled_widget/styled_widget.dart';
|
|
import 'package:styled_widget/styled_widget.dart';
|
|
|
|
|
|
|
|
+import 'package:app_flowy/workspace/domain/image.dart';
|
|
|
|
+import 'package:app_flowy/workspace/domain/view_edit.dart';
|
|
|
|
+import 'package:app_flowy/workspace/presentation/widgets/menu/widget/app/menu_app.dart';
|
|
|
|
+
|
|
class ViewWidgetContext {
|
|
class ViewWidgetContext {
|
|
final View view;
|
|
final View view;
|
|
-
|
|
|
|
ViewWidgetContext(this.view);
|
|
ViewWidgetContext(this.view);
|
|
-
|
|
|
|
Key valueKey() => ValueKey("${view.id}${view.version}");
|
|
Key valueKey() => ValueKey("${view.id}${view.version}");
|
|
}
|
|
}
|
|
|
|
|
|
typedef OpenViewCallback = void Function(View);
|
|
typedef OpenViewCallback = void Function(View);
|
|
|
|
|
|
-class ViewSectionItem extends StatelessWidget {
|
|
|
|
|
|
+// ignore: must_be_immutable
|
|
|
|
+class ViewSectionItem extends StatefulWidget {
|
|
final ViewWidgetContext viewCtx;
|
|
final ViewWidgetContext viewCtx;
|
|
final bool isSelected;
|
|
final bool isSelected;
|
|
final OpenViewCallback onOpen;
|
|
final OpenViewCallback onOpen;
|
|
- ViewSectionItem({Key? key, required this.viewCtx, required this.onOpen, required this.isSelected})
|
|
|
|
- : super(key: viewCtx.valueKey());
|
|
|
|
|
|
+
|
|
|
|
+ ViewSectionItem({
|
|
|
|
+ Key? key,
|
|
|
|
+ required this.viewCtx,
|
|
|
|
+ required this.isSelected,
|
|
|
|
+ required this.onOpen,
|
|
|
|
+ }) : super(key: viewCtx.valueKey());
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ State<ViewSectionItem> createState() => _ViewSectionItemState();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+class _ViewSectionItemState extends State<ViewSectionItem> {
|
|
|
|
+ bool isOnSelected = false;
|
|
|
|
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
@@ -36,6 +52,7 @@ class ViewSectionItem extends StatelessWidget {
|
|
child: FlowyHover(
|
|
child: FlowyHover(
|
|
config: config,
|
|
config: config,
|
|
builder: (context, onHover) => _render(context, onHover, config),
|
|
builder: (context, onHover) => _render(context, onHover, config),
|
|
|
|
+ isOnSelected: () => isOnSelected || widget.isSelected,
|
|
),
|
|
),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
@@ -45,25 +62,36 @@ class ViewSectionItem extends StatelessWidget {
|
|
SizedBox(
|
|
SizedBox(
|
|
width: 16,
|
|
width: 16,
|
|
height: 16,
|
|
height: 16,
|
|
- child: svgForViewType(viewCtx.view.viewType),
|
|
|
|
|
|
+ child: svgForViewType(widget.viewCtx.view.viewType),
|
|
),
|
|
),
|
|
const HSpace(6),
|
|
const HSpace(6),
|
|
FlowyText.regular(
|
|
FlowyText.regular(
|
|
- viewCtx.view.name,
|
|
|
|
|
|
+ widget.viewCtx.view.name,
|
|
fontSize: 12,
|
|
fontSize: 12,
|
|
),
|
|
),
|
|
];
|
|
];
|
|
|
|
|
|
- if (onHover) {
|
|
|
|
|
|
+ if (onHover || isOnSelected) {
|
|
children.add(const Spacer());
|
|
children.add(const Spacer());
|
|
- children.add(ViewMoreButton(
|
|
|
|
- onPressed: () {
|
|
|
|
- debugPrint('show view setting');
|
|
|
|
|
|
+ children.add(ViewDisclosureButton(
|
|
|
|
+ onTap: () {
|
|
|
|
+ setState(() {
|
|
|
|
+ isOnSelected = true;
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ onSelected: (selected) {
|
|
|
|
+ selected.fold(() => null, (action) {
|
|
|
|
+ debugPrint('$action.name');
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ setState(() {
|
|
|
|
+ isOnSelected = false;
|
|
|
|
+ });
|
|
},
|
|
},
|
|
));
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
- Widget widget = Container(
|
|
|
|
|
|
+ return Container(
|
|
child: Row(children: children).padding(
|
|
child: Row(children: children).padding(
|
|
left: MenuAppSizes.expandedPadding,
|
|
left: MenuAppSizes.expandedPadding,
|
|
right: MenuAppSizes.expandedIconPadding,
|
|
right: MenuAppSizes.expandedIconPadding,
|
|
@@ -71,15 +99,100 @@ class ViewSectionItem extends StatelessWidget {
|
|
height: 24,
|
|
height: 24,
|
|
alignment: Alignment.centerLeft,
|
|
alignment: Alignment.centerLeft,
|
|
);
|
|
);
|
|
|
|
+ }
|
|
|
|
|
|
- if (isSelected) {
|
|
|
|
- widget = FlowyHoverBackground(child: widget, config: config);
|
|
|
|
- }
|
|
|
|
|
|
+ Function() _openView(BuildContext context) {
|
|
|
|
+ return () => widget.onOpen(widget.viewCtx.view);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- return widget;
|
|
|
|
|
|
+class ViewDisclosureButton extends StatelessWidget {
|
|
|
|
+ final Function(dartz.Option<ViewAction>) onSelected;
|
|
|
|
+ final Function() onTap;
|
|
|
|
+ const ViewDisclosureButton({
|
|
|
|
+ Key? key,
|
|
|
|
+ required this.onSelected,
|
|
|
|
+ required this.onTap,
|
|
|
|
+ }) : super(key: key);
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ Widget build(BuildContext context) {
|
|
|
|
+ return FlowyIconButton(
|
|
|
|
+ width: 16,
|
|
|
|
+ onPressed: () {
|
|
|
|
+ onTap();
|
|
|
|
+ ViewActionList(
|
|
|
|
+ anchorContext: context,
|
|
|
|
+ onSelected: onSelected,
|
|
|
|
+ ).show(context);
|
|
|
|
+ },
|
|
|
|
+ icon: svg("editor/details"),
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- Function() _openView(BuildContext context) {
|
|
|
|
- return () => onOpen(viewCtx.view);
|
|
|
|
|
|
+class ViewActionList implements FlowyOverlayDelegate {
|
|
|
|
+ final Function(dartz.Option<ViewAction>) onSelected;
|
|
|
|
+ final BuildContext anchorContext;
|
|
|
|
+ final String _identifier = 'ViewActionList';
|
|
|
|
+
|
|
|
|
+ const ViewActionList({required this.anchorContext, required this.onSelected});
|
|
|
|
+
|
|
|
|
+ void show(BuildContext buildContext) {
|
|
|
|
+ final items = ViewAction.values.map((action) {
|
|
|
|
+ return ActionItem(
|
|
|
|
+ action: action,
|
|
|
|
+ onSelected: (action) {
|
|
|
|
+ FlowyOverlay.of(buildContext).remove(_identifier);
|
|
|
|
+ onSelected(dartz.some(action));
|
|
|
|
+ });
|
|
|
|
+ }).toList();
|
|
|
|
+
|
|
|
|
+ // TODO: make sure the delegate of this wouldn't cause retain cycle
|
|
|
|
+ ListOverlay.showWithAnchor(
|
|
|
|
+ buildContext,
|
|
|
|
+ identifier: _identifier,
|
|
|
|
+ itemCount: items.length,
|
|
|
|
+ itemBuilder: (context, index) => items[index],
|
|
|
|
+ anchorContext: anchorContext,
|
|
|
|
+ anchorDirection: AnchorDirection.bottomRight,
|
|
|
|
+ maxWidth: 120,
|
|
|
|
+ maxHeight: 80,
|
|
|
|
+ delegate: this,
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ void didRemove() {
|
|
|
|
+ onSelected(dartz.none());
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+class ActionItem extends StatelessWidget {
|
|
|
|
+ final ViewAction action;
|
|
|
|
+ final Function(ViewAction) onSelected;
|
|
|
|
+ const ActionItem({
|
|
|
|
+ Key? key,
|
|
|
|
+ required this.action,
|
|
|
|
+ required this.onSelected,
|
|
|
|
+ }) : super(key: key);
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ Widget build(BuildContext context) {
|
|
|
|
+ final theme = context.watch<AppTheme>();
|
|
|
|
+ final config = HoverDisplayConfig(hoverColor: theme.hover);
|
|
|
|
+
|
|
|
|
+ return FlowyHover(
|
|
|
|
+ config: config,
|
|
|
|
+ builder: (context, onHover) {
|
|
|
|
+ return GestureDetector(
|
|
|
|
+ onTap: () => onSelected(action),
|
|
|
|
+ child: FlowyText.medium(
|
|
|
|
+ action.name,
|
|
|
|
+ fontSize: 12,
|
|
|
|
+ ).padding(horizontal: 10, vertical: 6),
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ );
|
|
}
|
|
}
|
|
}
|
|
}
|