diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml
index ee7b699f3..e58991e20 100644
--- a/.github/workflows/flatpak.yml
+++ b/.github/workflows/flatpak.yml
@@ -86,7 +86,7 @@ jobs:
draft: false
prerelease: false
title: "Latest Release"
- automatic_release_tag: "v5.0.152"
+ automatic_release_tag: "v5.0.153"
files: |
${{ github.workspace }}/artifacts/Invoice-Ninja-Archive
${{ github.workspace }}/artifacts/Invoice-Ninja-Hash
diff --git a/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml b/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml
index 72d8de22e..3c0fb28f6 100644
--- a/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml
+++ b/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml
@@ -50,6 +50,7 @@
+
diff --git a/lib/constants.dart b/lib/constants.dart
index 713d26454..84c5061e2 100644
--- a/lib/constants.dart
+++ b/lib/constants.dart
@@ -6,7 +6,7 @@ class Constants {
}
// TODO remove version once #46609 is fixed
-const String kClientVersion = '5.0.152';
+const String kClientVersion = '5.0.153';
const String kMinServerVersion = '5.0.4';
const String kAppName = 'Invoice Ninja';
@@ -704,9 +704,9 @@ final kReportMap = {
kReportQuoteItem: ExportType.quote_items,
kReportRecurringExpense: null,
kReportRecurringInvoice: ExportType.recurring_invoices,
- kReportPurchaseOrder: null,
- kReportPurchaseOrderItem: null,
- kReportVendor: null,
+ kReportPurchaseOrder: ExportType.purchase_order,
+ kReportPurchaseOrderItem: ExportType.purchase_order_item,
+ kReportVendor: ExportType.vendor,
kReportTransaction: null,
};
diff --git a/lib/data/models/import_model.dart b/lib/data/models/import_model.dart
index 90f7d5dfd..ee42b40ee 100644
--- a/lib/data/models/import_model.dart
+++ b/lib/data/models/import_model.dart
@@ -202,6 +202,9 @@ class ExportType extends EnumClass {
static const ExportType products = _$products;
static const ExportType tasks = _$tasks;
static const ExportType profitloss = _$profitloss;
+ static const ExportType vendor = _$vendor;
+ static const ExportType purchase_order = _$purchase_order;
+ static const ExportType purchase_order_item = _$purchase_order_item;
static const ExportType ar_detailed = _$ar_detailed;
static const ExportType ar_summary = _$ar_summary;
static const ExportType client_balance = _$client_balance;
diff --git a/lib/data/models/import_model.g.dart b/lib/data/models/import_model.g.dart
index 6cc1f2274..2752d4784 100644
--- a/lib/data/models/import_model.g.dart
+++ b/lib/data/models/import_model.g.dart
@@ -62,6 +62,10 @@ const ExportType _$payments = const ExportType._('payments');
const ExportType _$products = const ExportType._('products');
const ExportType _$tasks = const ExportType._('tasks');
const ExportType _$profitloss = const ExportType._('profitloss');
+const ExportType _$vendor = const ExportType._('vendor');
+const ExportType _$purchase_order = const ExportType._('purchase_order');
+const ExportType _$purchase_order_item =
+ const ExportType._('purchase_order_item');
const ExportType _$ar_detailed = const ExportType._('ar_detailed');
const ExportType _$ar_summary = const ExportType._('ar_summary');
const ExportType _$client_balance = const ExportType._('client_balance');
@@ -101,6 +105,12 @@ ExportType _$exportValueOf(String name) {
return _$tasks;
case 'profitloss':
return _$profitloss;
+ case 'vendor':
+ return _$vendor;
+ case 'purchase_order':
+ return _$purchase_order;
+ case 'purchase_order_item':
+ return _$purchase_order_item;
case 'ar_detailed':
return _$ar_detailed;
case 'ar_summary':
@@ -135,6 +145,9 @@ final BuiltSet _$exportValues =
_$products,
_$tasks,
_$profitloss,
+ _$vendor,
+ _$purchase_order,
+ _$purchase_order_item,
_$ar_detailed,
_$ar_summary,
_$client_balance,
diff --git a/lib/data/models/settings_model.dart b/lib/data/models/settings_model.dart
index 9f89278fe..6e1ec64f9 100644
--- a/lib/data/models/settings_model.dart
+++ b/lib/data/models/settings_model.dart
@@ -815,6 +815,9 @@ abstract class SettingsEntity
@BuiltValueField(wireName: 'payment_email_all_contacts')
bool? get paymentEmailAllContacts;
+ @BuiltValueField(wireName: 'show_pdfhtml_on_mobile')
+ bool? get showPdfhtmlOnMobile;
+
bool get hasAddress => address1 != null && address1!.isNotEmpty;
bool get hasLogo => companyLogo != null && companyLogo!.isNotEmpty;
diff --git a/lib/data/models/settings_model.g.dart b/lib/data/models/settings_model.g.dart
index 9b46e5b18..3b8399a29 100644
--- a/lib/data/models/settings_model.g.dart
+++ b/lib/data/models/settings_model.g.dart
@@ -1578,6 +1578,13 @@ class _$SettingsEntitySerializer
..add(
serializers.serialize(value, specifiedType: const FullType(bool)));
}
+ value = object.showPdfhtmlOnMobile;
+ if (value != null) {
+ result
+ ..add('show_pdfhtml_on_mobile')
+ ..add(
+ serializers.serialize(value, specifiedType: const FullType(bool)));
+ }
return result;
}
@@ -2496,6 +2503,10 @@ class _$SettingsEntitySerializer
result.paymentEmailAllContacts = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool?;
break;
+ case 'show_pdfhtml_on_mobile':
+ result.showPdfhtmlOnMobile = serializers.deserialize(value,
+ specifiedType: const FullType(bool)) as bool?;
+ break;
}
}
@@ -3023,6 +3034,8 @@ class _$SettingsEntity extends SettingsEntity {
final String? classification;
@override
final bool? paymentEmailAllContacts;
+ @override
+ final bool? showPdfhtmlOnMobile;
factory _$SettingsEntity([void Function(SettingsEntityBuilder)? updates]) =>
(new SettingsEntityBuilder()..update(updates))._build();
@@ -3251,7 +3264,8 @@ class _$SettingsEntity extends SettingsEntity {
this.eInvoiceType,
this.defaultExpensePaymentTypeId,
this.classification,
- this.paymentEmailAllContacts})
+ this.paymentEmailAllContacts,
+ this.showPdfhtmlOnMobile})
: super._();
@override
@@ -3494,7 +3508,8 @@ class _$SettingsEntity extends SettingsEntity {
eInvoiceType == other.eInvoiceType &&
defaultExpensePaymentTypeId == other.defaultExpensePaymentTypeId &&
classification == other.classification &&
- paymentEmailAllContacts == other.paymentEmailAllContacts;
+ paymentEmailAllContacts == other.paymentEmailAllContacts &&
+ showPdfhtmlOnMobile == other.showPdfhtmlOnMobile;
}
int? __hashCode;
@@ -3726,6 +3741,7 @@ class _$SettingsEntity extends SettingsEntity {
_$hash = $jc(_$hash, defaultExpensePaymentTypeId.hashCode);
_$hash = $jc(_$hash, classification.hashCode);
_$hash = $jc(_$hash, paymentEmailAllContacts.hashCode);
+ _$hash = $jc(_$hash, showPdfhtmlOnMobile.hashCode);
_$hash = $jf(_$hash);
return __hashCode ??= _$hash;
}
@@ -3961,7 +3977,8 @@ class _$SettingsEntity extends SettingsEntity {
..add('eInvoiceType', eInvoiceType)
..add('defaultExpensePaymentTypeId', defaultExpensePaymentTypeId)
..add('classification', classification)
- ..add('paymentEmailAllContacts', paymentEmailAllContacts))
+ ..add('paymentEmailAllContacts', paymentEmailAllContacts)
+ ..add('showPdfhtmlOnMobile', showPdfhtmlOnMobile))
.toString();
}
}
@@ -5077,6 +5094,11 @@ class SettingsEntityBuilder
set paymentEmailAllContacts(bool? paymentEmailAllContacts) =>
_$this._paymentEmailAllContacts = paymentEmailAllContacts;
+ bool? _showPdfhtmlOnMobile;
+ bool? get showPdfhtmlOnMobile => _$this._showPdfhtmlOnMobile;
+ set showPdfhtmlOnMobile(bool? showPdfhtmlOnMobile) =>
+ _$this._showPdfhtmlOnMobile = showPdfhtmlOnMobile;
+
SettingsEntityBuilder();
SettingsEntityBuilder get _$this {
@@ -5306,6 +5328,7 @@ class SettingsEntityBuilder
_defaultExpensePaymentTypeId = $v.defaultExpensePaymentTypeId;
_classification = $v.classification;
_paymentEmailAllContacts = $v.paymentEmailAllContacts;
+ _showPdfhtmlOnMobile = $v.showPdfhtmlOnMobile;
_$v = null;
}
return this;
@@ -5554,7 +5577,8 @@ class SettingsEntityBuilder
eInvoiceType: eInvoiceType,
defaultExpensePaymentTypeId: defaultExpensePaymentTypeId,
classification: classification,
- paymentEmailAllContacts: paymentEmailAllContacts);
+ paymentEmailAllContacts: paymentEmailAllContacts,
+ showPdfhtmlOnMobile: showPdfhtmlOnMobile);
} catch (_) {
late String _$failedField;
try {
diff --git a/lib/ui/settings/email_settings.dart b/lib/ui/settings/email_settings.dart
index 84387d4eb..f807e0a98 100644
--- a/lib/ui/settings/email_settings.dart
+++ b/lib/ui/settings/email_settings.dart
@@ -235,9 +235,10 @@ class _EmailSettingsState extends State {
DropdownMenuItem(
child: Text(localization.defaultWord),
value: SettingsEntity.EMAIL_SENDING_METHOD_DEFAULT),
- DropdownMenuItem(
- child: Text('SMTP'),
- value: SettingsEntity.EMAIL_SENDING_METHOD_SMTP),
+ if (!kReleaseMode)
+ DropdownMenuItem(
+ child: Text('SMTP'),
+ value: SettingsEntity.EMAIL_SENDING_METHOD_SMTP),
if (viewModel.state.isHosted) ...[
DropdownMenuItem(
child: Text('Gmail'),
diff --git a/lib/ui/settings/invoice_design.dart b/lib/ui/settings/invoice_design.dart
index 69808df2b..3359c6b01 100644
--- a/lib/ui/settings/invoice_design.dart
+++ b/lib/ui/settings/invoice_design.dart
@@ -622,6 +622,14 @@ class _InvoiceDesignState extends State
settings
.rebuild((b) => b..embedDocuments = value)),
),
+ BoolDropdownButton(
+ label: localization.mobileVersion,
+ value: settings.showPdfhtmlOnMobile ?? true,
+ iconData: Icons.mobile_friendly,
+ onChanged: (value) => viewModel.onSettingsChanged(
+ settings.rebuild(
+ (b) => b..showPdfhtmlOnMobile = value)),
+ ),
],
),
FormCard(
diff --git a/lib/ui/settings/settings_list.dart b/lib/ui/settings/settings_list.dart
index 4a22cc3f0..a5a4c4ac4 100644
--- a/lib/ui/settings/settings_list.dart
+++ b/lib/ui/settings/settings_list.dart
@@ -553,6 +553,7 @@ class SettingsSearch extends StatelessWidget {
'show_shipping_address#2023-01-29',
'share_invoice_quote_columns#2023-03-20',
'invoice_embed_documents#2023-10-27',
+ 'mobile_version#2024-01-29',
if (supportsDesignTemplates()) ...[
'delivery_note_design#2023-11-06',
'statement_design#2023-11-06',
diff --git a/lib/ui/task/edit/task_edit_times.dart b/lib/ui/task/edit/task_edit_times.dart
index 46843daa9..9da6d3514 100644
--- a/lib/ui/task/edit/task_edit_times.dart
+++ b/lib/ui/task/edit/task_edit_times.dart
@@ -31,18 +31,27 @@ class _TaskEditTimesState extends State {
TaskTime? selectedTaskTime;
void _showTaskTimeEditor(TaskTime? taskTime, BuildContext context) {
+ if (taskTime == null) {
+ return;
+ }
+
+ final viewModel = widget.viewModel;
+ final task = viewModel.task!;
+ final taskTimes = task.getTaskTimes();
+
+ if (taskTimes.where((time) => time.equalTo(taskTime)).isEmpty) {
+ return;
+ }
+
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
- final viewModel = widget.viewModel;
- final task = viewModel.task!;
- final taskTimes = task.getTaskTimes();
return TimeEditDetails(
viewModel: viewModel,
taskTime: taskTime,
index: taskTimes.indexOf(
- taskTimes.firstWhere((time) => time.equalTo(taskTime!))),
+ taskTimes.firstWhere((time) => time.equalTo(taskTime))),
);
});
}
diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart
index 809f925e7..b5a581265 100644
--- a/lib/utils/i18n.dart
+++ b/lib/utils/i18n.dart
@@ -18,6 +18,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
+ 'mobile_version': 'Mobile Version',
'venmo': 'Venmo',
'mercado_pago': 'Mercado Pago',
'my_bank': 'MyBank',
@@ -114268,6 +114269,10 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]!['email_report'] ??
_localizedValues['en']!['email_report']!;
+ String get mobileVersion =>
+ _localizedValues[localeCode]!['mobile_version'] ??
+ _localizedValues['en']!['mobile_version']!;
+
// STARTER: lang field - do not remove comment
String lookup(String? key) {
diff --git a/pubspec.foss.yaml b/pubspec.foss.yaml
index 7a4e1c51d..0c6e98d2a 100644
--- a/pubspec.foss.yaml
+++ b/pubspec.foss.yaml
@@ -1,6 +1,6 @@
name: invoiceninja_flutter
description: Client for Invoice Ninja
-version: 5.0.152+152
+version: 5.0.153+153
homepage: https://invoiceninja.com
documentation: https://invoiceninja.github.io
publish_to: none
@@ -44,7 +44,7 @@ dependencies:
git:
url: https://github.com/theyakka/qr.flutter.git
local_auth: ^2.1.5
- sentry_flutter: ^7.12.0
+ sentry_flutter: ^7.15.0
image_picker: ^1.0.4
flutter_colorpicker: ^1.0.3
flutter_json_viewer: ^1.0.1
diff --git a/pubspec.lock b/pubspec.lock
index b647d17d1..364601b02 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1302,18 +1302,18 @@ packages:
dependency: transitive
description:
name: sentry
- sha256: e7ded42974bac5f69e4ca4ddc57d30499dd79381838f24b7e8fd9aa4139e7b79
+ sha256: "5686ed515bb620dc52b4ae99a6586fe720d443591183cf1f620ec5d1f0eec100"
url: "https://pub.dev"
source: hosted
- version: "7.13.2"
+ version: "7.15.0"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
- sha256: d6f55ec7a1f681784165021f749007712a72ff57eadf91e963331b6ae326f089
+ sha256: "505dec3b6810562785d2c34ae871c73ff2cba6cf436c32c188f0464df226ba8f"
url: "https://pub.dev"
source: hosted
- version: "7.13.2"
+ version: "7.15.0"
share_plus:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 6daeb4c11..bddabaf81 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: invoiceninja_flutter
description: Client for Invoice Ninja
-version: 5.0.152+152
+version: 5.0.153+153
homepage: https://invoiceninja.com
documentation: https://invoiceninja.github.io
publish_to: none
@@ -49,7 +49,7 @@ dependencies:
git:
url: https://github.com/theyakka/qr.flutter.git
local_auth: ^2.1.5
- sentry_flutter: ^7.12.0
+ sentry_flutter: ^7.15.0
image_picker: ^1.0.4
flutter_colorpicker: ^1.0.3
flutter_json_viewer: ^1.0.1
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 533ce2bba..502087c11 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -1,5 +1,5 @@
name: invoiceninja
-version: '5.0.152'
+version: '5.0.153'
summary: Create invoices, accept payments, track expenses & time tasks
description: "### Note: if the app fails to run using `snap run invoiceninja` it may help to run `/snap/invoiceninja/current/bin/invoiceninja` instead