Projects
This commit is contained in:
parent
753e0e8590
commit
4763b8cba7
|
|
@ -367,7 +367,7 @@ abstract class ClientEntity extends Object
|
||||||
actions.add(null);
|
actions.add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions..addAll(getEntityBaseActions(user: user));
|
return actions..addAll(getBaseActions(user: user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ abstract class BaseEntity implements SelectableEntity {
|
||||||
|
|
||||||
bool get isArchived => archivedAt != null && !isDeleted;
|
bool get isArchived => archivedAt != null && !isDeleted;
|
||||||
|
|
||||||
List<EntityAction> getEntityBaseActions({UserEntity user}) {
|
List<EntityAction> getBaseActions({UserEntity user}) {
|
||||||
final actions = <EntityAction>[];
|
final actions = <EntityAction>[];
|
||||||
|
|
||||||
if (user.canEditEntity(this) && (isArchived || isDeleted)) {
|
if (user.canEditEntity(this) && (isArchived || isDeleted)) {
|
||||||
|
|
|
||||||
|
|
@ -420,7 +420,7 @@ abstract class InvoiceEntity extends Object
|
||||||
actions.add(null);
|
actions.add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions..addAll(getEntityBaseActions(user: user));
|
return actions..addAll(getBaseActions(user: user));
|
||||||
}
|
}
|
||||||
|
|
||||||
InvoiceEntity applyTax(TaxRateEntity taxRate) {
|
InvoiceEntity applyTax(TaxRateEntity taxRate) {
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ abstract class PaymentEntity extends Object
|
||||||
actions.add(null);
|
actions.add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions..addAll(getEntityBaseActions(user: user));
|
return actions..addAll(getBaseActions(user: user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ abstract class ProductEntity extends Object
|
||||||
actions.add(null);
|
actions.add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions..addAll(getEntityBaseActions(user: user));
|
return actions..addAll(getBaseActions(user: user));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Serializer<ProductEntity> get serializer => _$productEntitySerializer;
|
static Serializer<ProductEntity> get serializer => _$productEntitySerializer;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:built_collection/built_collection.dart';
|
||||||
import 'package:built_value/built_value.dart';
|
import 'package:built_value/built_value.dart';
|
||||||
import 'package:built_value/serializer.dart';
|
import 'package:built_value/serializer.dart';
|
||||||
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
||||||
|
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||||
|
|
||||||
part 'project_model.g.dart';
|
part 'project_model.g.dart';
|
||||||
|
|
@ -101,6 +102,12 @@ abstract class ProjectEntity extends Object
|
||||||
@BuiltValueField(wireName: 'custom_value2')
|
@BuiltValueField(wireName: 'custom_value2')
|
||||||
String get customValue2;
|
String get customValue2;
|
||||||
|
|
||||||
|
List<EntityAction> getEntityActions({UserEntity user, ClientEntity client}) {
|
||||||
|
final actions = <EntityAction>[];
|
||||||
|
|
||||||
|
return actions..addAll(getBaseActions(user: user));
|
||||||
|
}
|
||||||
|
|
||||||
int compareTo(ProjectEntity project, String sortField, bool sortAscending) {
|
int compareTo(ProjectEntity project, String sortField, bool sortAscending) {
|
||||||
int response = 0;
|
int response = 0;
|
||||||
final ProjectEntity projectA = sortAscending ? this : project;
|
final ProjectEntity projectA = sortAscending ? this : project;
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ class _ProjectEditState extends State<ProjectEdit> {
|
||||||
entityList: memoizedDropdownClientList(
|
entityList: memoizedDropdownClientList(
|
||||||
state.clientState.map, state.clientState.list),
|
state.clientState.map, state.clientState.list),
|
||||||
validator: (String val) => val.trim().isEmpty
|
validator: (String val) => val.trim().isEmpty
|
||||||
? AppLocalization.of(context).pleaseSelectAClient
|
? localization.pleaseSelectAClient
|
||||||
: null,
|
: null,
|
||||||
onSelected: (clientId) {
|
onSelected: (clientId) {
|
||||||
viewModel.onChanged(
|
viewModel.onChanged(
|
||||||
|
|
@ -146,7 +146,7 @@ class _ProjectEditState extends State<ProjectEdit> {
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
validator: (String val) => val.trim().isEmpty
|
validator: (String val) => val.trim().isEmpty
|
||||||
? AppLocalization.of(context).pleaseEnterAName
|
? localization.pleaseEnterAName
|
||||||
: null,
|
: null,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: localization.name,
|
labelText: localization.name,
|
||||||
|
|
|
||||||
|
|
@ -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/dialogs/error_dialog.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
|
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/project/project_screen.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:invoiceninja_flutter/utils/localization.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/project/project_actions.dart';
|
import 'package:invoiceninja_flutter/redux/project/project_actions.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/app/snackbar_row.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/project/project_list_item.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/ui/project/project_list_vm.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/icons.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
||||||
class ProjectList extends StatelessWidget {
|
class ProjectList extends StatelessWidget {
|
||||||
|
|
@ -34,48 +35,34 @@ class ProjectList extends StatelessWidget {
|
||||||
return _buildListView(context);
|
return _buildListView(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showMenu(BuildContext context, ProjectEntity project) async {
|
void _showMenu(
|
||||||
if (project == null) {
|
BuildContext context, ProjectEntity project) async {
|
||||||
return;
|
if (project == null) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final user = viewModel.user;
|
final user = viewModel.user;
|
||||||
final message = await showDialog<String>(
|
final message = await showDialog<String>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) => SimpleDialog(children: <Widget>[
|
builder: (BuildContext dialogContext) => SimpleDialog(
|
||||||
user.canCreate(EntityType.project)
|
children: project
|
||||||
? ListTile(
|
.getEntityActions(user: user)
|
||||||
leading: Icon(Icons.control_point_duplicate),
|
.map((entityAction) {
|
||||||
title: Text(AppLocalization.of(context).clone),
|
if (entityAction == null) {
|
||||||
onTap: () => viewModel.onEntityAction(
|
return Divider();
|
||||||
context, project, EntityAction.clone),
|
} else {
|
||||||
)
|
return ListTile(
|
||||||
: Container(),
|
leading: Icon(getEntityActionIcon(entityAction)),
|
||||||
Divider(),
|
title: Text(AppLocalization.of(context)
|
||||||
user.canEditEntity(project) && !project.isActive
|
.lookup(entityAction.toString())),
|
||||||
? ListTile(
|
onTap: () {
|
||||||
leading: Icon(Icons.restore),
|
Navigator.of(dialogContext).pop();
|
||||||
title: Text(AppLocalization.of(context).restore),
|
viewModel.onEntityAction(context, project, entityAction);
|
||||||
onTap: () => viewModel.onEntityAction(
|
},
|
||||||
context, project, EntityAction.restore),
|
);
|
||||||
)
|
}
|
||||||
: Container(),
|
}).toList()));
|
||||||
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(),
|
|
||||||
]));
|
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
Scaffold.of(context).showSnackBar(SnackBar(
|
Scaffold.of(context).showSnackBar(SnackBar(
|
||||||
content: SnackBarRow(
|
content: SnackBarRow(
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ class ProjectListVM {
|
||||||
@required this.isLoading,
|
@required this.isLoading,
|
||||||
@required this.isLoaded,
|
@required this.isLoaded,
|
||||||
@required this.onProjectTap,
|
@required this.onProjectTap,
|
||||||
@required this.onDismissed,
|
|
||||||
@required this.onRefreshed,
|
@required this.onRefreshed,
|
||||||
@required this.onEntityAction,
|
@required this.onEntityAction,
|
||||||
});
|
});
|
||||||
|
|
@ -57,69 +56,45 @@ class ProjectListVM {
|
||||||
final state = store.state;
|
final state = store.state;
|
||||||
|
|
||||||
return ProjectListVM(
|
return ProjectListVM(
|
||||||
user: state.user,
|
user: state.user,
|
||||||
projectList: memoizedFilteredProjectList(state.projectState.map,
|
projectList: memoizedFilteredProjectList(state.projectState.map,
|
||||||
state.projectState.list, state.projectListState),
|
state.projectState.list, state.projectListState),
|
||||||
projectMap: state.projectState.map,
|
projectMap: state.projectState.map,
|
||||||
isLoading: state.isLoading,
|
isLoading: state.isLoading,
|
||||||
isLoaded: state.projectState.isLoaded,
|
isLoaded: state.projectState.isLoaded,
|
||||||
filter: state.projectUIState.listUIState.filter,
|
filter: state.projectUIState.listUIState.filter,
|
||||||
onProjectTap: (context, project) {
|
onProjectTap: (context, project) {
|
||||||
store.dispatch(EditProject(project: project, context: context));
|
store.dispatch(EditProject(project: project, context: context));
|
||||||
},
|
},
|
||||||
onEntityAction: (context, project, action) {
|
onEntityAction: (context, project, action) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case EntityAction.clone:
|
case EntityAction.clone:
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
EditProject(context: context, project: project.clone));
|
EditProject(context: context, project: project.clone));
|
||||||
break;
|
break;
|
||||||
case EntityAction.restore:
|
case EntityAction.restore:
|
||||||
store.dispatch(RestoreProjectRequest(
|
store.dispatch(RestoreProjectRequest(
|
||||||
popCompleter(
|
snackBarCompleter(
|
||||||
context, AppLocalization.of(context).restoredProject),
|
context, AppLocalization.of(context).restoredProject),
|
||||||
project.id));
|
project.id));
|
||||||
break;
|
break;
|
||||||
case EntityAction.archive:
|
case EntityAction.archive:
|
||||||
store.dispatch(ArchiveProjectRequest(
|
store.dispatch(ArchiveProjectRequest(
|
||||||
popCompleter(
|
snackBarCompleter(
|
||||||
context, AppLocalization.of(context).archivedProject),
|
context, AppLocalization.of(context).archivedProject),
|
||||||
project.id));
|
project.id));
|
||||||
break;
|
break;
|
||||||
case EntityAction.delete:
|
case EntityAction.delete:
|
||||||
store.dispatch(DeleteProjectRequest(
|
store.dispatch(DeleteProjectRequest(
|
||||||
popCompleter(
|
snackBarCompleter(
|
||||||
context, AppLocalization.of(context).deletedProject),
|
context, AppLocalization.of(context).deletedProject),
|
||||||
project.id));
|
project.id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRefreshed: (context) => _handleRefresh(context),
|
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final UserEntity user;
|
final UserEntity user;
|
||||||
|
|
@ -129,7 +104,6 @@ class ProjectListVM {
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
final bool isLoaded;
|
final bool isLoaded;
|
||||||
final Function(BuildContext, ProjectEntity) onProjectTap;
|
final Function(BuildContext, ProjectEntity) onProjectTap;
|
||||||
final Function(BuildContext, ProjectEntity, DismissDirection) onDismissed;
|
|
||||||
final Function(BuildContext) onRefreshed;
|
final Function(BuildContext) onRefreshed;
|
||||||
final Function(BuildContext, ProjectEntity, EntityAction) onEntityAction;
|
final Function(BuildContext, ProjectEntity, EntityAction) onEntityAction;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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/app/snackbar_row.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/stub/stub_list_item.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/ui/stub/stub_list_vm.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/icons.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
||||||
class StubList extends StatelessWidget {
|
class StubList extends StatelessWidget {
|
||||||
|
|
@ -34,48 +35,34 @@ class StubList extends StatelessWidget {
|
||||||
return _buildListView(context);
|
return _buildListView(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showMenu(BuildContext context, StubEntity stub) async {
|
void _showMenu(
|
||||||
if (stub == null) {
|
BuildContext context, StubEntity stub) async {
|
||||||
return;
|
if (stub == null) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final user = viewModel.user;
|
final user = viewModel.user;
|
||||||
final message = await showDialog<String>(
|
final message = await showDialog<String>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) => SimpleDialog(children: <Widget>[
|
builder: (BuildContext dialogContext) => SimpleDialog(
|
||||||
user.canCreate(EntityType.stub)
|
children: stub
|
||||||
? ListTile(
|
.getEntityActions(user: user)
|
||||||
leading: Icon(Icons.control_point_duplicate),
|
.map((entityAction) {
|
||||||
title: Text(AppLocalization.of(context).clone),
|
if (entityAction == null) {
|
||||||
onTap: () => viewModel.onEntityAction(
|
return Divider();
|
||||||
context, stub, EntityAction.clone),
|
} else {
|
||||||
)
|
return ListTile(
|
||||||
: Container(),
|
leading: Icon(getEntityActionIcon(entityAction)),
|
||||||
Divider(),
|
title: Text(AppLocalization.of(context)
|
||||||
user.canEditEntity(stub) && !stub.isActive
|
.lookup(entityAction.toString())),
|
||||||
? ListTile(
|
onTap: () {
|
||||||
leading: Icon(Icons.restore),
|
Navigator.of(dialogContext).pop();
|
||||||
title: Text(AppLocalization.of(context).restore),
|
viewModel.onEntityAction(context, stub, entityAction);
|
||||||
onTap: () => viewModel.onEntityAction(
|
},
|
||||||
context, stub, EntityAction.restore),
|
);
|
||||||
)
|
}
|
||||||
: Container(),
|
}).toList()));
|
||||||
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(),
|
|
||||||
]));
|
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
Scaffold.of(context).showSnackBar(SnackBar(
|
Scaffold.of(context).showSnackBar(SnackBar(
|
||||||
content: SnackBarRow(
|
content: SnackBarRow(
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ class StubListVM {
|
||||||
@required this.isLoading,
|
@required this.isLoading,
|
||||||
@required this.isLoaded,
|
@required this.isLoaded,
|
||||||
@required this.onStubTap,
|
@required this.onStubTap,
|
||||||
@required this.onDismissed,
|
|
||||||
@required this.onRefreshed,
|
@required this.onRefreshed,
|
||||||
@required this.onEntityAction,
|
@required this.onEntityAction,
|
||||||
});
|
});
|
||||||
|
|
@ -95,31 +94,7 @@ class StubListVM {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRefreshed: (context) => _handleRefresh(context),
|
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;
|
final UserEntity user;
|
||||||
|
|
@ -129,7 +104,6 @@ class StubListVM {
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
final bool isLoaded;
|
final bool isLoaded;
|
||||||
final Function(BuildContext, StubEntity) onStubTap;
|
final Function(BuildContext, StubEntity) onStubTap;
|
||||||
final Function(BuildContext, StubEntity, DismissDirection) onDismissed;
|
|
||||||
final Function(BuildContext) onRefreshed;
|
final Function(BuildContext) onRefreshed;
|
||||||
final Function(BuildContext, StubEntity, EntityAction) onEntityAction;
|
final Function(BuildContext, StubEntity, EntityAction) onEntityAction;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue