This commit is contained in:
Hillel Coren 2019-08-26 07:08:26 +03:00
parent 0d7847b5e3
commit 6005996fa5
7 changed files with 53 additions and 48 deletions

View File

@ -4,14 +4,18 @@ class DecoratedFormField extends StatelessWidget {
const DecoratedFormField({ const DecoratedFormField({
@required this.controller, @required this.controller,
@required this.label, @required this.label,
this.autovalidate = false,
this.validator, this.validator,
this.keyboardType, this.keyboardType,
this.maxLines,
}); });
final TextEditingController controller; final TextEditingController controller;
final String label; final String label;
final Function(String) validator; final Function(String) validator;
final TextInputType keyboardType; final TextInputType keyboardType;
final int maxLines;
final bool autovalidate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -24,6 +28,8 @@ class DecoratedFormField extends StatelessWidget {
), ),
validator: validator, validator: validator,
keyboardType: null, keyboardType: null,
maxLines: maxLines,
autovalidate: autovalidate,
); );
} }
} }

View File

@ -1,5 +1,6 @@
import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart'; import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart';
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
import 'package:invoiceninja_flutter/ui/app/invoice/invoice_item_view.dart'; import 'package:invoiceninja_flutter/ui/app/invoice/invoice_item_view.dart';
import 'package:invoiceninja_flutter/ui/app/invoice/tax_rate_dropdown.dart'; import 'package:invoiceninja_flutter/ui/app/invoice/tax_rate_dropdown.dart';
import 'package:invoiceninja_flutter/ui/app/responsive_padding.dart'; import 'package:invoiceninja_flutter/ui/app/responsive_padding.dart';
@ -217,20 +218,14 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
), ),
], ],
), ),
TextFormField( DecoratedFormField(
autocorrect: false, label: localization.product,
controller: _productKeyController, controller: _productKeyController,
decoration: InputDecoration(
labelText: localization.product,
), ),
), DecoratedFormField(
TextFormField( label: localization.description,
autocorrect: false,
controller: _notesController, controller: _notesController,
maxLines: 4, maxLines: 4,
decoration: InputDecoration(
labelText: localization.description,
),
), ),
CustomField( CustomField(
controller: _custom1Controller, controller: _custom1Controller,
@ -242,31 +237,25 @@ class ItemEditDetailsState extends State<ItemEditDetails> {
labelText: company.getCustomFieldLabel(CustomFieldType.product2), labelText: company.getCustomFieldLabel(CustomFieldType.product2),
options: company.getCustomFieldValues(CustomFieldType.product2), options: company.getCustomFieldValues(CustomFieldType.product2),
), ),
TextFormField( DecoratedFormField(
label: localization.unitCost,
controller: _costController, controller: _costController,
keyboardType: TextInputType.numberWithOptions(decimal: true), keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
labelText: localization.unitCost,
),
), ),
company.hasInvoiceField('quantity') company.hasInvoiceField('quantity')
? TextFormField( ? DecoratedFormField(
label: localization.quantity,
controller: _qtyController, controller: _qtyController,
keyboardType: keyboardType:
TextInputType.numberWithOptions(decimal: true), TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
labelText: localization.quantity,
),
) )
: Container(), : Container(),
company.hasInvoiceField('discount') company.hasInvoiceField('discount')
? TextFormField( ? DecoratedFormField(
label: localization.discount,
controller: _discountController, controller: _discountController,
keyboardType: keyboardType:
TextInputType.numberWithOptions(decimal: true), TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
labelText: localization.discount,
),
) )
: Container(), : Container(),
company.enableInvoiceItemTaxes company.enableInvoiceItemTaxes

View File

@ -172,6 +172,7 @@ class _InvoiceItemSelectorState extends State<InvoiceItemSelector>
) )
: IconButton( : IconButton(
icon: Icon(Icons.add_circle_outline), icon: Icon(Icons.add_circle_outline),
tooltip: localization.createNew,
onPressed: () => _addBlankItem(), onPressed: () => _addBlankItem(),
), ),
], ],

View File

@ -1,6 +1,7 @@
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart'; import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart';
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
import 'package:invoiceninja_flutter/ui/app/invoice/tax_rate_dropdown.dart'; import 'package:invoiceninja_flutter/ui/app/invoice/tax_rate_dropdown.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -148,25 +149,18 @@ class _ProductEditState extends State<ProductEdit> {
children: <Widget>[ children: <Widget>[
FormCard( FormCard(
children: <Widget>[ children: <Widget>[
TextFormField( DecoratedFormField(
key: Key(localization.productKey), label: localization.product,
controller: _productKeyController, controller: _productKeyController,
autocorrect: false,
decoration: InputDecoration(
labelText: localization.product,
),
validator: (val) => val.isEmpty || val.trim().isEmpty validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterAProductKey ? localization.pleaseEnterAProductKey
: null, : null,
autovalidate: autoValidate, autovalidate: autoValidate,
), ),
TextFormField( DecoratedFormField(
key: Key(localization.notes), label: localization.description,
controller: _notesController, controller: _notesController,
maxLines: 4, maxLines: 4,
decoration: InputDecoration(
labelText: localization.notes,
),
), ),
CustomField( CustomField(
controller: _custom1Controller, controller: _custom1Controller,
@ -182,14 +176,11 @@ class _ProductEditState extends State<ProductEdit> {
options: options:
company.getCustomFieldValues(CustomFieldType.product2), company.getCustomFieldValues(CustomFieldType.product2),
), ),
TextFormField( DecoratedFormField(
key: Key(localization.cost), label: localization.cost,
controller: _costController, controller: _costController,
keyboardType: keyboardType:
TextInputType.numberWithOptions(decimal: true), TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
labelText: localization.cost,
),
), ),
company.enableInvoiceItemTaxes company.enableInvoiceItemTaxes
? TaxRateDropdown( ? TaxRateDropdown(

View File

@ -12,6 +12,9 @@ void main() {
final clientName = makeUnique(faker.company.name()); final clientName = makeUnique(faker.company.name());
final poNumber = final poNumber =
faker.randomGenerator.integer(999999, min: 100000).toString(); faker.randomGenerator.integer(999999, min: 100000).toString();
final productKey = makeUnique(faker.food.cuisine());
final description = faker.lorem.sentences(5).toString();
final cost = faker.randomGenerator.decimal(min: 50, scale: 10).toStringAsFixed(2);
final updatedPoNumber = final updatedPoNumber =
faker.randomGenerator.integer(999999, min: 100000).toString(); faker.randomGenerator.integer(999999, min: 100000).toString();
@ -61,15 +64,29 @@ void main() {
print('Tap new invoice'); print('Tap new invoice');
await driver.tap(find.byTooltip(localization.newInvoice)); await driver.tap(find.byTooltip(localization.newInvoice));
print('Fill form: $clientName'); print('Create new client: $clientName');
await driver.tap(find.byValueKey(localization.client)); await driver.tap(find.byValueKey(localization.client));
await driver.tap(find.byTooltip(localization.createNew)); await driver.tap(find.byTooltip(localization.createNew));
print('Fill the client form');
await fillTextField( await fillTextField(
driver: driver, field: localization.name, value: clientName); driver: driver, field: localization.name, value: clientName);
await driver.tap(find.text(localization.save)); await driver.tap(find.text(localization.save));
print('Fill the invoice form');
await driver.tap(find.byTooltip(localization.addItem));
await driver.tap(find.byTooltip(localization.createNew));
await fillTextFields(driver, <String, String>{
localization.product: productKey,
localization.description: description,
localization.unitCost: cost,
localization.quantity: '1',
});
await driver.tap(find.text(localization.done));
await driver.tap(find.text(localization.details));
await fillAndSaveForm(driver, <String, String>{ await fillAndSaveForm(driver, <String, String>{
localization.poNumber: poNumber, localization.poNumber: poNumber,
}); });

View File

@ -10,11 +10,11 @@ void main() {
FlutterDriver driver; FlutterDriver driver;
final productKey = makeUnique(faker.food.cuisine()); final productKey = makeUnique(faker.food.cuisine());
final notes = faker.food.dish(); final description = faker.food.dish();
final cost = faker.randomGenerator.decimal(min: 50).toStringAsFixed(2); final cost = faker.randomGenerator.decimal(min: 50).toStringAsFixed(2);
final updatedProductKey = makeUnique(faker.food.cuisine()); final updatedProductKey = makeUnique(faker.food.cuisine());
final updatedNotes = faker.food.dish(); final updatedDescription = faker.food.dish();
final updatedCost = final updatedCost =
faker.randomGenerator.decimal(min: 50).toStringAsFixed(2); faker.randomGenerator.decimal(min: 50).toStringAsFixed(2);
@ -65,8 +65,8 @@ void main() {
print('Fill form: $productKey'); print('Fill form: $productKey');
await fillAndSaveForm(driver, <String, dynamic>{ await fillAndSaveForm(driver, <String, dynamic>{
localization.productKey: productKey, localization.product: productKey,
localization.notes: notes, localization.description: description,
localization.cost: cost, localization.cost: cost,
}); });
@ -91,8 +91,8 @@ void main() {
await driver.tap(find.text(localization.edit)); await driver.tap(find.text(localization.edit));
await fillAndSaveForm(driver, <String, dynamic>{ await fillAndSaveForm(driver, <String, dynamic>{
localization.productKey: updatedProductKey, localization.product: updatedProductKey,
localization.notes: updatedNotes, localization.description: updatedDescription,
localization.cost: updatedCost, localization.cost: updatedCost,
}); });
}); });

View File

@ -34,13 +34,15 @@ Future<void> login(FlutterDriver driver,
String loginSecret = Config.TEST_SECRET}) async { String loginSecret = Config.TEST_SECRET}) async {
final localization = TestLocalization('en'); final localization = TestLocalization('en');
if (selfHosted) {
await driver.tap(find.byValueKey(localization.selfhostLogin));
}
await fillTextFields(driver, <String, dynamic>{ await fillTextFields(driver, <String, dynamic>{
localization.email: loginEmail, localization.email: loginEmail,
localization.password: loginPassword, localization.password: loginPassword,
}); });
if (selfHosted) { if (selfHosted) {
await driver.tap(find.byValueKey(localization.selfhostLogin));
await fillTextFields(driver, <String, dynamic>{ await fillTextFields(driver, <String, dynamic>{
localization.url: loginUrl, localization.url: loginUrl,
localization.secret: loginSecret, localization.secret: loginSecret,
@ -104,7 +106,6 @@ Future<void> checkTextFields(
Future<void> fillAndSaveForm( Future<void> fillAndSaveForm(
FlutterDriver driver, Map<String, dynamic> values) async { FlutterDriver driver, Map<String, dynamic> values) async {
final localization = TestLocalization('en'); final localization = TestLocalization('en');
print('Fill in form'); print('Fill in form');