This commit is contained in:
Hillel Coren 2019-10-11 09:50:04 +03:00
parent 5a316302fd
commit a6d0e78f16
29 changed files with 145 additions and 94 deletions

View File

@ -84,6 +84,8 @@ class RefreshData {
class ClearLastError {}
class DiscardChanges {}
class FilterCompany {
FilterCompany(this.filter);

View File

@ -448,20 +448,26 @@ void _setLastLoadWasSuccesfull() async {
}
*/
bool hasChanges({Store<AppState> store, BuildContext context, bool force}) {
bool hasChanges({
@required Store<AppState> store,
@required BuildContext context,
@required dynamic action,
}) {
final localization = AppLocalization.of(context);
if (context == null) {
print('WARNING: context is null in hasChanges');
return false;
} else if (force == null) {
print('WARNING: force is null in hasChanges');
return false;
}
if (store.state.hasChanges() && !isMobile(context) && !force) {
if (store.state.hasChanges() && !isMobile(context)) {
showDialog<MessageDialog>(
context: context,
builder: (BuildContext context) {
return MessageDialog(AppLocalization.of(context).errorUnsavedChanges);
return MessageDialog(localization.errorUnsavedChanges, onDiscard: () {
store.dispatch(DiscardChanges());
store.dispatch(action);
});
});
return true;
} else {

View File

@ -43,8 +43,8 @@ Middleware<AppState> _editClient() {
NextDispatcher next) async {
final action = dynamicAction as EditClient;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
@ -63,8 +63,10 @@ Middleware<AppState> _viewClient() {
NextDispatcher next) async {
final action = dynamicAction as ViewClient;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store,
context: action.context,
action: action)) {
return;
}
@ -82,8 +84,10 @@ Middleware<AppState> _viewClientList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewClientList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store,
context: action.context,
action: action)) {
return;
}

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/client/client_state.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -92,6 +93,9 @@ final editingReducer = combineReducers<ClientEntity>([
TypedReducer<ClientEntity, SelectCompany>((client, action) {
return ClientEntity();
}),
TypedReducer<ClientEntity, DiscardChanges>((client, action) {
return ClientEntity();
}),
]);
final clientListReducer = combineReducers<ListUIState>([

View File

@ -25,8 +25,8 @@ Middleware<AppState> _createViewDashboard() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewDashboard;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -45,8 +45,8 @@ Middleware<AppState> _editExpense() {
NextDispatcher next) async {
final action = dynamicAction as EditExpense;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -70,8 +70,8 @@ Middleware<AppState> _viewExpense() {
NextDispatcher next) async {
final action = dynamicAction as ViewExpense;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -89,8 +89,8 @@ Middleware<AppState> _viewExpenseList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewExpenseList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,3 +1,4 @@
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -32,6 +33,7 @@ final editingReducer = combineReducers<ExpenseEntity>([
return action.expense.rebuild((b) => b..isChanged = true);
}),
TypedReducer<ExpenseEntity, SelectCompany>(_clearEditing),
TypedReducer<ExpenseEntity, DiscardChanges>(_clearEditing),
]);
ExpenseEntity _clearEditing(ExpenseEntity expense, dynamic action) {

View File

@ -44,8 +44,8 @@ Middleware<AppState> _editGroup() {
NextDispatcher next) async {
final action = dynamicAction as EditGroup;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -69,8 +69,8 @@ Middleware<AppState> _viewGroup() {
NextDispatcher next) async {
final action = dynamicAction as ViewGroup;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -88,8 +88,8 @@ Middleware<AppState> _viewGroupList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewGroupList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,4 +1,5 @@
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
@ -33,6 +34,7 @@ final editingReducer = combineReducers<GroupEntity>([
return action.group.rebuild((b) => b..isChanged = true);
}),
TypedReducer<GroupEntity, SelectCompany>(_clearEditing),
TypedReducer<GroupEntity, DiscardChanges>(_clearEditing),
]);
GroupEntity _clearEditing(GroupEntity group, dynamic action) {

View File

@ -53,8 +53,8 @@ Middleware<AppState> _viewInvoiceList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewInvoiceList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -78,8 +78,8 @@ Middleware<AppState> _viewInvoice() {
NextDispatcher next) async {
final action = dynamicAction as ViewInvoice;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -98,8 +98,8 @@ Middleware<AppState> _editInvoice() {
NextDispatcher next) async {
final action = dynamicAction as EditInvoice;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,4 +1,5 @@
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
@ -59,6 +60,7 @@ final editingReducer = combineReducers<InvoiceEntity>([
TypedReducer<InvoiceEntity, DeleteInvoiceItem>(_removeInvoiceItem),
TypedReducer<InvoiceEntity, UpdateInvoiceItem>(_updateInvoiceItem),
TypedReducer<InvoiceEntity, SelectCompany>(_clearEditing),
TypedReducer<InvoiceEntity, DiscardChanges>(_clearEditing),
]);
InvoiceEntity _clearEditing(InvoiceEntity client, dynamic action) {

View File

@ -47,8 +47,8 @@ Middleware<AppState> _editPayment() {
NextDispatcher next) async {
final action = dynamicAction as EditPayment;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -69,8 +69,8 @@ Middleware<AppState> _editPayment() {
Middleware<AppState> _viewPayment() {
return (Store<AppState> store, dynamic action, NextDispatcher next) async {
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -88,8 +88,8 @@ Middleware<AppState> _viewPaymentList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewPaymentList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,3 +1,4 @@
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -32,9 +33,10 @@ final editingReducer = combineReducers<PaymentEntity>([
return action.payment.rebuild((b) => b..isChanged = true);
}),
TypedReducer<PaymentEntity, SelectCompany>(_clearEditing),
TypedReducer<PaymentEntity, DiscardChanges>(_clearEditing),
]);
PaymentEntity _clearEditing(PaymentEntity payment, SelectCompany action) {
PaymentEntity _clearEditing(PaymentEntity payment, dynamic action) {
return PaymentEntity();
}

View File

@ -41,8 +41,8 @@ Middleware<AppState> _editProduct() {
NextDispatcher next) async {
final action = dynamicAction as EditProduct;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -61,8 +61,8 @@ Middleware<AppState> _viewProduct() {
NextDispatcher next) async {
final action = dynamicAction as ViewProduct;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -80,8 +80,8 @@ Middleware<AppState> _viewProductList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewProductList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,5 +1,6 @@
import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/product_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/product/product_actions.dart';
import 'package:invoiceninja_flutter/redux/product/product_state.dart';
@ -34,6 +35,7 @@ final editingReducer = combineReducers<ProductEntity>([
TypedReducer<ProductEntity, ArchiveProductSuccess>(_updateEditing),
TypedReducer<ProductEntity, DeleteProductSuccess>(_updateEditing),
TypedReducer<ProductEntity, SelectCompany>(_clearEditing),
TypedReducer<ProductEntity, DiscardChanges>(_clearEditing),
]);
ProductEntity _clearEditing(ProductEntity client, dynamic action) {

View File

@ -45,8 +45,8 @@ Middleware<AppState> _editProject() {
NextDispatcher next) async {
final action = dynamicAction as EditProject;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -70,8 +70,8 @@ Middleware<AppState> _viewProject() {
NextDispatcher next) async {
final action = dynamicAction as ViewProject;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -89,8 +89,8 @@ Middleware<AppState> _viewProjectList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewProjectList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -48,6 +49,7 @@ final editingReducer = combineReducers<ProjectEntity>([
}),
TypedReducer<ProjectEntity, UpdateProject>(_updateEditing),
TypedReducer<ProjectEntity, SelectCompany>(_clearEditing),
TypedReducer<ProjectEntity, DiscardChanges>(_clearEditing),
]);
ProjectEntity _clearEditing(ProjectEntity project, dynamic dynamicAction) {

View File

@ -53,8 +53,8 @@ Middleware<AppState> _viewQuote() {
NextDispatcher next) async {
final action = dynamicAction as ViewQuote;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -72,8 +72,8 @@ Middleware<AppState> _viewQuoteList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewQuoteList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -97,8 +97,8 @@ Middleware<AppState> _editQuote() {
NextDispatcher next) async {
final action = dynamicAction as EditQuote;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,5 +1,6 @@
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_state.dart';
@ -57,6 +58,7 @@ final editingReducer = combineReducers<InvoiceEntity>([
TypedReducer<InvoiceEntity, DeleteQuoteItem>(_removeQuoteItem),
TypedReducer<InvoiceEntity, UpdateQuoteItem>(_updateQuoteItem),
TypedReducer<InvoiceEntity, SelectCompany>(_clearEditing),
TypedReducer<InvoiceEntity, DiscardChanges>(_clearEditing),
]);
InvoiceEntity _clearEditing(InvoiceEntity client, dynamic action) {

View File

@ -30,8 +30,8 @@ Middleware<AppState> _viewSettings() {
final action = dynamicAction as ViewSettings;
final uiState = store.state.uiState;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -44,8 +44,8 @@ Middleware<AppState> _editTask() {
NextDispatcher next) async {
final action = dynamicAction as EditTask;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -69,8 +69,8 @@ Middleware<AppState> _viewTask() {
NextDispatcher next) async {
final action = dynamicAction as ViewTask;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -88,8 +88,8 @@ Middleware<AppState> _viewTaskList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewTaskList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,3 +1,4 @@
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -44,6 +45,7 @@ final editingReducer = combineReducers<TaskEntity>([
TypedReducer<TaskEntity, DeleteTaskTime>(_removeTaskTime),
TypedReducer<TaskEntity, UpdateTaskTime>(_updateTaskTime),
TypedReducer<TaskEntity, SelectCompany>(_clearEditing),
TypedReducer<TaskEntity, DiscardChanges>(_clearEditing),
]);
TaskEntity _clearEditing(TaskEntity task, dynamic action) {

View File

@ -45,8 +45,8 @@ Middleware<AppState> _editVendor() {
NextDispatcher next) async {
final action = dynamicAction as EditVendor;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -70,8 +70,8 @@ Middleware<AppState> _viewVendor() {
NextDispatcher next) async {
final action = dynamicAction as ViewVendor;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -89,8 +89,8 @@ Middleware<AppState> _viewVendorList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewVendorList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -63,6 +64,7 @@ final editingReducer = combineReducers<VendorEntity>([
TypedReducer<VendorEntity, DeleteVendorContact>(_removeContact),
TypedReducer<VendorEntity, UpdateVendorContact>(_updateContact),
TypedReducer<VendorEntity, SelectCompany>(_clearEditing),
TypedReducer<VendorEntity, DiscardChanges>(_clearEditing),
]);
VendorEntity _clearEditing(VendorEntity vendor, dynamic action) {

View File

@ -3,10 +3,11 @@ import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class MessageDialog extends StatelessWidget {
const MessageDialog(this.message, {this.onDismiss});
const MessageDialog(this.message, {this.onDismiss, this.onDiscard});
final String message;
final Function onDismiss;
final Function onDiscard;
@override
Widget build(BuildContext context) {
@ -22,24 +23,36 @@ class MessageDialog extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
/*
Text(localization.anErrorOccurred,
style: Theme.of(context).textTheme.title),
*/
SizedBox(height: 20.0),
Text(
message,
style: Theme.of(context).textTheme.title,
),
SizedBox(height: 40.0),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
if (onDismiss != null) {
onDismiss();
}
},
label: localization.dismiss,
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (onDiscard != null)
Padding(
padding: const EdgeInsets.only(right: 10),
child: FlatButton(
child: Text(localization.discardChanges),
onPressed: () {
Navigator.of(context).pop();
onDiscard();
}
),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
if (onDismiss != null) {
onDismiss();
}
},
label: localization.dismiss,
),
],
),
],
),

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
class AppForm extends StatelessWidget {
const AppForm({

View File

@ -14,6 +14,7 @@ abstract class LocaleCodeAware {
mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
'discard_changes': 'Discard Changes',
'default_value': 'Default value',
'disabled': 'Disabled',
'currency_format': 'Currency Format',
@ -112,7 +113,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
'email_login': 'Email Login',
'create_new': 'Create New',
'no_record_selected': 'No record selected',
'error_unsaved_changes': 'Please cancel or save your changes',
'error_unsaved_changes': 'Your changes have not been saved',
'download': 'Download',
'requires_an_enterprise_plan': 'Requires an enterprise plan',
'take_picture': 'Take Picture',
@ -14835,6 +14836,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get defaultValue => _localizedValues[localeCode]['default_value'];
String get discardChanges => _localizedValues[localeCode]['discard_changes'];
String lookup(String key) {
final lookupKey = toSnakeCase(key);

View File

@ -43,8 +43,8 @@ Middleware<AppState> _editStub() {
final action = dynamicAction as EditStub;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
@ -68,10 +68,10 @@ Middleware<AppState> _viewStub() {
final action = dynamicAction as ViewStub;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
return;
}
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}
next(action);
@ -88,8 +88,8 @@ Middleware<AppState> _viewStubList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewStubList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
if (!action.force && hasChanges(
store: store, context: action.context, action: action)) {
return;
}

View File

@ -1,4 +1,5 @@
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
@ -32,6 +33,7 @@ final editingReducer = combineReducers<StubEntity>([
return action.stub.rebuild((b) => b..isChanged = true);
}),
TypedReducer<StubEntity, SelectCompany>(_clearEditing),
TypedReducer<StubEntity, DiscardChanges>(_clearEditing),
]);
StubEntity _clearEditing(StubEntity stub, dynamic action) {