diff --git a/lib/redux/client/client_actions.dart b/lib/redux/client/client_actions.dart index ccf9cbeb0..38f428470 100644 --- a/lib/redux/client/client_actions.dart +++ b/lib/redux/client/client_actions.dart @@ -18,10 +18,16 @@ class ViewClient implements PersistUI { class EditClient implements PersistUI { final ClientEntity client; + final ContactEntity contact; final BuildContext context; final Completer completer; final bool trackRoute; - EditClient({this.client, this.context, this.completer, this.trackRoute = true}); + EditClient({this.client, this.contact, this.context, this.completer, this.trackRoute = true}); +} + +class EditContact implements PersistUI { + final ContactEntity contact; + EditContact([this.contact]); } class UpdateClient implements PersistUI { diff --git a/lib/redux/client/client_reducer.dart b/lib/redux/client/client_reducer.dart index bed510e02..68cd73ee8 100644 --- a/lib/redux/client/client_reducer.dart +++ b/lib/redux/client/client_reducer.dart @@ -10,10 +10,20 @@ EntityUIState clientUIReducer(ClientUIState state, dynamic action) { return state.rebuild((b) => b ..listUIState.replace(clientListReducer(state.listUIState, action)) ..editing.replace(editingReducer(state.editing, action)) + ..editingContact.replace(editingContactReducer(state.editingContact, action)) ..selectedId = selectedIdReducer(state.selectedId, action) ); } +final editingContactReducer = combineReducers([ + TypedReducer(editContact), + TypedReducer(editContact), +]); + +ContactEntity editContact(ContactEntity contact, dynamic action) { + return action.contact ?? ContactEntity(); +} + Reducer selectedIdReducer = combineReducers([ TypedReducer((int selectedId, dynamic action) => action.clientId), TypedReducer((int selectedId, dynamic action) => action.client.id), diff --git a/lib/redux/client/client_state.dart b/lib/redux/client/client_state.dart index d29b9155f..fd9d18805 100644 --- a/lib/redux/client/client_state.dart +++ b/lib/redux/client/client_state.dart @@ -45,6 +45,7 @@ abstract class ClientUIState extends Object with EntityUIState implements Built< return _$ClientUIState._( listUIState: ListUIState(ClientFields.name), editing: ClientEntity(), + editingContact: ContactEntity(), selectedId: 0, ); } @@ -53,6 +54,9 @@ abstract class ClientUIState extends Object with EntityUIState implements Built< @nullable ClientEntity get editing; + @nullable + ContactEntity get editingContact; + @override bool get isCreatingNew => editing.isNew; diff --git a/lib/redux/client/client_state.g.dart b/lib/redux/client/client_state.g.dart index 129fa2f99..efd2fdb88 100644 --- a/lib/redux/client/client_state.g.dart +++ b/lib/redux/client/client_state.g.dart @@ -105,6 +105,12 @@ class _$ClientUIStateSerializer implements StructuredSerializer { ..add(serializers.serialize(object.editing, specifiedType: const FullType(ClientEntity))); } + if (object.editingContact != null) { + result + ..add('editingContact') + ..add(serializers.serialize(object.editingContact, + specifiedType: const FullType(ContactEntity))); + } return result; } @@ -124,6 +130,10 @@ class _$ClientUIStateSerializer implements StructuredSerializer { result.editing.replace(serializers.deserialize(value, specifiedType: const FullType(ClientEntity)) as ClientEntity); break; + case 'editingContact': + result.editingContact.replace(serializers.deserialize(value, + specifiedType: const FullType(ContactEntity)) as ContactEntity); + break; case 'selectedId': result.selectedId = serializers.deserialize(value, specifiedType: const FullType(int)) as int; @@ -255,6 +265,8 @@ class _$ClientUIState extends ClientUIState { @override final ClientEntity editing; @override + final ContactEntity editingContact; + @override final int selectedId; @override final ListUIState listUIState; @@ -262,7 +274,8 @@ class _$ClientUIState extends ClientUIState { factory _$ClientUIState([void updates(ClientUIStateBuilder b)]) => (new ClientUIStateBuilder()..update(updates)).build(); - _$ClientUIState._({this.editing, this.selectedId, this.listUIState}) + _$ClientUIState._( + {this.editing, this.editingContact, this.selectedId, this.listUIState}) : super._() { if (selectedId == null) throw new BuiltValueNullFieldError('ClientUIState', 'selectedId'); @@ -282,13 +295,16 @@ class _$ClientUIState extends ClientUIState { if (identical(other, this)) return true; if (other is! ClientUIState) return false; return editing == other.editing && + editingContact == other.editingContact && selectedId == other.selectedId && listUIState == other.listUIState; } @override int get hashCode { - return $jf($jc($jc($jc(0, editing.hashCode), selectedId.hashCode), + return $jf($jc( + $jc($jc($jc(0, editing.hashCode), editingContact.hashCode), + selectedId.hashCode), listUIState.hashCode)); } @@ -296,6 +312,7 @@ class _$ClientUIState extends ClientUIState { String toString() { return (newBuiltValueToStringHelper('ClientUIState') ..add('editing', editing) + ..add('editingContact', editingContact) ..add('selectedId', selectedId) ..add('listUIState', listUIState)) .toString(); @@ -311,6 +328,12 @@ class ClientUIStateBuilder _$this._editing ??= new ClientEntityBuilder(); set editing(ClientEntityBuilder editing) => _$this._editing = editing; + ContactEntityBuilder _editingContact; + ContactEntityBuilder get editingContact => + _$this._editingContact ??= new ContactEntityBuilder(); + set editingContact(ContactEntityBuilder editingContact) => + _$this._editingContact = editingContact; + int _selectedId; int get selectedId => _$this._selectedId; set selectedId(int selectedId) => _$this._selectedId = selectedId; @@ -326,6 +349,7 @@ class ClientUIStateBuilder ClientUIStateBuilder get _$this { if (_$v != null) { _editing = _$v.editing?.toBuilder(); + _editingContact = _$v.editingContact?.toBuilder(); _selectedId = _$v.selectedId; _listUIState = _$v.listUIState?.toBuilder(); _$v = null; @@ -351,6 +375,7 @@ class ClientUIStateBuilder _$result = _$v ?? new _$ClientUIState._( editing: _editing?.build(), + editingContact: _editingContact?.build(), selectedId: selectedId, listUIState: listUIState.build()); } catch (_) { @@ -358,6 +383,8 @@ class ClientUIStateBuilder try { _$failedField = 'editing'; _editing?.build(); + _$failedField = 'editingContact'; + _editingContact?.build(); _$failedField = 'listUIState'; listUIState.build(); diff --git a/lib/ui/client/edit/client_edit.dart b/lib/ui/client/edit/client_edit.dart index e65048fb6..1119ee940 100644 --- a/lib/ui/client/edit/client_edit.dart +++ b/lib/ui/client/edit/client_edit.dart @@ -1,13 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:invoiceninja_flutter/ui/client/edit/client_edit_billing_address.dart'; +import 'package:invoiceninja_flutter/ui/client/edit/client_edit_contacts_vm.dart'; import 'package:invoiceninja_flutter/ui/client/edit/client_edit_details.dart'; import 'package:invoiceninja_flutter/ui/client/edit/client_edit_settings.dart'; import 'package:invoiceninja_flutter/ui/client/edit/client_edit_shipping_address.dart'; import 'package:invoiceninja_flutter/ui/client/edit/client_edit_vm.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/save_icon_button.dart'; -import 'package:invoiceninja_flutter/ui/client/edit/client_edit_contacts.dart'; class ClientEdit extends StatefulWidget { final ClientEditVM viewModel; @@ -97,9 +97,7 @@ class _ClientEditState extends State ClientEditDetails( viewModel: widget.viewModel, ), - ClientEditContacts( - viewModel: widget.viewModel, - ), + ClientEditContactsScreen(), ClientEditSettings( viewModel: widget.viewModel, ), diff --git a/lib/ui/client/edit/client_edit_contacts.dart b/lib/ui/client/edit/client_edit_contacts.dart index 6100de6e0..afeec0a2b 100644 --- a/lib/ui/client/edit/client_edit_contacts.dart +++ b/lib/ui/client/edit/client_edit_contacts.dart @@ -4,21 +4,30 @@ import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart'; import 'package:invoiceninja_flutter/ui/app/icon_text.dart'; -import 'package:invoiceninja_flutter/ui/client/edit/client_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/client/edit/client_edit_contacts_vm.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; -class ClientEditContacts extends StatelessWidget { +class ClientEditContacts extends StatefulWidget { const ClientEditContacts({ Key key, @required this.viewModel, }) : super(key: key); - final ClientEditVM viewModel; + final ClientEditContactsVM viewModel; + + @override + _ClientEditContactsState createState() => new _ClientEditContactsState(); +} + +class _ClientEditContactsState extends State { + + ContactEntity selectedContact; void _showContactEditor(ContactEntity contact, BuildContext context) { showDialog( context: context, builder: (BuildContext context) { + final viewModel = widget.viewModel; final client = viewModel.client; return ContactEditDetails( @@ -34,13 +43,26 @@ class ClientEditContacts extends StatelessWidget { @override Widget build(BuildContext context) { final localization = AppLocalization.of(context); + final viewModel = widget.viewModel; final client = viewModel.client; - final contacts = client.contacts.map((contact) => ContactListTile( contact: contact, onTap: () => _showContactEditor(contact, context), )); + /* + final contact = client.contacts.contains(viewModel.contact) + ? viewModel.contact + : null; + + if (contact != null && contact != selectedContact) { + selectedContact = contact; + WidgetsBinding.instance.addPostFrameCallback((duration) { + _showContactEditor(contact, context); + }); + } + */ + return ListView( children: [] ..addAll(contacts) @@ -100,7 +122,7 @@ class ContactEditDetails extends StatefulWidget { final int index; final ContactEntity contact; - final ClientEditVM viewModel; + final ClientEditContactsVM viewModel; final bool isRemoveVisible; @override diff --git a/lib/ui/client/edit/client_edit_contacts_vm.dart b/lib/ui/client/edit/client_edit_contacts_vm.dart new file mode 100644 index 000000000..f296e3520 --- /dev/null +++ b/lib/ui/client/edit/client_edit_contacts_vm.dart @@ -0,0 +1,64 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_redux/flutter_redux.dart'; +import 'package:invoiceninja_flutter/ui/client/edit/client_edit_contacts.dart'; +import 'package:redux/redux.dart'; +import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; +import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/redux/app/app_state.dart'; + +class ClientEditContactsScreen extends StatelessWidget { + const ClientEditContactsScreen({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return StoreConnector( + converter: (Store store) { + return ClientEditContactsVM.fromStore(store); + }, + builder: (context, vm) { + return ClientEditContacts( + viewModel: vm, + ); + }, + ); + } +} + +class ClientEditContactsVM { + final CompanyEntity company; + final ClientEntity client; + final ContactEntity contact; + final Function() onAddContactPressed; + final Function(int) onRemoveContactPressed; + final Function onDoneContactPressed; + final Function(ContactEntity, int) onChangedContact; + + ClientEditContactsVM({ + @required this.company, + @required this.client, + @required this.contact, + @required this.onAddContactPressed, + @required this.onRemoveContactPressed, + @required this.onDoneContactPressed, + @required this.onChangedContact, + }); + + factory ClientEditContactsVM.fromStore(Store store) { + final AppState state = store.state; + final client = state.clientUIState.editing; + + return ClientEditContactsVM( + company: state.selectedCompany, + client: client, + contact: state.clientUIState.editingContact, + onAddContactPressed: () => store.dispatch(AddContact()), + onRemoveContactPressed: (index) => + store.dispatch(DeleteContact(index)), + onDoneContactPressed: () => store.dispatch(EditContact()), + onChangedContact: (contact, index) { + store.dispatch( + UpdateContact(contact: contact, index: index)); + }); + } +} diff --git a/lib/ui/client/edit/client_edit_vm.dart b/lib/ui/client/edit/client_edit_vm.dart index a95462ec4..e0ba319a9 100644 --- a/lib/ui/client/edit/client_edit_vm.dart +++ b/lib/ui/client/edit/client_edit_vm.dart @@ -40,9 +40,6 @@ class ClientEditVM { final ClientEntity client; final ClientEntity origClient; final Function(ClientEntity) onChanged; - final Function() onAddContactPressed; - final Function(int) onRemoveContactPressed; - final Function(ContactEntity, int) onChangedContact; final Function(BuildContext) onSavePressed; final Function onBackPressed; final BuiltMap countryMap; @@ -54,9 +51,6 @@ class ClientEditVM { @required this.isSaving, @required this.client, @required this.origClient, - @required this.onAddContactPressed, - @required this.onRemoveContactPressed, - @required this.onChangedContact, @required this.onChanged, @required this.onSavePressed, @required this.onBackPressed, @@ -79,11 +73,6 @@ class ClientEditVM { isSaving: state.isSaving, onBackPressed: () => store.dispatch(UpdateCurrentRoute(ClientScreen.route)), - onAddContactPressed: () => store.dispatch(AddContact()), - onRemoveContactPressed: (index) => store.dispatch(DeleteContact(index)), - onChangedContact: (contact, index) { - store.dispatch(UpdateContact(contact: contact, index: index)); - }, onChanged: (ClientEntity client) => store.dispatch(UpdateClient(client)), onSavePressed: (BuildContext context) { diff --git a/lib/ui/invoice/edit/invoice_edit_items.dart b/lib/ui/invoice/edit/invoice_edit_items.dart index f41362ff8..15536d475 100644 --- a/lib/ui/invoice/edit/invoice_edit_items.dart +++ b/lib/ui/invoice/edit/invoice_edit_items.dart @@ -22,7 +22,7 @@ class InvoiceEditItems extends StatefulWidget { } class _InvoiceEditItemsState extends State { - InvoiceItemEntity dialogInvoiceItem; + InvoiceItemEntity selectedInvoiceItem; void _showInvoiceItemEditor( InvoiceItemEntity invoiceItem, BuildContext context) { @@ -47,8 +47,8 @@ class _InvoiceEditItemsState extends State { ? viewModel.invoiceItem : null; - if (invoiceItem != null && invoiceItem != dialogInvoiceItem) { - dialogInvoiceItem = invoiceItem; + if (invoiceItem != null && invoiceItem != selectedInvoiceItem) { + selectedInvoiceItem = invoiceItem; WidgetsBinding.instance.addPostFrameCallback((duration) { _showInvoiceItemEditor(invoiceItem, context); });