Bank accounts
This commit is contained in:
parent
d71c333f8f
commit
11e5219f3e
|
|
@ -496,6 +496,7 @@ const String kSettingsExpenseCategoryEdit = 'expense_category/edit';
|
||||||
const String kSettingsTaskStatuses = 'task_status';
|
const String kSettingsTaskStatuses = 'task_status';
|
||||||
const String kSettingsTaskStatusView = 'task_status/view';
|
const String kSettingsTaskStatusView = 'task_status/view';
|
||||||
const String kSettingsTaskStatusEdit = 'task_status/edit';
|
const String kSettingsTaskStatusEdit = 'task_status/edit';
|
||||||
|
const String kSettingsBankAccounts = 'bank_accounts';
|
||||||
|
|
||||||
const List<String> kAdvancedSettings = [
|
const List<String> kAdvancedSettings = [
|
||||||
kSettingsCustomDesigns,
|
kSettingsCustomDesigns,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
|
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/settings/bank_accounts_vm.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/settings/payment_settings_vm.dart';
|
import 'package:invoiceninja_flutter/ui/settings/payment_settings_vm.dart';
|
||||||
import 'package:local_auth/local_auth.dart';
|
import 'package:local_auth/local_auth.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
@ -509,21 +510,18 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
||||||
PurchaseOrderViewScreen(),
|
PurchaseOrderViewScreen(),
|
||||||
PurchaseOrderEditScreen.route: (context) =>
|
PurchaseOrderEditScreen.route: (context) =>
|
||||||
PurchaseOrderEditScreen(),
|
PurchaseOrderEditScreen(),
|
||||||
|
|
||||||
RecurringExpenseScreen.route: (context) =>
|
RecurringExpenseScreen.route: (context) =>
|
||||||
RecurringExpenseScreenBuilder(),
|
RecurringExpenseScreenBuilder(),
|
||||||
RecurringExpenseViewScreen.route: (context) =>
|
RecurringExpenseViewScreen.route: (context) =>
|
||||||
RecurringExpenseViewScreen(),
|
RecurringExpenseViewScreen(),
|
||||||
RecurringExpenseEditScreen.route: (context) =>
|
RecurringExpenseEditScreen.route: (context) =>
|
||||||
RecurringExpenseEditScreen(),
|
RecurringExpenseEditScreen(),
|
||||||
|
|
||||||
SubscriptionScreen.route: (context) =>
|
SubscriptionScreen.route: (context) =>
|
||||||
SubscriptionScreenBuilder(),
|
SubscriptionScreenBuilder(),
|
||||||
SubscriptionViewScreen.route: (context) =>
|
SubscriptionViewScreen.route: (context) =>
|
||||||
SubscriptionViewScreen(),
|
SubscriptionViewScreen(),
|
||||||
SubscriptionEditScreen.route: (context) =>
|
SubscriptionEditScreen.route: (context) =>
|
||||||
SubscriptionEditScreen(),
|
SubscriptionEditScreen(),
|
||||||
|
|
||||||
TaskStatusScreen.route: (context) =>
|
TaskStatusScreen.route: (context) =>
|
||||||
TaskStatusScreenBuilder(),
|
TaskStatusScreenBuilder(),
|
||||||
TaskStatusViewScreen.route: (context) =>
|
TaskStatusViewScreen.route: (context) =>
|
||||||
|
|
@ -631,6 +629,8 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
||||||
CreditCardsAndBanksScreen(),
|
CreditCardsAndBanksScreen(),
|
||||||
DataVisualizationsScreen.route: (context) =>
|
DataVisualizationsScreen.route: (context) =>
|
||||||
DataVisualizationsScreen(),
|
DataVisualizationsScreen(),
|
||||||
|
BankAccountsScreen.route: (context) =>
|
||||||
|
BankAccountsScreen(),
|
||||||
}
|
}
|
||||||
: {},
|
: {},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_pdf_vm.dar
|
||||||
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_screen.dart';
|
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_screen.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_screen_vm.dart';
|
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_screen_vm.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/purchase_order/view/purchase_order_view_vm.dart';
|
import 'package:invoiceninja_flutter/ui/purchase_order/view/purchase_order_view_vm.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/settings/bank_accounts_vm.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/settings/payment_settings_vm.dart';
|
import 'package:invoiceninja_flutter/ui/settings/payment_settings_vm.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
@ -934,6 +935,9 @@ class SettingsScreens extends StatelessWidget {
|
||||||
case kSettingsExpenseCategoryEdit:
|
case kSettingsExpenseCategoryEdit:
|
||||||
screen = ExpenseCategoryEditScreen();
|
screen = ExpenseCategoryEditScreen();
|
||||||
break;
|
break;
|
||||||
|
case kSettingsBankAccounts:
|
||||||
|
screen = BankAccountsScreen();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Row(children: <Widget>[
|
return Row(children: <Widget>[
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Flutter imports:
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// Project imports:
|
||||||
|
import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/settings/bank_accounts_vm.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
||||||
|
class BankAccounts extends StatefulWidget {
|
||||||
|
const BankAccounts({
|
||||||
|
Key key,
|
||||||
|
@required this.viewModel,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final BankAccountsVM viewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_BankAccountsState createState() => _BankAccountsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BankAccountsState extends State<BankAccounts> {
|
||||||
|
static final GlobalKey<FormState> _formKey =
|
||||||
|
GlobalKey<FormState>(debugLabel: '_BankAccounts');
|
||||||
|
FocusScopeNode _focusNode;
|
||||||
|
final _debouncer = Debouncer(sendFirstAction: true);
|
||||||
|
final _stockThresholdController = TextEditingController();
|
||||||
|
List<TextEditingController> _controllers = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_focusNode = FocusScopeNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
_controllers = [_stockThresholdController];
|
||||||
|
|
||||||
|
_controllers
|
||||||
|
.forEach((dynamic controller) => controller.removeListener(_onChanged));
|
||||||
|
|
||||||
|
final viewModel = widget.viewModel;
|
||||||
|
final company = viewModel.state.company;
|
||||||
|
|
||||||
|
_stockThresholdController.text = company.stockNotificationThreshold == 0
|
||||||
|
? ''
|
||||||
|
: formatNumber(
|
||||||
|
company.stockNotificationThreshold.toDouble(),
|
||||||
|
context,
|
||||||
|
formatNumberType: FormatNumberType.int,
|
||||||
|
);
|
||||||
|
|
||||||
|
_controllers
|
||||||
|
.forEach((dynamic controller) => controller.addListener(_onChanged));
|
||||||
|
|
||||||
|
super.didChangeDependencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_focusNode.dispose();
|
||||||
|
_controllers.forEach((dynamic controller) {
|
||||||
|
controller.removeListener(_onChanged);
|
||||||
|
controller.dispose();
|
||||||
|
});
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChanged() {
|
||||||
|
final company = widget.viewModel.company.rebuild((b) => b
|
||||||
|
..stockNotificationThreshold =
|
||||||
|
parseInt(_stockThresholdController.text.trim()));
|
||||||
|
if (company != widget.viewModel.company) {
|
||||||
|
_debouncer.run(() {
|
||||||
|
widget.viewModel.onCompanyChanged(company);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localization = AppLocalization.of(context);
|
||||||
|
final viewModel = widget.viewModel;
|
||||||
|
//final company = viewModel.company;
|
||||||
|
|
||||||
|
return EditScaffold(
|
||||||
|
title: localization.bankAccounts,
|
||||||
|
onSavePressed: viewModel.onSavePressed,
|
||||||
|
body: AppForm(
|
||||||
|
formKey: _formKey,
|
||||||
|
focusNode: _focusNode,
|
||||||
|
children: <Widget>[
|
||||||
|
//
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Flutter imports:
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
// Package imports:
|
||||||
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/settings/bank_accounts.dart';
|
||||||
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
|
// Project imports:
|
||||||
|
import 'package:invoiceninja_flutter/constants.dart';
|
||||||
|
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
||||||
|
class BankAccountsScreen extends StatelessWidget {
|
||||||
|
const BankAccountsScreen({Key key}) : super(key: key);
|
||||||
|
static const String route = '/$kSettings/$kSettingsBankAccounts';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StoreConnector<AppState, BankAccountsVM>(
|
||||||
|
converter: BankAccountsVM.fromStore,
|
||||||
|
builder: (context, viewModel) {
|
||||||
|
return BankAccounts(
|
||||||
|
viewModel: viewModel,
|
||||||
|
key: ValueKey(viewModel.state.settingsUIState.updatedAt),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BankAccountsVM {
|
||||||
|
BankAccountsVM({
|
||||||
|
@required this.state,
|
||||||
|
@required this.company,
|
||||||
|
@required this.onCompanyChanged,
|
||||||
|
@required this.onSavePressed,
|
||||||
|
});
|
||||||
|
|
||||||
|
static BankAccountsVM fromStore(Store<AppState> store) {
|
||||||
|
final state = store.state;
|
||||||
|
|
||||||
|
return BankAccountsVM(
|
||||||
|
state: state,
|
||||||
|
company: state.uiState.settingsUIState.company,
|
||||||
|
onCompanyChanged: (company) =>
|
||||||
|
store.dispatch(UpdateCompany(company: company)),
|
||||||
|
onSavePressed: (context) {
|
||||||
|
Debouncer.runOnComplete(() {
|
||||||
|
final settingsUIState = store.state.uiState.settingsUIState;
|
||||||
|
final completer = snackBarCompleter<Null>(
|
||||||
|
context, AppLocalization.of(context).savedSettings);
|
||||||
|
store.dispatch(SaveCompanyRequest(
|
||||||
|
completer: completer, company: settingsUIState.company));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final AppState state;
|
||||||
|
final Function(BuildContext) onSavePressed;
|
||||||
|
final CompanyEntity company;
|
||||||
|
final Function(CompanyEntity) onCompanyChanged;
|
||||||
|
}
|
||||||
|
|
@ -204,6 +204,11 @@ class _SettingsListState extends State<SettingsList> {
|
||||||
section: kSettingsTemplatesAndReminders,
|
section: kSettingsTemplatesAndReminders,
|
||||||
viewModel: widget.viewModel,
|
viewModel: widget.viewModel,
|
||||||
),
|
),
|
||||||
|
if (showAll)
|
||||||
|
SettingsListTile(
|
||||||
|
section: kSettingsBankAccounts,
|
||||||
|
viewModel: widget.viewModel,
|
||||||
|
),
|
||||||
if (showAll)
|
if (showAll)
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
section: kSettingsGroupSettings,
|
section: kSettingsGroupSettings,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
static final Map<String, Map<String, String>> _localizedValues = {
|
static final Map<String, Map<String, String>> _localizedValues = {
|
||||||
'en': {
|
'en': {
|
||||||
// STARTER: lang key - do not remove comment
|
// STARTER: lang key - do not remove comment
|
||||||
|
'bank_accounts': 'Bank Accounts',
|
||||||
'mark_paid_payment_email': 'Mark Paid Payment Email',
|
'mark_paid_payment_email': 'Mark Paid Payment Email',
|
||||||
'convert_to_project': 'Convert to Project',
|
'convert_to_project': 'Convert to Project',
|
||||||
'client_email': 'Client Email',
|
'client_email': 'Client Email',
|
||||||
|
|
@ -75973,6 +75974,10 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
_localizedValues[localeCode]['mark_paid_payment_email'] ??
|
_localizedValues[localeCode]['mark_paid_payment_email'] ??
|
||||||
_localizedValues['en']['mark_paid_payment_email'];
|
_localizedValues['en']['mark_paid_payment_email'];
|
||||||
|
|
||||||
|
String get bankAccounts =>
|
||||||
|
_localizedValues[localeCode]['bank_accounts'] ??
|
||||||
|
_localizedValues['en']['bank_accounts'];
|
||||||
|
|
||||||
// STARTER: lang field - do not remove comment
|
// STARTER: lang field - do not remove comment
|
||||||
|
|
||||||
String lookup(String key) {
|
String lookup(String key) {
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,8 @@ IconData getSettingIcon(String section) {
|
||||||
return getEntityIcon(EntityType.task);
|
return getEntityIcon(EntityType.task);
|
||||||
case kSettingsSubscriptions:
|
case kSettingsSubscriptions:
|
||||||
return getEntityIcon(EntityType.subscription);
|
return getEntityIcon(EntityType.subscription);
|
||||||
|
case kSettingsBankAccounts:
|
||||||
|
return MdiIcons.bank;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue