diff --git a/CHANGELOG.md b/CHANGELOG.md index f5d68fbc..d41f77ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Persian (Iran) support thanks to @arefbhrn[https://github.com/arefbhrn] * Location tags are suggested if you're within 50m of the tag. Requires location to be enabled. Closes [#648](https://github.com/flow-mn/flow/issues/648) +* Now it's possible to duplicate transfers ### Changes diff --git a/lib/objectbox/actions.dart b/lib/objectbox/actions.dart index b04b3be1..73ece6ab 100644 --- a/lib/objectbox/actions.dart +++ b/lib/objectbox/actions.dart @@ -614,8 +614,40 @@ extension TransactionActions on Transaction { /// Returns the ObjectBox ID for the newly created transaction int duplicate() { - if (isTransfer) { - throw Exception("Cannot duplicate transfer transactions"); + if (extensions.transfer case Transfer transferDetails) { + final Account? fromAccount = AccountsService().findOneSync( + transferDetails.fromAccountUuid, + ); + final Account? toAccount = AccountsService().findOneSync( + transferDetails.toAccountUuid, + ); + + if (fromAccount == null || toAccount == null) { + _log.severe( + "Failed to duplicate transfer transaction due to missing account data", + ); + throw Exception( + "Failed to duplicate transfer transaction due to missing account data", + ); + } + + final (int a, _) = fromAccount.transferTo( + targetAccount: toAccount, + amount: amount, + description: description, + createdDate: Moment.now(), + isPending: isPending, + transactionDate: transactionDate, + title: title, + tags: tags.toList(), + attachments: attachments.toList(), + extraTags: extraTags, + extensions: extensions.data, + latitude: extensions.geo?.latitude, + longitude: extensions.geo?.longitude, + ); + + return a; } final Transaction duplicate = @@ -630,6 +662,7 @@ extension TransactionActions on Transaction { uuid: Uuid().v4(), extraTags: extraTags, subtype: subtype, + location: extensions.geo?.toLatLng(), ) ..setTags(tags.toList()) ..setAttachments(attachments.toList()) diff --git a/lib/routes/debug/debug_theme_page.dart b/lib/routes/debug/debug_theme_page.dart index 9f2d23f3..211e2250 100644 --- a/lib/routes/debug/debug_theme_page.dart +++ b/lib/routes/debug/debug_theme_page.dart @@ -11,6 +11,7 @@ import "package:flow/widgets/general/frame.dart"; import "package:flow/widgets/general/list_header.dart"; import "package:flow/widgets/general/wavy_divider.dart"; import "package:flow/widgets/transaction_list_tile.dart"; +import "package:flow/widgets/transaction_tag_chip.dart"; import "package:flutter/material.dart"; import "package:go_router/go_router.dart"; import "package:material_symbols_icons/symbols.dart"; @@ -56,6 +57,15 @@ class DebugThemePage extends StatelessWidget { selected: true, ), ActionChip(label: Text("ActionChip"), onPressed: () {}), + TransactionTagChip(tag: .new(title: "Example Tag")), + TransactionTagChip( + tag: .new(title: "Example Tag"), + selected: true, + ), + TransactionTagChip( + tag: .new(title: "Example Tag"), + isSuggestion: true, + ), ], ), ), diff --git a/lib/routes/transaction_page.dart b/lib/routes/transaction_page.dart index 6ad4ba0a..f74cbe63 100644 --- a/lib/routes/transaction_page.dart +++ b/lib/routes/transaction_page.dart @@ -579,14 +579,11 @@ class _TransactionPageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (!isTransfer) - ListTile( - leading: Icon(Symbols.content_copy_rounded), - title: Text( - "transaction.duplicate".t(context), - ), - onTap: () => _duplicate(), - ), + ListTile( + leading: Icon(Symbols.content_copy_rounded), + title: Text("transaction.duplicate".t(context)), + onTap: () => _duplicate(), + ), if (_currentlyEditing.isDeleted == true) ListTile( leading: Icon(Symbols.restore_page_rounded), diff --git a/lib/routes/transaction_page/sections/tags_section.dart b/lib/routes/transaction_page/sections/tags_section.dart index f52e9999..1402cf32 100644 --- a/lib/routes/transaction_page/sections/tags_section.dart +++ b/lib/routes/transaction_page/sections/tags_section.dart @@ -38,6 +38,9 @@ class TagsSection extends StatelessWidget { _ => null, }; + print("suggestedGeoTags: $suggestedGeoTags"); + print("location: $location"); + final bool hasSuggestedGeoTags = suggestedGeoTags?.isNotEmpty == true; return Section( @@ -61,18 +64,17 @@ class TagsSection extends StatelessWidget { onPressed: selectTags, title: "transaction.tags.add".t(context), ), - if (hasSuggestedGeoTags) - ...suggestedGeoTags!.map( - (tag) => TransactionTagChip( - tag: tag, - selected: false, - isSuggestion: true, - onPressed: () { - _addTag(context, tag); - }, - ), + ...?suggestedGeoTags?.map( + (tag) => TransactionTagChip( + tag: tag, + selected: false, + isSuggestion: true, + onPressed: () { + _addTag(context, tag); + }, ), - ...selectedTags!.map( + ), + ...?selectedTags?.map( (tag) => IgnorePointer( child: TransactionTagChip(tag: tag, selected: true), ), @@ -102,12 +104,12 @@ class TagsSection extends StatelessWidget { } void _addTag(BuildContext context, TransactionTag tag) { - if (selectedTags!.contains(tag)) return; + if (selectedTags?.contains(tag) == true) return; if (LocalPreferences().enableHapticFeedback.get()) { HapticFeedback.lightImpact(); } - onTagsChanged([...selectedTags!, tag]); + onTagsChanged([...?selectedTags, tag]); } } diff --git a/lib/widgets/account_card.dart b/lib/widgets/account_card.dart index 14b44f5a..cddf52b0 100644 --- a/lib/widgets/account_card.dart +++ b/lib/widgets/account_card.dart @@ -86,10 +86,14 @@ class AccountCard extends StatelessWidget { if (primary) WidgetSpan( alignment: .middle, - child: Icon( - Symbols.star_rounded, - size: context.textTheme.titleSmall?.fontSize, - color: context.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.only(right: 4.0), + child: Icon( + Symbols.star_rounded, + size: + context.textTheme.titleSmall?.fontSize, + color: context.colorScheme.primary, + ), ), ), TextSpan( diff --git a/lib/widgets/transaction_list_tile.dart b/lib/widgets/transaction_list_tile.dart index db86f328..0104e489 100644 --- a/lib/widgets/transaction_list_tile.dart +++ b/lib/widgets/transaction_list_tile.dart @@ -72,9 +72,7 @@ class TransactionListTile extends StatelessWidget { confirmFn != null && transaction.confirmable(); final bool showDuplicateButton = - transaction.isDeleted != true && - !transaction.isTransfer && - duplicateFn != null; + transaction.isDeleted != true && duplicateFn != null; final bool showHoldButton = confirmFn != null && transaction.holdable(); final bool showConfirmButton = confirmFn != null && transaction.confirmable(); diff --git a/lib/widgets/transaction_tag_chip.dart b/lib/widgets/transaction_tag_chip.dart index 03a68472..cd3de39b 100644 --- a/lib/widgets/transaction_tag_chip.dart +++ b/lib/widgets/transaction_tag_chip.dart @@ -28,7 +28,13 @@ class TransactionTagChip extends StatelessWidget { Widget build(BuildContext context) { final FlowColorScheme? colorScheme = tag.colorScheme; - final Widget childn = GestureDetector( + final Color borderColor = selected + ? kTransparent + : context.colorScheme.outline.withAlpha(0x80); + + final BorderRadius borderRadius = .circular(8.0); + + final Widget child = GestureDetector( onTap: onPressed, behavior: onPressed != null ? .opaque : .translucent, child: Container( @@ -37,43 +43,37 @@ class TransactionTagChip extends StatelessWidget { color: selected ? context.colorScheme.secondary : context.colorScheme.surface, - borderRadius: .circular(8.0), + borderRadius: borderRadius, border: isSuggestion ? DashedBorder( - color: context.colorScheme.outline.withAlpha(0x80), - width: 2.0, - borderRadius: .circular(8.0), + color: borderColor, + width: 1.0, + borderRadius: borderRadius, dashLength: 4.0, dashGap: 4.0, ) - : Border.all( - color: selected - ? kTransparent - : context.colorScheme.outline.withAlpha(0x80), - width: 1.0, - ), - ), - padding: EdgeInsets.symmetric( - horizontal: 12.0, - vertical: 8.0 + (selected ? 1.0 : (isSuggestion ? 0.0 : 1.0)), + : Border.all(color: borderColor, width: 1.0), ), + padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), child: Row( spacing: 8.0, mainAxisSize: .min, children: [ FlowIcon(tag.icon, colorScheme: colorScheme, size: 16.0), Text(tag.title, style: context.textTheme.labelLarge), - if (isSuggestion) - Icon( - Symbols.add_rounded, - size: 16.0, - color: context.colorScheme.outline, - ), ], ), ), ); - return childn; + if (isSuggestion) { + return Badge( + label: Icon(Symbols.star_rounded, color: context.colorScheme.onPrimary), + backgroundColor: context.colorScheme.primary, + child: Opacity(opacity: .7, child: child), + ); + } + + return child; } } diff --git a/pubspec.yaml b/pubspec.yaml index 8504dd5b..f3a55cee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: A personal finance managing app publish_to: "none" # Remove this line if you wish to publish to pub.dev -version: "0.19.0+323" +version: "0.19.0+324" environment: sdk: ">=3.10.0 <4.0.0"