diff --git a/lib/main_app.dart b/lib/main_app.dart index e9e3be2df..7b72c1d98 100644 --- a/lib/main_app.dart +++ b/lib/main_app.dart @@ -29,6 +29,7 @@ import 'package:invoiceninja_flutter/ui/design/design_screen.dart'; import 'package:invoiceninja_flutter/ui/design/design_screen_vm.dart'; import 'package:invoiceninja_flutter/ui/design/edit/design_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/design/view/design_view_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf_vm.dart'; import 'package:invoiceninja_flutter/ui/payment/refund/payment_refund_vm.dart'; import 'package:invoiceninja_flutter/ui/payment_term/edit/payment_term_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/payment_term/payment_term_screen.dart'; @@ -298,6 +299,7 @@ class InvoiceNinjaAppState extends State { InvoiceViewScreen.route: (context) => InvoiceViewScreen(), InvoiceEditScreen.route: (context) => InvoiceEditScreen(), InvoiceEmailScreen.route: (context) => InvoiceEmailScreen(), + InvoicePdfScreen.route: (context) => InvoicePdfScreen(), DocumentScreen.route: (context) => DocumentScreenBuilder(), DocumentViewScreen.route: (context) => DocumentViewScreen(), DocumentEditScreen.route: (context) => DocumentEditScreen(), diff --git a/lib/redux/invoice/invoice_actions.dart b/lib/redux/invoice/invoice_actions.dart index be9416c45..07aec1cad 100644 --- a/lib/redux/invoice/invoice_actions.dart +++ b/lib/redux/invoice/invoice_actions.dart @@ -56,6 +56,13 @@ class ShowEmailInvoice { final Completer completer; } +class ShowPdfInvoice { + ShowPdfInvoice({this.invoice, this.context}); + + final InvoiceEntity invoice; + final BuildContext context; +} + class EditInvoiceItem implements PersistUI { EditInvoiceItem([this.invoiceItemIndex]); @@ -484,7 +491,7 @@ void handleInvoiceAction(BuildContext context, List invoices, editEntity(context: context, entity: invoice); break; case EntityAction.viewPdf: - viewPdf(invoice, context); + store.dispatch(ShowPdfInvoice(invoice: invoice, context: context)); break; case EntityAction.clientPortal: if (await canLaunch(invoice.invitationSilentLink)) { diff --git a/lib/redux/invoice/invoice_middleware.dart b/lib/redux/invoice/invoice_middleware.dart index 3b78a791b..840b89745 100644 --- a/lib/redux/invoice/invoice_middleware.dart +++ b/lib/redux/invoice/invoice_middleware.dart @@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_a import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; import 'package:invoiceninja_flutter/ui/invoice/invoice_email_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/invoice_screen.dart'; import 'package:invoiceninja_flutter/ui/invoice/view/invoice_view_vm.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; @@ -21,6 +22,7 @@ List> createStoreInvoicesMiddleware([ final viewInvoice = _viewInvoice(); final editInvoice = _editInvoice(); final showEmailInvoice = _showEmailInvoice(); + final showPdfInvoice = _showPdfInvoice(); final loadInvoices = _loadInvoices(repository); final loadInvoice = _loadInvoice(repository); final saveInvoice = _saveInvoice(repository); @@ -40,6 +42,7 @@ List> createStoreInvoicesMiddleware([ TypedMiddleware(viewInvoice), TypedMiddleware(editInvoice), TypedMiddleware(showEmailInvoice), + TypedMiddleware(showPdfInvoice), TypedMiddleware(loadInvoices), TypedMiddleware(loadInvoice), TypedMiddleware(saveInvoice), @@ -124,6 +127,21 @@ Middleware _showEmailInvoice() { }; } +Middleware _showPdfInvoice() { + return (Store store, dynamic dynamicAction, + NextDispatcher next) async { + final action = dynamicAction as ShowPdfInvoice; + + next(action); + + store.dispatch(UpdateCurrentRoute(InvoicePdfScreen.route)); + + if (isMobile(action.context)) { + Navigator.of(action.context).pushNamed(InvoicePdfScreen.route); + } + }; +} + Middleware _cancelInvoices(InvoiceRepository repository) { return (Store store, dynamic dynamicAction, NextDispatcher next) { final action = dynamicAction as CancelInvoicesRequest; diff --git a/lib/redux/invoice/invoice_reducer.dart b/lib/redux/invoice/invoice_reducer.dart index b3e8c41ae..1e120359c 100644 --- a/lib/redux/invoice/invoice_reducer.dart +++ b/lib/redux/invoice/invoice_reducer.dart @@ -41,6 +41,8 @@ Reducer selectedIdReducer = combineReducers([ (selectedId, action) => action.invoice.id), TypedReducer( (selectedId, action) => action.invoice.id), + TypedReducer( + (selectedId, action) => action.invoice.id), TypedReducer( (selectedId, action) => action.clearSelection ? '' : selectedId), TypedReducer((selectedId, action) => ''), diff --git a/lib/ui/app/main_screen.dart b/lib/ui/app/main_screen.dart index 48a1e4be6..b0e5f768c 100644 --- a/lib/ui/app/main_screen.dart +++ b/lib/ui/app/main_screen.dart @@ -26,6 +26,7 @@ import 'package:invoiceninja_flutter/ui/design/view/design_view_vm.dart'; import 'package:invoiceninja_flutter/ui/expense_category/edit/expense_category_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/expense_category/expense_category_screen_vm.dart'; import 'package:invoiceninja_flutter/ui/expense_category/view/expense_category_view_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf_vm.dart'; import 'package:invoiceninja_flutter/ui/payment_term/edit/payment_term_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/payment_term/payment_term_screen_vm.dart'; import 'package:invoiceninja_flutter/ui/payment_term/view/payment_term_view_vm.dart'; @@ -73,6 +74,7 @@ class MainScreen extends StatelessWidget { bool isFullScreen = false; final isEdit = subRoute == '/edit'; final isEmail = subRoute == '/email'; + final isPdf = subRoute == '/pdf'; if ([ InvoiceScreen.route, @@ -81,7 +83,7 @@ class MainScreen extends StatelessWidget { RecurringInvoiceScreen.route, TaskScreen.route, ].contains(mainRoute)) { - if (isEmail) { + if (isEmail || isPdf) { isFullScreen = true; } else if (isEdit) { if (mainRoute == TaskScreen.route) { @@ -99,16 +101,28 @@ class MainScreen extends StatelessWidget { if (isFullScreen) { switch (mainRoute) { case InvoiceScreen.route: - screen = isEmail ? InvoiceEmailScreen() : InvoiceEditScreen(); + screen = isPdf + ? InvoicePdfScreen() + : isEmail + ? InvoiceEmailScreen() + : InvoiceEditScreen(); break; case QuoteScreen.route: - screen = isEmail ? QuoteEmailScreen() : QuoteEditScreen(); + screen = isPdf + ? Placeholder() + : isEmail + ? QuoteEmailScreen() + : QuoteEditScreen(); break; case CreditScreen.route: - screen = isEmail ? CreditEmailScreen() : CreditEditScreen(); + screen = isPdf + ? Placeholder() + : isEmail + ? CreditEmailScreen() + : CreditEditScreen(); break; case RecurringInvoiceScreen.route: - screen = RecurringInvoiceEditScreen(); + screen = isPdf ? Placeholder() : RecurringInvoiceEditScreen(); break; case TaskScreen.route: screen = TaskEditScreen(); diff --git a/lib/ui/invoice/invoice_pdf.dart b/lib/ui/invoice/invoice_pdf.dart new file mode 100644 index 000000000..8990c28d7 --- /dev/null +++ b/lib/ui/invoice/invoice_pdf.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf_vm.dart'; +import 'package:invoiceninja_flutter/utils/pdf.dart'; + +class InvoicePdfView extends StatelessWidget { + const InvoicePdfView({Key key, this.viewModel}) : super(key: key); + + final EntityPdfVM viewModel; + + @override + Widget build(BuildContext context) { + return PDFScaffold(invoice: viewModel.invoice); + } +} diff --git a/lib/ui/invoice/invoice_pdf_vm.dart b/lib/ui/invoice/invoice_pdf_vm.dart new file mode 100644 index 000000000..7cd4193c5 --- /dev/null +++ b/lib/ui/invoice/invoice_pdf_vm.dart @@ -0,0 +1,59 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_redux/flutter_redux.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf.dart'; +import 'package:redux/redux.dart'; +import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/redux/app/app_state.dart'; + +class InvoicePdfScreen extends StatelessWidget { + const InvoicePdfScreen({Key key}) : super(key: key); + + static const String route = '/invoice/pdf'; + + @override + Widget build(BuildContext context) { + return StoreConnector( + converter: (Store store) { + return InvoicePdfVM.fromStore(store); + }, + builder: (context, vm) { + return InvoicePdfView( + key: ValueKey('__invoice_pdf_${vm.invoice.id}__'), + viewModel: vm, + ); + }, + ); + } +} + +abstract class EntityPdfVM { + EntityPdfVM({ + @required this.state, + @required this.invoice, + }); + + final AppState state; + final InvoiceEntity invoice; +} + +class InvoicePdfVM extends EntityPdfVM { + InvoicePdfVM({ + AppState state, + InvoiceEntity invoice, + }) : super( + state: state, + invoice: invoice, + ); + + factory InvoicePdfVM.fromStore(Store store) { + final state = store.state; + final invoiceId = state.uiState.invoiceUIState.selectedId; + final invoice = state.invoiceState.get(invoiceId); + + return InvoicePdfVM( + state: state, + invoice: invoice, + ); + } +}