Skip to content

Commit

Permalink
Add context region
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Oct 26, 2024
1 parent 71ebfd7 commit 987ae6a
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 30 deletions.
93 changes: 93 additions & 0 deletions packages/material_leap/lib/src/widgets/context_region.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:material_leap/material_leap.dart';

typedef ContextRegionChildBuilder = Widget Function(
BuildContext context, Widget button, MenuController controller);
typedef ContextRegionChildrenBuidler = List<ContextMenuButtonItem>? Function(
BuildContext context);
typedef ContextRegionButtonBuilder = Widget Function(
BuildContext context, MenuController controller);

class ContextRegion extends StatefulWidget {
final ContextRegionChildBuilder builder;
final List<Widget> menuChildren;
final Widget? icon;
final MenuAnchorChildBuilder? buttonBuilder;
final String? tooltip;

const ContextRegion({
super.key,
this.icon,
this.buttonBuilder,
this.tooltip,
required this.builder,
required this.menuChildren,
});

@override
State<ContextRegion> createState() => _ContextRegionState();
}

class _ContextRegionState extends State<ContextRegion> {
Offset? _longPressOffset;
final GlobalKey _buttonKey = GlobalKey();
final MenuController _menuController = MenuController();

static bool get _longPressEnabled {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
return true;
case TargetPlatform.macOS:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return false;
}
}

void _onSecondaryTapUp(TapUpDetails details) {
_show(details.globalPosition);
}

void _onLongPressStart(LongPressStartDetails details) {
_longPressOffset = details.globalPosition;
}

void _onLongPress() {
assert(_longPressOffset != null);
_show(_longPressOffset!);
_longPressOffset = null;
}

void _show([Offset? position]) {
if (position != null) {
final RenderBox renderBox =
_buttonKey.currentContext?.findRenderObject() as RenderBox;

position = renderBox.globalToLocal(position);
}
_menuController.open(position: position);
}

@override
Widget build(BuildContext context) {
return MenuAnchor(
controller: _menuController,
menuChildren: widget.menuChildren,
key: _buttonKey,
builder: (context, controller, child) => GestureDetector(
onSecondaryTapUp: _onSecondaryTapUp,
onLongPress: _longPressEnabled ? _onLongPress : null,
onLongPressStart: _longPressEnabled ? _onLongPressStart : null,
child: widget.builder(
context,
widget.buttonBuilder?.call(context, controller, null) ??
defaultMenuButton(calculateLocalOffset: true)(
context, controller, null),
controller),
),
);
}
}
98 changes: 68 additions & 30 deletions packages/material_leap/lib/src/widgets/menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,43 @@ extension MenuControllerToggleExtension on MenuController {
isOpen ? close() : open(position: position);
}

Widget _offsetCalculator(
BuildContext context,
Widget Function(Offset offset) builder, {
bool calculateLocalOffset = true,
}) {
if (!calculateLocalOffset) {
return builder(Offset.zero);
}
return Builder(builder: (currentContext) {
final RenderBox renderBox = currentContext.findRenderObject() as RenderBox;
final localOffset = renderBox.globalToLocal(Offset.zero,
ancestor: context.findRenderObject());
return builder(localOffset);
});
}

MenuAnchorChildBuilder defaultMenuButton({
Widget? icon,
MenuAnchorChildBuilder? iconBuilder,
bool enabled = true,
bool? isSelected,
bool selectedOnOpen = true,
String? tooltip,
bool calculateLocalOffset = false,
}) =>
(context, controller, child) => IconButton(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected: (selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
);
(context, controller, child) => _offsetCalculator(
context,
(offset) => IconButton(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected:
(selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
),
calculateLocalOffset: calculateLocalOffset);

MenuAnchorChildBuilder defaultFilledMenuButton({
Widget? icon,
Expand All @@ -30,15 +51,20 @@ MenuAnchorChildBuilder defaultFilledMenuButton({
bool? isSelected,
bool selectedOnOpen = true,
String? tooltip,
bool calculateLocalOffset = false,
}) =>
(context, controller, child) => IconButton.filled(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected: (selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
);
(context, controller, child) => _offsetCalculator(
context,
(offset) => IconButton.filled(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected:
(selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
),
calculateLocalOffset: calculateLocalOffset);

MenuAnchorChildBuilder defaultFilledTonalMenuButton({
Widget? icon,
Expand All @@ -47,14 +73,20 @@ MenuAnchorChildBuilder defaultFilledTonalMenuButton({
bool? isSelected,
bool selectedOnOpen = true,
String? tooltip,
bool calculateLocalOffset = false,
}) =>
(context, controller, child) => IconButton.filledTonal(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected: (selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
(context, controller, child) => _offsetCalculator(
context,
(offset) => IconButton.filledTonal(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected:
(selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
),
calculateLocalOffset: calculateLocalOffset,
);

MenuAnchorChildBuilder defaultOutlinedMenuButton({
Expand All @@ -64,12 +96,18 @@ MenuAnchorChildBuilder defaultOutlinedMenuButton({
bool? isSelected,
bool selectedOnOpen = true,
String? tooltip,
bool calculateLocalOffset = false,
}) =>
(context, controller, child) => IconButton.outlined(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected: (selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
(context, controller, child) => _offsetCalculator(
context,
(offset) => IconButton.outlined(
icon: iconBuilder?.call(context, controller, child) ??
icon ??
const PhosphorIcon(PhosphorIconsLight.dotsThreeVertical),
tooltip: tooltip,
isSelected:
(selectedOnOpen && controller.isOpen) ? true : isSelected,
onPressed: enabled ? controller.toggle : null,
),
calculateLocalOffset: calculateLocalOffset,
);
1 change: 1 addition & 0 deletions packages/material_leap/lib/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export 'src/widgets/advanced_text_field.dart';
export 'src/widgets/advanced_switch_list_tile.dart';
export 'src/widgets/box_tile.dart';
export 'src/widgets/color_button.dart';
export 'src/widgets/context_region.dart';
export 'src/widgets/exact_slider.dart';
export 'src/widgets/date_time_field.dart';
export 'src/widgets/header.dart';
Expand Down

0 comments on commit 987ae6a

Please sign in to comment.