From 4f2373f4ac8a0c61494828ca16ed7068671aaded Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 19 Jun 2024 15:46:29 +0300 Subject: [PATCH 01/12] Fix typo --- bump_version.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bump_version.sh b/bump_version.sh index db5c8f8765..ad6f4c2eda 100644 --- a/bump_version.sh +++ b/bump_version.sh @@ -1,17 +1,17 @@ #!/bin/bash current_version=$(grep "version: 5.0." pubspec.yaml | cut -f2 -d "+" ) -new_vesion=$((current_version+1)) +new_version=$((current_version+1)) date_today=$(date +%F) -echo "Bump version... $current_version => $new_vesion" +echo "Bump version... $current_version => $new_version" -sed -i -e "s/version: 5.0.$current_version+$current_version/version: 5.0.$new_vesion+$new_vesion/g" ./pubspec.yaml -sed -i -e "s/version: 5.0.$current_version+$current_version/version: 5.0.$new_vesion+$new_vesion/g" ./pubspec.foss.yaml -sed -i -e "s/v5.0.$current_version/v5.0.$new_vesion/g" ./.github/workflows/flatpak.yml -sed -i -e 's//\n /g' ./flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml -sed -i -e "s/kClientVersion = '5.0.$current_version'/kClientVersion = '5.0.$new_vesion'/g" ./lib/constants.dart -sed -i -e "s/version: '5.0.$current_version'/version: '5.0.$new_vesion'/g" ./snap/snapcraft.yaml +sed -i -e "s/version: 5.0.$current_version+$current_version/version: 5.0.$new_version+$new_version/g" ./pubspec.yaml +sed -i -e "s/version: 5.0.$current_version+$current_version/version: 5.0.$new_version+$new_version/g" ./pubspec.foss.yaml +sed -i -e "s/v5.0.$current_version/v5.0.$new_version/g" ./.github/workflows/flatpak.yml +sed -i -e 's//\n /g' ./flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml +sed -i -e "s/kClientVersion = '5.0.$current_version'/kClientVersion = '5.0.$new_version'/g" ./lib/constants.dart +sed -i -e "s/version: '5.0.$current_version'/version: '5.0.$new_version'/g" ./snap/snapcraft.yaml rm lib/flutter_version.dart echo "const FLUTTER_VERSION = const " > lib/flutter_version.dart From 63c97bcc1549090ca3641953a963072f11b7a25d Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 16:39:31 +0300 Subject: [PATCH 02/12] Support comments --- lib/data/models/entities.dart | 30 ++++++++++++++++++++++++ lib/ui/app/lists/activity_list_tile.dart | 7 ++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/data/models/entities.dart b/lib/data/models/entities.dart index 193211aa61..fae4c734ee 100644 --- a/lib/data/models/entities.dart +++ b/lib/data/models/entities.dart @@ -767,7 +767,37 @@ abstract class ActivityEntity InvoiceHistoryEntity? get history; + bool get isComment => activityTypeId.isEmpty; + EntityType? get entityType { + if (isComment) { + if ((invoiceId ?? '').isNotEmpty) { + return EntityType.invoice; + } else if ((quoteId ?? '').isNotEmpty) { + return EntityType.quote; + } else if ((creditId ?? '').isNotEmpty) { + return EntityType.credit; + } else if ((recurringInvoiceId ?? '').isNotEmpty) { + return EntityType.recurringInvoice; + } else if ((paymentId ?? '').isNotEmpty) { + return EntityType.payment; + } else if ((projectId ?? '').isNotEmpty) { + return EntityType.project; + } else if ((taskId ?? '').isNotEmpty) { + return EntityType.task; + } else if ((expenseId ?? '').isNotEmpty) { + return EntityType.expense; + } else if ((recurringExpenseId ?? '').isNotEmpty) { + return EntityType.recurringExpense; + } else if ((purchaseOrderId ?? '').isNotEmpty) { + return EntityType.purchaseOrder; + } else if ((clientId ?? '').isNotEmpty) { + return EntityType.client; + } else if ((vendorId ?? '').isNotEmpty) { + return EntityType.vendor; + } + } + if ([ kActivityCreateClient, kActivityUpdateClient, diff --git a/lib/ui/app/lists/activity_list_tile.dart b/lib/ui/app/lists/activity_list_tile.dart index 6bb74fcb14..fd20cd656d 100644 --- a/lib/ui/app/lists/activity_list_tile.dart +++ b/lib/ui/app/lists/activity_list_tile.dart @@ -13,6 +13,7 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart'; import 'package:invoiceninja_flutter/utils/icons.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; class ActivityListTile extends StatelessWidget { const ActivityListTile({ @@ -70,8 +71,10 @@ class ActivityListTile extends StatelessWidget { ); return ListTile( - leading: Icon(getEntityIcon(activity.entityType)), - title: Text(title), + leading: Icon(activity.isComment + ? MdiIcons.comment + : getEntityIcon(activity.entityType)), + title: Text(activity.isComment ? activity.notes : title), onTap: !enableNavigation ? null : () { From 89412ee9909735f1dda87a358c3d724a542a0a6c Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 16:48:39 +0300 Subject: [PATCH 03/12] Support comments --- lib/ui/app/lists/activity_list_tile.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ui/app/lists/activity_list_tile.dart b/lib/ui/app/lists/activity_list_tile.dart index fd20cd656d..b3f8e10b62 100644 --- a/lib/ui/app/lists/activity_list_tile.dart +++ b/lib/ui/app/lists/activity_list_tile.dart @@ -74,7 +74,11 @@ class ActivityListTile extends StatelessWidget { leading: Icon(activity.isComment ? MdiIcons.comment : getEntityIcon(activity.entityType)), - title: Text(activity.isComment ? activity.notes : title), + title: Text(activity.isComment + ? (user?.fullName == null + ? '' + : (user!.fullName + ': ' + activity.notes)) + : title), onTap: !enableNavigation ? null : () { @@ -142,7 +146,7 @@ class ActivityListTile extends StatelessWidget { subtitle: Row( children: [ Flexible( - child: Text((activity.notes.isNotEmpty + child: Text((!activity.isComment && activity.notes.isNotEmpty ? localization.lookup(activity.notes).trim() + '\n' : '') + formatDate( From ed4e331e13b1fdc32e69be223da4da8194745258 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 17:11:24 +0300 Subject: [PATCH 04/12] Support comments --- lib/data/models/invoice_model.dart | 4 ++ lib/data/models/models.dart | 1 + lib/data/models/models.g.dart | 4 ++ lib/redux/invoice/invoice_actions.dart | 10 +++++ lib/utils/dialogs.dart | 60 ++++++++++++++++++++++++++ lib/utils/i18n.dart | 10 +++++ lib/utils/icons.dart | 2 + 7 files changed, 91 insertions(+) diff --git a/lib/data/models/invoice_model.dart b/lib/data/models/invoice_model.dart index c2668f5cf7..2a8f99affe 100644 --- a/lib/data/models/invoice_model.dart +++ b/lib/data/models/invoice_model.dart @@ -1080,6 +1080,10 @@ abstract class InvoiceEntity extends Object store.state.designState.map, entityType!)) { actions.add(EntityAction.runTemplate); } + + if (!multiselect) { + actions.add(EntityAction.addComment); + } } if (userCompany.canEditEntity(this) && !isCancelledOrReversed) { diff --git a/lib/data/models/models.dart b/lib/data/models/models.dart index 14405c7fb4..8f66fb9a27 100644 --- a/lib/data/models/models.dart +++ b/lib/data/models/models.dart @@ -141,6 +141,7 @@ class EntityAction extends EnumClass { static const EntityAction runTemplate = _$runTemplate; static const EntityAction bulkUpdate = _$bulkUpdate; static const EntityAction reconnect = _$reconnect; + static const EntityAction addComment = _$addComment; @override String toString() { diff --git a/lib/data/models/models.g.dart b/lib/data/models/models.g.dart index 25fd3f485a..ed62581ad5 100644 --- a/lib/data/models/models.g.dart +++ b/lib/data/models/models.g.dart @@ -106,6 +106,7 @@ const EntityAction _$unlink = const EntityAction._('unlink'); const EntityAction _$runTemplate = const EntityAction._('runTemplate'); const EntityAction _$bulkUpdate = const EntityAction._('bulkUpdate'); const EntityAction _$reconnect = const EntityAction._('reconnect'); +const EntityAction _$addComment = const EntityAction._('addComment'); EntityAction _$valueOf(String name) { switch (name) { @@ -287,6 +288,8 @@ EntityAction _$valueOf(String name) { return _$bulkUpdate; case 'reconnect': return _$reconnect; + case 'addComment': + return _$addComment; default: throw new ArgumentError(name); } @@ -383,6 +386,7 @@ final BuiltSet _$values = _$runTemplate, _$bulkUpdate, _$reconnect, + _$addComment, ]); Serializer _$entityActionSerializer = diff --git a/lib/redux/invoice/invoice_actions.dart b/lib/redux/invoice/invoice_actions.dart index e94382adf6..5ee6ba5ea0 100644 --- a/lib/redux/invoice/invoice_actions.dart +++ b/lib/redux/invoice/invoice_actions.dart @@ -883,6 +883,16 @@ void handleInvoiceAction(BuildContext? context, List invoices, ), ); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.invoice, + entityId: invoice.id, + ), + ); + break; case EntityAction.more: showEntityActionsDialog( entities: [invoice], diff --git a/lib/utils/dialogs.dart b/lib/utils/dialogs.dart index 522066fa44..44899b8b7c 100644 --- a/lib/utils/dialogs.dart +++ b/lib/utils/dialogs.dart @@ -992,3 +992,63 @@ class _RunTemplateDialogState extends State { ); } } + +class AddCommentDialog extends StatefulWidget { + const AddCommentDialog({ + super.key, + required this.entityId, + required this.entityType, + }); + + final String entityId; + final EntityType entityType; + + @override + State createState() => _AddCommentDialogState(); +} + +class _AddCommentDialogState extends State { + String _comment = ''; + + @override + Widget build(BuildContext context) { + final localization = AppLocalization.of(context)!; + + return AlertDialog( + title: Text(localization.addComment), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + localization.cancel.toUpperCase(), + ), + ), + TextButton( + onPressed: _comment.isEmpty + ? null + : () { + // + }, + child: Text( + localization.save.toUpperCase(), + ), + ), + ], + content: DecoratedFormField( + label: localization.comment, + keyboardType: TextInputType.multiline, + initialValue: _comment, + onChanged: (value) { + setState(() { + _comment = value; + }); + }, + minLines: 6, + maxLines: 6, + autofocus: true, + ), + ); + } +} diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index 5ef026c468..d1361745b8 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -18,6 +18,8 @@ mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { // STARTER: lang key - do not remove comment + 'comment': 'Comment', + 'add_comment': 'Add Comment', 'disconnected': 'Disconnected', 'reconnect': 'Reconnect', 'e_invoice_settings': 'E-Invoice Settings', @@ -115515,6 +115517,14 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]!['disconnected'] ?? _localizedValues['en']!['disconnected']!; + String get addComment => + _localizedValues[localeCode]!['add_comment'] ?? + _localizedValues['en']!['add_comment']!; + + String get comment => + _localizedValues[localeCode]!['comment'] ?? + _localizedValues['en']!['comment']!; + // STARTER: lang field - do not remove comment String lookup(String? key, {String? overrideLocaleCode}) { diff --git a/lib/utils/icons.dart b/lib/utils/icons.dart index c994b819fb..9db63618dc 100644 --- a/lib/utils/icons.dart +++ b/lib/utils/icons.dart @@ -138,6 +138,8 @@ IconData? getEntityActionIcon(EntityAction? entityAction) { return MdiIcons.arrowRightCircleOutline; case EntityAction.bulkUpdate: return MdiIcons.squareEditOutline; + case EntityAction.addComment: + return MdiIcons.comment; default: return null; } From 9197cf17f248eb1aef9866cedc260aca74a5d746 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 17:21:40 +0300 Subject: [PATCH 05/12] Support comments --- lib/utils/dialogs.dart | 53 +++++++++++++++++++++++++++++++----------- lib/utils/i18n.dart | 5 ++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/lib/utils/dialogs.dart b/lib/utils/dialogs.dart index 44899b8b7c..d281b0bb80 100644 --- a/lib/utils/dialogs.dart +++ b/lib/utils/dialogs.dart @@ -1009,10 +1009,13 @@ class AddCommentDialog extends StatefulWidget { class _AddCommentDialogState extends State { String _comment = ''; + bool _isLoading = false; @override Widget build(BuildContext context) { final localization = AppLocalization.of(context)!; + final store = StoreProvider.of(context); + final state = store.state; return AlertDialog( title: Text(localization.addComment), @@ -1029,26 +1032,48 @@ class _AddCommentDialogState extends State { onPressed: _comment.isEmpty ? null : () { - // + final credentials = state.credentials; + final url = '${credentials.url}/activities/notes'; + final data = { + 'entity': widget.entityType.pluralApiValue, + 'entity_id': widget.entityId, + 'notes': _comment.trim(), + }; + + print('DATA: $data'); + setState(() => _isLoading = true); + + WebClient() + .post(url, credentials.token, data: jsonEncode(data)) + .then((response) async { + setState(() => _isLoading = false); + Navigator.of(navigatorKey.currentContext!).pop(); + showToast(localization.addedComment); + }).catchError((error) { + showErrorDialog(message: error); + setState(() => _isLoading = false); + }); }, child: Text( localization.save.toUpperCase(), ), ), ], - content: DecoratedFormField( - label: localization.comment, - keyboardType: TextInputType.multiline, - initialValue: _comment, - onChanged: (value) { - setState(() { - _comment = value; - }); - }, - minLines: 6, - maxLines: 6, - autofocus: true, - ), + content: _isLoading + ? LinearProgressIndicator() + : DecoratedFormField( + label: localization.comment, + keyboardType: TextInputType.multiline, + initialValue: _comment, + onChanged: (value) { + setState(() { + _comment = value.trim(); + }); + }, + minLines: 6, + maxLines: 6, + autofocus: true, + ), ); } } diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index d1361745b8..2e2378acd1 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -20,6 +20,7 @@ mixin LocalizationsProvider on LocaleCodeAware { // STARTER: lang key - do not remove comment 'comment': 'Comment', 'add_comment': 'Add Comment', + 'added_comment': 'Successfully saved comment', 'disconnected': 'Disconnected', 'reconnect': 'Reconnect', 'e_invoice_settings': 'E-Invoice Settings', @@ -115525,6 +115526,10 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]!['comment'] ?? _localizedValues['en']!['comment']!; + String get addedComment => + _localizedValues[localeCode]!['added_comment'] ?? + _localizedValues['en']!['added_comment']!; + // STARTER: lang field - do not remove comment String lookup(String? key, {String? overrideLocaleCode}) { From 99cf44011a620427f4c2e04689031c458408a76e Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 17:24:48 +0300 Subject: [PATCH 06/12] Support comments --- lib/ui/app/lists/activity_list_tile.dart | 2 +- lib/utils/dialogs.dart | 80 ++++++++++++------------ 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/lib/ui/app/lists/activity_list_tile.dart b/lib/ui/app/lists/activity_list_tile.dart index b3f8e10b62..d2cbf5a100 100644 --- a/lib/ui/app/lists/activity_list_tile.dart +++ b/lib/ui/app/lists/activity_list_tile.dart @@ -77,7 +77,7 @@ class ActivityListTile extends StatelessWidget { title: Text(activity.isComment ? (user?.fullName == null ? '' - : (user!.fullName + ': ' + activity.notes)) + : (user!.fullName + ': ' + activity.notes.replaceAll('\n', ' '))) : title), onTap: !enableNavigation ? null diff --git a/lib/utils/dialogs.dart b/lib/utils/dialogs.dart index d281b0bb80..b8c28df611 100644 --- a/lib/utils/dialogs.dart +++ b/lib/utils/dialogs.dart @@ -1019,46 +1019,48 @@ class _AddCommentDialogState extends State { return AlertDialog( title: Text(localization.addComment), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text( - localization.cancel.toUpperCase(), - ), - ), - TextButton( - onPressed: _comment.isEmpty - ? null - : () { - final credentials = state.credentials; - final url = '${credentials.url}/activities/notes'; - final data = { - 'entity': widget.entityType.pluralApiValue, - 'entity_id': widget.entityId, - 'notes': _comment.trim(), - }; - - print('DATA: $data'); - setState(() => _isLoading = true); - - WebClient() - .post(url, credentials.token, data: jsonEncode(data)) - .then((response) async { - setState(() => _isLoading = false); - Navigator.of(navigatorKey.currentContext!).pop(); - showToast(localization.addedComment); - }).catchError((error) { - showErrorDialog(message: error); - setState(() => _isLoading = false); - }); + actions: _isLoading + ? [] + : [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); }, - child: Text( - localization.save.toUpperCase(), - ), - ), - ], + child: Text( + localization.cancel.toUpperCase(), + ), + ), + TextButton( + onPressed: _comment.isEmpty + ? null + : () { + final credentials = state.credentials; + final url = '${credentials.url}/activities/notes'; + final data = { + 'entity': widget.entityType.pluralApiValue, + 'entity_id': widget.entityId, + 'notes': _comment.trim(), + }; + + print('DATA: $data'); + setState(() => _isLoading = true); + + WebClient() + .post(url, credentials.token, + data: jsonEncode(data)) + .then((response) async { + Navigator.of(navigatorKey.currentContext!).pop(); + showToast(localization.addedComment); + }).catchError((error) { + showErrorDialog(message: error); + setState(() => _isLoading = false); + }); + }, + child: Text( + localization.save.toUpperCase(), + ), + ), + ], content: _isLoading ? LinearProgressIndicator() : DecoratedFormField( From 26a5035f16152e8a44714626207f52bc41536f6a Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 17:33:08 +0300 Subject: [PATCH 07/12] Support comments --- lib/data/models/client_model.dart | 4 ++++ lib/data/models/expense_model.dart | 4 ++++ lib/data/models/payment_model.dart | 4 ++++ lib/data/models/project_model.dart | 4 ++++ lib/data/models/task_model.dart | 4 ++++ lib/data/models/vendor_model.dart | 4 ++++ lib/redux/client/client_actions.dart | 11 +++++++++++ lib/redux/credit/credit_actions.dart | 11 +++++++++++ lib/redux/expense/expense_actions.dart | 11 +++++++++++ lib/redux/payment/payment_actions.dart | 11 +++++++++++ lib/redux/project/project_actions.dart | 11 +++++++++++ .../purchase_order_actions.dart | 15 ++++++++++++++- lib/redux/quote/quote_actions.dart | 11 +++++++++++ .../recurring_expense_actions.dart | 12 ++++++++++++ .../recurring_invoice_actions.dart | 19 ++++++++++++++++++- lib/redux/task/task_actions.dart | 11 +++++++++++ lib/redux/vendor/vendor_actions.dart | 12 ++++++++++++ 17 files changed, 157 insertions(+), 2 deletions(-) diff --git a/lib/data/models/client_model.dart b/lib/data/models/client_model.dart index c38a75b5d0..14b75427c0 100644 --- a/lib/data/models/client_model.dart +++ b/lib/data/models/client_model.dart @@ -683,6 +683,10 @@ abstract class ClientEntity extends Object store.state.designState.map, entityType)) { actions.add(EntityAction.runTemplate); } + + if (!multiselect) { + actions.add(EntityAction.addComment); + } } if (!isDeleted! && multiselect) { diff --git a/lib/data/models/expense_model.dart b/lib/data/models/expense_model.dart index ef54f70806..4dab561b6a 100644 --- a/lib/data/models/expense_model.dart +++ b/lib/data/models/expense_model.dart @@ -373,6 +373,10 @@ abstract class ExpenseEntity extends Object actions.add(EntityAction.documents); } + if (!isDeleted! && !multiselect) { + actions.add(EntityAction.addComment); + } + final superActions = super.getActions(userCompany: userCompany); if (actions.isNotEmpty && superActions.isNotEmpty && actions.last != null) { diff --git a/lib/data/models/payment_model.dart b/lib/data/models/payment_model.dart index a052370d8c..ba02e4ae89 100644 --- a/lib/data/models/payment_model.dart +++ b/lib/data/models/payment_model.dart @@ -457,6 +457,10 @@ abstract class PaymentEntity extends Object store.state.designState.map, entityType)) { actions.add(EntityAction.runTemplate); } + + if (!multiselect) { + actions.add(EntityAction.addComment); + } } if (!isDeleted! && multiselect) { diff --git a/lib/data/models/project_model.dart b/lib/data/models/project_model.dart index c7b1989e28..cc5b02b5c9 100644 --- a/lib/data/models/project_model.dart +++ b/lib/data/models/project_model.dart @@ -211,6 +211,10 @@ abstract class ProjectEntity extends Object store.state.designState.map, entityType)) { actions.add(EntityAction.runTemplate); } + + if (!multiselect) { + actions.add(EntityAction.addComment); + } } if (actions.isNotEmpty && actions.last != null) { diff --git a/lib/data/models/task_model.dart b/lib/data/models/task_model.dart index 2be989b25f..9b437ce8fc 100644 --- a/lib/data/models/task_model.dart +++ b/lib/data/models/task_model.dart @@ -699,6 +699,10 @@ abstract class TaskEntity extends Object store.state.designState.map, entityType)) { actions.add(EntityAction.runTemplate); } + + if (!multiselect) { + actions.add(EntityAction.addComment); + } } if (actions.isNotEmpty && actions.last != null) { diff --git a/lib/data/models/vendor_model.dart b/lib/data/models/vendor_model.dart index d6256a4c60..0e0d971e51 100644 --- a/lib/data/models/vendor_model.dart +++ b/lib/data/models/vendor_model.dart @@ -269,6 +269,10 @@ abstract class VendorEntity extends Object actions.add(EntityAction.documents); } + if (!isDeleted! && !multiselect) { + actions.add(EntityAction.addComment); + } + if (actions.isNotEmpty && actions.last != null) { actions.add(null); } diff --git a/lib/redux/client/client_actions.dart b/lib/redux/client/client_actions.dart index e5a9d142e9..5537851320 100644 --- a/lib/redux/client/client_actions.dart +++ b/lib/redux/client/client_actions.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:built_collection/built_collection.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:http/http.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; import 'package:invoiceninja_flutter/ui/app/forms/client_picker.dart'; import 'package:invoiceninja_flutter/utils/dialogs.dart'; @@ -560,6 +561,16 @@ void handleClientAction(BuildContext? context, List clients, ), ); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.client, + entityId: client.id, + ), + ); + break; default: print('## Error: action $action not handled in client_actions'); } diff --git a/lib/redux/credit/credit_actions.dart b/lib/redux/credit/credit_actions.dart index 0f33815d18..868c244a8d 100644 --- a/lib/redux/credit/credit_actions.dart +++ b/lib/redux/credit/credit_actions.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:built_collection/built_collection.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:http/http.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart'; import 'package:invoiceninja_flutter/utils/files.dart'; @@ -754,6 +755,16 @@ Future handleCreditAction(BuildContext context, List credits, ); } break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.credit, + entityId: credit.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in credit_actions'); break; diff --git a/lib/redux/expense/expense_actions.dart b/lib/redux/expense/expense_actions.dart index 9834137ec0..2e21cbd9e0 100644 --- a/lib/redux/expense/expense_actions.dart +++ b/lib/redux/expense/expense_actions.dart @@ -12,6 +12,7 @@ import 'package:http/http.dart'; // Project imports: import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; @@ -397,6 +398,16 @@ void handleExpenseAction( ); } break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.expense, + entityId: expense.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in expense_actions'); break; diff --git a/lib/redux/payment/payment_actions.dart b/lib/redux/payment/payment_actions.dart index b3ebd392a3..c0a7ed6aca 100644 --- a/lib/redux/payment/payment_actions.dart +++ b/lib/redux/payment/payment_actions.dart @@ -11,6 +11,7 @@ import 'package:http/http.dart'; // Project imports: import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; @@ -469,6 +470,16 @@ void handlePaymentAction( ), ); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.payment, + entityId: payment.id, + ), + ); + break; default: print('## Error: action $action not handled in client_actions'); } diff --git a/lib/redux/project/project_actions.dart b/lib/redux/project/project_actions.dart index 33f96ddac6..1912e3c42e 100644 --- a/lib/redux/project/project_actions.dart +++ b/lib/redux/project/project_actions.dart @@ -11,6 +11,7 @@ import 'package:http/http.dart'; // Project imports: import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; @@ -399,6 +400,16 @@ void handleProjectAction( ), ); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.project, + entityId: project.id, + ), + ); + break; default: print('## Error: action $action not handled in project_actions'); } diff --git a/lib/redux/purchase_order/purchase_order_actions.dart b/lib/redux/purchase_order/purchase_order_actions.dart index 87a0b5807b..64ead888cb 100644 --- a/lib/redux/purchase_order/purchase_order_actions.dart +++ b/lib/redux/purchase_order/purchase_order_actions.dart @@ -468,7 +468,10 @@ class RemovePurchaseOrderContact implements PersistUI { } class AddPurchaseOrderItem implements PersistUI { - AddPurchaseOrderItem({this.purchaseOrderItem, this.index,}); + AddPurchaseOrderItem({ + this.purchaseOrderItem, + this.index, + }); final int? index; final InvoiceItemEntity? purchaseOrderItem; @@ -876,6 +879,16 @@ void handlePurchaseOrderAction(BuildContext? context, entities: [purchaseOrder], ); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.purchaseOrder, + entityId: purchaseOrder.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in purchase_order_actions'); break; diff --git a/lib/redux/quote/quote_actions.dart b/lib/redux/quote/quote_actions.dart index 74c8203dc0..d22ec1f98d 100644 --- a/lib/redux/quote/quote_actions.dart +++ b/lib/redux/quote/quote_actions.dart @@ -10,6 +10,7 @@ import 'package:built_collection/built_collection.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:http/http.dart'; import 'package:invoiceninja_flutter/constants.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart'; import 'package:invoiceninja_flutter/utils/files.dart'; @@ -808,6 +809,16 @@ Future handleQuoteAction( ); } break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.quote, + entityId: quote.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in quote_actions'); break; diff --git a/lib/redux/recurring_expense/recurring_expense_actions.dart b/lib/redux/recurring_expense/recurring_expense_actions.dart index 6d4b94edcc..2f1ebf97ee 100644 --- a/lib/redux/recurring_expense/recurring_expense_actions.dart +++ b/lib/redux/recurring_expense/recurring_expense_actions.dart @@ -2,6 +2,7 @@ import 'dart:async'; // Flutter imports: +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; // Package imports: @@ -11,6 +12,7 @@ import 'package:http/http.dart'; // Project imports: import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; @@ -459,6 +461,16 @@ void handleRecurringExpenseAction(BuildContext? context, ); } break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.recurringExpense, + entityId: recurringExpense.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in recurring_expense_actions'); break; diff --git a/lib/redux/recurring_invoice/recurring_invoice_actions.dart b/lib/redux/recurring_invoice/recurring_invoice_actions.dart index ff4179c11c..8ce147a42e 100644 --- a/lib/redux/recurring_invoice/recurring_invoice_actions.dart +++ b/lib/redux/recurring_invoice/recurring_invoice_actions.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:built_collection/built_collection.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:http/http.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart'; @@ -200,7 +201,10 @@ class AddRecurringInvoiceSuccess implements StopSaving, PersistData, PersistUI { } class AddRecurringInvoiceItem implements PersistUI { - AddRecurringInvoiceItem({this.invoiceItem, this.index,}); + AddRecurringInvoiceItem({ + this.invoiceItem, + this.index, + }); final int? index; final InvoiceItemEntity? invoiceItem; @@ -723,6 +727,19 @@ void handleRecurringInvoiceAction(BuildContext? context, recurringInvoiceIds, )); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.recurringInvoice, + entityId: recurringInvoice.id, + ), + ); + break; + default: + print( + '## Error: action $action not handled in recurring_invoice_actions'); } } diff --git a/lib/redux/task/task_actions.dart b/lib/redux/task/task_actions.dart index 65b441cefe..68c46636f6 100644 --- a/lib/redux/task/task_actions.dart +++ b/lib/redux/task/task_actions.dart @@ -11,6 +11,7 @@ import 'package:http/http.dart'; // Project imports: import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; @@ -553,6 +554,16 @@ void handleTaskAction( ), ); break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.task, + entityId: task.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in task_actions'); break; diff --git a/lib/redux/vendor/vendor_actions.dart b/lib/redux/vendor/vendor_actions.dart index b0b865fe7f..07b7c666fa 100644 --- a/lib/redux/vendor/vendor_actions.dart +++ b/lib/redux/vendor/vendor_actions.dart @@ -2,6 +2,7 @@ import 'dart:async'; // Flutter imports: +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; // Package imports: @@ -11,6 +12,7 @@ import 'package:http/http.dart'; // Project imports: import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/document/document_actions.dart'; @@ -395,6 +397,16 @@ void handleVendorAction( ); } break; + case EntityAction.addComment: + showDialog( + context: navigatorKey.currentContext!, + barrierDismissible: false, + builder: (context) => AddCommentDialog( + entityType: EntityType.vendor, + entityId: vendor.id, + ), + ); + break; default: print('## ERROR: unhandled action $action in vendor_actions'); break; From 556fb1b089e3403f3cc8d560892d577ced2b73cc Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 18:39:16 +0300 Subject: [PATCH 08/12] Code cleanup --- lib/redux/expense/expense_actions.dart | 1 - lib/redux/recurring_expense/recurring_expense_actions.dart | 1 - lib/redux/vendor/vendor_actions.dart | 1 - 3 files changed, 3 deletions(-) diff --git a/lib/redux/expense/expense_actions.dart b/lib/redux/expense/expense_actions.dart index 2e21cbd9e0..2861bcf00b 100644 --- a/lib/redux/expense/expense_actions.dart +++ b/lib/redux/expense/expense_actions.dart @@ -3,7 +3,6 @@ import 'dart:async'; // Flutter imports: import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; // Package imports: import 'package:built_collection/built_collection.dart'; diff --git a/lib/redux/recurring_expense/recurring_expense_actions.dart b/lib/redux/recurring_expense/recurring_expense_actions.dart index 2f1ebf97ee..a4e09ddce6 100644 --- a/lib/redux/recurring_expense/recurring_expense_actions.dart +++ b/lib/redux/recurring_expense/recurring_expense_actions.dart @@ -3,7 +3,6 @@ import 'dart:async'; // Flutter imports: import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; // Package imports: import 'package:built_collection/built_collection.dart'; diff --git a/lib/redux/vendor/vendor_actions.dart b/lib/redux/vendor/vendor_actions.dart index 07b7c666fa..3daacfa364 100644 --- a/lib/redux/vendor/vendor_actions.dart +++ b/lib/redux/vendor/vendor_actions.dart @@ -3,7 +3,6 @@ import 'dart:async'; // Flutter imports: import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; // Package imports: import 'package:built_collection/built_collection.dart'; From a47a5d96ea81f5c8123e86554fe0114f5e390982 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 18:43:15 +0300 Subject: [PATCH 09/12] Add quote.project field --- lib/ui/settings/invoice_design.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/settings/invoice_design.dart b/lib/ui/settings/invoice_design.dart index 2d545a5c4a..5f42d35218 100644 --- a/lib/ui/settings/invoice_design.dart +++ b/lib/ui/settings/invoice_design.dart @@ -916,7 +916,7 @@ class _InvoiceDesignState extends State QuoteFields.date, QuoteFields.validUntil, QuoteFields.total, - if (false) QuoteFields.project, + QuoteFields.project, QuoteFields.customValue1, QuoteFields.customValue2, QuoteFields.customValue3, From 46b7eb2e336a2964a85fb77964bdbe7d75138055 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 19:41:15 +0300 Subject: [PATCH 10/12] Set comment activity type id --- lib/constants.dart | 1 + lib/data/models/entities.dart | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/constants.dart b/lib/constants.dart index 0cf6717201..c9872a779f 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -1128,3 +1128,4 @@ const String kActivityAcceptPurchaseOrder = '137'; const String kActivityEmailPayment = '138'; const String kActivityExpenseNotificationSent = '139'; const String kActivityStatementSent = '140'; +const String kActivityComment = '141'; diff --git a/lib/data/models/entities.dart b/lib/data/models/entities.dart index fae4c734ee..a5dbf8e28a 100644 --- a/lib/data/models/entities.dart +++ b/lib/data/models/entities.dart @@ -767,7 +767,9 @@ abstract class ActivityEntity InvoiceHistoryEntity? get history; - bool get isComment => activityTypeId.isEmpty; + // TODO remove isEmpty check + bool get isComment => + activityTypeId == kActivityComment || activityTypeId.isEmpty; EntityType? get entityType { if (isComment) { From 1ca6bf09316843e053ab9fdcb0d0106a94ab78d3 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 19:45:01 +0300 Subject: [PATCH 11/12] Hide add comment from unsupported types --- lib/data/models/expense_model.dart | 2 +- lib/data/models/payment_model.dart | 2 +- lib/data/models/project_model.dart | 2 +- lib/data/models/task_model.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/data/models/expense_model.dart b/lib/data/models/expense_model.dart index 4dab561b6a..1e2c683ddd 100644 --- a/lib/data/models/expense_model.dart +++ b/lib/data/models/expense_model.dart @@ -374,7 +374,7 @@ abstract class ExpenseEntity extends Object } if (!isDeleted! && !multiselect) { - actions.add(EntityAction.addComment); + //actions.add(EntityAction.addComment); } final superActions = super.getActions(userCompany: userCompany); diff --git a/lib/data/models/payment_model.dart b/lib/data/models/payment_model.dart index ba02e4ae89..79caca5c8d 100644 --- a/lib/data/models/payment_model.dart +++ b/lib/data/models/payment_model.dart @@ -459,7 +459,7 @@ abstract class PaymentEntity extends Object } if (!multiselect) { - actions.add(EntityAction.addComment); + //actions.add(EntityAction.addComment); } } diff --git a/lib/data/models/project_model.dart b/lib/data/models/project_model.dart index cc5b02b5c9..0e03420437 100644 --- a/lib/data/models/project_model.dart +++ b/lib/data/models/project_model.dart @@ -213,7 +213,7 @@ abstract class ProjectEntity extends Object } if (!multiselect) { - actions.add(EntityAction.addComment); + //actions.add(EntityAction.addComment); } } diff --git a/lib/data/models/task_model.dart b/lib/data/models/task_model.dart index 9b437ce8fc..803231a398 100644 --- a/lib/data/models/task_model.dart +++ b/lib/data/models/task_model.dart @@ -701,7 +701,7 @@ abstract class TaskEntity extends Object } if (!multiselect) { - actions.add(EntityAction.addComment); + //actions.add(EntityAction.addComment); } } From dd7ec12aab1a8378e7292b7e77eb11d877c3315c Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Jun 2024 19:54:00 +0300 Subject: [PATCH 12/12] Fix for P&L converted amount --- lib/ui/reports/profit_loss_report.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/reports/profit_loss_report.dart b/lib/ui/reports/profit_loss_report.dart index a0d7081148..6295560290 100644 --- a/lib/ui/reports/profit_loss_report.dart +++ b/lib/ui/reports/profit_loss_report.dart @@ -294,7 +294,7 @@ ReportResult profitAndLossReport( .lookup(expense.entityState); break; case ProfitAndLossReportFields.converted_amount: - value = expense.convertedAmount; + value = -expense.convertedAmount; break; }