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