Rich text editor for Flutter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

171 lines
4.4 KiB

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../models/documents/nodes/node.dart';
import '../translations/toolbar.i18n.dart';
/// List of possible actions returned from [LinkActionPickerDelegate].
enum LinkMenuAction {
/// Launch the link
launch,
/// Copy to clipboard
copy,
/// Remove link style attribute
remove,
/// No-op
none,
}
/// Used internally by widget layer.
typedef LinkActionPicker = Future<LinkMenuAction> Function(Node linkNode);
typedef LinkActionPickerDelegate = Future<LinkMenuAction> Function(
BuildContext context, String link);
Future<LinkMenuAction> defaultLinkActionPickerDelegate(
BuildContext context, String link) async {
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
return _showCupertinoLinkMenu(context, link);
case TargetPlatform.android:
return _showMaterialMenu(context, link);
default:
assert(
false,
'defaultShowLinkActionsMenu not supposed to '
'be invoked for $defaultTargetPlatform');
return LinkMenuAction.none;
}
}
Future<LinkMenuAction> _showCupertinoLinkMenu(
BuildContext context, String link) async {
final result = await showCupertinoModalPopup<LinkMenuAction>(
context: context,
builder: (ctx) {
return CupertinoActionSheet(
title: Text(link),
actions: [
_CupertinoAction(
title: 'Open',
icon: Icons.language_sharp,
onPressed: () => Navigator.of(context).pop(LinkMenuAction.launch),
),
_CupertinoAction(
title: 'Copy',
icon: Icons.copy_sharp,
onPressed: () => Navigator.of(context).pop(LinkMenuAction.copy),
),
_CupertinoAction(
title: 'Remove',
icon: Icons.link_off_sharp,
onPressed: () => Navigator.of(context).pop(LinkMenuAction.remove),
),
],
);
},
);
return result ?? LinkMenuAction.none;
}
class _CupertinoAction extends StatelessWidget {
const _CupertinoAction({
required this.title,
required this.icon,
required this.onPressed,
Key? key,
}) : super(key: key);
final String title;
final IconData icon;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return CupertinoActionSheetAction(
onPressed: onPressed,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
children: [
Expanded(
child: Text(
title,
textAlign: TextAlign.start,
style: TextStyle(color: theme.colorScheme.onSurface),
),
),
Icon(
icon,
size: theme.iconTheme.size,
color: theme.colorScheme.onSurface.withOpacity(0.75),
)
],
),
),
);
}
}
Future<LinkMenuAction> _showMaterialMenu(
BuildContext context, String link) async {
final result = await showModalBottomSheet<LinkMenuAction>(
context: context,
builder: (ctx) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
_MaterialAction(
title: 'Open'.i18n,
icon: Icons.language_sharp,
onPressed: () => Navigator.of(context).pop(LinkMenuAction.launch),
),
_MaterialAction(
title: 'Copy'.i18n,
icon: Icons.copy_sharp,
onPressed: () => Navigator.of(context).pop(LinkMenuAction.copy),
),
_MaterialAction(
title: 'Remove'.i18n,
icon: Icons.link_off_sharp,
onPressed: () => Navigator.of(context).pop(LinkMenuAction.remove),
),
],
);
},
);
return result ?? LinkMenuAction.none;
}
class _MaterialAction extends StatelessWidget {
const _MaterialAction({
required this.title,
required this.icon,
required this.onPressed,
Key? key,
}) : super(key: key);
final String title;
final IconData icon;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return ListTile(
leading: Icon(
icon,
size: theme.iconTheme.size,
color: theme.colorScheme.onSurface.withOpacity(0.75),
),
title: Text(title),
onTap: onPressed,
);
}
}