diff --git a/android/app/build.gradle b/android/app/build.gradle index c01d58726..873647555 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -29,8 +29,8 @@ android { applicationId "com.invoiceninja.flutter" minSdkVersion 18 targetSdkVersion 27 - versionCode 33 - versionName "0.1.33" + versionCode 34 + versionName "0.1.34" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } diff --git a/ios/Runner/Info.plist.example b/ios/Runner/Info.plist.example index 92aea9ec6..2627125b2 100644 --- a/ios/Runner/Info.plist.example +++ b/ios/Runner/Info.plist.example @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1.33 + 0.1.34 CFBundleSignature ???? CFBundleVersion - 33 + 34 LSRequiresIPhoneOS UILaunchStoryboardName diff --git a/lib/constants.dart b/lib/constants.dart index c4606b990..71665bc2b 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; // This version must be updated in tandem with the pubspec version. -const String kAppVersion = '0.1.33'; +const String kAppVersion = '0.1.34'; const String kAppUrl = 'https://app.invoiceninja.com'; const String kAppleStoreUrl = diff --git a/lib/data/models/invoice_model.dart b/lib/data/models/invoice_model.dart index 369577c41..911d1af81 100644 --- a/lib/data/models/invoice_model.dart +++ b/lib/data/models/invoice_model.dart @@ -407,8 +407,10 @@ abstract class InvoiceEntity extends Object actions.add(EntityAction.viewInvoice); } - actions.add(EntityAction.pdf); - actions.add(EntityAction.clientPortal); + if (invitations.isNotEmpty) { + actions.add(EntityAction.pdf); + actions.add(EntityAction.clientPortal); + } if (actions.isNotEmpty) { actions.add(null); diff --git a/lib/data/models/task_model.dart b/lib/data/models/task_model.dart index 02c1a419f..f32a259c4 100644 --- a/lib/data/models/task_model.dart +++ b/lib/data/models/task_model.dart @@ -87,7 +87,7 @@ abstract class TaskTime implements Built { Map getParts(int timezoneOffset) { final localStartDate = startDate.toLocal(); - final localEndDate = endDate.toLocal(); + final localEndDate = (endDate ?? DateTime.now()).toLocal(); final startSqlDate = convertDateTimeToSqlDate(localStartDate); final endSqlDate = convertDateTimeToSqlDate(localEndDate); diff --git a/lib/redux/invoice/invoice_reducer.dart b/lib/redux/invoice/invoice_reducer.dart index b83d3e51b..67378a477 100644 --- a/lib/redux/invoice/invoice_reducer.dart +++ b/lib/redux/invoice/invoice_reducer.dart @@ -215,6 +215,10 @@ InvoiceState _archiveInvoiceFailure(InvoiceState invoiceState, InvoiceState _deleteInvoiceRequest(InvoiceState invoiceState, DeleteInvoiceRequest action) { + if (!invoiceState.map.containsKey(action.invoiceId)) { + return invoiceState; + } + final invoice = invoiceState.map[action.invoiceId].rebuild((b) => b ..archivedAt = DateTime @@ -227,6 +231,10 @@ InvoiceState _deleteInvoiceRequest(InvoiceState invoiceState, InvoiceState _deleteInvoiceSuccess(InvoiceState invoiceState, DeleteInvoiceSuccess action) { + if (!invoiceState.map.containsKey(action.invoice.id)) { + return invoiceState; + } + return invoiceState .rebuild((b) => b..map[action.invoice.id] = action.invoice); } diff --git a/lib/redux/quote/quote_middleware.dart b/lib/redux/quote/quote_middleware.dart index 6925377a1..50902fd9d 100644 --- a/lib/redux/quote/quote_middleware.dart +++ b/lib/redux/quote/quote_middleware.dart @@ -85,7 +85,7 @@ Middleware _showEmailQuote() { final emailWasSent = await Navigator.of(action.context).pushNamed(QuoteEmailScreen.route); - if (action.completer != null && emailWasSent) { + if (action.completer != null && emailWasSent != null && emailWasSent) { action.completer.complete(null); } }; diff --git a/lib/redux/quote/quote_reducer.dart b/lib/redux/quote/quote_reducer.dart index 6458e99f3..53a947cd0 100644 --- a/lib/redux/quote/quote_reducer.dart +++ b/lib/redux/quote/quote_reducer.dart @@ -191,6 +191,10 @@ QuoteState _archiveQuoteFailure( QuoteState _deleteQuoteRequest( QuoteState quoteState, DeleteQuoteRequest action) { + if (!quoteState.map.containsKey(action.quoteId)) { + return quoteState; + } + final quote = quoteState.map[action.quoteId].rebuild((b) => b ..archivedAt = DateTime.now().millisecondsSinceEpoch ..isDeleted = true); @@ -200,6 +204,10 @@ QuoteState _deleteQuoteRequest( QuoteState _deleteQuoteSuccess( QuoteState quoteState, DeleteQuoteSuccess action) { + if (!quoteState.map.containsKey(action.quote.id)) { + return quoteState; + } + return quoteState.rebuild((b) => b..map[action.quote.id] = action.quote); } @@ -229,9 +237,8 @@ QuoteState _restoreQuoteFailure( QuoteState _convertQuoteSuccess( QuoteState quoteState, ConvertQuoteSuccess action) { final quote = action.quote.rebuild((b) => b - ..quoteInvoiceId = action.invoice.id - ..invoiceStatusId = kInvoiceStatusApproved - ); + ..quoteInvoiceId = action.invoice.id + ..invoiceStatusId = kInvoiceStatusApproved); return quoteState.rebuild((b) => b..map[action.quote.id] = quote); } diff --git a/lib/ui/app/forms/time_picker.dart b/lib/ui/app/forms/time_picker.dart index 3c2d6a301..089ad0709 100644 --- a/lib/ui/app/forms/time_picker.dart +++ b/lib/ui/app/forms/time_picker.dart @@ -64,7 +64,7 @@ class _TimePickerState extends State { _textController.text = formatDate(dateTime.toIso8601String(), context, showTime: true, showDate: false); - widget.onSelected(dateTime); + widget.onSelected(dateTime.toLocal()); } } diff --git a/lib/ui/settings/settings_list_vm.dart b/lib/ui/settings/settings_list_vm.dart index a6816a1a4..6851ef9a2 100644 --- a/lib/ui/settings/settings_list_vm.dart +++ b/lib/ui/settings/settings_list_vm.dart @@ -126,7 +126,18 @@ class SettingsListVM { autoStartTasks: store.state.uiState.autoStartTasks, enableDarkMode: store.state.uiState.enableDarkMode, requireAuthentication: store.state.uiState.requireAuthentication, - authenticationSupported: LocalAuthentication().canCheckBiometrics, + //authenticationSupported: LocalAuthentication().canCheckBiometrics, + // TODO remove this once issue is resolved: + // https://github.com/flutter/flutter/issues/24339 + authenticationSupported: Future(() async { + bool enable = false; + try { + enable = await LocalAuthentication().canCheckBiometrics; + } catch (e) { + // do nothing + } + return enable; + }), ); } diff --git a/lib/ui/task/edit/task_edit_times.dart b/lib/ui/task/edit/task_edit_times.dart index dfbc26c30..0d17a3947 100644 --- a/lib/ui/task/edit/task_edit_times.dart +++ b/lib/ui/task/edit/task_edit_times.dart @@ -113,10 +113,10 @@ class TimeEditDetailsState extends State { final endDate = taskTime.endDate; _date = startDate.toIso8601String(); - _startDate = startDate; + _startDate = startDate.toLocal(); if (endDate != null) { - _endDate = endDate; + _endDate = endDate.toLocal(); _durationController.text = formatDuration(taskTime.duration); } diff --git a/pubspec.yaml b/pubspec.yaml index 4b4789628..e5a2b2d1a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: invoiceninja_flutter description: Mobile app for Invoice Ninja -version: 0.1.33 +version: 0.1.34 author: Hillel Coren homepage: https://www.invoiceninja.com documentation: http://docs.invoiceninja.com