From 4763b8cba76eb8fbb92f1b1e907d4d0b4a7bf9dc Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 13 Dec 2018 22:44:16 +0200 Subject: [PATCH] Projects --- lib/data/models/client_model.dart | 2 +- lib/data/models/entities.dart | 2 +- lib/data/models/invoice_model.dart | 2 +- lib/data/models/payment_model.dart | 2 +- lib/data/models/product_model.dart | 2 +- lib/data/models/project_model.dart | 7 ++ lib/ui/project/edit/project_edit.dart | 4 +- lib/ui/project/edit/project_edit_vm.dart | 1 - lib/ui/project/project_list.dart | 65 ++++++-------- lib/ui/project/project_list_vm.dart | 104 +++++++++-------------- stubs/ui/stub/stub_list | 65 ++++++-------- stubs/ui/stub/stub_list_vm | 28 +----- 12 files changed, 106 insertions(+), 178 deletions(-) diff --git a/lib/data/models/client_model.dart b/lib/data/models/client_model.dart index 1c320732d..b0c7fcd37 100644 --- a/lib/data/models/client_model.dart +++ b/lib/data/models/client_model.dart @@ -367,7 +367,7 @@ abstract class ClientEntity extends Object actions.add(null); } - return actions..addAll(getEntityBaseActions(user: user)); + return actions..addAll(getBaseActions(user: user)); } @override diff --git a/lib/data/models/entities.dart b/lib/data/models/entities.dart index 0b7c417c2..e9d891f8b 100644 --- a/lib/data/models/entities.dart +++ b/lib/data/models/entities.dart @@ -136,7 +136,7 @@ abstract class BaseEntity implements SelectableEntity { bool get isArchived => archivedAt != null && !isDeleted; - List getEntityBaseActions({UserEntity user}) { + List getBaseActions({UserEntity user}) { final actions = []; if (user.canEditEntity(this) && (isArchived || isDeleted)) { diff --git a/lib/data/models/invoice_model.dart b/lib/data/models/invoice_model.dart index aa9519759..78843bb43 100644 --- a/lib/data/models/invoice_model.dart +++ b/lib/data/models/invoice_model.dart @@ -420,7 +420,7 @@ abstract class InvoiceEntity extends Object actions.add(null); } - return actions..addAll(getEntityBaseActions(user: user)); + return actions..addAll(getBaseActions(user: user)); } InvoiceEntity applyTax(TaxRateEntity taxRate) { diff --git a/lib/data/models/payment_model.dart b/lib/data/models/payment_model.dart index 77951076c..fcba6a42a 100644 --- a/lib/data/models/payment_model.dart +++ b/lib/data/models/payment_model.dart @@ -186,7 +186,7 @@ abstract class PaymentEntity extends Object actions.add(null); } - return actions..addAll(getEntityBaseActions(user: user)); + return actions..addAll(getBaseActions(user: user)); } @override diff --git a/lib/data/models/product_model.dart b/lib/data/models/product_model.dart index 50cae3d37..14ca1a839 100644 --- a/lib/data/models/product_model.dart +++ b/lib/data/models/product_model.dart @@ -205,7 +205,7 @@ abstract class ProductEntity extends Object actions.add(null); } - return actions..addAll(getEntityBaseActions(user: user)); + return actions..addAll(getBaseActions(user: user)); } static Serializer get serializer => _$productEntitySerializer; diff --git a/lib/data/models/project_model.dart b/lib/data/models/project_model.dart index a32c56f00..3b6a68e49 100644 --- a/lib/data/models/project_model.dart +++ b/lib/data/models/project_model.dart @@ -2,6 +2,7 @@ import 'package:built_collection/built_collection.dart'; import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart'; +import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart'; part 'project_model.g.dart'; @@ -101,6 +102,12 @@ abstract class ProjectEntity extends Object @BuiltValueField(wireName: 'custom_value2') String get customValue2; + List getEntityActions({UserEntity user, ClientEntity client}) { + final actions = []; + + return actions..addAll(getBaseActions(user: user)); + } + int compareTo(ProjectEntity project, String sortField, bool sortAscending) { int response = 0; final ProjectEntity projectA = sortAscending ? this : project; diff --git a/lib/ui/project/edit/project_edit.dart b/lib/ui/project/edit/project_edit.dart index 0b89c5f75..83d386ec0 100644 --- a/lib/ui/project/edit/project_edit.dart +++ b/lib/ui/project/edit/project_edit.dart @@ -132,7 +132,7 @@ class _ProjectEditState extends State { entityList: memoizedDropdownClientList( state.clientState.map, state.clientState.list), validator: (String val) => val.trim().isEmpty - ? AppLocalization.of(context).pleaseSelectAClient + ? localization.pleaseSelectAClient : null, onSelected: (clientId) { viewModel.onChanged( @@ -146,7 +146,7 @@ class _ProjectEditState extends State { autocorrect: false, controller: _nameController, validator: (String val) => val.trim().isEmpty - ? AppLocalization.of(context).pleaseEnterAName + ? localization.pleaseEnterAName : null, decoration: InputDecoration( labelText: localization.name, diff --git a/lib/ui/project/edit/project_edit_vm.dart b/lib/ui/project/edit/project_edit_vm.dart index 544e921a0..fd78f3d9a 100644 --- a/lib/ui/project/edit/project_edit_vm.dart +++ b/lib/ui/project/edit/project_edit_vm.dart @@ -9,7 +9,6 @@ import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart'; import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart'; import 'package:invoiceninja_flutter/ui/project/project_screen.dart'; -import 'package:invoiceninja_flutter/utils/completers.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:redux/redux.dart'; import 'package:invoiceninja_flutter/redux/project/project_actions.dart'; diff --git a/lib/ui/project/project_list.dart b/lib/ui/project/project_list.dart index 5cc053ba3..103f4abf1 100644 --- a/lib/ui/project/project_list.dart +++ b/lib/ui/project/project_list.dart @@ -5,6 +5,7 @@ import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart'; import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart'; import 'package:invoiceninja_flutter/ui/project/project_list_item.dart'; import 'package:invoiceninja_flutter/ui/project/project_list_vm.dart'; +import 'package:invoiceninja_flutter/utils/icons.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; class ProjectList extends StatelessWidget { @@ -34,48 +35,34 @@ class ProjectList extends StatelessWidget { return _buildListView(context); } - void _showMenu(BuildContext context, ProjectEntity project) async { - if (project == null) { - return; - } + void _showMenu( + BuildContext context, ProjectEntity project) async { + if (project == null) { + return; + } + final user = viewModel.user; final message = await showDialog( context: context, - builder: (BuildContext context) => SimpleDialog(children: [ - user.canCreate(EntityType.project) - ? ListTile( - leading: Icon(Icons.control_point_duplicate), - title: Text(AppLocalization.of(context).clone), - onTap: () => viewModel.onEntityAction( - context, project, EntityAction.clone), - ) - : Container(), - Divider(), - user.canEditEntity(project) && !project.isActive - ? ListTile( - leading: Icon(Icons.restore), - title: Text(AppLocalization.of(context).restore), - onTap: () => viewModel.onEntityAction( - context, project, EntityAction.restore), - ) - : Container(), - user.canEditEntity(project) && project.isActive - ? ListTile( - leading: Icon(Icons.archive), - title: Text(AppLocalization.of(context).archive), - onTap: () => viewModel.onEntityAction( - context, project, EntityAction.archive), - ) - : Container(), - user.canEditEntity(project) && !project.isDeleted - ? ListTile( - leading: Icon(Icons.delete), - title: Text(AppLocalization.of(context).delete), - onTap: () => viewModel.onEntityAction( - context, project, EntityAction.delete), - ) - : Container(), - ])); + builder: (BuildContext dialogContext) => SimpleDialog( + children: project + .getEntityActions(user: user) + .map((entityAction) { + if (entityAction == null) { + return Divider(); + } else { + return ListTile( + leading: Icon(getEntityActionIcon(entityAction)), + title: Text(AppLocalization.of(context) + .lookup(entityAction.toString())), + onTap: () { + Navigator.of(dialogContext).pop(); + viewModel.onEntityAction(context, project, entityAction); + }, + ); + } + }).toList())); + if (message != null) { Scaffold.of(context).showSnackBar(SnackBar( content: SnackBarRow( diff --git a/lib/ui/project/project_list_vm.dart b/lib/ui/project/project_list_vm.dart index dd699f9cb..3c165f17d 100644 --- a/lib/ui/project/project_list_vm.dart +++ b/lib/ui/project/project_list_vm.dart @@ -38,7 +38,6 @@ class ProjectListVM { @required this.isLoading, @required this.isLoaded, @required this.onProjectTap, - @required this.onDismissed, @required this.onRefreshed, @required this.onEntityAction, }); @@ -57,69 +56,45 @@ class ProjectListVM { final state = store.state; return ProjectListVM( - user: state.user, - projectList: memoizedFilteredProjectList(state.projectState.map, - state.projectState.list, state.projectListState), - projectMap: state.projectState.map, - isLoading: state.isLoading, - isLoaded: state.projectState.isLoaded, - filter: state.projectUIState.listUIState.filter, - onProjectTap: (context, project) { - store.dispatch(EditProject(project: project, context: context)); - }, - onEntityAction: (context, project, action) { - switch (action) { - case EntityAction.clone: - Navigator.of(context).pop(); - store.dispatch( - EditProject(context: context, project: project.clone)); - break; - case EntityAction.restore: - store.dispatch(RestoreProjectRequest( - popCompleter( - context, AppLocalization.of(context).restoredProject), - project.id)); - break; - case EntityAction.archive: - store.dispatch(ArchiveProjectRequest( - popCompleter( - context, AppLocalization.of(context).archivedProject), - project.id)); - break; - case EntityAction.delete: - store.dispatch(DeleteProjectRequest( - popCompleter( - context, AppLocalization.of(context).deletedProject), - project.id)); - break; - } - }, - onRefreshed: (context) => _handleRefresh(context), - onDismissed: (BuildContext context, ProjectEntity project, - DismissDirection direction) { - final localization = AppLocalization.of(context); - if (direction == DismissDirection.endToStart) { - if (project.isDeleted || project.isArchived) { - store.dispatch(RestoreProjectRequest( - snackBarCompleter(context, localization.restoredProject), - project.id)); - } else { - store.dispatch(ArchiveProjectRequest( - snackBarCompleter(context, localization.archivedProject), - project.id)); - } - } else if (direction == DismissDirection.startToEnd) { - if (project.isDeleted) { - store.dispatch(RestoreProjectRequest( - snackBarCompleter(context, localization.restoredProject), - project.id)); - } else { - store.dispatch(DeleteProjectRequest( - snackBarCompleter(context, localization.deletedProject), - project.id)); - } - } - }); + user: state.user, + projectList: memoizedFilteredProjectList(state.projectState.map, + state.projectState.list, state.projectListState), + projectMap: state.projectState.map, + isLoading: state.isLoading, + isLoaded: state.projectState.isLoaded, + filter: state.projectUIState.listUIState.filter, + onProjectTap: (context, project) { + store.dispatch(EditProject(project: project, context: context)); + }, + onEntityAction: (context, project, action) { + switch (action) { + case EntityAction.clone: + Navigator.of(context).pop(); + store.dispatch( + EditProject(context: context, project: project.clone)); + break; + case EntityAction.restore: + store.dispatch(RestoreProjectRequest( + snackBarCompleter( + context, AppLocalization.of(context).restoredProject), + project.id)); + break; + case EntityAction.archive: + store.dispatch(ArchiveProjectRequest( + snackBarCompleter( + context, AppLocalization.of(context).archivedProject), + project.id)); + break; + case EntityAction.delete: + store.dispatch(DeleteProjectRequest( + snackBarCompleter( + context, AppLocalization.of(context).deletedProject), + project.id)); + break; + } + }, + onRefreshed: (context) => _handleRefresh(context), + ); } final UserEntity user; @@ -129,7 +104,6 @@ class ProjectListVM { final bool isLoading; final bool isLoaded; final Function(BuildContext, ProjectEntity) onProjectTap; - final Function(BuildContext, ProjectEntity, DismissDirection) onDismissed; final Function(BuildContext) onRefreshed; final Function(BuildContext, ProjectEntity, EntityAction) onEntityAction; } diff --git a/stubs/ui/stub/stub_list b/stubs/ui/stub/stub_list index 56d514d3a..57fc35e20 100644 --- a/stubs/ui/stub/stub_list +++ b/stubs/ui/stub/stub_list @@ -5,6 +5,7 @@ import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart'; import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart'; import 'package:invoiceninja_flutter/ui/stub/stub_list_item.dart'; import 'package:invoiceninja_flutter/ui/stub/stub_list_vm.dart'; +import 'package:invoiceninja_flutter/utils/icons.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; class StubList extends StatelessWidget { @@ -34,48 +35,34 @@ class StubList extends StatelessWidget { return _buildListView(context); } - void _showMenu(BuildContext context, StubEntity stub) async { - if (stub == null) { - return; - } + void _showMenu( + BuildContext context, StubEntity stub) async { + if (stub == null) { + return; + } + final user = viewModel.user; final message = await showDialog( context: context, - builder: (BuildContext context) => SimpleDialog(children: [ - user.canCreate(EntityType.stub) - ? ListTile( - leading: Icon(Icons.control_point_duplicate), - title: Text(AppLocalization.of(context).clone), - onTap: () => viewModel.onEntityAction( - context, stub, EntityAction.clone), - ) - : Container(), - Divider(), - user.canEditEntity(stub) && !stub.isActive - ? ListTile( - leading: Icon(Icons.restore), - title: Text(AppLocalization.of(context).restore), - onTap: () => viewModel.onEntityAction( - context, stub, EntityAction.restore), - ) - : Container(), - user.canEditEntity(stub) && stub.isActive - ? ListTile( - leading: Icon(Icons.archive), - title: Text(AppLocalization.of(context).archive), - onTap: () => viewModel.onEntityAction( - context, stub, EntityAction.archive), - ) - : Container(), - user.canEditEntity(stub) && !stub.isDeleted - ? ListTile( - leading: Icon(Icons.delete), - title: Text(AppLocalization.of(context).delete), - onTap: () => viewModel.onEntityAction( - context, stub, EntityAction.delete), - ) - : Container(), - ])); + builder: (BuildContext dialogContext) => SimpleDialog( + children: stub + .getEntityActions(user: user) + .map((entityAction) { + if (entityAction == null) { + return Divider(); + } else { + return ListTile( + leading: Icon(getEntityActionIcon(entityAction)), + title: Text(AppLocalization.of(context) + .lookup(entityAction.toString())), + onTap: () { + Navigator.of(dialogContext).pop(); + viewModel.onEntityAction(context, stub, entityAction); + }, + ); + } + }).toList())); + if (message != null) { Scaffold.of(context).showSnackBar(SnackBar( content: SnackBarRow( diff --git a/stubs/ui/stub/stub_list_vm b/stubs/ui/stub/stub_list_vm index f85bd4943..fb7cef78e 100644 --- a/stubs/ui/stub/stub_list_vm +++ b/stubs/ui/stub/stub_list_vm @@ -38,7 +38,6 @@ class StubListVM { @required this.isLoading, @required this.isLoaded, @required this.onStubTap, - @required this.onDismissed, @required this.onRefreshed, @required this.onEntityAction, }); @@ -95,31 +94,7 @@ class StubListVM { } }, onRefreshed: (context) => _handleRefresh(context), - onDismissed: (BuildContext context, StubEntity stub, - DismissDirection direction) { - final localization = AppLocalization.of(context); - if (direction == DismissDirection.endToStart) { - if (stub.isDeleted || stub.isArchived) { - store.dispatch(RestoreStubRequest( - snackBarCompleter(context, localization.restoredStub), - stub.id)); - } else { - store.dispatch(ArchiveStubRequest( - snackBarCompleter(context, localization.archivedStub), - stub.id)); - } - } else if (direction == DismissDirection.startToEnd) { - if (stub.isDeleted) { - store.dispatch(RestoreStubRequest( - snackBarCompleter(context, localization.restoredStub), - stub.id)); - } else { - store.dispatch(DeleteStubRequest( - snackBarCompleter(context, localization.deletedStub), - stub.id)); - } - } - }); + ); } final UserEntity user; @@ -129,7 +104,6 @@ class StubListVM { final bool isLoading; final bool isLoaded; final Function(BuildContext, StubEntity) onStubTap; - final Function(BuildContext, StubEntity, DismissDirection) onDismissed; final Function(BuildContext) onRefreshed; final Function(BuildContext, StubEntity, EntityAction) onEntityAction; }