mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 12:08:41 +00:00
99 lines
2.3 KiB
Dart
99 lines
2.3 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
|
|
class ContextMenu extends StatefulWidget {
|
|
const ContextMenu({
|
|
required this.child,
|
|
required this.items,
|
|
super.key,
|
|
});
|
|
|
|
final List<ContextMenuItem> items;
|
|
final Widget child;
|
|
|
|
@override
|
|
State<ContextMenu> createState() => _ContextMenuState();
|
|
}
|
|
|
|
class _ContextMenuState extends State<ContextMenu> {
|
|
Offset? _tapPosition;
|
|
|
|
Widget _getIcon(IconData icon) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(left: 12),
|
|
child: FaIcon(
|
|
icon,
|
|
size: 20,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _showCustomMenu() async {
|
|
if (_tapPosition == null) {
|
|
return;
|
|
}
|
|
final overlay = Overlay.of(context).context.findRenderObject();
|
|
if (overlay == null) {
|
|
return;
|
|
}
|
|
unawaited(HapticFeedback.heavyImpact());
|
|
|
|
await showMenu(
|
|
context: context,
|
|
menuPadding: EdgeInsetsGeometry.zero,
|
|
elevation: 1,
|
|
clipBehavior: Clip.hardEdge,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
popUpAnimationStyle: const AnimationStyle(
|
|
duration: Duration.zero,
|
|
curve: Curves.fastOutSlowIn,
|
|
),
|
|
items: <PopupMenuEntry<int>>[
|
|
...widget.items.map(
|
|
(item) => PopupMenuItem(
|
|
padding: const EdgeInsets.only(right: 4),
|
|
child: ListTile(
|
|
title: Text(item.title),
|
|
onTap: () async {
|
|
if (mounted) Navigator.pop(context);
|
|
await item.onTap();
|
|
},
|
|
leading: _getIcon(item.icon),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
position: RelativeRect.fromRect(
|
|
_tapPosition! & const Size(40, 40),
|
|
Offset.zero & overlay.semanticBounds.size,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
onLongPress: _showCustomMenu,
|
|
onTapDown: (TapDownDetails details) {
|
|
_tapPosition = details.globalPosition;
|
|
},
|
|
child: widget.child,
|
|
);
|
|
}
|
|
}
|
|
|
|
class ContextMenuItem {
|
|
ContextMenuItem({
|
|
required this.title,
|
|
required this.onTap,
|
|
required this.icon,
|
|
});
|
|
final String title;
|
|
final Future<void> Function() onTap;
|
|
final IconData icon;
|
|
}
|