Settings
This commit is contained in:
parent
e0a1d69bf6
commit
b214daccd8
|
|
@ -4,21 +4,28 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
|||
|
||||
class AppForm extends StatelessWidget {
|
||||
const AppForm({
|
||||
@required this.children,
|
||||
this.children,
|
||||
this.child,
|
||||
@required this.formKey,
|
||||
@required this.focusNode,
|
||||
});
|
||||
|
||||
final GlobalKey<FormState> formKey;
|
||||
final List<Widget> children;
|
||||
final Widget child;
|
||||
final FocusScopeNode focusNode;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
return FocusScope(
|
||||
node: focusNode,
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: ListView(
|
||||
child: child ?? ListView(
|
||||
shrinkWrap: true,
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:invoiceninja_flutter/constants.dart';
|
|||
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/client_picker.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/custom_surcharges.dart';
|
||||
|
|
@ -38,6 +39,10 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
with SingleTickerProviderStateMixin {
|
||||
TabController _tabController;
|
||||
|
||||
FocusNode _focusNode;
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_invoicesEdit');
|
||||
|
||||
final _invoiceNumberController = TextEditingController();
|
||||
final _poNumberController = TextEditingController();
|
||||
final _discountController = TextEditingController();
|
||||
|
|
@ -63,6 +68,7 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_focusNode = FocusScopeNode();
|
||||
_tabController = TabController(vsync: this, length: 4);
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +131,7 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
_tabController.dispose();
|
||||
_controllers.forEach((controller) {
|
||||
controller.removeListener(_onChanged);
|
||||
|
|
@ -136,7 +143,8 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
|
||||
void _onChanged() {
|
||||
_debouncer.run(() {
|
||||
final invoice = widget.viewModel.invoice.rebuild((b) => b
|
||||
final invoice = widget.viewModel.invoice.rebuild((b) =>
|
||||
b
|
||||
..number = widget.viewModel.invoice.isNew
|
||||
? ''
|
||||
: _invoiceNumberController.text.trim()
|
||||
|
|
@ -168,7 +176,10 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
final invoice = viewModel.invoice;
|
||||
final company = viewModel.company;
|
||||
|
||||
return ListView(
|
||||
return AppForm(
|
||||
formKey: _formKey,
|
||||
focusNode: _focusNode,
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -193,8 +204,10 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
),
|
||||
UserPicker(
|
||||
userId: invoice.assignedUserId,
|
||||
onChanged: (userId) => viewModel.onChanged(
|
||||
invoice.rebuild((b) => b..assignedUserId = userId)),
|
||||
onChanged: (userId) =>
|
||||
viewModel.onChanged(
|
||||
invoice.rebuild((
|
||||
b) => b..assignedUserId = userId)),
|
||||
),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
|
|
@ -212,8 +225,13 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
left: kMobileDialogPadding / 2),
|
||||
children: <Widget>[
|
||||
DatePicker(
|
||||
validator: (String val) => val.trim().isEmpty
|
||||
? AppLocalization.of(context).pleaseSelectADate
|
||||
validator: (String val) =>
|
||||
val
|
||||
.trim()
|
||||
.isEmpty
|
||||
? AppLocalization
|
||||
.of(context)
|
||||
.pleaseSelectADate
|
||||
: null,
|
||||
labelText: widget.isQuote
|
||||
? localization.quoteDate
|
||||
|
|
@ -231,7 +249,8 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
selectedDate: invoice.dueDate,
|
||||
onSelected: (date) {
|
||||
viewModel
|
||||
.onChanged(invoice.rebuild((b) => b..dueDate = date));
|
||||
.onChanged(
|
||||
invoice.rebuild((b) => b..dueDate = date));
|
||||
},
|
||||
),
|
||||
DecoratedFormField(
|
||||
|
|
@ -275,9 +294,14 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
label: widget.isQuote
|
||||
? localization.quoteNumber
|
||||
: localization.invoiceNumber,
|
||||
validator: (String val) => val.trim().isEmpty &&
|
||||
validator: (String val) =>
|
||||
val
|
||||
.trim()
|
||||
.isEmpty &&
|
||||
invoice.isOld
|
||||
? AppLocalization.of(context).pleaseEnterAnInvoiceNumber
|
||||
? AppLocalization
|
||||
.of(context)
|
||||
.pleaseEnterAnInvoiceNumber
|
||||
: null,
|
||||
),
|
||||
DecoratedFormField(
|
||||
|
|
@ -288,8 +312,10 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
controller: _discountController,
|
||||
value: invoice.discount,
|
||||
isAmountDiscount: invoice.isAmountDiscount,
|
||||
onTypeChanged: (value) => viewModel.onChanged(
|
||||
invoice.rebuild((b) => b..isAmountDiscount = value)),
|
||||
onTypeChanged: (value) =>
|
||||
viewModel.onChanged(
|
||||
invoice.rebuild((
|
||||
b) => b..isAmountDiscount = value)),
|
||||
),
|
||||
CustomField(
|
||||
controller: _custom2Controller,
|
||||
|
|
@ -396,16 +422,20 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
),
|
||||
if (company.settings.enableSecondInvoiceTaxRate)
|
||||
TaxRateDropdown(
|
||||
onSelected: (taxRate) => viewModel
|
||||
.onChanged(invoice.applyTax(taxRate, isSecond: true)),
|
||||
onSelected: (taxRate) =>
|
||||
viewModel
|
||||
.onChanged(
|
||||
invoice.applyTax(taxRate, isSecond: true)),
|
||||
labelText: localization.tax,
|
||||
initialTaxName: invoice.taxName2,
|
||||
initialTaxRate: invoice.taxRate2,
|
||||
),
|
||||
if (company.settings.enableThirdInvoiceTaxRate)
|
||||
TaxRateDropdown(
|
||||
onSelected: (taxRate) => viewModel
|
||||
.onChanged(invoice.applyTax(taxRate, isThird: true)),
|
||||
onSelected: (taxRate) =>
|
||||
viewModel
|
||||
.onChanged(
|
||||
invoice.applyTax(taxRate, isThird: true)),
|
||||
labelText: localization.tax,
|
||||
initialTaxName: invoice.taxName3,
|
||||
initialTaxRate: invoice.taxRate3,
|
||||
|
|
@ -420,10 +450,13 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
AppDropdownButton(
|
||||
labelText: localization.design,
|
||||
value: invoice.designId,
|
||||
onChanged: (dynamic value) => viewModel
|
||||
.onChanged(invoice.rebuild((b) => b..designId = value)),
|
||||
onChanged: (dynamic value) =>
|
||||
viewModel
|
||||
.onChanged(
|
||||
invoice.rebuild((b) => b..designId = value)),
|
||||
items: company.invoiceDesignIds
|
||||
.map((designId) => DropdownMenuItem<String>(
|
||||
.map((designId) =>
|
||||
DropdownMenuItem<String>(
|
||||
value: designId,
|
||||
child: Text(kInvoiceDesigns[designId]),
|
||||
))
|
||||
|
|
@ -435,6 +468,7 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
|
|||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import 'package:invoiceninja_flutter/utils/localization.dart';
|
|||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
|
||||
class InvoiceEditItemsDesktop extends StatefulWidget {
|
||||
const InvoiceEditItemsDesktop({this.viewModel});
|
||||
const InvoiceEditItemsDesktop({
|
||||
this.viewModel,
|
||||
});
|
||||
|
||||
final EntityEditItemsVM viewModel;
|
||||
|
||||
|
|
@ -20,6 +22,32 @@ class InvoiceEditItemsDesktop extends StatefulWidget {
|
|||
class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
|
||||
int _updatedAt;
|
||||
|
||||
/*
|
||||
final Map<int, FocusNode> _focusNodes = {};
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_focusNodes.values.forEach((node) => node.dispose());
|
||||
|
||||
final lineItems = widget.viewModel.invoice.lineItems;
|
||||
for (var index = 0; index < lineItems.length; index++) {
|
||||
_focusNodes[index] = FocusNode()
|
||||
..addListener(() => _onFocusChange(index));
|
||||
}
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNodes.values.forEach((node) => node.dispose());
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onFocusChange(int index) {
|
||||
setState(() {});
|
||||
}
|
||||
*/
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final localization = AppLocalization.of(context);
|
||||
|
|
@ -96,6 +124,8 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
|
|||
lineItems[index].rebuild((b) => b..notes = value), index),
|
||||
minLines: 1,
|
||||
maxLines: 6,
|
||||
//maxLines: _focusNodes[index].hasFocus ? 6 : 1,
|
||||
//focusNode: _focusNodes[index],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ import 'package:invoiceninja_flutter/data/models/models.dart';
|
|||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class InvoiceEditItemsScreen extends StatelessWidget {
|
||||
const InvoiceEditItemsScreen({Key key}) : super(key: key);
|
||||
const InvoiceEditItemsScreen({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ import 'package:invoiceninja_flutter/data/models/models.dart';
|
|||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class QuoteEditItemsScreen extends StatelessWidget {
|
||||
const QuoteEditItemsScreen({Key key}) : super(key: key);
|
||||
const QuoteEditItemsScreen({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -33,11 +33,19 @@ class _LocalizationSettingsState extends State<LocalizationSettings> {
|
|||
bool autoValidate = false;
|
||||
|
||||
final _firstNameController = TextEditingController();
|
||||
FocusScopeNode _focusNode;
|
||||
|
||||
List<TextEditingController> _controllers = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusScopeNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
_controllers.forEach((dynamic controller) {
|
||||
controller.removeListener(_onChanged);
|
||||
controller.dispose();
|
||||
|
|
@ -78,6 +86,7 @@ class _LocalizationSettingsState extends State<LocalizationSettings> {
|
|||
onSavePressed: viewModel.onSavePressed,
|
||||
body: AppForm(
|
||||
formKey: _formKey,
|
||||
focusNode: _focusNode,
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
children: <Widget>[
|
||||
|
|
|
|||
|
|
@ -21,6 +21,19 @@ class ProductSettings extends StatefulWidget {
|
|||
class _ProductSettingsState extends State<ProductSettings> {
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_productSettings');
|
||||
FocusScopeNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusScopeNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -33,6 +46,7 @@ class _ProductSettingsState extends State<ProductSettings> {
|
|||
onSavePressed: viewModel.onSavePressed,
|
||||
body: AppForm(
|
||||
formKey: _formKey,
|
||||
focusNode: _focusNode,
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
children: <Widget>[
|
||||
|
|
|
|||
|
|
@ -26,6 +26,19 @@ class TaxSettings extends StatefulWidget {
|
|||
class _TaxSettingsState extends State<TaxSettings> {
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_taxSettings');
|
||||
FocusScopeNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusScopeNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -39,6 +52,7 @@ class _TaxSettingsState extends State<TaxSettings> {
|
|||
onSavePressed: viewModel.onSavePressed,
|
||||
body: AppForm(
|
||||
formKey: _formKey,
|
||||
focusNode: _focusNode,
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
children: <Widget>[
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class UserDetails extends StatefulWidget {
|
|||
class _UserDetailsState extends State<UserDetails> {
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_userDetails');
|
||||
|
||||
FocusScopeNode _focusNode;
|
||||
bool autoValidate = false;
|
||||
|
||||
final _firstNameController = TextEditingController();
|
||||
|
|
@ -34,8 +34,15 @@ class _UserDetailsState extends State<UserDetails> {
|
|||
List<TextEditingController> _controllers = [];
|
||||
final _debouncer = Debouncer();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusScopeNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
_controllers.forEach((dynamic controller) {
|
||||
controller.removeListener(_onChanged);
|
||||
controller.dispose();
|
||||
|
|
@ -89,6 +96,7 @@ class _UserDetailsState extends State<UserDetails> {
|
|||
title: localization.userDetails,
|
||||
onSavePressed: viewModel.onSavePressed,
|
||||
body: AppForm(
|
||||
focusNode: _focusNode,
|
||||
formKey: _formKey,
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class _TaxRateEditState extends State<TaxRateEdit> {
|
|||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_taxRateEdit');
|
||||
|
||||
FocusScopeNode _focusNode;
|
||||
bool autoValidate = false;
|
||||
|
||||
final _nameController = TextEditingController();
|
||||
|
|
@ -85,6 +86,7 @@ class _TaxRateEditState extends State<TaxRateEdit> {
|
|||
onSavePressed: viewModel.onSavePressed,
|
||||
onCancelPressed: viewModel.onCancelPressed,
|
||||
body: AppForm(
|
||||
focusNode: _focusNode,
|
||||
formKey: _formKey,
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class _UserEditState extends State<UserEdit> {
|
|||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_userEdit');
|
||||
final _debouncer = Debouncer();
|
||||
|
||||
FocusScopeNode _focusNode;
|
||||
bool autoValidate = false;
|
||||
|
||||
final _firstNameController = TextEditingController();
|
||||
|
|
@ -143,6 +143,7 @@ class _UserEditState extends State<UserEdit> {
|
|||
],
|
||||
),
|
||||
body: AppForm(
|
||||
focusNode: _focusNode,
|
||||
formKey: _formKey,
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
|
|
|
|||
Loading…
Reference in New Issue