mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #808 from aryaman31/side_context_menu
Added right click context menu feature request.
This commit is contained in:
commit
ec3a84c557
@ -3,6 +3,7 @@ import 'package:dartz/dartz.dart' as dartz;
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@ -11,10 +12,13 @@ import 'item.dart';
|
||||
|
||||
// [[Widget: LifeCycle]]
|
||||
// https://flutterbyexample.com/lesson/stateful-widget-lifecycle
|
||||
class ViewDisclosureButton extends StatelessWidget with ActionList<ViewDisclosureActionWrapper>, FlowyOverlayDelegate {
|
||||
class ViewDisclosureButton extends StatelessWidget
|
||||
with ActionList<ViewDisclosureActionWrapper>, FlowyOverlayDelegate {
|
||||
final Function() onTap;
|
||||
final Function(dartz.Option<ViewDisclosureAction>) onSelected;
|
||||
final _items = ViewDisclosureAction.values.map((action) => ViewDisclosureActionWrapper(action)).toList();
|
||||
final _items = ViewDisclosureAction.values
|
||||
.map((action) => ViewDisclosureActionWrapper(action))
|
||||
.toList();
|
||||
|
||||
ViewDisclosureButton({
|
||||
Key? key,
|
||||
@ -40,12 +44,13 @@ class ViewDisclosureButton extends StatelessWidget with ActionList<ViewDisclosur
|
||||
List<ViewDisclosureActionWrapper> get items => _items;
|
||||
|
||||
@override
|
||||
void Function(dartz.Option<ViewDisclosureActionWrapper> p1) get selectCallback => (result) {
|
||||
result.fold(
|
||||
() => onSelected(dartz.none()),
|
||||
(wrapper) => onSelected(dartz.some(wrapper.inner)),
|
||||
);
|
||||
};
|
||||
void Function(dartz.Option<ViewDisclosureActionWrapper> p1)
|
||||
get selectCallback => (result) {
|
||||
result.fold(
|
||||
() => onSelected(dartz.none()),
|
||||
(wrapper) => onSelected(dartz.some(wrapper.inner)),
|
||||
);
|
||||
};
|
||||
|
||||
@override
|
||||
FlowyOverlayDelegate? get delegate => this;
|
||||
@ -56,6 +61,63 @@ class ViewDisclosureButton extends StatelessWidget with ActionList<ViewDisclosur
|
||||
}
|
||||
}
|
||||
|
||||
class ViewDisclosureRegion extends StatelessWidget
|
||||
with ActionList<ViewDisclosureActionWrapper>, FlowyOverlayDelegate {
|
||||
final Widget child;
|
||||
final Function() onTap;
|
||||
final Function(dartz.Option<ViewDisclosureAction>) onSelected;
|
||||
final _items = ViewDisclosureAction.values
|
||||
.map((action) => ViewDisclosureActionWrapper(action))
|
||||
.toList();
|
||||
|
||||
ViewDisclosureRegion(
|
||||
{Key? key,
|
||||
required this.onSelected,
|
||||
required this.onTap,
|
||||
required this.child})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Listener(
|
||||
onPointerDown: (event) => {_handleClick(event, context)},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
FlowyOverlayDelegate? get delegate => this;
|
||||
|
||||
@override
|
||||
List<ViewDisclosureActionWrapper> get items => _items;
|
||||
|
||||
@override
|
||||
void Function(dartz.Option<ViewDisclosureActionWrapper> p1)
|
||||
get selectCallback => (result) {
|
||||
result.fold(
|
||||
() => onSelected(dartz.none()),
|
||||
(wrapper) => onSelected(dartz.some(wrapper.inner)),
|
||||
);
|
||||
};
|
||||
|
||||
@override
|
||||
void didRemove() {
|
||||
onSelected(dartz.none());
|
||||
}
|
||||
|
||||
void _handleClick(PointerDownEvent event, BuildContext context) {
|
||||
if (event.kind == PointerDeviceKind.mouse &&
|
||||
event.buttons == kSecondaryMouseButton) {
|
||||
RenderBox box = context.findRenderObject() as RenderBox;
|
||||
Offset position = box.localToGlobal(Offset.zero);
|
||||
double x = event.position.dx - position.dx - box.size.width;
|
||||
double y = event.position.dy - position.dy - box.size.height;
|
||||
onTap();
|
||||
show(context, anchorOffset: Offset(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ViewDisclosureActionWrapper extends ActionItem {
|
||||
final ViewDisclosureAction inner;
|
||||
|
||||
|
@ -36,37 +36,57 @@ class ViewSectionItem extends StatelessWidget {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(create: (ctx) => getIt<ViewBloc>(param1: view)..add(const ViewEvent.initial())),
|
||||
BlocProvider(
|
||||
create: (ctx) =>
|
||||
getIt<ViewBloc>(param1: view)..add(const ViewEvent.initial())),
|
||||
],
|
||||
child: BlocBuilder<ViewBloc, ViewState>(
|
||||
builder: (context, state) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: InkWell(
|
||||
onTap: () => onSelected(context.read<ViewBloc>().state.view),
|
||||
child: FlowyHover(
|
||||
style: HoverStyle(hoverColor: theme.bg3),
|
||||
builder: (_, onHover) => _render(context, onHover, state, theme.iconColor),
|
||||
setSelected: () => state.isEditing || isSelected,
|
||||
),
|
||||
),
|
||||
);
|
||||
return ViewDisclosureRegion(
|
||||
onTap: () => context
|
||||
.read<ViewBloc>()
|
||||
.add(const ViewEvent.setIsEditing(true)),
|
||||
onSelected: (action) {
|
||||
context
|
||||
.read<ViewBloc>()
|
||||
.add(const ViewEvent.setIsEditing(false));
|
||||
_handleAction(context, action);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: InkWell(
|
||||
onTap: () => onSelected(context.read<ViewBloc>().state.view),
|
||||
child: FlowyHover(
|
||||
style: HoverStyle(hoverColor: theme.bg3),
|
||||
builder: (_, onHover) =>
|
||||
_render(context, onHover, state, theme.iconColor),
|
||||
setSelected: () => state.isEditing || isSelected,
|
||||
),
|
||||
),
|
||||
));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _render(BuildContext context, bool onHover, ViewState state, Color iconColor) {
|
||||
Widget _render(
|
||||
BuildContext context, bool onHover, ViewState state, Color iconColor) {
|
||||
List<Widget> children = [
|
||||
SizedBox(width: 16, height: 16, child: state.view.renderThumbnail(iconColor: iconColor)),
|
||||
SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: state.view.renderThumbnail(iconColor: iconColor)),
|
||||
const HSpace(2),
|
||||
Expanded(child: FlowyText.regular(state.view.name, fontSize: 12, overflow: TextOverflow.clip)),
|
||||
Expanded(
|
||||
child: FlowyText.regular(state.view.name,
|
||||
fontSize: 12, overflow: TextOverflow.clip)),
|
||||
];
|
||||
|
||||
if (onHover || state.isEditing) {
|
||||
children.add(
|
||||
ViewDisclosureButton(
|
||||
onTap: () => context.read<ViewBloc>().add(const ViewEvent.setIsEditing(true)),
|
||||
onTap: () =>
|
||||
context.read<ViewBloc>().add(const ViewEvent.setIsEditing(true)),
|
||||
onSelected: (action) {
|
||||
context.read<ViewBloc>().add(const ViewEvent.setIsEditing(false));
|
||||
_handleAction(context, action);
|
||||
@ -84,7 +104,8 @@ class ViewSectionItem extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleAction(BuildContext context, dartz.Option<ViewDisclosureAction> action) {
|
||||
void _handleAction(
|
||||
BuildContext context, dartz.Option<ViewDisclosureAction> action) {
|
||||
action.foldRight({}, (action, previous) {
|
||||
switch (action) {
|
||||
case ViewDisclosureAction.rename:
|
||||
|
Loading…
Reference in New Issue
Block a user