This commit is contained in:
unknown 2018-06-18 22:51:42 -07:00
parent 013f8e29f9
commit 859a78be4b
14 changed files with 158 additions and 129 deletions

View File

@ -25,7 +25,7 @@ import 'package:invoiceninja/redux/product/product_actions.dart';
import 'package:invoiceninja/redux/product/product_middleware.dart';
import 'package:invoiceninja/redux/invoice/invoice_middleware.dart';
import 'package:invoiceninja/ui/invoice/invoice_screen.dart';
//import 'package:redux_logging/redux_logging.dart';
import 'package:redux_logging/redux_logging.dart';
void main() {
final store = Store<AppState>(appReducer,
@ -38,7 +38,7 @@ void main() {
..addAll(createStoreInvoicesMiddleware())
..addAll(createStorePersistenceMiddleware())
..addAll([
//LoggingMiddleware.printer(),
LoggingMiddleware.printer(),
]));
runApp(InvoiceNinjaApp(store: store));
@ -89,6 +89,7 @@ class _InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
routes: {
LoginVM.route: (context) {
widget.store.dispatch(LoadStateRequest(context));
//widget.store.dispatch(LoadUserLogin());
return LoginVM();
},
DashboardScreen.route: (context) {

View File

@ -89,4 +89,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
InvoiceState get invoiceState => this.selectedCompanyState.invoiceState;
InvoiceUIState get invoiceUIState => this.uiState.invoiceUIState;
ListUIState get invoiceListState => this.uiState.invoiceUIState.listUIState;
@override
String toString() {
return 'State: ' + this.invoiceUIState.selected.toString();
}
}

View File

@ -190,20 +190,6 @@ class _$AppState extends AppState {
companyState4.hashCode),
companyState5.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('AppState')
..add('isLoading', isLoading)
..add('authState', authState)
..add('uiState', uiState)
..add('companyState1', companyState1)
..add('companyState2', companyState2)
..add('companyState3', companyState3)
..add('companyState4', companyState4)
..add('companyState5', companyState5))
.toString();
}
}
class AppStateBuilder implements Builder<AppState, AppStateBuilder> {

View File

@ -8,7 +8,7 @@ import 'package:invoiceninja/redux/client/client_state.dart';
EntityUIState clientUIReducer(ClientUIState state, action) {
return state.rebuild((b) => b
..listUIState.replace(clientListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.selected, action))
..selected.replace(editingReducer(state.selected, action))
);
}

View File

@ -98,7 +98,7 @@ class _$ClientUIStateSerializer implements StructuredSerializer<ClientUIState> {
];
if (object.selected != null) {
result
..add('editing')
..add('selected')
..add(serializers.serialize(object.selected,
specifiedType: const FullType(ClientEntity)));
}
@ -117,8 +117,8 @@ class _$ClientUIStateSerializer implements StructuredSerializer<ClientUIState> {
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'editing':
result.editing.replace(serializers.deserialize(value,
case 'selected':
result.selected.replace(serializers.deserialize(value,
specifiedType: const FullType(ClientEntity)) as ClientEntity);
break;
case 'listUIState':
@ -280,7 +280,7 @@ class _$ClientUIState extends ClientUIState {
@override
String toString() {
return (newBuiltValueToStringHelper('ClientUIState')
..add('editing', selected)
..add('selected', selected)
..add('listUIState', listUIState))
.toString();
}
@ -290,10 +290,10 @@ class ClientUIStateBuilder
implements Builder<ClientUIState, ClientUIStateBuilder> {
_$ClientUIState _$v;
ClientEntityBuilder _editing;
ClientEntityBuilder get editing =>
_$this._editing ??= new ClientEntityBuilder();
set editing(ClientEntityBuilder editing) => _$this._editing = editing;
ClientEntityBuilder _selected;
ClientEntityBuilder get selected =>
_$this._selected ??= new ClientEntityBuilder();
set selected(ClientEntityBuilder selected) => _$this._selected = selected;
ListUIStateBuilder _listUIState;
ListUIStateBuilder get listUIState =>
@ -305,7 +305,7 @@ class ClientUIStateBuilder
ClientUIStateBuilder get _$this {
if (_$v != null) {
_editing = _$v.selected?.toBuilder();
_selected = _$v.selected?.toBuilder();
_listUIState = _$v.listUIState?.toBuilder();
_$v = null;
}
@ -329,12 +329,12 @@ class ClientUIStateBuilder
try {
_$result = _$v ??
new _$ClientUIState._(
selected: _editing?.build(), listUIState: listUIState.build());
selected: _selected?.build(), listUIState: listUIState.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'editing';
_editing?.build();
_$failedField = 'selected';
_selected?.build();
_$failedField = 'listUIState';
listUIState.build();
} catch (e) {

View File

@ -8,7 +8,7 @@ import 'package:invoiceninja/redux/invoice/invoice_state.dart';
EntityUIState invoiceUIReducer(InvoiceUIState state, action) {
return state.rebuild((b) => b
..listUIState.replace(invoiceListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.selected, action))
..selected.replace(editingReducer(state.selected, action))
);
}
@ -18,12 +18,33 @@ final editingReducer = combineReducers<InvoiceEntity>([
TypedReducer<InvoiceEntity, ViewInvoice>(_updateEditing),
TypedReducer<InvoiceEntity, EditInvoice>(_updateEditing),
TypedReducer<InvoiceEntity, UpdateInvoice>(_updateEditing),
TypedReducer<InvoiceEntity, AddInvoiceItem>(_addInvoiceItem),
TypedReducer<InvoiceEntity, DeleteInvoiceItem>(_removeInvoiceItem),
TypedReducer<InvoiceEntity, UpdateInvoiceItem>(_updateInvoiceItem),
]);
InvoiceEntity _updateEditing(InvoiceEntity client, action) {
InvoiceEntity _updateEditing(InvoiceEntity invoice, action) {
return action.invoice;
}
InvoiceEntity _addInvoiceItem(InvoiceEntity invoice, AddInvoiceItem action) {
return invoice.rebuild((b) => b
..invoiceItems.add(InvoiceItemEntity())
);
}
InvoiceEntity _removeInvoiceItem(InvoiceEntity invoice, DeleteInvoiceItem action) {
return invoice.rebuild((b) => b
..invoiceItems.removeAt(action.index)
);
}
InvoiceEntity _updateInvoiceItem(InvoiceEntity invoice, UpdateInvoiceItem action) {
return invoice.rebuild((b) => b
..invoiceItems[action.index] = action.invoiceItem
);
}
final invoiceListReducer = combineReducers<ListUIState>([
TypedReducer<ListUIState, SortInvoices>(_sortInvoices),
TypedReducer<ListUIState, FilterInvoicesByState>(_filterInvoicesByState),

View File

@ -100,7 +100,7 @@ class _$InvoiceUIStateSerializer
];
if (object.selected != null) {
result
..add('editing')
..add('selected')
..add(serializers.serialize(object.selected,
specifiedType: const FullType(InvoiceEntity)));
}
@ -119,8 +119,8 @@ class _$InvoiceUIStateSerializer
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'editing':
result.editing.replace(serializers.deserialize(value,
case 'selected':
result.selected.replace(serializers.deserialize(value,
specifiedType: const FullType(InvoiceEntity)) as InvoiceEntity);
break;
case 'listUIState':
@ -285,7 +285,7 @@ class _$InvoiceUIState extends InvoiceUIState {
@override
String toString() {
return (newBuiltValueToStringHelper('InvoiceUIState')
..add('editing', selected)
..add('selected', selected)
..add('listUIState', listUIState))
.toString();
}
@ -295,10 +295,10 @@ class InvoiceUIStateBuilder
implements Builder<InvoiceUIState, InvoiceUIStateBuilder> {
_$InvoiceUIState _$v;
InvoiceEntityBuilder _editing;
InvoiceEntityBuilder get editing =>
_$this._editing ??= new InvoiceEntityBuilder();
set editing(InvoiceEntityBuilder editing) => _$this._editing = editing;
InvoiceEntityBuilder _selected;
InvoiceEntityBuilder get selected =>
_$this._selected ??= new InvoiceEntityBuilder();
set selected(InvoiceEntityBuilder selected) => _$this._selected = selected;
ListUIStateBuilder _listUIState;
ListUIStateBuilder get listUIState =>
@ -310,7 +310,7 @@ class InvoiceUIStateBuilder
InvoiceUIStateBuilder get _$this {
if (_$v != null) {
_editing = _$v.selected?.toBuilder();
_selected = _$v.selected?.toBuilder();
_listUIState = _$v.listUIState?.toBuilder();
_$v = null;
}
@ -334,12 +334,12 @@ class InvoiceUIStateBuilder
try {
_$result = _$v ??
new _$InvoiceUIState._(
selected: _editing?.build(), listUIState: listUIState.build());
selected: _selected?.build(), listUIState: listUIState.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'editing';
_editing?.build();
_$failedField = 'selected';
_selected?.build();
_$failedField = 'listUIState';
listUIState.build();
} catch (e) {

View File

@ -8,7 +8,7 @@ import 'package:invoiceninja/redux/product/product_state.dart';
EntityUIState productUIReducer(ProductUIState state, action) {
return state.rebuild((b) => b
..listUIState.replace(productListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.selected, action))
..selected.replace(editingReducer(state.selected, action))
);
}

View File

@ -100,7 +100,7 @@ class _$ProductUIStateSerializer
];
if (object.selected != null) {
result
..add('editing')
..add('selected')
..add(serializers.serialize(object.selected,
specifiedType: const FullType(ProductEntity)));
}
@ -119,8 +119,8 @@ class _$ProductUIStateSerializer
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'editing':
result.editing.replace(serializers.deserialize(value,
case 'selected':
result.selected.replace(serializers.deserialize(value,
specifiedType: const FullType(ProductEntity)) as ProductEntity);
break;
case 'listUIState':
@ -285,7 +285,7 @@ class _$ProductUIState extends ProductUIState {
@override
String toString() {
return (newBuiltValueToStringHelper('ProductUIState')
..add('editing', selected)
..add('selected', selected)
..add('listUIState', listUIState))
.toString();
}
@ -295,10 +295,10 @@ class ProductUIStateBuilder
implements Builder<ProductUIState, ProductUIStateBuilder> {
_$ProductUIState _$v;
ProductEntityBuilder _editing;
ProductEntityBuilder get editing =>
_$this._editing ??= new ProductEntityBuilder();
set editing(ProductEntityBuilder editing) => _$this._editing = editing;
ProductEntityBuilder _selected;
ProductEntityBuilder get selected =>
_$this._selected ??= new ProductEntityBuilder();
set selected(ProductEntityBuilder selected) => _$this._selected = selected;
ListUIStateBuilder _listUIState;
ListUIStateBuilder get listUIState =>
@ -310,7 +310,7 @@ class ProductUIStateBuilder
ProductUIStateBuilder get _$this {
if (_$v != null) {
_editing = _$v.selected?.toBuilder();
_selected = _$v.selected?.toBuilder();
_listUIState = _$v.listUIState?.toBuilder();
_$v = null;
}
@ -334,12 +334,12 @@ class ProductUIStateBuilder
try {
_$result = _$v ??
new _$ProductUIState._(
selected: _editing?.build(), listUIState: listUIState.build());
selected: _selected?.build(), listUIState: listUIState.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'editing';
_editing?.build();
_$failedField = 'selected';
_selected?.build();
_$failedField = 'listUIState';
listUIState.build();
} catch (e) {

View File

@ -62,9 +62,6 @@ class ClientEditVM {
onAddContactClicked: () => store.dispatch(AddContact()),
onRemoveContactPressed: (index) => store.dispatch(DeleteContact(index)),
onChangedContact: (contact, index) {
print('== ON CHANGED');
print(store.state.clientUIState.selected);
print(contact);
store.dispatch(UpdateContact(contact: contact, index: index));
},
onChanged: (ClientEntity client) =>

View File

@ -43,12 +43,10 @@ class _InvoiceEditState extends State<InvoiceEdit>
List<Widget> editors = [
InvoiceEditDetails(
invoice: invoice,
clientList: viewModel.clientList,
clientMap: viewModel.clientMap,
viewModel: viewModel,
),
InvoiceEditItems(
invoice: invoice,
viewModel: viewModel,
),
];

View File

@ -3,21 +3,16 @@ import 'package:flutter/material.dart';
import 'package:invoiceninja/data/models/models.dart';
import 'package:invoiceninja/ui/app/entity_dropdown.dart';
import 'package:invoiceninja/ui/app/form_card.dart';
import 'package:invoiceninja/ui/invoice/edit/invoice_edit_vm.dart';
import 'package:invoiceninja/utils/localization.dart';
class InvoiceEditDetails extends StatefulWidget {
InvoiceEditDetails({
Key key,
@required this.invoice,
@required this.clientList,
@required this.clientMap,
@required this.onChanged,
@required this.viewModel,
}) : super(key: key);
final InvoiceEntity invoice;
final List<int> clientList;
final BuiltMap<int, ClientEntity> clientMap;
final Function(InvoiceEntity) onChanged;
final InvoiceEditVM viewModel;
@override
InvoiceEditDetailsState createState() => new InvoiceEditDetailsState();
@ -44,7 +39,7 @@ class InvoiceEditDetailsState extends State<InvoiceEditDetails> {
_controllers.forEach((controller) => controller.removeListener(_onChanged));
var invoice = widget.invoice;
var invoice = widget.viewModel.invoice;
_invoiceNumberController.text = invoice.invoiceNumber;
_poNumberController.text = invoice.poNumber;
_discountController.text = invoice.discount?.toStringAsFixed(2) ?? '';
@ -66,20 +61,21 @@ class InvoiceEditDetailsState extends State<InvoiceEditDetails> {
}
_onChanged() {
var invoice = widget.invoice.rebuild((b) => b
var invoice = widget.viewModel.invoice.rebuild((b) => b
..poNumber = _poNumberController.text.trim()
..discount = double.tryParse(_discountController.text) ?? 0.0
..partial = double.tryParse(_partialController.text) ?? 0.0
);
if (invoice != widget.invoice) {
widget.onChanged(invoice);
if (invoice != widget.viewModel.invoice) {
widget.viewModel.onChanged(invoice);
}
}
@override
Widget build(BuildContext context) {
var localization = AppLocalization.of(context);
var invoice = widget.invoice;
var viewModel = widget.viewModel;
var invoice = viewModel.invoice;
return ListView(
children: <Widget>[
@ -88,8 +84,8 @@ class InvoiceEditDetailsState extends State<InvoiceEditDetails> {
invoice.isNew()
? EntityDropdown(
labelText: localization.client,
entityList: widget.clientList,
entityMap: widget.clientMap,
entityList: viewModel.clientList,
entityMap: viewModel.clientMap,
) : TextFormField(
autocorrect: false,
controller: _invoiceNumberController,

View File

@ -1,42 +1,62 @@
import 'package:flutter/material.dart';
import 'package:invoiceninja/data/models/models.dart';
import 'package:invoiceninja/ui/invoice/edit/invoice_edit_vm.dart';
import 'package:invoiceninja/utils/localization.dart';
import 'package:invoiceninja/ui/app/form_card.dart';
class InvoiceEditItems extends StatelessWidget {
InvoiceEditItems({
Key key,
@required this.invoice,
@required this.onChanged,
@required this.viewModel,
}) : super(key: key);
final InvoiceEntity invoice;
final Function(InvoiceEntity) onChanged;
final InvoiceEditVM viewModel;
@override
Widget build(BuildContext context) {
return new Container();
var localization = AppLocalization.of(context);
var invoice = viewModel.invoice;
var invoiceItems = invoice.invoiceItems.map((invoiceItem) =>
ItemEditDetails(
viewModel: viewModel,
invoiceItem: invoiceItem,
index: invoice.invoiceItems.indexOf(invoiceItem)));
return ListView(
children: []
..addAll(invoice.invoiceItems.map((contact) => Container()))
..addAll(invoiceItems)
..add(Padding(
padding: const EdgeInsets.all(12.0),
child: RaisedButton(
elevation: 4.0,
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).secondaryHeaderColor,
child: Text(localization.addItem.toUpperCase()),
onPressed: viewModel.onAddInvoiceItemClicked,
),
)),
);
}
}
class ItemEditDetails extends StatefulWidget {
ItemEditDetails({
Key key,
@required this.index,
@required this.invoiceItem,
@required this.onRemovePressed,
@required this.isRemoveVisible,
@required this.viewModel,
}) : super(key: key);
final int index;
final InvoiceItemEntity invoiceItem;
final Function(GlobalKey<ItemEditDetailsState>) onRemovePressed;
final bool isRemoveVisible;
final InvoiceEditVM viewModel;
@override
ItemEditDetailsState createState() => ItemEditDetailsState();
}
class ItemEditDetailsState extends State<ItemEditDetails> {
final _productKeyController = TextEditingController();
final _notesController = TextEditingController();
final _costController = TextEditingController();
@ -46,7 +66,6 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
@override
void didChangeDependencies() {
_controllers = [
_productKeyController,
_notesController,
@ -56,8 +75,11 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
_controllers.forEach((controller) => controller.removeListener(_onChanged));
//var client = widget.client;
//_nameController.text = client.name;
var invoiceItem = widget.invoiceItem;
_productKeyController.text = invoiceItem.productKey;
_notesController.text = invoiceItem.notes;
_costController.text = invoiceItem.cost?.toStringAsFixed(2) ?? '';
_qtyController.text = invoiceItem.qty?.toStringAsFixed(2) ?? '';
_controllers.forEach((controller) => controller.addListener(_onChanged));
@ -75,20 +97,14 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
}
_onChanged() {
/*
var client = widget.client.rebuild((b) => b
..name = _nameController.text.trim()
);
if (client != widget.client) {
widget.onChanged(client);
var invoiceItem = widget.invoiceItem.rebuild((b) => b
..productKey = _productKeyController.text.trim()
..notes = _notesController.text.trim()
..cost = double.tryParse(_costController.text) ?? 0.0
..qty = double.tryParse(_qtyController.text) ?? 0.0);
if (invoiceItem != widget.invoiceItem) {
widget.viewModel.onChangedInvoiceItem(invoiceItem, widget.index);
}
*/
}
InvoiceItemEntity getItem() {
return widget.invoiceItem.rebuild((b) => b
//..phone = _phone
);
}
@override
@ -110,7 +126,7 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
new FlatButton(
child: Text(localization.ok.toUpperCase()),
onPressed: () {
widget.onRemovePressed(widget.key);
widget.viewModel.onRemoveInvoiceItemPressed(widget.index);
Navigator.pop(context);
})
],
@ -122,12 +138,14 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
children: <Widget>[
TextFormField(
autocorrect: false,
controller: _productKeyController,
decoration: InputDecoration(
labelText: localization.product,
),
),
TextFormField(
autocorrect: false,
controller: _notesController,
maxLines: 4,
decoration: InputDecoration(
labelText: localization.description,
@ -135,35 +153,35 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
),
TextFormField(
autocorrect: false,
controller: _costController,
decoration: InputDecoration(
labelText: localization.unitCost,
),
),
TextFormField(
autocorrect: false,
controller: _qtyController,
decoration: InputDecoration(
labelText: localization.quantity,
),
),
widget.isRemoveVisible
? Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 14.0),
child: FlatButton(
child: Text(
localization.remove,
style: TextStyle(
color: Colors.grey[600],
),
),
onPressed: _confirmDelete,
),
)
],
)
: Container(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 14.0),
child: FlatButton(
child: Text(
localization.remove,
style: TextStyle(
color: Colors.grey[600],
),
),
onPressed: _confirmDelete,
),
)
],
),
],
);
}

View File

@ -41,6 +41,9 @@ class InvoiceEditVM {
final Function(InvoiceEntity) onChanged;
final Function(BuildContext) onSaveClicked;
final Function(BuildContext, EntityAction) onActionSelected;
final Function() onAddInvoiceItemClicked;
final Function(int) onRemoveInvoiceItemPressed;
final Function(InvoiceItemEntity, int) onChangedInvoiceItem;
final Function onBackClicked;
final bool isLoading;
@ -50,6 +53,9 @@ class InvoiceEditVM {
@required this.clientMap,
@required this.onChanged,
@required this.onSaveClicked,
@required this.onAddInvoiceItemClicked,
@required this.onRemoveInvoiceItemPressed,
@required this.onChangedInvoiceItem,
@required this.onBackClicked,
@required this.onActionSelected,
@required this.isLoading,
@ -65,12 +71,13 @@ class InvoiceEditVM {
clientList: memoizedActiveClientList(
state.clientState.map, state.clientState.list),
clientMap: state.clientState.map,
onBackClicked: () {
store.dispatch(UpdateCurrentRoute(InvoiceScreen.route));
},
onChanged: (InvoiceEntity invoice) {
store.dispatch(UpdateInvoice(invoice));
onBackClicked: () => store.dispatch(UpdateCurrentRoute(InvoiceScreen.route)),
onAddInvoiceItemClicked: () => store.dispatch(AddInvoiceItem()),
onRemoveInvoiceItemPressed: (index) => store.dispatch(DeleteInvoiceItem(index)),
onChangedInvoiceItem: (invoiceItem, index) {
store.dispatch(UpdateInvoiceItem(invoiceItem: invoiceItem, index: index));
},
onChanged: (InvoiceEntity invoice) => store.dispatch(UpdateInvoice(invoice)),
onSaveClicked: (BuildContext context) {
final Completer<Null> completer = new Completer<Null>();
store.dispatch(