Skip to content

Commit

Permalink
Allow pasting in amount input bottom sheet
Browse files Browse the repository at this point in the history
Fixes #157
  • Loading branch information
sadespresso committed Nov 13, 2024
1 parent 2bbd8d9 commit 2dae094
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 3 deletions.
2 changes: 2 additions & 0 deletions assets/l10n/en_IN.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"general.delete.all": "Delete all",
"general.copy.success": "Copied to clipboard",
"general.copy.clickToCopy": "Click to copy",
"general.paste": "Paste",
"general.timeSelector.select.month": "Select a month",
"general.timeSelector.select.year": "Select a year",
"general.timeSelector.now": "Now",
Expand Down Expand Up @@ -319,6 +320,7 @@
"error.input.noImagePicked": "No image was selected",
"error.input.cropFailed": "An error occured during cropping the picture",
"error.input.wrongFileType": "Please choose a {type} file",
"error.input.pasteFormatMismatch": "Unable to parse",
"error.sync.invalidBackupFile": "Invalid backup file",
"error.sync.safetyBackupFailed": "Unable to start import",
"error.sync.exportFailed": "Unable to export, please contact developer.",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"general.delete.all": "Delete all",
"general.copy.success": "Copied to clipboard",
"general.copy.clickToCopy": "Click to copy",
"general.paste": "Paste",
"general.timeSelector.select.month": "Select a month",
"general.timeSelector.select.year": "Select a year",
"general.timeSelector.now": "Now",
Expand Down Expand Up @@ -319,6 +320,7 @@
"error.input.cropFailed": "An error occured during cropping the picture",
"error.input.wrongFileType": "Please choose a {type} file",
"error.sync.invalidBackupFile": "Invalid backup file",
"error.input.pasteFormatMismatch": "Unable to parse",
"error.sync.safetyBackupFailed": "Unable to start import",
"error.sync.exportFailed": "Unable to export, please contact developer.",
"error.sync.fileDeleteFailed": "An error occured during backup deletion",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/it_IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"general.delete.all": "Elimina tutto",
"general.copy.success": "Copiato negli appunti",
"general.copy.clickToCopy": "Clicca per copiare",
"general.paste": "Incolla",
"general.timeSelector.select.month": "Seleziona un mese",
"general.timeSelector.select.year": "Seleziona un anno",
"general.timeSelector.now": "Ora",
Expand Down Expand Up @@ -319,6 +320,7 @@
"error.input.noImagePicked": "Nessuna immagine selezionata",
"error.input.cropFailed": "Si è verificato un errore durante il ritaglio dell'immagine",
"error.input.wrongFileType": "Si prega di scegliere un file {type}",
"error.input.pasteFormatMismatch": "Impossibile analizzare",
"error.sync.invalidBackupFile": "File di backup non valido",
"error.sync.safetyBackupFailed": "Impossibile avviare l'importazione",
"error.sync.exportFailed": "Impossibile esportare, si prega di contattare lo sviluppatore.",
Expand Down
4 changes: 3 additions & 1 deletion assets/l10n/mn_MN.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"general.select.all": "Бүгдийг сонгох",
"general.delete.all": "Бүгдийг устгах",
"general.copy.success": "Амжилттай хууллаа",
"general.copy.clickToCopy": "Дарвал бичвэр хуулна",
"general.copy.clickToCopy": "Дарвал бичвэрийг хуулна",
"general.paste": "Буулгах",
"general.timeSelector.select.month": "Сар сонгох",
"general.timeSelector.select.year": "Жил сонгох",
"general.timeSelector.now": "Одоо",
Expand Down Expand Up @@ -319,6 +320,7 @@
"error.input.noImagePicked": "Та зураг сонгоогүй байна",
"error.input.cropFailed": "Зураг хайчлах үед алдаа гарлаа",
"error.input.wrongFileType": "Зөвхөн {} төрлийн файл сонгох боломжтой",
"error.input.pasteFormatMismatch": "Өгөгдлийг таньж чадсангүй",
"error.sync.invalidBackupFile": "Нөөц файл алдаатай байна",
"error.sync.safetyBackupFailed": "Сэргээх үйлдэл эхлэх боломжгүй",
"error.sync.exportFailed": "Нөөцлөх явцад алдаа гарлаа, хөгжүүлэгчид хандана уу.",
Expand Down
20 changes: 18 additions & 2 deletions lib/routes/new_transaction/amount_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import "package:flow/l10n/extensions.dart";
import "package:flow/routes/new_transaction/input_amount_sheet/input_value.dart";
import "package:flow/theme/theme.dart";
import "package:flow/utils/utils.dart";
import "package:flow/widgets/general/long_press_context_menu.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";

class AmountText extends StatefulWidget {
final FocusNode focusNode;
Expand Down Expand Up @@ -90,8 +92,14 @@ class _AmountTextState extends State<AmountText>

return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: SelectionArea(
focusNode: widget.focusNode,
child: LongPressContextMenu(
actions: [
PopupMenuItem(
value: "copy",
child: Text("general.copy".t(context)),
),
],
onSelected: handleContextMenuAction,
child: Transform.scale(
scale: _amountTextScaleAnimation.value,
child: SizedBox(
Expand Down Expand Up @@ -132,4 +140,12 @@ class _AmountTextState extends State<AmountText>
await _amountTextAnimationController.forward().orCancel;
await _amountTextAnimationController.reverse().orCancel;
}

void handleContextMenuAction(String? action) {
switch (action) {
case "copy":
Clipboard.setData(ClipboardData(text: amountText()));
break;
}
}
}
98 changes: 98 additions & 0 deletions lib/widgets/general/long_press_context_menu.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import "package:flow/l10n/extensions.dart";
import "package:flutter/gestures.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";

class LongPressContextMenu extends StatefulWidget {
final bool addPasteAction;

final List<PopupMenuEntry<String>> actions;

final ValueChanged<String?> onSelected;
final void Function(String text)? onPaste;

final Widget child;

const LongPressContextMenu({
super.key,
required this.child,
required this.actions,
required this.onSelected,
this.addPasteAction = false,
this.onPaste,
});

@override
State<StatefulWidget> createState() => _LongPressContextMenuState();
}

class _LongPressContextMenuState extends State<LongPressContextMenu> {
Offset _lastPointerPosition = Offset.zero;

@override
Widget build(BuildContext context) {
return Listener(
onPointerDown: (PointerDownEvent event) {
if (event.kind == PointerDeviceKind.mouse &&
event.buttons == kSecondaryMouseButton) {
_lastPointerPosition = event.position;

_open();
}
},
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTapDown: (TapDownDetails details) {
_lastPointerPosition = details.globalPosition;
},
onLongPress: _open,
child: widget.child,
),
);
}

void _open() async {
final RenderBox? overlay =
Overlay.of(context).context.findRenderObject() as RenderBox?;

if (overlay == null) return;

String? pasteText;

if (widget.addPasteAction && widget.onPaste != null) {
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);

final String? text = clipboardData?.text?.trim();

if (text != null && text.isNotEmpty) {
pasteText = text;
}
}

if (!context.mounted) return;

final String? value = await showMenu<String>(
context: context,
items: [
if (pasteText != null)
PopupMenuItem<String>(
value: "paste",
child: Text("general.paste".t(context)),
),
...widget.actions
],
position: RelativeRect.fromLTRB(
_lastPointerPosition.dx,
_lastPointerPosition.dy,
overlay.size.width - _lastPointerPosition.dx,
overlay.size.height - _lastPointerPosition.dy,
),
);

if (value == "paste") {
widget.onPaste?.call(pasteText ?? "");
} else {
widget.onSelected(value);
}
}
}

0 comments on commit 2dae094

Please sign in to comment.