Add designs templates
This commit is contained in:
parent
2490e21207
commit
4a3c5a1e0b
|
|
@ -4,6 +4,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
// Flutter imports:
|
// Flutter imports:
|
||||||
import 'package:built_collection/built_collection.dart';
|
import 'package:built_collection/built_collection.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
// Package imports:
|
// Package imports:
|
||||||
|
|
@ -19,6 +20,7 @@ import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
|
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/forms/date_picker.dart';
|
import 'package:invoiceninja_flutter/ui/app/forms/date_picker.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/multiselect.dart';
|
import 'package:invoiceninja_flutter/ui/app/multiselect.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/files.dart';
|
import 'package:invoiceninja_flutter/utils/files.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||||
import 'package:printing/printing.dart';
|
import 'package:printing/printing.dart';
|
||||||
|
|
@ -37,6 +39,9 @@ import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
||||||
|
|
||||||
|
import 'package:invoiceninja_flutter/utils/web_stub.dart'
|
||||||
|
if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart';
|
||||||
|
|
||||||
class ClientPdfView extends StatefulWidget {
|
class ClientPdfView extends StatefulWidget {
|
||||||
const ClientPdfView({
|
const ClientPdfView({
|
||||||
Key? key,
|
Key? key,
|
||||||
|
|
@ -62,6 +67,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
convertDateTimeToSqlDate(DateTime.now().subtract(Duration(days: 365)));
|
convertDateTimeToSqlDate(DateTime.now().subtract(Duration(days: 365)));
|
||||||
String? _endDate = convertDateTimeToSqlDate();
|
String? _endDate = convertDateTimeToSqlDate();
|
||||||
String _status = kStatementStatusAll;
|
String _status = kStatementStatusAll;
|
||||||
|
String? _pdfString;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -85,6 +91,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
final localization = AppLocalization.of(context);
|
final localization = AppLocalization.of(context);
|
||||||
|
final state = widget.viewModel.state;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
|
|
@ -98,6 +105,12 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_response = response;
|
_response = response;
|
||||||
|
|
||||||
|
if (kIsWeb && state.prefState.enableNativeBrowser) {
|
||||||
|
_pdfString = 'data:application/pdf;base64,' +
|
||||||
|
base64Encode(response!.bodyBytes);
|
||||||
|
WebUtils.registerWebView(_pdfString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
|
|
@ -172,8 +185,88 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final store = StoreProvider.of<AppState>(context);
|
final store = StoreProvider.of<AppState>(context);
|
||||||
final state = store.state;
|
final state = store.state;
|
||||||
final localization = AppLocalization.of(context);
|
final localization = AppLocalization.of(context)!;
|
||||||
final client = widget.viewModel.client;
|
final client = widget.viewModel.client!;
|
||||||
|
|
||||||
|
final datePicker = Flexible(
|
||||||
|
child: Theme(
|
||||||
|
data: state.prefState.enableDarkMode || state.hasAccentColor
|
||||||
|
? ThemeData.dark()
|
||||||
|
: ThemeData.light(),
|
||||||
|
child: AppDropdownButton<DateRange>(
|
||||||
|
labelText: localization.dateRange,
|
||||||
|
blankValue: null,
|
||||||
|
//showBlank: true,
|
||||||
|
value: _dateRange,
|
||||||
|
onChanged: (dynamic value) {
|
||||||
|
setState(() {
|
||||||
|
_dateRange = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value != DateRange.custom) {
|
||||||
|
loadPDF();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
items: DateRange.values
|
||||||
|
.where((value) => value != DateRange.allTime)
|
||||||
|
.map((dateRange) => DropdownMenuItem<DateRange>(
|
||||||
|
child: Text(localization.lookup(dateRange.toString())),
|
||||||
|
value: dateRange,
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final statusPicker = Flexible(
|
||||||
|
child: Theme(
|
||||||
|
data: state.prefState.enableDarkMode || state.hasAccentColor
|
||||||
|
? ThemeData.dark()
|
||||||
|
: ThemeData.light(),
|
||||||
|
child: AppDropdownButton<String>(
|
||||||
|
labelText: localization.status,
|
||||||
|
blankValue: null,
|
||||||
|
value: _status,
|
||||||
|
onChanged: (dynamic value) {
|
||||||
|
setState(() {
|
||||||
|
_status = value;
|
||||||
|
});
|
||||||
|
loadPDF();
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
kStatementStatusAll,
|
||||||
|
kStatementStatusPaid,
|
||||||
|
kStatementStatusUnpaid,
|
||||||
|
]
|
||||||
|
.map((value) => DropdownMenuItem<String>(
|
||||||
|
child: Text(localization.lookup(value)),
|
||||||
|
value: value,
|
||||||
|
))
|
||||||
|
.toList()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final sectionPicker = Flexible(
|
||||||
|
child: DropDownMultiSelect(
|
||||||
|
onChanged: (List<dynamic> selected) {
|
||||||
|
//_selectedOptions = selected;
|
||||||
|
store.dispatch(UpdateUserPreferences(
|
||||||
|
statementIncludes: BuiltList<String>(selected)));
|
||||||
|
loadPDF();
|
||||||
|
},
|
||||||
|
selectedValues: state.prefState.statementIncludes.toList(),
|
||||||
|
menuItembuilder: (dynamic option) => Text(
|
||||||
|
localization.lookup(option),
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
isDense: true,
|
||||||
|
options: <String>[
|
||||||
|
kStatementIncludePayments,
|
||||||
|
kStatementIncludeCredits,
|
||||||
|
kStatementIncludeAging,
|
||||||
|
],
|
||||||
|
whenEmpty: '',
|
||||||
|
));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
final pageSelector = _pageCount == 1
|
final pageSelector = _pageCount == 1
|
||||||
|
|
@ -218,104 +311,11 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
/*
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
EntityPresenter().initialize(client, context).title(),
|
EntityPresenter().initialize(client, context).title()!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
*/
|
|
||||||
Flexible(
|
|
||||||
child: Theme(
|
|
||||||
data:
|
|
||||||
state.prefState.enableDarkMode || state.hasAccentColor
|
|
||||||
? ThemeData.dark()
|
|
||||||
: ThemeData.light(),
|
|
||||||
child: AppDropdownButton<DateRange>(
|
|
||||||
labelText: localization!.dateRange,
|
|
||||||
blankValue: null,
|
|
||||||
//showBlank: true,
|
|
||||||
value: _dateRange,
|
|
||||||
onChanged: (dynamic value) {
|
|
||||||
setState(() {
|
|
||||||
_dateRange = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (value != DateRange.custom) {
|
|
||||||
loadPDF();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
items: DateRange.values
|
|
||||||
.where((value) => value != DateRange.allTime)
|
|
||||||
.map((dateRange) => DropdownMenuItem<DateRange>(
|
|
||||||
child: Text(localization
|
|
||||||
.lookup(dateRange.toString())),
|
|
||||||
value: dateRange,
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 16),
|
|
||||||
Flexible(
|
|
||||||
child: Theme(
|
|
||||||
data:
|
|
||||||
state.prefState.enableDarkMode || state.hasAccentColor
|
|
||||||
? ThemeData.dark()
|
|
||||||
: ThemeData.light(),
|
|
||||||
child: AppDropdownButton<String>(
|
|
||||||
labelText: localization.status,
|
|
||||||
blankValue: null,
|
|
||||||
value: _status,
|
|
||||||
onChanged: (dynamic value) {
|
|
||||||
setState(() {
|
|
||||||
_status = value;
|
|
||||||
});
|
|
||||||
loadPDF();
|
|
||||||
},
|
|
||||||
items: [
|
|
||||||
kStatementStatusAll,
|
|
||||||
kStatementStatusPaid,
|
|
||||||
kStatementStatusUnpaid,
|
|
||||||
]
|
|
||||||
.map((value) => DropdownMenuItem<String>(
|
|
||||||
child: Text(localization.lookup(value)),
|
|
||||||
value: value,
|
|
||||||
))
|
|
||||||
.toList()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (isDesktop(context)) ...[
|
|
||||||
Theme(
|
|
||||||
data: ThemeData(
|
|
||||||
appBarTheme: AppBarTheme(
|
|
||||||
titleTextStyle: TextStyle(fontSize: 60),
|
|
||||||
)),
|
|
||||||
child: Flexible(
|
|
||||||
child: DropDownMultiSelect(
|
|
||||||
onChanged: (List<dynamic> selected) {
|
|
||||||
//_selectedOptions = selected;
|
|
||||||
store.dispatch(UpdateUserPreferences(
|
|
||||||
statementIncludes: BuiltList<String>(selected)));
|
|
||||||
loadPDF();
|
|
||||||
},
|
|
||||||
selectedValues:
|
|
||||||
state.prefState.statementIncludes.toList(),
|
|
||||||
menuItembuilder: (dynamic option) => Text(
|
|
||||||
localization.lookup(option),
|
|
||||||
style: TextStyle(fontSize: 14),
|
|
||||||
),
|
|
||||||
isDense: true,
|
|
||||||
options: <String>[
|
|
||||||
kStatementIncludePayments,
|
|
||||||
kStatementIncludeCredits,
|
|
||||||
kStatementIncludeAging,
|
|
||||||
],
|
|
||||||
whenEmpty: '',
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
//...pageSelector,
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
|
|
@ -327,7 +327,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
: () async {
|
: () async {
|
||||||
final fileName = localization.statement +
|
final fileName = localization.statement +
|
||||||
'_' +
|
'_' +
|
||||||
(client!.number) +
|
(client.number) +
|
||||||
'.pdf';
|
'.pdf';
|
||||||
saveDownloadedFile(_response!.bodyBytes, fileName);
|
saveDownloadedFile(_response!.bodyBytes, fileName);
|
||||||
},
|
},
|
||||||
|
|
@ -338,7 +338,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
onPressed: _response == null
|
onPressed: _response == null
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
if (!client!.hasEmailAddress) {
|
if (!client.hasEmailAddress) {
|
||||||
showMessageDialog(
|
showMessageDialog(
|
||||||
message: localization.clientEmailNotSet,
|
message: localization.clientEmailNotSet,
|
||||||
secondaryActions: [
|
secondaryActions: [
|
||||||
|
|
@ -384,7 +384,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
entity: ScheduleEntity(
|
entity: ScheduleEntity(
|
||||||
ScheduleEntity.TEMPLATE_EMAIL_STATEMENT)
|
ScheduleEntity.TEMPLATE_EMAIL_STATEMENT)
|
||||||
.rebuild((b) => b
|
.rebuild((b) => b
|
||||||
..parameters.clients.add(client!.id)
|
..parameters.clients.add(client.id)
|
||||||
..parameters.showAgingTable =
|
..parameters.showAgingTable =
|
||||||
includes.contains(localization.aging)
|
includes.contains(localization.aging)
|
||||||
..parameters.showPaymentsTable =
|
..parameters.showPaymentsTable =
|
||||||
|
|
@ -401,7 +401,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
child: Text(localization.close,
|
child: Text(localization.close,
|
||||||
style: TextStyle(color: state.headerTextColor)),
|
style: TextStyle(color: state.headerTextColor)),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
viewEntity(entity: client!);
|
viewEntity(entity: client);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -409,6 +409,20 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
: null,
|
: null,
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
|
Material(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: isDesktop(context)
|
||||||
|
? Row(
|
||||||
|
children: [
|
||||||
|
datePicker,
|
||||||
|
statusPicker,
|
||||||
|
sectionPicker,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Placeholder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
if (_dateRange == DateRange.custom)
|
if (_dateRange == DateRange.custom)
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
|
|
@ -421,7 +435,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
child: DatePicker(
|
child: DatePicker(
|
||||||
labelText: localization!.startDate,
|
labelText: localization.startDate,
|
||||||
onSelected: (value, _) {
|
onSelected: (value, _) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_startDate = value;
|
_startDate = value;
|
||||||
|
|
@ -457,15 +471,19 @@ class _ClientPdfViewState extends State<ClientPdfView> {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _isLoading || _response == null
|
child: _isLoading || _response == null
|
||||||
? LoadingIndicator()
|
? LoadingIndicator()
|
||||||
: PdfPreview(
|
: (kIsWeb && state.prefState.enableNativeBrowser)
|
||||||
build: (format) => _response!.bodyBytes,
|
? HtmlElementView(viewType: _pdfString!)
|
||||||
canChangeOrientation: false,
|
: PdfPreview(
|
||||||
canChangePageFormat: false,
|
build: (format) => _response!.bodyBytes,
|
||||||
canDebug: false,
|
canChangeOrientation: false,
|
||||||
maxPageWidth: 600,
|
canChangePageFormat: false,
|
||||||
pdfFileName:
|
canDebug: false,
|
||||||
localization!.statement + '_' + client!.number + '.pdf',
|
maxPageWidth: 600,
|
||||||
),
|
pdfFileName: localization.statement +
|
||||||
|
'_' +
|
||||||
|
client.number +
|
||||||
|
'.pdf',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,6 @@ class _InvoicePdfViewState extends State<InvoicePdfView> {
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
body: Column(
|
body: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
Material(
|
Material(
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue