From 00334fa91d57a74d235154e3e2cf193d88963d3a Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 23 Sep 2019 20:24:20 +0300 Subject: [PATCH] Fix fab/heo issue --- lib/redux/company/company_reducer.dart | 1 - lib/ui/client/client_screen.dart | 1 + lib/ui/client/view/client_view.dart | 1 + lib/ui/document/document_screen.dart | 2 +- lib/ui/expense/expense_screen.dart | 2 +- lib/ui/expense/view/expense_view.dart | 1 + lib/ui/invoice/edit/invoice_edit.dart | 28 ++--- lib/ui/invoice/invoice_screen.dart | 1 + lib/ui/payment/payment_screen.dart | 2 +- lib/ui/product/product_screen.dart | 1 + lib/ui/project/project_screen.dart | 2 +- lib/ui/project/view/project_view.dart | 1 + lib/ui/quote/edit/quote_edit_vm.dart | 4 +- lib/ui/quote/quote_edit.dart | 166 +++++++++++++++++++++++++ lib/ui/quote/quote_screen.dart | 1 + lib/ui/task/edit/task_edit.dart | 1 + lib/ui/task/task_screen.dart | 2 +- lib/ui/task/view/task_view.dart | 1 + lib/ui/vendor/vendor_screen.dart | 2 +- lib/ui/vendor/view/vendor_view.dart | 1 + stubs/ui/stub/stub_screen | 2 +- 21 files changed, 193 insertions(+), 30 deletions(-) create mode 100644 lib/ui/quote/quote_edit.dart diff --git a/lib/redux/company/company_reducer.dart b/lib/redux/company/company_reducer.dart index 72a926570..d61b8de36 100644 --- a/lib/redux/company/company_reducer.dart +++ b/lib/redux/company/company_reducer.dart @@ -15,7 +15,6 @@ import 'package:invoiceninja_flutter/redux/task/task_reducer.dart'; import 'package:invoiceninja_flutter/redux/project/project_reducer.dart'; import 'package:invoiceninja_flutter/redux/payment/payment_reducer.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_reducer.dart'; -import 'package:sentry/sentry.dart'; // STARTER: import - do not remove comment UserCompanyState companyReducer(UserCompanyState state, dynamic action) { diff --git a/lib/ui/client/client_screen.dart b/lib/ui/client/client_screen.dart index 07767caaf..8aea49734 100644 --- a/lib/ui/client/client_screen.dart +++ b/lib/ui/client/client_screen.dart @@ -62,6 +62,7 @@ class ClientScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.client) ? FloatingActionButton( + heroTag: 'client_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () => store.dispatch( EditClient(client: ClientEntity(), context: context)), diff --git a/lib/ui/client/view/client_view.dart b/lib/ui/client/view/client_view.dart index 8bd1c88b0..ce17589a2 100644 --- a/lib/ui/client/view/client_view.dart +++ b/lib/ui/client/view/client_view.dart @@ -71,6 +71,7 @@ class _ClientViewState extends State controller: _controller, ), floatingActionButton: FloatingActionButton( + heroTag: 'client_view_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { showDialog( diff --git a/lib/ui/document/document_screen.dart b/lib/ui/document/document_screen.dart index 26714f506..a0847cef7 100644 --- a/lib/ui/document/document_screen.dart +++ b/lib/ui/document/document_screen.dart @@ -53,7 +53,7 @@ class DocumentScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.document) ? FloatingActionButton( - //key: Key(DocumentKeys.documentScreenFABKeyString), + heroTag: 'document_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch( diff --git a/lib/ui/expense/expense_screen.dart b/lib/ui/expense/expense_screen.dart index 0b0e909d8..154da6290 100644 --- a/lib/ui/expense/expense_screen.dart +++ b/lib/ui/expense/expense_screen.dart @@ -79,7 +79,7 @@ class ExpenseScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.expense) ? FloatingActionButton( - //key: Key(ExpenseKeys.expenseScreenFABKeyString), + heroTag: 'expense_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(EditExpense( diff --git a/lib/ui/expense/view/expense_view.dart b/lib/ui/expense/view/expense_view.dart index 05e9a27b9..168481724 100644 --- a/lib/ui/expense/view/expense_view.dart +++ b/lib/ui/expense/view/expense_view.dart @@ -63,6 +63,7 @@ class _ExpenseViewState extends State floatingActionButton: company.isEnterprisePlan ? Builder(builder: (BuildContext context) { return FloatingActionButton( + heroTag: 'expense_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () async { final image = diff --git a/lib/ui/invoice/edit/invoice_edit.dart b/lib/ui/invoice/edit/invoice_edit.dart index 97ade530c..4f0f89d86 100644 --- a/lib/ui/invoice/edit/invoice_edit.dart +++ b/lib/ui/invoice/edit/invoice_edit.dart @@ -5,9 +5,6 @@ import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_items_vm.dart' import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_notes_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_item_selector.dart'; -import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_details_vm.dart'; -import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_items_vm.dart'; -import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_notes_vm.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/action_icon_button.dart'; @@ -69,12 +66,8 @@ class _InvoiceEditState extends State appBar: AppBar( automaticallyImplyLeading: isMobile(context), title: Text(invoice.isNew - ? invoice.isQuote - ? localization.newQuote - : localization.newInvoice - : invoice.isQuote - ? localization.editQuote - : localization.editInvoice), + ? localization.newInvoice + : localization.editInvoice), actions: [ if (!isMobile(context)) FlatButton( @@ -120,17 +113,11 @@ class _InvoiceEditState extends State child: TabBarView( key: ValueKey(viewModel.invoice.id), controller: _controller, - children: invoice.isQuote - ? [ - QuoteEditDetailsScreen(), - QuoteEditItemsScreen(), - QuoteEditNotesScreen(), - ] - : [ - InvoiceEditDetailsScreen(), - InvoiceEditItemsScreen(), - InvoiceEditNotesScreen(), - ], + children: [ + InvoiceEditDetailsScreen(), + InvoiceEditItemsScreen(), + InvoiceEditNotesScreen(), + ], ), ), bottomNavigationBar: BottomAppBar( @@ -150,6 +137,7 @@ class _InvoiceEditState extends State ), floatingActionButtonLocation: FloatingActionButtonLocation.endDocked, floatingActionButton: FloatingActionButton( + heroTag: 'invoice_edit_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { showDialog( diff --git a/lib/ui/invoice/invoice_screen.dart b/lib/ui/invoice/invoice_screen.dart index d9ca48c1e..86acf8735 100644 --- a/lib/ui/invoice/invoice_screen.dart +++ b/lib/ui/invoice/invoice_screen.dart @@ -98,6 +98,7 @@ class InvoiceScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.invoice) ? FloatingActionButton( + heroTag: 'invoice_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(EditInvoice( diff --git a/lib/ui/payment/payment_screen.dart b/lib/ui/payment/payment_screen.dart index a295ee8cc..15a0131e4 100644 --- a/lib/ui/payment/payment_screen.dart +++ b/lib/ui/payment/payment_screen.dart @@ -53,7 +53,7 @@ class PaymentScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.payment) ? FloatingActionButton( - //key: Key(PaymentKeys.paymentScreenFABKeyString), + heroTag: 'payment_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(EditPayment( diff --git a/lib/ui/product/product_screen.dart b/lib/ui/product/product_screen.dart index cc0580166..e3b2268bc 100644 --- a/lib/ui/product/product_screen.dart +++ b/lib/ui/product/product_screen.dart @@ -59,6 +59,7 @@ class ProductScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.product) ? FloatingActionButton( + heroTag: 'product_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch( diff --git a/lib/ui/project/project_screen.dart b/lib/ui/project/project_screen.dart index 4dc292e25..c4f0a90e4 100644 --- a/lib/ui/project/project_screen.dart +++ b/lib/ui/project/project_screen.dart @@ -58,7 +58,7 @@ class ProjectScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.project) ? FloatingActionButton( - //key: Key(ProjectKeys.projectScreenFABKeyString), + heroTag: 'project_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(EditProject( diff --git a/lib/ui/project/view/project_view.dart b/lib/ui/project/view/project_view.dart index 74996ae30..0ebd527ca 100644 --- a/lib/ui/project/view/project_view.dart +++ b/lib/ui/project/view/project_view.dart @@ -153,6 +153,7 @@ class _ProjectViewState extends State { }, ), floatingActionButton: FloatingActionButton( + heroTag: 'project_view_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () => viewModel.onAddTaskPressed(context), child: Icon( diff --git a/lib/ui/quote/edit/quote_edit_vm.dart b/lib/ui/quote/edit/quote_edit_vm.dart index c4cac813b..bcceca402 100644 --- a/lib/ui/quote/edit/quote_edit_vm.dart +++ b/lib/ui/quote/edit/quote_edit_vm.dart @@ -5,8 +5,8 @@ import 'package:flutter_redux/flutter_redux.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/dialogs/error_dialog.dart'; -import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/quote/quote_edit.dart'; import 'package:invoiceninja_flutter/ui/quote/quote_screen.dart'; import 'package:invoiceninja_flutter/ui/quote/view/quote_view_vm.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; @@ -28,7 +28,7 @@ class QuoteEditScreen extends StatelessWidget { return QuoteEditVM.fromStore(store); }, builder: (context, viewModel) { - return InvoiceEdit( + return QuoteEdit( viewModel: viewModel, formKey: _formKey, ); diff --git a/lib/ui/quote/quote_edit.dart b/lib/ui/quote/quote_edit.dart new file mode 100644 index 000000000..f40a9819b --- /dev/null +++ b/lib/ui/quote/quote_edit.dart @@ -0,0 +1,166 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_item_selector.dart'; +import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_details_vm.dart'; +import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_items_vm.dart'; +import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_notes_vm.dart'; +import 'package:invoiceninja_flutter/utils/formatting.dart'; +import 'package:invoiceninja_flutter/utils/localization.dart'; +import 'package:invoiceninja_flutter/ui/app/buttons/action_icon_button.dart'; +import 'package:invoiceninja_flutter/utils/platforms.dart'; + +class QuoteEdit extends StatefulWidget { + const QuoteEdit({ + Key key, + @required this.formKey, + @required this.viewModel, + }) : super(key: key); + + final EntityEditVM viewModel; + final GlobalKey formKey; + + @override + _QuoteEditState createState() => _QuoteEditState(); +} + +class _QuoteEditState extends State + with SingleTickerProviderStateMixin { + TabController _controller; + + static const kDetailsScreen = 0; + static const kItemScreen = 1; + static const kNotesScreen = 2; + + @override + void initState() { + super.initState(); + + final invoice = widget.viewModel.invoice; + final invoiceItem = widget.viewModel.invoiceItem; + + final index = invoice.invoiceItems.contains(invoiceItem) + ? kItemScreen + : kDetailsScreen; + _controller = TabController(vsync: this, length: 3, initialIndex: index); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final localization = AppLocalization.of(context); + final viewModel = widget.viewModel; + final invoice = viewModel.invoice; + + return WillPopScope( + onWillPop: () async { + viewModel.onBackPressed(); + return true; + }, + child: Scaffold( + appBar: AppBar( + automaticallyImplyLeading: isMobile(context), + title: Text( + invoice.isNew ? localization.newQuote : localization.editQuote), + actions: [ + if (!isMobile(context)) + FlatButton( + child: Text( + localization.cancel, + style: TextStyle(color: Colors.white), + ), + onPressed: () => viewModel.onCancelPressed(context), + ), + ActionIconButton( + icon: Icons.cloud_upload, + tooltip: localization.save, + isVisible: !invoice.isDeleted, + isSaving: widget.viewModel.isSaving, + isDirty: invoice.isNew || invoice != viewModel.origInvoice, + onPressed: () { + if (!widget.formKey.currentState.validate()) { + return; + } + + widget.viewModel.onSavePressed(context); + }, + ) + ], + bottom: TabBar( + controller: _controller, + //isScrollable: true, + tabs: [ + Tab( + text: localization.details, + ), + Tab( + text: localization.items, + ), + Tab( + text: localization.notes, + ), + ], + ), + ), + body: Form( + key: widget.formKey, + child: TabBarView( + key: ValueKey(viewModel.invoice.id), + controller: _controller, + children: [ + QuoteEditDetailsScreen(), + QuoteEditItemsScreen(), + QuoteEditNotesScreen(), + ], + ), + ), + bottomNavigationBar: BottomAppBar( + color: Theme.of(context).primaryColor, + shape: CircularNotchedRectangle(), + child: Padding( + padding: const EdgeInsets.all(14.0), + child: Text( + '${localization.total}: ${formatNumber(invoice.calculateTotal(viewModel.company.settings.enableInclusiveTaxes), context, clientId: viewModel.invoice.clientId)}', + style: TextStyle( + //color: Theme.of(context).selectedRowColor, + color: Colors.white, + fontSize: 20.0, + ), + ), + ), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.endDocked, + floatingActionButton: FloatingActionButton( + heroTag: 'quote_edit_fab', + backgroundColor: Theme.of(context).primaryColorDark, + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return InvoiceItemSelector( + excluded: invoice.invoiceItems + .where((item) => item.isTask || item.isExpense) + .map((item) => item.isTask + ? viewModel.state.taskState.map[item.taskId] + : viewModel.state.expenseState.map[item.expenseId]) + .toList(), + clientId: invoice.clientId, + onItemsSelected: (items, [clientId]) { + viewModel.onItemsAdded(items, clientId); + _controller.animateTo(kItemScreen); + }, + ); + }); + }, + child: const Icon(Icons.add, color: Colors.white), + tooltip: localization.addItem, + ), + ), + ); + } +} diff --git a/lib/ui/quote/quote_screen.dart b/lib/ui/quote/quote_screen.dart index 0578e0120..51963e84c 100644 --- a/lib/ui/quote/quote_screen.dart +++ b/lib/ui/quote/quote_screen.dart @@ -91,6 +91,7 @@ class QuoteScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.quote) ? FloatingActionButton( + heroTag: 'quote_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(EditQuote( diff --git a/lib/ui/task/edit/task_edit.dart b/lib/ui/task/edit/task_edit.dart index 49ea01dc3..043f0244a 100644 --- a/lib/ui/task/edit/task_edit.dart +++ b/lib/ui/task/edit/task_edit.dart @@ -137,6 +137,7 @@ class _TaskEditState extends State floatingActionButton: task.isInvoiced || task.isDeleted ? SizedBox() : FloatingActionButton( + heroTag: 'task_edit_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () => viewModel.onFabPressed(), child: Icon( diff --git a/lib/ui/task/task_screen.dart b/lib/ui/task/task_screen.dart index 278eef108..bcd6c1628 100644 --- a/lib/ui/task/task_screen.dart +++ b/lib/ui/task/task_screen.dart @@ -78,7 +78,7 @@ class TaskScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.task) ? FloatingActionButton( - //key: Key(TaskKeys.taskScreenFABKeyString), + heroTag: 'task_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(EditTask( diff --git a/lib/ui/task/view/task_view.dart b/lib/ui/task/view/task_view.dart index a763af9a0..330a75491 100644 --- a/lib/ui/task/view/task_view.dart +++ b/lib/ui/task/view/task_view.dart @@ -219,6 +219,7 @@ class _TaskViewState extends State { return task.isInvoiced || task.isDeleted ? SizedBox() : FloatingActionButton( + heroTag: 'task_view_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () => viewModel.onFabPressed(context), child: Icon( diff --git a/lib/ui/vendor/vendor_screen.dart b/lib/ui/vendor/vendor_screen.dart index 39342fe64..1ee945036 100644 --- a/lib/ui/vendor/vendor_screen.dart +++ b/lib/ui/vendor/vendor_screen.dart @@ -58,7 +58,7 @@ class VendorScreen extends StatelessWidget { ), floatingActionButton: userCompany.canCreate(EntityType.vendor) ? FloatingActionButton( - //key: Key(VendorKeys.vendorScreenFABKeyString), + heroTag: 'vendor_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch( diff --git a/lib/ui/vendor/view/vendor_view.dart b/lib/ui/vendor/view/vendor_view.dart index 22f4a7b0d..fbd3d57fc 100644 --- a/lib/ui/vendor/view/vendor_view.dart +++ b/lib/ui/vendor/view/vendor_view.dart @@ -57,6 +57,7 @@ class _VendorViewState extends State controller: _controller, ), floatingActionButton: FloatingActionButton( + heroTag: 'vendor_view_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () => viewModel.onAddExpensePressed(context), child: Icon( diff --git a/stubs/ui/stub/stub_screen b/stubs/ui/stub/stub_screen index a0f4508a0..2f24d793a 100644 --- a/stubs/ui/stub/stub_screen +++ b/stubs/ui/stub/stub_screen @@ -60,7 +60,7 @@ class StubScreen extends StatelessWidget { ), floatingActionButton: user.canCreate(EntityType.stub) ? FloatingActionButton( - //key: Key(StubKeys.stubScreenFABKeyString), + heroTag: 'stub_fab', backgroundColor: Theme.of(context).primaryColorDark, onPressed: () { store.dispatch(