diff --git a/README.md b/README.md index 917ff827d..b4edb6e15 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ Join the Android beta: https://play.google.com/apps/testing/com.invoiceninja.inv - [x] Clients - [x] Products - [x] Invoices +- [x] Quotes - [ ] Payments -- [ ] Quotes - [ ] Credits - [ ] Recurring - [ ] Vendors diff --git a/lib/main.dart b/lib/main.dart index 7f4353867..f783dd0b8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,8 @@ import 'package:intl/intl.dart'; import 'package:invoiceninja_flutter/redux/company/company_selectors.dart'; import 'package:invoiceninja_flutter/ui/app/app_builder.dart'; -import 'package:invoiceninja_flutter/ui/app/invoice/invoice_email_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_email_vm.dart'; +import 'package:invoiceninja_flutter/ui/quote/quote_email_vm.dart'; import 'package:redux/redux.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter/material.dart'; @@ -146,6 +147,7 @@ class InvoiceNinjaAppState extends State { }, QuoteViewScreen.route: (context) => QuoteViewScreen(), QuoteEditScreen.route: (context) => QuoteEditScreen(), + QuoteEmailScreen.route: (context) => QuoteEmailScreen(), SettingsScreen.route: (context) => SettingsScreen(), }, ); diff --git a/lib/redux/invoice/invoice_middleware.dart b/lib/redux/invoice/invoice_middleware.dart index 0bb953719..43b5c8338 100644 --- a/lib/redux/invoice/invoice_middleware.dart +++ b/lib/redux/invoice/invoice_middleware.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; -import 'package:invoiceninja_flutter/ui/app/invoice/invoice_email_vm.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_screen.dart'; import 'package:invoiceninja_flutter/ui/invoice/view/invoice_view_vm.dart'; diff --git a/lib/redux/quote/quote_middleware.dart b/lib/redux/quote/quote_middleware.dart index cd483dc27..217bdae4b 100644 --- a/lib/redux/quote/quote_middleware.dart +++ b/lib/redux/quote/quote_middleware.dart @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; -import 'package:invoiceninja_flutter/ui/app/invoice/invoice_email_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_email_vm.dart'; import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/quote/quote_email_vm.dart'; import 'package:invoiceninja_flutter/ui/quote/quote_screen.dart'; import 'package:invoiceninja_flutter/ui/quote/view/quote_view_vm.dart'; import 'package:redux/redux.dart'; @@ -68,7 +69,7 @@ Middleware _editQuote() { store.dispatch(UpdateCurrentRoute(QuoteEditScreen.route)); final quote = - await Navigator.of(action.context).pushNamed(QuoteEditScreen.route); + await Navigator.of(action.context).pushNamed(QuoteEditScreen.route); if (action.completer != null && quote != null) { action.completer.complete(quote); @@ -80,7 +81,8 @@ Middleware _showEmailQuote() { return (Store store, dynamic action, NextDispatcher next) async { next(action); - final emailWasSent = await Navigator.of(action.context).pushNamed(InvoiceEmailScreen.route); + final emailWasSent = + await Navigator.of(action.context).pushNamed(QuoteEmailScreen.route); if (action.completer != null && emailWasSent) { action.completer.complete(null); @@ -92,8 +94,8 @@ Middleware _archiveQuote(QuoteRepository repository) { return (Store store, dynamic action, NextDispatcher next) { final origQuote = store.state.quoteState.map[action.quoteId]; repository - .saveData(store.state.selectedCompany, store.state.authState, - origQuote, EntityAction.archive) + .saveData(store.state.selectedCompany, store.state.authState, origQuote, + EntityAction.archive) .then((dynamic quote) { store.dispatch(ArchiveQuoteSuccess(quote)); if (action.completer != null) { @@ -115,8 +117,8 @@ Middleware _deleteQuote(QuoteRepository repository) { return (Store store, dynamic action, NextDispatcher next) { final origQuote = store.state.quoteState.map[action.quoteId]; repository - .saveData(store.state.selectedCompany, store.state.authState, - origQuote, EntityAction.delete) + .saveData(store.state.selectedCompany, store.state.authState, origQuote, + EntityAction.delete) .then((InvoiceEntity quote) { store.dispatch(DeleteQuoteSuccess(quote)); store.dispatch(LoadClient(clientId: quote.clientId)); @@ -139,8 +141,8 @@ Middleware _restoreQuote(QuoteRepository repository) { return (Store store, dynamic action, NextDispatcher next) { final origQuote = store.state.quoteState.map[action.quoteId]; repository - .saveData(store.state.selectedCompany, store.state.authState, - origQuote, EntityAction.restore) + .saveData(store.state.selectedCompany, store.state.authState, origQuote, + EntityAction.restore) .then((InvoiceEntity quote) { store.dispatch(RestoreQuoteSuccess(quote)); store.dispatch(LoadClient(clientId: quote.clientId)); @@ -163,8 +165,8 @@ Middleware _markSentQuote(QuoteRepository repository) { return (Store store, dynamic action, NextDispatcher next) { final origQuote = store.state.quoteState.map[action.quoteId]; repository - .saveData(store.state.selectedCompany, store.state.authState, - origQuote, EntityAction.markSent) + .saveData(store.state.selectedCompany, store.state.authState, origQuote, + EntityAction.markSent) .then((dynamic quote) { store.dispatch(MarkSentQuoteSuccess(quote)); store.dispatch(LoadClient(clientId: quote.clientId)); @@ -212,7 +214,7 @@ Middleware _saveQuote(QuoteRepository repository) { return (Store store, dynamic action, NextDispatcher next) { repository .saveData( - store.state.selectedCompany, store.state.authState, action.quote) + store.state.selectedCompany, store.state.authState, action.quote) .then((dynamic quote) { if (action.quote.isNew) { store.dispatch(AddQuoteSuccess(quote)); @@ -275,7 +277,7 @@ Middleware _loadQuotes(QuoteRepository repository) { } final int updatedAt = - action.force ? 0 : (state.quoteState.lastUpdated / 1000).round(); + action.force ? 0 : (state.quoteState.lastUpdated / 1000).round(); store.dispatch(LoadQuotesRequest()); repository diff --git a/lib/ui/app/invoice/invoice_email_view.dart b/lib/ui/app/invoice/invoice_email_view.dart index dc2d4b6d6..d5c23095e 100644 --- a/lib/ui/app/invoice/invoice_email_view.dart +++ b/lib/ui/app/invoice/invoice_email_view.dart @@ -2,7 +2,7 @@ import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/refresh_icon_button.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart'; -import 'package:invoiceninja_flutter/ui/app/invoice/invoice_email_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/invoice_email_vm.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:invoiceninja_flutter/ui/app/lists/activity_list_tile.dart'; @@ -14,7 +14,7 @@ import 'package:invoiceninja_flutter/utils/templates.dart'; import 'package:html/parser.dart'; class InvoiceEmailView extends StatefulWidget { - final EmailInvoiceVM viewModel; + final EmailEntityVM viewModel; const InvoiceEmailView({ Key key, @@ -68,14 +68,20 @@ class _InvoiceEmailViewState extends State { } void loadTemplate(EmailTemplate template) { - final company = widget.viewModel.company; + final viewModel = widget.viewModel; + final company = viewModel.company; selectedTemplate = template; switch (template) { case EmailTemplate.initial: - emailSubject = company.emailSubjectInvoice; - emailBody = company.emailBodyInvoice; + if (viewModel.invoice.isQuote) { + emailSubject = company.emailSubjectQuote; + emailBody = company.emailBodyQuote; + } else { + emailSubject = company.emailSubjectInvoice; + emailBody = company.emailBodyInvoice; + } break; case EmailTemplate.reminder1: emailSubject = company.emailSubjectReminder1; diff --git a/lib/ui/app/invoice/invoice_email_vm.dart b/lib/ui/invoice/invoice_email_vm.dart similarity index 85% rename from lib/ui/app/invoice/invoice_email_vm.dart rename to lib/ui/invoice/invoice_email_vm.dart index 2e897dd8f..ffc93358e 100644 --- a/lib/ui/app/invoice/invoice_email_vm.dart +++ b/lib/ui/invoice/invoice_email_vm.dart @@ -41,7 +41,7 @@ class InvoiceEmailScreen extends StatelessWidget { } } -class EmailInvoiceVM { +abstract class EmailEntityVM { final bool isLoading; final bool isSaving; final CompanyEntity company; @@ -49,7 +49,7 @@ class EmailInvoiceVM { final ClientEntity client; final Function(BuildContext, EmailTemplate, String, String) onSendPressed; - EmailInvoiceVM({ + EmailEntityVM({ @required this.isLoading, @required this.isSaving, @required this.company, @@ -57,6 +57,25 @@ class EmailInvoiceVM { @required this.client, @required this.onSendPressed, }); +} + +class EmailInvoiceVM extends EmailEntityVM { + + EmailInvoiceVM({ + bool isLoading, + bool isSaving, + CompanyEntity company, + InvoiceEntity invoice, + ClientEntity client, + Function(BuildContext, EmailTemplate, String, String) onSendPressed, + }): super( + isLoading: isLoading, + isSaving: isSaving, + company: company, + invoice: invoice, + client: client, + onSendPressed: onSendPressed, + ); factory EmailInvoiceVM.fromStore( Store store, InvoiceEntity invoice) { diff --git a/lib/ui/quote/view/quote_view.dart b/lib/ui/quote/view/quote_view.dart index 850ac2406..b0fe5a51c 100644 --- a/lib/ui/quote/view/quote_view.dart +++ b/lib/ui/quote/view/quote_view.dart @@ -9,7 +9,6 @@ import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart'; import 'package:invoiceninja_flutter/ui/app/icon_message.dart'; import 'package:invoiceninja_flutter/ui/app/invoice/invoice_item_view.dart'; -import 'package:invoiceninja_flutter/ui/app/two_value_header.dart'; import 'package:invoiceninja_flutter/ui/quote/view/quote_view_vm.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';