From 11e8fa59fe77080c9d3a17b64f43ffe2e4787e5f Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 10 Oct 2019 14:13:26 +0300 Subject: [PATCH] Settings --- lib/constants.dart | 26 +++ lib/data/models/company_model.dart | 28 ---- .../edit/client_edit_billing_address.dart | 1 - lib/ui/settings/localization_settings.dart | 158 +++++++++++++----- lib/ui/settings/localization_vm.dart | 13 +- lib/ui/vendor/edit/vendor_edit_address.dart | 1 - lib/utils/i18n.dart | 65 +++++++ 7 files changed, 213 insertions(+), 79 deletions(-) diff --git a/lib/constants.dart b/lib/constants.dart index e63fe932a..7b105426c 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -243,3 +243,29 @@ const List kLanguages = [ 'tr_TR', 'bg', ]; + +const kDaysOfTheWeek = { + 0: 'sunday', + 1: 'monday', + 2: 'tuesday', + 3: 'wednesday', + 4: 'thursday', + 5: 'friday', + 6: 'saturday', +}; + +const kMonthsOfTheYear = { + 0: 'january', + 1: 'february', + 2: 'march', + 3: 'april', + 4: 'may', + 5: 'june', + 6: 'july', + 7: 'august', + 8: 'september', + 9: 'october', + 10: 'november', + 11: 'december', +}; + diff --git a/lib/data/models/company_model.dart b/lib/data/models/company_model.dart index 3634d62f9..f5b0f07fc 100644 --- a/lib/data/models/company_model.dart +++ b/lib/data/models/company_model.dart @@ -536,17 +536,14 @@ abstract class SettingsEntity @BuiltValueField(wireName: 'show_tasks_in_portal') bool get showTasksInPortal; - // TODO remove this @nullable @BuiltValueField(wireName: 'invoice_terms') String get defaultInvoiceTerms; - // TODO remove this @nullable @BuiltValueField(wireName: 'invoice_taxes') bool get enableInvoiceTaxes; - // TODO remove this @nullable @BuiltValueField(wireName: 'invoice_item_taxes') bool get enableInvoiceItemTaxes; @@ -559,37 +556,30 @@ abstract class SettingsEntity @BuiltValueField(wireName: 'quote_design_id') String get defaultQuoteDesignId; - // TODO remove this @nullable @BuiltValueField(wireName: 'invoice_footer') String get defaultInvoiceFooter; - // TODO remove this @nullable @BuiltValueField(wireName: 'show_item_taxes') bool get showInvoiceItemTaxes; - // TODO remove this @nullable @BuiltValueField(wireName: 'tax_name1') String get defaultTaxName1; - // TODO remove this @nullable @BuiltValueField(wireName: 'tax_rate1_HIDDEN') double get defaultTaxRate1; - // TODO remove this @nullable @BuiltValueField(wireName: 'tax_name2') String get defaultTaxName2; - // TODO remove this @nullable @BuiltValueField(wireName: 'tax_rate2_HIDDEN') double get defaultTaxRate2; - // TODO remove this @nullable @BuiltValueField(wireName: 'quote_terms') String get defaultQuoteTerms; @@ -598,17 +588,14 @@ abstract class SettingsEntity @BuiltValueField(wireName: 'show_currency_code') bool get showCurrencyCode; - // TODO remove this @nullable @BuiltValueField(wireName: 'enable_second_tax_rate') bool get enableSecondTaxRate; - // TODO change to int/remove nullable @nullable @BuiltValueField(wireName: 'payment_terms_HIDDEN') int get defaultPaymentTerms; - // TODO remove this @nullable @BuiltValueField(wireName: 'payment_type_id') String get defaultPaymentTypeId; @@ -621,7 +608,6 @@ abstract class SettingsEntity @BuiltValueField(wireName: 'inclusive_taxes') bool get enableInclusiveTaxes; - // TODO remove this @nullable @BuiltValueField(wireName: 'convert_products') bool get convertProductExchangeRate; @@ -634,37 +620,30 @@ abstract class SettingsEntity @BuiltValueField(wireName: 'custom_invoice_taxes2') bool get enableCustomInvoiceTaxes2; - // TODO remove this @nullable @BuiltValueField(wireName: 'custom_payment_terms') BuiltList get customPaymentTerms; - // TODO remove this @nullable @BuiltValueField(wireName: 'invoice_fields') String get invoiceFields; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_footer') String get emailFooter; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_subject_invoice') String get emailSubjectInvoice; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_subject_quote') String get emailSubjectQuote; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_subject_payment') String get emailSubjectPayment; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_template_invoice') String get emailBodyInvoice; @@ -674,37 +653,30 @@ abstract class SettingsEntity @BuiltValueField(wireName: 'email_template_quote') String get emailBodyQuote; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_template_payment') String get emailBodyPayment; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_subject_reminder1') String get emailSubjectReminder1; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_subject_reminder2') String get emailSubjectReminder2; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_subject_reminder3') String get emailSubjectReminder3; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_template_reminder1') String get emailBodyReminder1; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_template_reminder2') String get emailBodyReminder2; - // TODO remove this @nullable @BuiltValueField(wireName: 'email_template_reminder3') String get emailBodyReminder3; diff --git a/lib/ui/client/edit/client_edit_billing_address.dart b/lib/ui/client/edit/client_edit_billing_address.dart index 5acded0b8..c780ae67a 100644 --- a/lib/ui/client/edit/client_edit_billing_address.dart +++ b/lib/ui/client/edit/client_edit_billing_address.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart'; import 'package:invoiceninja_flutter/ui/app/entity_dropdown.dart'; diff --git a/lib/ui/settings/localization_settings.dart b/lib/ui/settings/localization_settings.dart index 3aab9ff9e..955ac8cde 100644 --- a/lib/ui/settings/localization_settings.dart +++ b/lib/ui/settings/localization_settings.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/redux/static/static_selectors.dart'; import 'package:invoiceninja_flutter/ui/app/entity_dropdown.dart'; @@ -73,6 +74,7 @@ class _LocalizationSettingsState extends State { final viewModel = widget.viewModel; final state = viewModel.state; final settings = viewModel.settings; + final company = viewModel.company; return SettingsScaffold( title: localization.localization, @@ -89,46 +91,48 @@ class _LocalizationSettingsState extends State { labelText: localization.currency, initialValue: state.staticState.currencyMap[settings.currencyId]?.name, - onSelected: (SelectableEntity currency) => viewModel.onChanged( - settings.rebuild((b) => b..currencyId = currency.id)), + onSelected: (SelectableEntity currency) => + viewModel.onSettingsChanged( + settings.rebuild((b) => b..currencyId = currency.id)), ), - SizedBox(height: 12), - Row( - children: [ - Radio( - value: false, - groupValue: settings.showCurrencyCode, - activeColor: Theme.of(context).accentColor, - onChanged: (bool value) => viewModel.onChanged( - settings.rebuild((b) => b..showCurrencyCode = false)), - ), - GestureDetector( - child: Text('${localization.symbol}: ' + - formatNumber(1000, context, - showCurrencyCode: false, - currencyId: settings.currencyId)), - onTap: () => viewModel.onChanged( - settings.rebuild((b) => b..showCurrencyCode = false)), - ), - SizedBox(width: 10), - Radio( - value: true, - groupValue: settings.showCurrencyCode, - activeColor: Theme.of(context).accentColor, - onChanged: (bool value) => viewModel.onChanged( - settings.rebuild((b) => b..showCurrencyCode = true)), - ), - GestureDetector( - child: Text('${localization.code}: ' + - formatNumber(1000, context, - showCurrencyCode: true, - currencyId: settings.currencyId)), - onTap: () => viewModel.onChanged( - settings.rebuild((b) => b..showCurrencyCode = true)), - ), - ], + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 20), + child: Row( + children: [ + Radio( + value: false, + groupValue: settings.showCurrencyCode, + activeColor: Theme.of(context).accentColor, + onChanged: (bool value) => viewModel.onSettingsChanged( + settings.rebuild((b) => b..showCurrencyCode = false)), + ), + GestureDetector( + child: Text('${localization.symbol}: ' + + formatNumber(1000, context, + showCurrencyCode: false, + currencyId: settings.currencyId)), + onTap: () => viewModel.onSettingsChanged( + settings.rebuild((b) => b..showCurrencyCode = false)), + ), + SizedBox(width: 10), + Radio( + value: true, + groupValue: settings.showCurrencyCode, + activeColor: Theme.of(context).accentColor, + onChanged: (bool value) => viewModel.onSettingsChanged( + settings.rebuild((b) => b..showCurrencyCode = true)), + ), + GestureDetector( + child: Text('${localization.code}: ' + + formatNumber(1000, context, + showCurrencyCode: true, + currencyId: settings.currencyId)), + onTap: () => viewModel.onSettingsChanged( + settings.rebuild((b) => b..showCurrencyCode = true)), + ), + ], + ), ), - SizedBox(height: 20), EntityDropdown( key: ValueKey('__language_${settings.languageId}'), entityType: EntityType.language, @@ -137,8 +141,9 @@ class _LocalizationSettingsState extends State { labelText: localization.language, initialValue: state.staticState.languageMap[settings.languageId]?.name, - onSelected: (SelectableEntity language) => viewModel.onChanged( - settings.rebuild((b) => b..languageId = language.id)), + onSelected: (SelectableEntity language) => + viewModel.onSettingsChanged( + settings.rebuild((b) => b..languageId = language.id)), ), EntityDropdown( key: ValueKey('__timezone_${settings.timezoneId}'), @@ -147,9 +152,10 @@ class _LocalizationSettingsState extends State { entityList: memoizedTimezoneList(state.staticState.timezoneMap), labelText: localization.timezone, initialValue: - state.staticState.timezoneMap[settings.timezoneId]?.name, - onSelected: (SelectableEntity timezone) => viewModel.onChanged( - settings.rebuild((b) => b..timezoneId = timezone.id)), + state.staticState.timezoneMap[settings.timezoneId]?.name, + onSelected: (SelectableEntity timezone) => + viewModel.onSettingsChanged( + settings.rebuild((b) => b..timezoneId = timezone.id)), ), EntityDropdown( key: ValueKey('__date_format_${settings.dateFormatId}'), @@ -158,9 +164,69 @@ class _LocalizationSettingsState extends State { entityList: memoizedDateFormatList(state.staticState.dateFormatMap), labelText: localization.dateFormat, initialValue: - state.staticState.dateFormatMap[settings.dateFormatId]?.preview, - onSelected: (SelectableEntity dateFormat) => viewModel.onChanged( - settings.rebuild((b) => b..dateFormatId = dateFormat.id)), + state.staticState.dateFormatMap[settings.dateFormatId]?.preview, + onSelected: (SelectableEntity dateFormat) => + viewModel.onSettingsChanged( + settings.rebuild((b) => b..dateFormatId = dateFormat.id)), + ), + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 20), + child: CheckboxListTile( + title: Text(localization.militaryTime), + value: settings.enableMilitaryTime, + activeColor: Theme.of(context).accentColor, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (value) => viewModel.onSettingsChanged( + settings.rebuild((b) => b..enableMilitaryTime = value)), + ), + ), + InputDecorator( + decoration: InputDecoration( + labelText: localization.firstDayOfTheWeek, + ), + isEmpty: company.startOfWeek == null, + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: company.startOfWeek, + isExpanded: true, + isDense: true, + onChanged: (value) => viewModel.onCompanyChanged( + company.rebuild((b) => b..startOfWeek = value)), + items: kDaysOfTheWeek + .map( + (id, day) => MapEntry>( + id, + DropdownMenuItem( + child: Text(localization.lookup(day)), + value: id, + ))) + .values + .toList()), + ), + ), + InputDecorator( + decoration: InputDecoration( + labelText: localization.firstMonthOfTheYear, + ), + isEmpty: company.financialYearStart == null, + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: company.financialYearStart, + isExpanded: true, + isDense: true, + onChanged: (value) => viewModel.onCompanyChanged( + company.rebuild((b) => b..financialYearStart = value)), + items: kMonthsOfTheYear + .map( + (id, month) => MapEntry>( + id, + DropdownMenuItem( + child: Text(localization.lookup(month)), + value: id, + ))) + .values + .toList()), + ), ), ], ), diff --git a/lib/ui/settings/localization_vm.dart b/lib/ui/settings/localization_vm.dart index 0e8655b93..c1a8376d5 100644 --- a/lib/ui/settings/localization_vm.dart +++ b/lib/ui/settings/localization_vm.dart @@ -34,8 +34,10 @@ class LocalizationScreen extends StatelessWidget { class LocalizationSettingsVM { LocalizationSettingsVM({ @required this.state, + @required this.company, @required this.settings, - @required this.onChanged, + @required this.onSettingsChanged, + @required this.onCompanyChanged, @required this.onSavePressed, @required this.onCancelPressed, }); @@ -46,9 +48,12 @@ class LocalizationSettingsVM { return LocalizationSettingsVM( state: state, settings: state.uiState.settingsUIState.settings, - onChanged: (settings) { + company: state.uiState.settingsUIState.userCompany.company, + onSettingsChanged: (settings) { store.dispatch(UpdateSettings(settings: settings)); }, + onCompanyChanged: (company) => + store.dispatch(UpdateCompany(company: company)), onCancelPressed: (context) => store.dispatch(ResetSettings()), onSavePressed: (context) { final settingsUIState = state.uiState.settingsUIState; @@ -73,8 +78,10 @@ class LocalizationSettingsVM { } final AppState state; + final CompanyEntity company; final SettingsEntity settings; - final Function(SettingsEntity) onChanged; + final Function(CompanyEntity) onCompanyChanged; + final Function(SettingsEntity) onSettingsChanged; final Function(BuildContext) onSavePressed; final Function(BuildContext) onCancelPressed; } diff --git a/lib/ui/vendor/edit/vendor_edit_address.dart b/lib/ui/vendor/edit/vendor_edit_address.dart index a036fb24c..cd852a5b7 100644 --- a/lib/ui/vendor/edit/vendor_edit_address.dart +++ b/lib/ui/vendor/edit/vendor_edit_address.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/ui/app/entity_dropdown.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart'; diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index e36f97289..18869a08c 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -14,6 +14,27 @@ abstract class LocaleCodeAware { mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { + 'first_day_of_the_week': 'First day of the week', + 'first_month_of_the_year': 'First month of the year', + 'sunday': 'Sunday', + 'monday': 'Monday', + 'tuesday': 'Tuesday', + 'wednesday': 'Wednesday', + 'thursday': 'Thursday', + 'friday': 'Friday', + 'saturday': 'Saturday', + 'january': 'January', + 'february': 'February', + 'march': 'March', + 'april': 'April', + 'may': 'May', + 'june': 'June', + 'july': 'July', + 'august': 'August', + 'september': 'September', + 'october': 'October', + 'november': 'November', + 'december': 'December', 'symbol': 'Symbol', 'ocde': 'Code', 'date_format': 'Date Format', @@ -14655,6 +14676,7 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]['long_press_multiselect']; String get all => _localizedValues[localeCode]['all']; + String get emailSignUp => _localizedValues[localeCode]['email_sign_up']; String get googleSignUp => _localizedValues[localeCode]['google_sign_up']; @@ -14762,6 +14784,49 @@ mixin LocalizationsProvider on LocaleCodeAware { String get code => _localizedValues[localeCode]['ocde']; + String get sunday => _localizedValues[localeCode]['sunday']; + + String get monday => _localizedValues[localeCode]['monday']; + + String get tuesday => _localizedValues[localeCode]['tuesday']; + + String get wednesday => _localizedValues[localeCode]['wednesday']; + + String get thursday => _localizedValues[localeCode]['thursday']; + + String get friday => _localizedValues[localeCode]['friday']; + + String get saturday => _localizedValues[localeCode]['saturday']; + + String get january => _localizedValues[localeCode]['january']; + + String get february => _localizedValues[localeCode]['february']; + + String get march => _localizedValues[localeCode]['march']; + + String get april => _localizedValues[localeCode]['april']; + + String get may => _localizedValues[localeCode]['may']; + + String get june => _localizedValues[localeCode]['june']; + + String get july => _localizedValues[localeCode]['july']; + + String get august => _localizedValues[localeCode]['august']; + + String get september => _localizedValues[localeCode]['september']; + + String get october => _localizedValues[localeCode]['october']; + + String get november => _localizedValues[localeCode]['november']; + + String get december => _localizedValues[localeCode]['december']; + + String get firstDayOfTheWeek => _localizedValues[localeCode]['first_day_of_the_week']; + + String get firstMonthOfTheYear => _localizedValues[localeCode]['first_month_of_the_year']; + + String lookup(String key) { final lookupKey = toSnakeCase(key); return _localizedValues[localeCode][lookupKey] ??