diff --git a/lib/redux/app/app_middleware.dart b/lib/redux/app/app_middleware.dart index ce6a4e5f5..1bf7fbdc8 100644 --- a/lib/redux/app/app_middleware.dart +++ b/lib/redux/app/app_middleware.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/data/file_storage.dart'; @@ -15,8 +16,10 @@ import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart'; import 'package:invoiceninja_flutter/redux/static/static_state.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_state.dart'; import 'package:invoiceninja_flutter/ui/app/app_builder.dart'; +import 'package:invoiceninja_flutter/ui/app/dialogs/alert_dialog.dart'; import 'package:invoiceninja_flutter/ui/app/main_screen.dart'; import 'package:invoiceninja_flutter/ui/auth/login_vm.dart'; +import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:redux/redux.dart'; import 'package:path_provider/path_provider.dart'; @@ -421,3 +424,16 @@ void _setLastLoadWasSuccesfull() async { prefs.setBool('initialized', true); } */ + +bool hasChanges(Store store, dynamic action) { + if (store.state.hasChanges() && !isMobile(action.context) && !action.force) { + showDialog( + context: action.context, + builder: (BuildContext context) { + return MessageDialog(AppLocalization.of(context).errorUnsavedChanges); + }); + return true; + } else { + return false; + } +} \ No newline at end of file diff --git a/lib/redux/client/client_actions.dart b/lib/redux/client/client_actions.dart index 1cd0e789a..6f61ab4e1 100644 --- a/lib/redux/client/client_actions.dart +++ b/lib/redux/client/client_actions.dart @@ -12,23 +12,29 @@ import 'package:invoiceninja_flutter/utils/completers.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; class ViewClientList implements PersistUI { - ViewClientList(this.context); + ViewClientList({@required this.context, this.force = false}); final BuildContext context; + final bool force; } class ViewClient implements PersistUI { - ViewClient({this.clientId, this.context}); + ViewClient({ + @required this.clientId, + @required this.context, + this.force = false, + }); final int clientId; final BuildContext context; + final bool force; } class EditClient implements PersistUI { EditClient( - {this.client, + {@required this.client, + @required this.context, this.contact, - this.context, this.completer, this.trackRoute = true}); diff --git a/lib/redux/client/client_middleware.dart b/lib/redux/client/client_middleware.dart index 183ec3dff..ed37c94ed 100644 --- a/lib/redux/client/client_middleware.dart +++ b/lib/redux/client/client_middleware.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/redux/app/app_middleware.dart'; import 'package:invoiceninja_flutter/redux/product/product_actions.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; -import 'package:invoiceninja_flutter/ui/app/dialogs/alert_dialog.dart'; import 'package:invoiceninja_flutter/ui/client/client_screen.dart'; import 'package:invoiceninja_flutter/ui/client/edit/client_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/client/view/client_view_vm.dart'; -import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:redux/redux.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; @@ -42,13 +41,17 @@ List> createStoreClientsMiddleware([ Middleware _editClient() { return (Store store, dynamic action, NextDispatcher next) async { + if (hasChanges(store, action)) { + return; + } + next(action); if (action.trackRoute) { store.dispatch(UpdateCurrentRoute(ClientEditScreen.route)); } - if (action.context != null && isMobile(action.context)) { + if (isMobile(action.context)) { final client = await Navigator.of(action.context).pushNamed(ClientEditScreen.route); @@ -61,17 +64,12 @@ Middleware _editClient() { Middleware _viewClient() { return (Store store, dynamic action, NextDispatcher next) async { - next(action); - - if (store.state.hasChanges() && !isMobile(action.context)) { - showDialog( - context: action.context, - builder: (BuildContext context) { - return MessageDialog(AppLocalization.of(context).errorUnsavedChanges); - }); + if (hasChanges(store, action)) { return; } + next(action); + store.dispatch(UpdateCurrentRoute(ClientViewScreen.route)); if (isMobile(action.context)) { @@ -82,15 +80,15 @@ Middleware _viewClient() { Middleware _viewClientList() { return (Store store, dynamic action, NextDispatcher next) { - next(action); - - if (store.state.hasChanges()) { + if (hasChanges(store, action)) { return; } + next(action); + store.dispatch(UpdateCurrentRoute(ClientScreen.route)); - if (action.context != null && isMobile(action.context)) { + if (isMobile(action.context)) { Navigator.of(action.context).pushNamedAndRemoveUntil( ClientScreen.route, (Route route) => false); } diff --git a/lib/redux/client/client_reducer.dart b/lib/redux/client/client_reducer.dart index 62b8ff777..6036fd267 100644 --- a/lib/redux/client/client_reducer.dart +++ b/lib/redux/client/client_reducer.dart @@ -42,6 +42,8 @@ final editingReducer = combineReducers([ TypedReducer(_addContact), TypedReducer(_removeContact), TypedReducer(_updateContact), + TypedReducer(_clearEditing), + TypedReducer(_clearEditing), TypedReducer(_clearEditing), ]); diff --git a/lib/redux/product/product_middleware.dart b/lib/redux/product/product_middleware.dart index 75d6e1b65..b84ab36da 100644 --- a/lib/redux/product/product_middleware.dart +++ b/lib/redux/product/product_middleware.dart @@ -3,7 +3,6 @@ import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart'; import 'package:invoiceninja_flutter/ui/app/dialogs/alert_dialog.dart'; -import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart'; import 'package:invoiceninja_flutter/ui/product/edit/product_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/product/product_screen.dart'; import 'package:invoiceninja_flutter/ui/product/view/product_view_vm.dart'; diff --git a/lib/redux/ui/ui_state.dart b/lib/redux/ui/ui_state.dart index 96790918f..a7c894162 100644 --- a/lib/redux/ui/ui_state.dart +++ b/lib/redux/ui/ui_state.dart @@ -2,7 +2,6 @@ import 'package:built_collection/built_collection.dart'; import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart'; -import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/redux/client/client_state.dart'; import 'package:invoiceninja_flutter/redux/dashboard/dashboard_state.dart'; import 'package:invoiceninja_flutter/redux/invoice/invoice_state.dart'; diff --git a/lib/ui/app/app_drawer.dart b/lib/ui/app/app_drawer.dart index 762439658..7b6bdfcbb 100644 --- a/lib/ui/app/app_drawer.dart +++ b/lib/ui/app/app_drawer.dart @@ -178,7 +178,7 @@ class AppDrawer extends StatelessWidget { entityType: EntityType.client, icon: getEntityIcon(EntityType.client), title: localization.clients, - onTap: () => store.dispatch(ViewClientList(context)), + onTap: () => store.dispatch(ViewClientList(context: context)), onCreateTap: () { if (isMobile(context)) { navigator.pop(); diff --git a/lib/ui/client/edit/client_edit.dart b/lib/ui/client/edit/client_edit.dart index faee1463e..95f1d3786 100644 --- a/lib/ui/client/edit/client_edit.dart +++ b/lib/ui/client/edit/client_edit.dart @@ -57,6 +57,11 @@ class _ClientEditState extends State title: Text( client.isNew ? localization.newClient : localization.editClient), actions: [ + if (!isMobile(context)) + FlatButton( + child: Text(localization.cancel), + onPressed: () => viewModel.onCancelPressed(context), + ), ActionIconButton( icon: Icons.cloud_upload, tooltip: localization.save, diff --git a/lib/ui/client/edit/client_edit_vm.dart b/lib/ui/client/edit/client_edit_vm.dart index cd3098c2f..0e7044844 100644 --- a/lib/ui/client/edit/client_edit_vm.dart +++ b/lib/ui/client/edit/client_edit_vm.dart @@ -48,6 +48,7 @@ class ClientEditVM { @required this.onChanged, @required this.onSavePressed, @required this.onBackPressed, + @required this.onCancelPressed, @required this.staticState, @required this.copyBillingAddress, @required this.copyShippingAddress, @@ -87,6 +88,15 @@ class ClientEditVM { ..state = client.shippingState ..postalCode = client.shippingPostalCode ..countryId = client.shippingCountryId))), + onCancelPressed: (BuildContext context) { + store.dispatch(EditClient(client: ClientEntity(), context: context)); + if (client.isNew) { + store.dispatch(ViewClientList(context: context, force: true)); + } else { + store.dispatch( + ViewClient(context: context, clientId: client.id, force: true)); + } + }, onSavePressed: (BuildContext context) { if (!client.hasNameSet) { showDialog( @@ -138,6 +148,7 @@ class ClientEditVM { final Function(ClientEntity) onChanged; final Function(BuildContext) onSavePressed; final Function onBackPressed; + final Function(BuildContext) onCancelPressed; final StaticState staticState; final Function() copyShippingAddress; final Function() copyBillingAddress;