feat: Add markdown context actions for text input

pull/1487/head
krille-chan 4 months ago
parent 9fab7630a3
commit 22023450d5
No known key found for this signature in database

@ -2806,5 +2806,11 @@
"name": "Name",
"version": "Version",
"website": "Website",
"sendUncompressed": "Send uncompressed"
"sendUncompressed": "Send uncompressed",
"boldText": "Bold text",
"italicText": "Italic text",
"strikeThrough": "Strikethrough",
"pleaseFillOut": "Please fill out",
"invalidUrl": "Invalid url",
"addLink": "Add link"
}

@ -9,6 +9,7 @@ import 'package:pasteboard/pasteboard.dart';
import 'package:slugify/slugify.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/markdown_context_builder.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
import '../../widgets/avatar.dart';
@ -456,6 +457,8 @@ class InputBar extends StatelessWidget {
builder: (context, controller, focusNode) => TextField(
controller: controller,
focusNode: focusNode,
contextMenuBuilder: (c, e) =>
markdownContextBuilder(c, e, controller),
contentInsertionConfiguration: ContentInsertionConfiguration(
onContentInserted: (KeyboardInsertedContent content) {
final data = content.data;

@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
Widget markdownContextBuilder(
BuildContext context,
EditableTextState editableTextState,
TextEditingController controller,
) {
final value = editableTextState.textEditingValue;
final selectedText = value.selection.textInside(value.text);
final buttonItems = editableTextState.contextMenuButtonItems;
final l10n = L10n.of(context);
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: editableTextState.contextMenuAnchors,
buttonItems: [
...buttonItems,
if (selectedText.isNotEmpty) ...[
ContextMenuButtonItem(
label: l10n.link,
onPressed: () async {
final input = await showTextInputDialog(
context: context,
title: l10n.addLink,
okLabel: l10n.ok,
cancelLabel: l10n.cancel,
textFields: [
DialogTextField(
validator: (text) {
if (text == null || text.isEmpty) {
return l10n.pleaseFillOut;
}
try {
text.startsWith('http')
? Uri.parse(text)
: Uri.https(text);
} catch (_) {
return l10n.invalidUrl;
}
return null;
},
hintText: 'www...',
keyboardType: TextInputType.url,
),
],
);
final urlString = input?.singleOrNull;
if (urlString == null) return;
final url = urlString.startsWith('http')
? Uri.parse(urlString)
: Uri.https(urlString);
final selection = controller.selection;
controller.text = controller.text.replaceRange(
selection.start,
selection.end,
'[$selectedText](${url.toString()})',
);
ContextMenuController.removeAny();
},
),
ContextMenuButtonItem(
label: l10n.boldText,
onPressed: () {
final selection = controller.selection;
controller.text = controller.text.replaceRange(
selection.start,
selection.end,
'**$selectedText**',
);
ContextMenuController.removeAny();
},
),
ContextMenuButtonItem(
label: l10n.italicText,
onPressed: () {
final selection = controller.selection;
controller.text = controller.text.replaceRange(
selection.start,
selection.end,
'*$selectedText*',
);
ContextMenuController.removeAny();
},
),
ContextMenuButtonItem(
label: l10n.strikeThrough,
onPressed: () {
final selection = controller.selection;
controller.text = controller.text.replaceRange(
selection.start,
selection.end,
'~~$selectedText~~',
);
ContextMenuController.removeAny();
},
),
],
],
);
}
Loading…
Cancel
Save