diff --git a/lib/data/models/invoice_model.dart b/lib/data/models/invoice_model.dart index 323133080..3dc8c91dd 100644 --- a/lib/data/models/invoice_model.dart +++ b/lib/data/models/invoice_model.dart @@ -48,6 +48,7 @@ class InvoiceFields { static const String invoiceDate = 'invoiceDate'; static const String dueDate = 'dueDate'; static const String terms = 'terms'; + static const String footer = 'footer'; static const String partial = 'partial'; static const String partialDueDate = 'partialDueDate'; static const String publicNotes = 'publicNotes'; @@ -71,7 +72,6 @@ abstract class InvoiceEntity extends Object return _$InvoiceEntity._( id: id ?? BaseEntity.nextId, isChanged: false, - settings: SettingsEntity(), amount: 0.0, balance: 0.0, clientId: '', @@ -83,6 +83,9 @@ abstract class InvoiceEntity extends Object dueDate: '', publicNotes: '', privateNotes: '', + terms: '', + footer: '', + designId: '1', taxName1: company?.settings?.defaultTaxName1 ?? '', taxRate1: company?.settings?.defaultTaxRate1 ?? 0.0, taxName2: company?.settings?.defaultTaxName2 ?? '', @@ -157,6 +160,14 @@ abstract class InvoiceEntity extends Object @BuiltValueField(wireName: 'private_notes') String get privateNotes; + String get terms; + + String get footer; + + @nullable + @BuiltValueField(wireName: 'design_id') + String get designId; + /* @BuiltValueField(wireName: 'frequency_id') int get frequencyId; @@ -235,8 +246,6 @@ abstract class InvoiceEntity extends Object String get filename; - SettingsEntity get settings; - @override @BuiltValueField(wireName: 'invoice_items') BuiltList get invoiceItems; diff --git a/lib/data/models/invoice_model.g.dart b/lib/data/models/invoice_model.g.dart index 619f76d93..b4d9abf29 100644 --- a/lib/data/models/invoice_model.g.dart +++ b/lib/data/models/invoice_model.g.dart @@ -152,6 +152,12 @@ class _$InvoiceEntitySerializer implements StructuredSerializer { 'private_notes', serializers.serialize(object.privateNotes, specifiedType: const FullType(String)), + 'terms', + serializers.serialize(object.terms, + specifiedType: const FullType(String)), + 'footer', + serializers.serialize(object.footer, + specifiedType: const FullType(String)), 'tax_name1', serializers.serialize(object.taxName1, specifiedType: const FullType(String)), @@ -206,9 +212,6 @@ class _$InvoiceEntitySerializer implements StructuredSerializer { 'filename', serializers.serialize(object.filename, specifiedType: const FullType(String)), - 'settings', - serializers.serialize(object.settings, - specifiedType: const FullType(SettingsEntity)), 'invoice_items', serializers.serialize(object.invoiceItems, specifiedType: const FullType( @@ -224,6 +227,12 @@ class _$InvoiceEntitySerializer implements StructuredSerializer { ..add(serializers.serialize(object.clientId, specifiedType: const FullType(String))); } + if (object.designId != null) { + result + ..add('design_id') + ..add(serializers.serialize(object.designId, + specifiedType: const FullType(String))); + } if (object.isChanged != null) { result ..add('isChanged') @@ -325,6 +334,18 @@ class _$InvoiceEntitySerializer implements StructuredSerializer { result.privateNotes = serializers.deserialize(value, specifiedType: const FullType(String)) as String; break; + case 'terms': + result.terms = serializers.deserialize(value, + specifiedType: const FullType(String)) as String; + break; + case 'footer': + result.footer = serializers.deserialize(value, + specifiedType: const FullType(String)) as String; + break; + case 'design_id': + result.designId = serializers.deserialize(value, + specifiedType: const FullType(String)) as String; + break; case 'tax_name1': result.taxName1 = serializers.deserialize(value, specifiedType: const FullType(String)) as String; @@ -397,10 +418,6 @@ class _$InvoiceEntitySerializer implements StructuredSerializer { result.filename = serializers.deserialize(value, specifiedType: const FullType(String)) as String; break; - case 'settings': - result.settings.replace(serializers.deserialize(value, - specifiedType: const FullType(SettingsEntity)) as SettingsEntity); - break; case 'invoice_items': result.invoiceItems.replace(serializers.deserialize(value, specifiedType: const FullType( @@ -997,6 +1014,12 @@ class _$InvoiceEntity extends InvoiceEntity { @override final String privateNotes; @override + final String terms; + @override + final String footer; + @override + final String designId; + @override final String taxName1; @override final double taxRate1; @@ -1033,8 +1056,6 @@ class _$InvoiceEntity extends InvoiceEntity { @override final String filename; @override - final SettingsEntity settings; - @override final BuiltList invoiceItems; @override final BuiltList invitations; @@ -1068,6 +1089,9 @@ class _$InvoiceEntity extends InvoiceEntity { this.dueDate, this.publicNotes, this.privateNotes, + this.terms, + this.footer, + this.designId, this.taxName1, this.taxRate1, this.taxName2, @@ -1086,7 +1110,6 @@ class _$InvoiceEntity extends InvoiceEntity { this.customTextValue1, this.customTextValue2, this.filename, - this.settings, this.invoiceItems, this.invitations, this.isChanged, @@ -1127,6 +1150,12 @@ class _$InvoiceEntity extends InvoiceEntity { if (privateNotes == null) { throw new BuiltValueNullFieldError('InvoiceEntity', 'privateNotes'); } + if (terms == null) { + throw new BuiltValueNullFieldError('InvoiceEntity', 'terms'); + } + if (footer == null) { + throw new BuiltValueNullFieldError('InvoiceEntity', 'footer'); + } if (taxName1 == null) { throw new BuiltValueNullFieldError('InvoiceEntity', 'taxName1'); } @@ -1181,9 +1210,6 @@ class _$InvoiceEntity extends InvoiceEntity { if (filename == null) { throw new BuiltValueNullFieldError('InvoiceEntity', 'filename'); } - if (settings == null) { - throw new BuiltValueNullFieldError('InvoiceEntity', 'settings'); - } if (invoiceItems == null) { throw new BuiltValueNullFieldError('InvoiceEntity', 'invoiceItems'); } @@ -1214,6 +1240,9 @@ class _$InvoiceEntity extends InvoiceEntity { dueDate == other.dueDate && publicNotes == other.publicNotes && privateNotes == other.privateNotes && + terms == other.terms && + footer == other.footer && + designId == other.designId && taxName1 == other.taxName1 && taxRate1 == other.taxRate1 && taxName2 == other.taxName2 && @@ -1232,7 +1261,6 @@ class _$InvoiceEntity extends InvoiceEntity { customTextValue1 == other.customTextValue1 && customTextValue2 == other.customTextValue2 && filename == other.filename && - settings == other.settings && invoiceItems == other.invoiceItems && invitations == other.invitations && isChanged == other.isChanged && @@ -1264,17 +1292,17 @@ class _$InvoiceEntity extends InvoiceEntity { $jc( $jc( $jc( - $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, amount.hashCode), balance.hashCode), clientId.hashCode), invoiceStatusId.hashCode), invoiceNumber.hashCode), discount.hashCode), poNumber.hashCode), invoiceDate.hashCode), dueDate.hashCode), publicNotes.hashCode), privateNotes.hashCode), taxName1.hashCode), taxRate1.hashCode), taxName2.hashCode), taxRate2.hashCode), isAmountDiscount.hashCode), partial.hashCode), partialDueDate.hashCode), hasTasks.hashCode), autoBill.hashCode), - customValue1.hashCode), - customValue2.hashCode), - customTaxes1.hashCode), - customTaxes2.hashCode), - hasExpenses.hashCode), - quoteInvoiceId.hashCode), - customTextValue1.hashCode), - customTextValue2.hashCode), - filename.hashCode), - settings.hashCode), + $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, amount.hashCode), balance.hashCode), clientId.hashCode), invoiceStatusId.hashCode), invoiceNumber.hashCode), discount.hashCode), poNumber.hashCode), invoiceDate.hashCode), dueDate.hashCode), publicNotes.hashCode), privateNotes.hashCode), terms.hashCode), footer.hashCode), designId.hashCode), taxName1.hashCode), taxRate1.hashCode), taxName2.hashCode), taxRate2.hashCode), isAmountDiscount.hashCode), partial.hashCode), partialDueDate.hashCode), hasTasks.hashCode), + autoBill.hashCode), + customValue1.hashCode), + customValue2.hashCode), + customTaxes1.hashCode), + customTaxes2.hashCode), + hasExpenses.hashCode), + quoteInvoiceId.hashCode), + customTextValue1.hashCode), + customTextValue2.hashCode), + filename.hashCode), invoiceItems.hashCode), invitations.hashCode), isChanged.hashCode), @@ -1300,6 +1328,9 @@ class _$InvoiceEntity extends InvoiceEntity { ..add('dueDate', dueDate) ..add('publicNotes', publicNotes) ..add('privateNotes', privateNotes) + ..add('terms', terms) + ..add('footer', footer) + ..add('designId', designId) ..add('taxName1', taxName1) ..add('taxRate1', taxRate1) ..add('taxName2', taxName2) @@ -1318,7 +1349,6 @@ class _$InvoiceEntity extends InvoiceEntity { ..add('customTextValue1', customTextValue1) ..add('customTextValue2', customTextValue2) ..add('filename', filename) - ..add('settings', settings) ..add('invoiceItems', invoiceItems) ..add('invitations', invitations) ..add('isChanged', isChanged) @@ -1382,6 +1412,18 @@ class InvoiceEntityBuilder String get privateNotes => _$this._privateNotes; set privateNotes(String privateNotes) => _$this._privateNotes = privateNotes; + String _terms; + String get terms => _$this._terms; + set terms(String terms) => _$this._terms = terms; + + String _footer; + String get footer => _$this._footer; + set footer(String footer) => _$this._footer = footer; + + String _designId; + String get designId => _$this._designId; + set designId(String designId) => _$this._designId = designId; + String _taxName1; String get taxName1 => _$this._taxName1; set taxName1(String taxName1) => _$this._taxName1 = taxName1; @@ -1459,11 +1501,6 @@ class InvoiceEntityBuilder String get filename => _$this._filename; set filename(String filename) => _$this._filename = filename; - SettingsEntityBuilder _settings; - SettingsEntityBuilder get settings => - _$this._settings ??= new SettingsEntityBuilder(); - set settings(SettingsEntityBuilder settings) => _$this._settings = settings; - ListBuilder _invoiceItems; ListBuilder get invoiceItems => _$this._invoiceItems ??= new ListBuilder(); @@ -1519,6 +1556,9 @@ class InvoiceEntityBuilder _dueDate = _$v.dueDate; _publicNotes = _$v.publicNotes; _privateNotes = _$v.privateNotes; + _terms = _$v.terms; + _footer = _$v.footer; + _designId = _$v.designId; _taxName1 = _$v.taxName1; _taxRate1 = _$v.taxRate1; _taxName2 = _$v.taxName2; @@ -1537,7 +1577,6 @@ class InvoiceEntityBuilder _customTextValue1 = _$v.customTextValue1; _customTextValue2 = _$v.customTextValue2; _filename = _$v.filename; - _settings = _$v.settings?.toBuilder(); _invoiceItems = _$v.invoiceItems?.toBuilder(); _invitations = _$v.invitations?.toBuilder(); _isChanged = _$v.isChanged; @@ -1582,6 +1621,9 @@ class InvoiceEntityBuilder dueDate: dueDate, publicNotes: publicNotes, privateNotes: privateNotes, + terms: terms, + footer: footer, + designId: designId, taxName1: taxName1, taxRate1: taxRate1, taxName2: taxName2, @@ -1600,7 +1642,6 @@ class InvoiceEntityBuilder customTextValue1: customTextValue1, customTextValue2: customTextValue2, filename: filename, - settings: settings.build(), invoiceItems: invoiceItems.build(), invitations: invitations.build(), isChanged: isChanged, @@ -1613,8 +1654,6 @@ class InvoiceEntityBuilder } catch (_) { String _$failedField; try { - _$failedField = 'settings'; - settings.build(); _$failedField = 'invoiceItems'; invoiceItems.build(); _$failedField = 'invitations'; diff --git a/lib/ui/app/forms/app_form.dart b/lib/ui/app/forms/app_form.dart index 6034d4f69..a5ce84c31 100644 --- a/lib/ui/app/forms/app_form.dart +++ b/lib/ui/app/forms/app_form.dart @@ -32,7 +32,7 @@ class AppTabForm extends StatelessWidget { this.tabBarKey, }); - final FocusNode focusNode; + final FocusScopeNode focusNode; final GlobalKey formKey; final List children; final TabController tabController; diff --git a/lib/ui/invoice/edit/invoice_edit_details.dart b/lib/ui/invoice/edit/invoice_edit_details.dart index db50b63ad..e888c4f6c 100644 --- a/lib/ui/invoice/edit/invoice_edit_details.dart +++ b/lib/ui/invoice/edit/invoice_edit_details.dart @@ -70,8 +70,8 @@ class InvoiceEditDetailsState extends State { formatNumberType: FormatNumberType.input); _surcharge2Controller.text = formatNumber(invoice.customValue2, context, formatNumberType: FormatNumberType.input); - _designController.text = invoice.settings.defaultInvoiceDesignId != null - ? kInvoiceDesigns[invoice.settings.defaultInvoiceDesignId] + _designController.text = invoice.designId != null + ? kInvoiceDesigns[invoice.designId] : ''; _controllers .forEach((dynamic controller) => controller.addListener(_onChanged)); @@ -296,15 +296,12 @@ class InvoiceEditDetailsState extends State { initialTaxRate: invoice.taxRate2, ) : Container(), - invoice.settings.defaultInvoiceDesignId == - null // TODO Remove check in v2 - ? SizedBox() - : PopupMenuButton( + PopupMenuButton( padding: EdgeInsets.zero, onSelected: (String design) { _designController.text = design; viewModel.onChanged(invoice.rebuild( - (b) => b..settings.defaultInvoiceDesignId = design)); + (b) => b..designId = design)); }, child: InkWell( child: IgnorePointer( diff --git a/lib/ui/invoice/edit/invoice_edit_notes.dart b/lib/ui/invoice/edit/invoice_edit_notes.dart index 3c0706c5f..8fcb737c1 100644 --- a/lib/ui/invoice/edit/invoice_edit_notes.dart +++ b/lib/ui/invoice/edit/invoice_edit_notes.dart @@ -38,8 +38,8 @@ class InvoiceEditNotesState extends State { final invoice = widget.viewModel.invoice; _publicNotesController.text = invoice.publicNotes; _privateNotesController.text = invoice.privateNotes; - _termsController.text = invoice.settings.defaultInvoiceTerms; - _footerController.text = invoice.settings.defaultInvoiceFooter; + _termsController.text = invoice.terms; + _footerController.text = invoice.footer; _controllers .forEach((dynamic controller) => controller.addListener(_onChanged)); @@ -61,8 +61,8 @@ class InvoiceEditNotesState extends State { final invoice = widget.viewModel.invoice.rebuild((b) => b ..publicNotes = _publicNotesController.text.trim() ..privateNotes = _privateNotesController.text.trim() - ..settings.defaultInvoiceTerms = _termsController.text.trim() - ..settings.defaultInvoiceFooter = _footerController.text.trim()); + ..terms = _termsController.text.trim() + ..footer = _footerController.text.trim()); if (invoice != widget.viewModel.invoice) { widget.viewModel.onChanged(invoice); } diff --git a/lib/ui/settings/client_portal.dart b/lib/ui/settings/client_portal.dart index 9bf5a48f4..add5cd8e5 100644 --- a/lib/ui/settings/client_portal.dart +++ b/lib/ui/settings/client_portal.dart @@ -1,6 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart'; +import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart'; import 'package:invoiceninja_flutter/ui/settings/client_portal_vm.dart'; import 'package:invoiceninja_flutter/ui/settings/settings_scaffold.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; @@ -25,7 +27,9 @@ class _ClientPortalState extends State bool autoValidate = false; - final _nameController = TextEditingController(); + final _subdomainController = TextEditingController(); + final _domainController = TextEditingController(); + final _iFrameController = TextEditingController(); List _controllers = []; @@ -47,7 +51,11 @@ class _ClientPortalState extends State @override void didChangeDependencies() { - _controllers = [_nameController]; + _controllers = [ + _subdomainController, + _domainController, + _iFrameController, + ]; _controllers .forEach((dynamic controller) => controller.removeListener(_onChanged)); @@ -87,7 +95,7 @@ class _ClientPortalState extends State controller: _controller, tabs: [ Tab( - text: localization.credentials, + text: localization.settings, ), Tab( text: localization.settings, @@ -102,7 +110,42 @@ class _ClientPortalState extends State formKey: _formKey, focusNode: _focusNode, children: [ - ListView(), + ListView( + children: [ + FormCard( + children: [ + InputDecorator( + decoration: InputDecoration( + labelText: localization.linkType, + ), + //isEmpty: false, + child: DropdownButtonHideUnderline( + child: DropdownButton( + //value: companyGateway.gatewayTypeId, + isExpanded: true, + isDense: true, + //onChanged: (value) => viewModel.onChanged(companyGateway.rebuild((b) => b..gatewayTypeId = value)), + items: []), + ), + ), + DecoratedFormField( + label: localization.subdomain, + controller: _subdomainController, + ), + DecoratedFormField( + label: localization.domain, + controller: _domainController, + keyboardType: TextInputType.url, + ), + DecoratedFormField( + label: 'iFrame', + controller: _iFrameController, + keyboardType: TextInputType.url, + ), + ], + ) + ], + ), ListView(), ListView(), ], diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index ac3d57b6a..7247468b4 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -14,6 +14,11 @@ abstract class LocaleCodeAware { mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { + 'subdomain': 'Subdomain', + 'domain': 'Domain', + 'link_type': 'Link Type', + 'custom_subdomain': 'Custom Subdomain', + 'custom_domain': 'Custom Domain', 'email_signature': 'Email Signature', 'enable_email_markup_help': 'Make it easier for your clients to pay you by adding schema.org markup to your emails.', @@ -15051,6 +15056,16 @@ mixin LocalizationsProvider on LocaleCodeAware { String get emailSignature => _localizedValues[localeCode]['email_signature']; + String get linkType => _localizedValues[localeCode]['link_type']; + + String get customSubdomain => _localizedValues[localeCode]['custom_subdomain']; + + String get customDomain => _localizedValues[localeCode]['custom_domain']; + + String get domain => _localizedValues[localeCode]['domain']; + + String get subdomain => _localizedValues[localeCode]['subdomain']; + String lookup(String key) { final lookupKey = toSnakeCase(key);