Dashboard overview
This commit is contained in:
parent
e3f1203331
commit
d12ccee003
|
|
@ -49,7 +49,7 @@ enum DashboardSections {
|
||||||
expenses,
|
expenses,
|
||||||
}
|
}
|
||||||
|
|
||||||
class DashboardPanels extends StatelessWidget {
|
class DashboardPanels extends StatefulWidget {
|
||||||
const DashboardPanels({
|
const DashboardPanels({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.viewModel,
|
@required this.viewModel,
|
||||||
|
|
@ -59,18 +59,24 @@ class DashboardPanels extends StatelessWidget {
|
||||||
final DashboardVM viewModel;
|
final DashboardVM viewModel;
|
||||||
final ScrollController scrollController;
|
final ScrollController scrollController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DashboardPanels> createState() => _DashboardPanelsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DashboardPanelsState extends State<DashboardPanels> {
|
||||||
void _showDateOptions(BuildContext context) {
|
void _showDateOptions(BuildContext context) {
|
||||||
showDialog<DashboardDateRangePicker>(
|
showDialog<DashboardDateRangePicker>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return DashboardDateRangePicker(
|
return DashboardDateRangePicker(
|
||||||
state: viewModel.dashboardUIState,
|
state: widget.viewModel.dashboardUIState,
|
||||||
onSettingsChanged: viewModel.onSettingsChanged);
|
onSettingsChanged: widget.viewModel.onSettingsChanged);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _header(BuildContext context) {
|
Widget _header(BuildContext context) {
|
||||||
final state = viewModel.state;
|
final store = StoreProvider.of<AppState>(context);
|
||||||
|
final state = widget.viewModel.state;
|
||||||
final company = state.company;
|
final company = state.company;
|
||||||
final clientMap = state.clientState.map;
|
final clientMap = state.clientState.map;
|
||||||
final groupMap = state.groupState.map;
|
final groupMap = state.groupState.map;
|
||||||
|
|
@ -108,10 +114,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
viewModel.onGroupByChanged(value);
|
widget.viewModel.onGroupByChanged(value);
|
||||||
if (!isWide && Navigator.canPop(context)) {
|
setState(() {});
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
value: settings.groupBy,
|
value: settings.groupBy,
|
||||||
),
|
),
|
||||||
|
|
@ -133,10 +137,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
viewModel.onTaxesChanged(value);
|
widget.viewModel.onTaxesChanged(value);
|
||||||
if (!isWide && Navigator.canPop(context)) {
|
setState(() {});
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
value: settings.includeTaxes,
|
value: settings.includeTaxes,
|
||||||
),
|
),
|
||||||
|
|
@ -177,7 +179,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
settings.dateRange = dateRange;
|
settings.dateRange = dateRange;
|
||||||
viewModel.onSettingsChanged(settings);
|
widget.viewModel.onSettingsChanged(settings);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -192,15 +194,13 @@ class DashboardPanels extends StatelessWidget {
|
||||||
.map((currencyId) => DropdownMenuItem<String>(
|
.map((currencyId) => DropdownMenuItem<String>(
|
||||||
child: Text(currencyId == kCurrencyAll
|
child: Text(currencyId == kCurrencyAll
|
||||||
? localization.all
|
? localization.all
|
||||||
: viewModel.currencyMap[currencyId]?.code),
|
: widget.viewModel.currencyMap[currencyId]?.code),
|
||||||
value: currencyId,
|
value: currencyId,
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
onChanged: (currencyId) {
|
onChanged: (currencyId) {
|
||||||
viewModel.onCurrencyChanged(currencyId);
|
widget.viewModel.onCurrencyChanged(currencyId);
|
||||||
if (!isWide && Navigator.canPop(context)) {
|
setState(() {});
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
value: settings.currencyId,
|
value: settings.currencyId,
|
||||||
),
|
),
|
||||||
|
|
@ -208,6 +208,167 @@ class DashboardPanels extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showSettings() {
|
||||||
|
final List<DropdownMenuItem<String>> items = [];
|
||||||
|
final fieldMap = {
|
||||||
|
EntityType.invoice: [
|
||||||
|
DashboardUISettings.FIELD_ACTIVE_INVOICES,
|
||||||
|
DashboardUISettings.FIELD_OUTSTANDING_INVOICES,
|
||||||
|
],
|
||||||
|
EntityType.payment: [
|
||||||
|
DashboardUISettings.FIELD_COMPLETED_PAYMENTS,
|
||||||
|
DashboardUISettings.FIELD_REFUNDED_PAYMENTS,
|
||||||
|
],
|
||||||
|
EntityType.quote: [
|
||||||
|
DashboardUISettings.FIELD_ACTIVE_QUOTES,
|
||||||
|
DashboardUISettings.FIELD_APPROVED_QUOTES,
|
||||||
|
DashboardUISettings.FIELD_UNAPPROVED_QUOTES,
|
||||||
|
],
|
||||||
|
EntityType.task: [
|
||||||
|
DashboardUISettings.FIELD_LOGGED_TASKS,
|
||||||
|
DashboardUISettings.FIELD_INVOICED_TASKS,
|
||||||
|
DashboardUISettings.FIELD_PAID_TASKS,
|
||||||
|
],
|
||||||
|
EntityType.expense: [
|
||||||
|
DashboardUISettings.FIELD_LOGGED_EXPENSES,
|
||||||
|
DashboardUISettings.FIELD_PENDING_EXPENSES,
|
||||||
|
DashboardUISettings.FIELD_INVOICED_EXPENSES,
|
||||||
|
DashboardUISettings.FIELD_INVOICE_PAID_EXPENSES,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
fieldMap.forEach((entityType, fields) {
|
||||||
|
fields.forEach((field) {
|
||||||
|
if (company.isModuleEnabled(entityType) &&
|
||||||
|
!settings.totalFields.contains(field)) {
|
||||||
|
items.add(DropdownMenuItem<String>(
|
||||||
|
child: Text(localization.lookup(field)),
|
||||||
|
value: field,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
showDialog<AlertDialog>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(localization.settings),
|
||||||
|
key: ValueKey(
|
||||||
|
'__${settings.includeTaxes}_${settings.currencyId}__'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text(localization.close.toUpperCase()),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (!isWide) ...[
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(localization.groupBy),
|
||||||
|
Spacer(),
|
||||||
|
groupBy,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (hasMultipleCurrencies)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(localization.currency),
|
||||||
|
Spacer(),
|
||||||
|
currencySettings,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (company.hasTaxes)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(localization.taxes),
|
||||||
|
Spacer(),
|
||||||
|
taxSettings,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
for (var field in settings.totalFields)
|
||||||
|
ListTile(
|
||||||
|
title: Text(localization.lookup(field)),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: Icon(Icons.close),
|
||||||
|
onPressed: () {
|
||||||
|
store.dispatch(UpdateDashboardSettings(
|
||||||
|
totalFields: settings.totalFields
|
||||||
|
.rebuild((b) => b..remove(field))));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton<String>(
|
||||||
|
isExpanded: true,
|
||||||
|
onChanged: (value) {
|
||||||
|
store.dispatch(UpdateDashboardSettings(
|
||||||
|
totalFields: settings.totalFields
|
||||||
|
.rebuild((b) => b..add(value))));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
hint: Text(localization.addField),
|
||||||
|
items: items,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CheckboxListTile(
|
||||||
|
value: settings.showCurrentPeriod,
|
||||||
|
onChanged: (value) {
|
||||||
|
store.dispatch(UpdateDashboardSettings(
|
||||||
|
showCurrentPeriod: value));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
title: Text(localization.currentPeriod),
|
||||||
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
|
),
|
||||||
|
CheckboxListTile(
|
||||||
|
value: settings.showPreviousPeriod,
|
||||||
|
onChanged: (value) {
|
||||||
|
store.dispatch(UpdateDashboardSettings(
|
||||||
|
showPreviousPeriod: value));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
title: Text(localization.previousPeriod),
|
||||||
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
|
),
|
||||||
|
CheckboxListTile(
|
||||||
|
value: settings.showTotal,
|
||||||
|
onChanged: (value) {
|
||||||
|
store.dispatch(
|
||||||
|
UpdateDashboardSettings(showTotal: value));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
title: Text(localization.total),
|
||||||
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
|
),
|
||||||
|
AppDropdownButton<int>(
|
||||||
|
labelText: localization.fieldsPerRow,
|
||||||
|
value: settings.numberFieldsPerRow,
|
||||||
|
onChanged: (dynamic value) {
|
||||||
|
store.dispatch(UpdateDashboardSettings(
|
||||||
|
numberFieldsPerRow: value));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
items: List<int>.generate(8, (i) => i + 1)
|
||||||
|
.map((value) => DropdownMenuItem<int>(
|
||||||
|
child: Text('$value'),
|
||||||
|
value: value,
|
||||||
|
))
|
||||||
|
.toList())
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
elevation: 6.0,
|
elevation: 6.0,
|
||||||
|
|
@ -218,12 +379,12 @@ class DashboardPanels extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.navigate_before),
|
icon: Icon(Icons.navigate_before),
|
||||||
onPressed: () => viewModel.onOffsetChanged(1),
|
onPressed: () => widget.viewModel.onOffsetChanged(1),
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.navigate_next),
|
icon: Icon(Icons.navigate_next),
|
||||||
onPressed: () => viewModel.onOffsetChanged(-1),
|
onPressed: () => widget.viewModel.onOffsetChanged(-1),
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
),
|
),
|
||||||
SizedBox(width: 4),
|
SizedBox(width: 4),
|
||||||
|
|
@ -237,56 +398,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(MdiIcons.tuneVariant),
|
icon: Icon(MdiIcons.tuneVariant),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog<AlertDialog>(
|
_showSettings();
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text(localization.settings),
|
|
||||||
key: ValueKey(
|
|
||||||
'__${settings.includeTaxes}_${settings.currencyId}__'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: Text(localization.close.toUpperCase()),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (!isWide) ...[
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(localization.groupBy),
|
|
||||||
Spacer(),
|
|
||||||
groupBy,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (hasMultipleCurrencies)
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(localization.currency),
|
|
||||||
Spacer(),
|
|
||||||
currencySettings,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (company.hasTaxes)
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(localization.taxes),
|
|
||||||
Spacer(),
|
|
||||||
taxSettings,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
_DashboardTotalsSettings(
|
|
||||||
viewModel: viewModel,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (isDesktop(context) &&
|
if (isDesktop(context) &&
|
||||||
|
|
@ -295,7 +407,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: localization.showSidebar,
|
tooltip: localization.showSidebar,
|
||||||
icon: Icon(Icons.view_sidebar),
|
icon: Icon(Icons.view_sidebar),
|
||||||
onPressed: () => viewModel.onShowSidebar()),
|
onPressed: () => widget.viewModel.onShowSidebar()),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -308,8 +420,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
@required Function(List<String>) onDateSelected,
|
@required Function(List<String>) onDateSelected,
|
||||||
}) {
|
}) {
|
||||||
final settings = viewModel.dashboardUIState.settings;
|
final settings = widget.viewModel.dashboardUIState.settings;
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final isLoaded = state.isLoaded || state.paymentState.list.isNotEmpty;
|
final isLoaded = state.isLoaded || state.paymentState.list.isNotEmpty;
|
||||||
final currentData = memoizedChartPayments(
|
final currentData = memoizedChartPayments(
|
||||||
state.staticState.currencyMap,
|
state.staticState.currencyMap,
|
||||||
|
|
@ -331,7 +443,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return _DashboardPanel(
|
return _DashboardPanel(
|
||||||
viewModel: viewModel,
|
viewModel: widget.viewModel,
|
||||||
currentData: currentData,
|
currentData: currentData,
|
||||||
previousData: previousData,
|
previousData: previousData,
|
||||||
isLoaded: isLoaded,
|
isLoaded: isLoaded,
|
||||||
|
|
@ -345,8 +457,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
@required Function(List<String>) onDateSelected,
|
@required Function(List<String>) onDateSelected,
|
||||||
}) {
|
}) {
|
||||||
final settings = viewModel.dashboardUIState.settings;
|
final settings = widget.viewModel.dashboardUIState.settings;
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final isLoaded = state.isLoaded || state.invoiceState.list.isNotEmpty;
|
final isLoaded = state.isLoaded || state.invoiceState.list.isNotEmpty;
|
||||||
final currentData = memoizedChartInvoices(
|
final currentData = memoizedChartInvoices(
|
||||||
state.staticState.currencyMap,
|
state.staticState.currencyMap,
|
||||||
|
|
@ -368,7 +480,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return _DashboardPanel(
|
return _DashboardPanel(
|
||||||
viewModel: viewModel,
|
viewModel: widget.viewModel,
|
||||||
currentData: currentData,
|
currentData: currentData,
|
||||||
previousData: previousData,
|
previousData: previousData,
|
||||||
isLoaded: isLoaded,
|
isLoaded: isLoaded,
|
||||||
|
|
@ -382,8 +494,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
@required Function(List<String>) onDateSelected,
|
@required Function(List<String>) onDateSelected,
|
||||||
}) {
|
}) {
|
||||||
final settings = viewModel.dashboardUIState.settings;
|
final settings = widget.viewModel.dashboardUIState.settings;
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final isLoaded = state.isLoaded || state.quoteState.list.isNotEmpty;
|
final isLoaded = state.isLoaded || state.quoteState.list.isNotEmpty;
|
||||||
final currentData = memoizedChartQuotes(
|
final currentData = memoizedChartQuotes(
|
||||||
state.staticState.currencyMap,
|
state.staticState.currencyMap,
|
||||||
|
|
@ -405,7 +517,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return _DashboardPanel(
|
return _DashboardPanel(
|
||||||
viewModel: viewModel,
|
viewModel: widget.viewModel,
|
||||||
currentData: currentData,
|
currentData: currentData,
|
||||||
previousData: previousData,
|
previousData: previousData,
|
||||||
isLoaded: isLoaded,
|
isLoaded: isLoaded,
|
||||||
|
|
@ -419,8 +531,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
@required Function(List<String>) onDateSelected,
|
@required Function(List<String>) onDateSelected,
|
||||||
}) {
|
}) {
|
||||||
final settings = viewModel.dashboardUIState.settings;
|
final settings = widget.viewModel.dashboardUIState.settings;
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final isLoaded = state.isLoaded || state.taskState.list.isNotEmpty;
|
final isLoaded = state.isLoaded || state.taskState.list.isNotEmpty;
|
||||||
final currentData = memoizedChartTasks(
|
final currentData = memoizedChartTasks(
|
||||||
state.staticState.currencyMap,
|
state.staticState.currencyMap,
|
||||||
|
|
@ -448,7 +560,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return _DashboardPanel(
|
return _DashboardPanel(
|
||||||
viewModel: viewModel,
|
viewModel: widget.viewModel,
|
||||||
currentData: currentData,
|
currentData: currentData,
|
||||||
previousData: previousData,
|
previousData: previousData,
|
||||||
isLoaded: isLoaded,
|
isLoaded: isLoaded,
|
||||||
|
|
@ -462,8 +574,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
@required Function(List<String>) onDateSelected,
|
@required Function(List<String>) onDateSelected,
|
||||||
}) {
|
}) {
|
||||||
final settings = viewModel.dashboardUIState.settings;
|
final settings = widget.viewModel.dashboardUIState.settings;
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final isLoaded = state.isLoaded || state.expenseState.list.isNotEmpty;
|
final isLoaded = state.isLoaded || state.expenseState.list.isNotEmpty;
|
||||||
final currentData = memoizedChartExpenses(
|
final currentData = memoizedChartExpenses(
|
||||||
state.staticState.currencyMap,
|
state.staticState.currencyMap,
|
||||||
|
|
@ -483,7 +595,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return _DashboardPanel(
|
return _DashboardPanel(
|
||||||
viewModel: viewModel,
|
viewModel: widget.viewModel,
|
||||||
currentData: currentData,
|
currentData: currentData,
|
||||||
previousData: previousData,
|
previousData: previousData,
|
||||||
isLoaded: isLoaded,
|
isLoaded: isLoaded,
|
||||||
|
|
@ -494,7 +606,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _runningTasks(BuildContext context) {
|
Widget _runningTasks(BuildContext context) {
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
|
|
||||||
final runningTasks =
|
final runningTasks =
|
||||||
memoizedRunningTasks(state.taskState.map, state.user.id);
|
memoizedRunningTasks(state.taskState.map, state.user.id);
|
||||||
|
|
@ -553,7 +665,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final company = state.company;
|
final company = state.company;
|
||||||
final localization = AppLocalization.of(context);
|
final localization = AppLocalization.of(context);
|
||||||
final runningTasks = _runningTasks(context);
|
final runningTasks = _runningTasks(context);
|
||||||
|
|
@ -582,7 +694,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: kTopBottomBarHeight),
|
padding: const EdgeInsets.only(top: kTopBottomBarHeight),
|
||||||
child: ScrollableListViewBuilder(
|
child: ScrollableListViewBuilder(
|
||||||
scrollController: scrollController,
|
scrollController: widget.scrollController,
|
||||||
itemCount: sections.length + 1,
|
itemCount: sections.length + 1,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == sections.length) {
|
if (index == sections.length) {
|
||||||
|
|
@ -645,8 +757,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
case DashboardSections.overview:
|
case DashboardSections.overview:
|
||||||
final settings = viewModel.dashboardUIState.settings;
|
final settings = widget.viewModel.dashboardUIState.settings;
|
||||||
final state = viewModel.state;
|
final state = widget.viewModel.state;
|
||||||
final isLoaded =
|
final isLoaded =
|
||||||
state.isLoaded || state.invoiceState.list.isNotEmpty;
|
state.isLoaded || state.invoiceState.list.isNotEmpty;
|
||||||
|
|
||||||
|
|
@ -701,7 +813,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_OverviewPanel(
|
_OverviewPanel(
|
||||||
viewModel: viewModel,
|
viewModel: widget.viewModel,
|
||||||
title: localization.overview,
|
title: localization.overview,
|
||||||
invoiceData: invoiceData,
|
invoiceData: invoiceData,
|
||||||
paymentData: paymentData,
|
paymentData: paymentData,
|
||||||
|
|
@ -713,27 +825,27 @@ class DashboardPanels extends StatelessWidget {
|
||||||
case DashboardSections.invoices:
|
case DashboardSections.invoices:
|
||||||
return _invoiceChart(
|
return _invoiceChart(
|
||||||
context: context,
|
context: context,
|
||||||
onDateSelected: (entityIds) => viewModel
|
onDateSelected: (entityIds) => widget.viewModel
|
||||||
.onSelectionChanged(EntityType.invoice, entityIds));
|
.onSelectionChanged(EntityType.invoice, entityIds));
|
||||||
case DashboardSections.payments:
|
case DashboardSections.payments:
|
||||||
return _paymentChart(
|
return _paymentChart(
|
||||||
context: context,
|
context: context,
|
||||||
onDateSelected: (entityIds) => viewModel
|
onDateSelected: (entityIds) => widget.viewModel
|
||||||
.onSelectionChanged(EntityType.payment, entityIds));
|
.onSelectionChanged(EntityType.payment, entityIds));
|
||||||
case DashboardSections.quotes:
|
case DashboardSections.quotes:
|
||||||
return _quoteChart(
|
return _quoteChart(
|
||||||
context: context,
|
context: context,
|
||||||
onDateSelected: (entityIds) => viewModel
|
onDateSelected: (entityIds) => widget.viewModel
|
||||||
.onSelectionChanged(EntityType.quote, entityIds));
|
.onSelectionChanged(EntityType.quote, entityIds));
|
||||||
case DashboardSections.tasks:
|
case DashboardSections.tasks:
|
||||||
return _taskChart(
|
return _taskChart(
|
||||||
context: context,
|
context: context,
|
||||||
onDateSelected: (entityIds) => viewModel
|
onDateSelected: (entityIds) => widget.viewModel
|
||||||
.onSelectionChanged(EntityType.task, entityIds));
|
.onSelectionChanged(EntityType.task, entityIds));
|
||||||
case DashboardSections.expenses:
|
case DashboardSections.expenses:
|
||||||
return _expenseChart(
|
return _expenseChart(
|
||||||
context: context,
|
context: context,
|
||||||
onDateSelected: (entityIds) => viewModel
|
onDateSelected: (entityIds) => widget.viewModel
|
||||||
.onSelectionChanged(EntityType.expense, entityIds));
|
.onSelectionChanged(EntityType.expense, entityIds));
|
||||||
case DashboardSections.runningTasks:
|
case DashboardSections.runningTasks:
|
||||||
return runningTasks;
|
return runningTasks;
|
||||||
|
|
@ -984,143 +1096,3 @@ class __OverviewPanelState extends State<_OverviewPanel> {
|
||||||
return chart;
|
return chart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DashboardTotalsSettings extends StatefulWidget {
|
|
||||||
const _DashboardTotalsSettings({Key key, @required this.viewModel})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final DashboardVM viewModel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<_DashboardTotalsSettings> createState() =>
|
|
||||||
_DashboardTotalsSettingsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DashboardTotalsSettingsState extends State<_DashboardTotalsSettings> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final localization = AppLocalization.of(context);
|
|
||||||
final store = StoreProvider.of<AppState>(context);
|
|
||||||
final state = store.state;
|
|
||||||
final company = state.company;
|
|
||||||
final settings = state.dashboardUIState.settings;
|
|
||||||
|
|
||||||
final List<DropdownMenuItem<String>> items = [];
|
|
||||||
final fieldMap = {
|
|
||||||
EntityType.invoice: [
|
|
||||||
DashboardUISettings.FIELD_ACTIVE_INVOICES,
|
|
||||||
DashboardUISettings.FIELD_OUTSTANDING_INVOICES,
|
|
||||||
],
|
|
||||||
EntityType.payment: [
|
|
||||||
DashboardUISettings.FIELD_COMPLETED_PAYMENTS,
|
|
||||||
DashboardUISettings.FIELD_REFUNDED_PAYMENTS,
|
|
||||||
],
|
|
||||||
EntityType.quote: [
|
|
||||||
DashboardUISettings.FIELD_ACTIVE_QUOTES,
|
|
||||||
DashboardUISettings.FIELD_APPROVED_QUOTES,
|
|
||||||
DashboardUISettings.FIELD_UNAPPROVED_QUOTES,
|
|
||||||
],
|
|
||||||
EntityType.task: [
|
|
||||||
DashboardUISettings.FIELD_LOGGED_TASKS,
|
|
||||||
DashboardUISettings.FIELD_INVOICED_TASKS,
|
|
||||||
DashboardUISettings.FIELD_PAID_TASKS,
|
|
||||||
],
|
|
||||||
EntityType.expense: [
|
|
||||||
DashboardUISettings.FIELD_LOGGED_EXPENSES,
|
|
||||||
DashboardUISettings.FIELD_PENDING_EXPENSES,
|
|
||||||
DashboardUISettings.FIELD_INVOICED_EXPENSES,
|
|
||||||
DashboardUISettings.FIELD_INVOICE_PAID_EXPENSES,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
fieldMap.forEach((entityType, fields) {
|
|
||||||
fields.forEach((field) {
|
|
||||||
if (company.isModuleEnabled(entityType) &&
|
|
||||||
!settings.totalFields.contains(field)) {
|
|
||||||
items.add(DropdownMenuItem<String>(
|
|
||||||
child: Text(localization.lookup(field)),
|
|
||||||
value: field,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
for (var field in settings.totalFields)
|
|
||||||
ListTile(
|
|
||||||
title: Text(localization.lookup(field)),
|
|
||||||
trailing: IconButton(
|
|
||||||
icon: Icon(Icons.close),
|
|
||||||
onPressed: () {
|
|
||||||
store.dispatch(UpdateDashboardSettings(
|
|
||||||
totalFields:
|
|
||||||
settings.totalFields.rebuild((b) => b..remove(field))));
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16, right: 24),
|
|
||||||
child: DropdownButtonHideUnderline(
|
|
||||||
child: DropdownButton<String>(
|
|
||||||
isExpanded: true,
|
|
||||||
onChanged: (value) {
|
|
||||||
store.dispatch(UpdateDashboardSettings(
|
|
||||||
totalFields:
|
|
||||||
settings.totalFields.rebuild((b) => b..add(value))));
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
hint: Text(localization.addField),
|
|
||||||
items: items,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
value: settings.showCurrentPeriod,
|
|
||||||
onChanged: (value) {
|
|
||||||
store.dispatch(UpdateDashboardSettings(showCurrentPeriod: value));
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
title: Text(localization.currentPeriod),
|
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
value: settings.showPreviousPeriod,
|
|
||||||
onChanged: (value) {
|
|
||||||
store.dispatch(UpdateDashboardSettings(showPreviousPeriod: value));
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
title: Text(localization.previousPeriod),
|
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
value: settings.showTotal,
|
|
||||||
onChanged: (value) {
|
|
||||||
store.dispatch(UpdateDashboardSettings(showTotal: value));
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
title: Text(localization.total),
|
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16, right: 24),
|
|
||||||
child: AppDropdownButton<int>(
|
|
||||||
labelText: localization.fieldsPerRow,
|
|
||||||
value: settings.numberFieldsPerRow,
|
|
||||||
onChanged: (dynamic value) {
|
|
||||||
store.dispatch(
|
|
||||||
UpdateDashboardSettings(numberFieldsPerRow: value));
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
items: List<int>.generate(8, (i) => i + 1)
|
|
||||||
.map((value) => DropdownMenuItem<int>(
|
|
||||||
child: Text('$value'),
|
|
||||||
value: value,
|
|
||||||
))
|
|
||||||
.toList()),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue