diff --git a/lib/ui/client/edit/client_edit_vm.dart b/lib/ui/client/edit/client_edit_vm.dart index bfbc70575..6c712d6ae 100644 --- a/lib/ui/client/edit/client_edit_vm.dart +++ b/lib/ui/client/edit/client_edit_vm.dart @@ -14,6 +14,7 @@ import 'package:invoiceninja_flutter/ui/client/view/client_view_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/project/edit/project_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/task/edit/task_edit_vm.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:redux/redux.dart'; @@ -82,6 +83,7 @@ class ClientEditVM { InvoiceEditScreen.route, QuoteEditScreen.route, ProjectEditScreen.route, + TaskEditScreen.route, ].contains(store.state.uiState.currentRoute)) { Navigator.of(context).pop(savedClient); } else { diff --git a/lib/ui/task/edit/task_edit.dart b/lib/ui/task/edit/task_edit.dart index 653eef9be..0de4ed8ff 100644 --- a/lib/ui/task/edit/task_edit.dart +++ b/lib/ui/task/edit/task_edit.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/ui/app/entity_dropdown.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/forms/custom_field.dart'; import 'package:invoiceninja_flutter/ui/task/edit/task_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/refresh_icon_button.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; +import 'package:invoiceninja_flutter/redux/client/client_selectors.dart'; class TaskEdit extends StatefulWidget { const TaskEdit({ @@ -74,6 +76,7 @@ class _TaskEditState extends State { final localization = AppLocalization.of(context); final task = viewModel.task; final company = viewModel.company; + final state = viewModel.state; return WillPopScope( onWillPop: () async { @@ -110,6 +113,26 @@ class _TaskEditState extends State { children: [ FormCard( children: [ + EntityDropdown( + entityType: EntityType.client, + labelText: localization.client, + initialValue: (state.clientState.map[task.clientId] ?? + ClientEntity()) + .displayName, + entityMap: state.clientState.map, + entityList: memoizedDropdownClientList( + state.clientState.map, state.clientState.list), + validator: (String val) => val.trim().isEmpty + ? localization.pleaseSelectAClient + : null, + onSelected: (clientId) { + viewModel.onChanged( + task.rebuild((b) => b..clientId = clientId)); + }, + onAddPressed: (completer) { + viewModel.onAddClientPressed(context, completer); + }, + ), TextFormField( maxLines: 4, controller: _descriptionController, diff --git a/lib/ui/task/edit/task_edit_vm.dart b/lib/ui/task/edit/task_edit_vm.dart index 544f5bc1a..3af6d09ba 100644 --- a/lib/ui/task/edit/task_edit_vm.dart +++ b/lib/ui/task/edit/task_edit_vm.dart @@ -3,8 +3,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; +import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart'; import 'package:invoiceninja_flutter/ui/task/task_screen.dart'; +import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:redux/redux.dart'; import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart'; import 'package:invoiceninja_flutter/ui/task/view/task_view_vm.dart'; @@ -34,9 +37,11 @@ class TaskEditScreen extends StatelessWidget { class TaskEditVM { TaskEditVM({ + @required this.state, @required this.task, @required this.company, @required this.onChanged, + @required this.onAddClientPressed, @required this.isSaving, @required this.origTask, @required this.onSavePressed, @@ -53,6 +58,7 @@ class TaskEditVM { isSaving: state.isSaving, origTask: state.taskState.map[task.id], task: task, + state: state, company: state.selectedCompany, onChanged: (TaskEntity task) { store.dispatch(UpdateTask(task)); @@ -60,23 +66,36 @@ class TaskEditVM { onBackPressed: () { store.dispatch(UpdateCurrentRoute(TaskScreen.route)); }, + onAddClientPressed: (context, completer) { + store.dispatch(EditClient( + client: ClientEntity(), + context: context, + completer: completer, + trackRoute: false)); + completer.future.then((SelectableEntity client) { + Scaffold.of(context).showSnackBar(SnackBar( + content: SnackBarRow( + message: AppLocalization.of(context).createdClient, + ))); + }); + }, onSavePressed: (BuildContext context) { final Completer completer = new Completer(); store.dispatch(SaveTaskRequest(completer: completer, task: task)); return completer.future.then((_) { - return completer.future.then((savedTask) { - if (task.isNew) { - Navigator.of(context).pushReplacementNamed(TaskViewScreen.route); - } else { - Navigator.of(context).pop(savedTask); - } - }).catchError((Object error) { - showDialog( - context: context, - builder: (BuildContext context) { - return ErrorDialog(error); - }); - }); + return completer.future.then((savedTask) { + if (task.isNew) { + Navigator.of(context).pushReplacementNamed(TaskViewScreen.route); + } else { + Navigator.of(context).pop(savedTask); + } + }).catchError((Object error) { + showDialog( + context: context, + builder: (BuildContext context) { + return ErrorDialog(error); + }); + }); }); }, ); @@ -90,5 +109,7 @@ class TaskEditVM { final bool isLoading; final bool isSaving; final TaskEntity origTask; - + final AppState state; + final Function(BuildContext context, Completer completer) + onAddClientPressed; } diff --git a/stubs/ui/stub/edit/stub_edit_vm b/stubs/ui/stub/edit/stub_edit_vm index ca861c969..2ceb47daa 100644 --- a/stubs/ui/stub/edit/stub_edit_vm +++ b/stubs/ui/stub/edit/stub_edit_vm @@ -34,6 +34,7 @@ class StubEditScreen extends StatelessWidget { class StubEditVM { StubEditVM({ + @required this.state, @required this.stub, @required this.company, @required this.onChanged, @@ -49,6 +50,7 @@ class StubEditVM { final state = store.state; return StubEditVM( + state: state, isLoading: state.isLoading, isSaving: state.isSaving, origStub: state.stubState.map[stub.id], @@ -90,5 +92,5 @@ class StubEditVM { final bool isLoading; final bool isSaving; final TaskEntity origStub; - + final AppState state; }