This commit is contained in:
Hillel Coren 2019-12-15 19:14:57 +02:00
parent 30a028a07d
commit ea16feae8f
18 changed files with 398 additions and 474 deletions

View File

@ -9,6 +9,7 @@ import 'package:invoiceninja_flutter/data/models/static/static_data_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company_gateway/company_gateway_actions.dart';
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
@ -21,6 +22,7 @@ import 'package:invoiceninja_flutter/redux/tax_rate/tax_rate_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/pref_state.dart';
import 'package:invoiceninja_flutter/redux/user/user_actions.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
@ -662,49 +664,80 @@ void editEntityById(
Completer completer}) {
final store = StoreProvider.of<AppState>(context);
final navigator = Navigator.of(context);
final localization = AppLocalization.of(context);
final map = store.state.getEntityMap(entityType);
final entity = map[entityId] as BaseEntity;
switch (entityType) {
case EntityType.client:
store.dispatch(EditClient(
store.dispatch(
EditClient(
client: map[entityId],
navigator: navigator,
completer: completer,
));
completer: completer ??
snackBarCompleter<ClientEntity>(
context,
entity.isNew
? localization.createdClient
: localization.updatedClient)),
);
break;
case EntityType.user:
store.dispatch(EditUser(
store.dispatch(
EditUser(
user: map[entityId],
navigator: navigator,
completer: completer,
));
completer: completer ??
snackBarCompleter<UserEntity>(
context,
entity.isNew
? localization.createdUser
: localization.updatedUser)),
);
break;
case EntityType.project:
store.dispatch(EditProject(
project: map[entityId],
navigator: navigator,
completer: completer,
));
completer: completer ??
snackBarCompleter<ProjectEntity>(
context,
entity.isNew
? localization.createdProject
: localization.updatedProject)));
break;
case EntityType.taxRate:
store.dispatch(EditTaxRate(
taxRate: map[entityId],
navigator: navigator,
completer: completer,
));
completer: completer ??
snackBarCompleter<TaxRateEntity>(
context,
entity.isNew
? localization.createdTaxRate
: localization.updatedTaxRate)));
break;
case EntityType.companyGateway:
store.dispatch(EditCompanyGateway(
companyGateway: map[entityId],
navigator: navigator,
completer: completer,
));
completer: completer ??
snackBarCompleter<CompanyGatewayEntity>(
context,
entity.isNew
? localization.createdCompanyGateway
: localization.updatedCompanyGateway)));
break;
case EntityType.invoice:
store.dispatch(EditInvoice(
invoice: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<InvoiceEntity>(
context,
entity.isNew
? localization.createdInvoice
: localization.updatedInvoice),
invoiceItemIndex: subIndex,
));
break;
@ -715,7 +748,12 @@ void editEntityById(
store.dispatch(EditQuote(
quote: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<InvoiceEntity>(
context,
entity.isNew
? localization.createdQuote
: localization.updatedQuote),
quoteItemIndex: subIndex,
));
break;
@ -723,28 +761,47 @@ void editEntityById(
store.dispatch(EditVendor(
vendor: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<VendorEntity>(
context,
entity.isNew
? localization.createdVendor
: localization.updatedVendor),
));
break;
case EntityType.product:
store.dispatch(EditProduct(
product: map[entityId],
navigator: navigator,
completer: completer,
));
completer: completer ??
snackBarCompleter<ProductEntity>(
context,
entity.isNew
? localization.createdProduct
: localization.updatedProduct)));
break;
case EntityType.task:
store.dispatch(EditTask(
task: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<TaskEntity>(
context,
entity.isNew
? localization.createdTask
: localization.updatedTask),
));
break;
case EntityType.expense:
store.dispatch(EditExpense(
expense: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<ExpenseEntity>(
context,
entity.isNew
? localization.createdExpense
: localization.updatedExpense),
));
break;
//case EntityType.expenseCategory:
@ -757,14 +814,24 @@ void editEntityById(
store.dispatch(EditPayment(
payment: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<PaymentEntity>(
context,
entity.isNew
? localization.createdPayment
: localization.updatedPayment),
));
break;
case EntityType.group:
store.dispatch(EditGroup(
group: map[entityId],
navigator: navigator,
completer: completer,
completer: completer ??
snackBarCompleter<GroupEntity>(
context,
entity.isNew
? localization.createdGroup
: localization.updatedGroup),
));
break;
// TODO Add to starter
@ -782,3 +849,59 @@ void editEntity(
entityType: entity.entityType,
subIndex: subIndex,
completer: completer);
void handleEntityAction(
BuildContext context, BaseEntity entity, dynamic action) {
handleEntitiesActions(context, [entity], action);
}
void handleEntitiesActions(
BuildContext context, List<BaseEntity> entities, dynamic action) {
if (entities.isEmpty) {
return;
}
switch (entities.first.entityType) {
case EntityType.client:
handleClientAction(context, entities, action);
break;
case EntityType.product:
handleProductAction(context, entities, action);
break;
case EntityType.invoice:
handleInvoiceAction(context, entities, action);
break;
case EntityType.payment:
handlePaymentAction(context, entities, action);
break;
case EntityType.quote:
handleQuoteAction(context, entities, action);
break;
case EntityType.task:
handleTaskAction(context, entities, action);
break;
case EntityType.project:
handleProjectAction(context, entities, action);
break;
case EntityType.expense:
handleExpenseAction(context, entities, action);
break;
case EntityType.vendor:
handleVendorAction(context, entities, action);
break;
case EntityType.user:
handleUserAction(context, entities, action);
break;
case EntityType.companyGateway:
handleCompanyGatewayAction(context, entities, action);
break;
case EntityType.taxRate:
handleTaxRateAction(context, entities, action);
break;
case EntityType.group:
handleGroupAction(context, entities, action);
break;
case EntityType.document:
handleDocumentAction(context, entities, action);
}
}

View File

@ -1,7 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'buttons/edit_icon_button.dart';
import 'entities/entity_state_title.dart';
class ViewScaffold extends StatelessWidget {
@ -19,6 +23,10 @@ class ViewScaffold extends StatelessWidget {
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final userCompany = state.userCompany;
return WillPopScope(
onWillPop: () async {
return true;
@ -28,6 +36,24 @@ class ViewScaffold extends StatelessWidget {
automaticallyImplyLeading: isMobile(context),
title: EntityStateTitle(entity: entity),
bottom: appBarBottom,
actions: entity.isNew
? []
: [
userCompany.canEditEntity(entity)
? EditIconButton(
isVisible: !entity.isDeleted,
onPressed: () =>
editEntity(context: context, entity: entity),
)
: Container(),
ActionMenuButton(
isSaving: state.isSaving,
entity: entity,
onSelected: (context, action) =>
handleEntityAction(context, entity, action),
entityActions: entity.getActions(userCompany: userCompany),
)
],
),
body: body,
),

View File

@ -7,8 +7,6 @@ import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/client/client_screen.dart';
import 'package:invoiceninja_flutter/ui/client/view/client_view.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';

View File

@ -46,7 +46,6 @@ class CompanyGatewayEditVM {
@required this.origCompanyGateway,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.onBackPressed,
@required this.isLoading,
});
@ -64,13 +63,6 @@ class CompanyGatewayEditVM {
onChanged: (CompanyGatewayEntity companyGateway) {
store.dispatch(UpdateCompanyGateway(companyGateway));
},
onBackPressed: () {
if (state.uiState.currentRoute.contains(CompanyGatewayScreen.route)) {
store.dispatch(UpdateCurrentRoute(companyGateway.isNew
? CompanyGatewayScreen.route
: CompanyGatewayViewScreen.route));
}
},
onCancelPressed: (BuildContext context) {
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
@ -111,7 +103,6 @@ class CompanyGatewayEditVM {
final Function(CompanyGatewayEntity) onChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final Function onBackPressed;
final bool isLoading;
final bool isSaving;
final CompanyGatewayEntity origCompanyGateway;

View File

@ -2,15 +2,12 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:invoiceninja_flutter/redux/document/document_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/edit_icon_button.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_state_title.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
import 'package:invoiceninja_flutter/ui/expense/view/expense_view_details.dart';
import 'package:invoiceninja_flutter/ui/expense/view/expense_view_documents.dart';
import 'package:invoiceninja_flutter/ui/expense/view/expense_view_vm.dart';
import 'package:invoiceninja_flutter/ui/expense/view/expense_view_overview.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
class ExpenseView extends StatefulWidget {
const ExpenseView({
@ -45,20 +42,46 @@ class _ExpenseViewState extends State<ExpenseView>
final localization = AppLocalization.of(context);
final viewModel = widget.viewModel;
final company = viewModel.state.company;
final expense = viewModel.expense;
final documentState = viewModel.state.documentState;
final documents =
memoizedExpenseDocumentsSelector(documentState.map, viewModel.expense);
return WillPopScope(
onWillPop: () async {
viewModel.onBackPressed();
return true;
},
child: Scaffold(
appBar: _CustomAppBar(
viewModel: viewModel,
return ViewScaffold(
entity: expense,
appBarBottom: TabBar(
controller: _controller,
tabs: [
Tab(
text: localization.overview,
),
body: CustomTabBarView(
viewModel: viewModel,
Tab(
text: localization.details,
),
Tab(
text: documents.isEmpty
? localization.documents
: '${localization.documents} (${documents.length})',
),
],
),
body: TabBarView(
controller: _controller,
children: <Widget>[
RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ExpenseOverview(viewModel: viewModel),
),
RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ExpenseViewDetails(expense: viewModel.expense),
),
RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ExpenseViewDocuments(
viewModel: viewModel, expense: viewModel.expense),
),
],
),
floatingActionButton: company.isEnterprisePlan
? Builder(builder: (BuildContext context) {
@ -80,112 +103,6 @@ class _ExpenseViewState extends State<ExpenseView>
);
})
: null,
),
);
}
}
class CustomTabBarView extends StatefulWidget {
const CustomTabBarView({
@required this.viewModel,
@required this.controller,
});
final ExpenseViewVM viewModel;
final TabController controller;
@override
_CustomTabBarViewState createState() => _CustomTabBarViewState();
}
class _CustomTabBarViewState extends State<CustomTabBarView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
return TabBarView(
controller: widget.controller,
children: <Widget>[
RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ExpenseOverview(viewModel: viewModel),
),
RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ExpenseViewDetails(expense: viewModel.expense),
),
RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ExpenseViewDocuments(
viewModel: viewModel, expense: viewModel.expense),
),
],
);
}
}
class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
const _CustomAppBar({
@required this.viewModel,
@required this.controller,
});
final ExpenseViewVM viewModel;
final TabController controller;
@override
final Size preferredSize = const Size(double.infinity, kToolbarHeight * 2);
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final expense = viewModel.expense;
final userCompany = viewModel.state.userCompany;
final documentState = viewModel.state.documentState;
final documents =
memoizedExpenseDocumentsSelector(documentState.map, viewModel.expense);
return AppBar(
automaticallyImplyLeading: isMobile(context),
title: EntityStateTitle(
entity: expense,
title: expense.publicNotes.isNotEmpty
? expense.publicNotes
: localization.expense,
),
bottom: TabBar(
controller: controller,
tabs: [
Tab(
text: localization.overview,
),
Tab(
text: localization.details,
),
Tab(
text: documents.isEmpty
? localization.documents
: '${localization.documents} (${documents.length})',
),
],
),
actions: expense.isNew
? []
: [
userCompany.canEditEntity(expense)
? EditIconButton(
isVisible: !expense.isDeleted,
onPressed: () => viewModel.onEditPressed(context),
)
: Container(),
ActionMenuButton(
isSaving: viewModel.isSaving,
entity: expense,
onSelected: viewModel.onEntityAction,
entityActions:
viewModel.expense.getActions(userCompany: userCompany),
)
],
);
}
}

View File

@ -46,7 +46,6 @@ class ExpenseViewVM {
@required this.onEntityAction,
@required this.onEntityPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onRefreshed,
@required this.onUploadDocument,
@required this.onDeleteDocument,
@ -85,11 +84,6 @@ class ExpenseViewVM {
context, AppLocalization.of(context).updatedExpense));
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(ExpenseScreen.route)) {
store.dispatch(UpdateCurrentRoute(ExpenseScreen.route));
}
},
onEntityPressed: (BuildContext context, EntityType entityType,
[longPress = false]) {
switch (entityType) {
@ -157,7 +151,6 @@ class ExpenseViewVM {
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext, EntityType, [bool]) onEntityPressed;
final Function(BuildContext) onEditPressed;
final Function onBackPressed;
final Function(BuildContext) onRefreshed;
final Function(BuildContext, String) onUploadDocument;
final Function(BuildContext, DocumentEntity) onDeleteDocument;

View File

@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart';
@ -79,44 +80,19 @@ class _GroupEditState extends State<GroupEdit> {
final localization = AppLocalization.of(context);
final group = viewModel.group;
return WillPopScope(
onWillPop: () async {
viewModel.onBackPressed();
return true;
},
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: isMobile(context),
title: Text(viewModel.group.isNew
? localization.newGroup
: localization.editGroup),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionFlatButton(
tooltip: localization.save,
isVisible: !(group.isDeleted ?? false),
// TODO remove this
isDirty: group.isNew || group != viewModel.origGroup,
isSaving: viewModel.isSaving,
onPressed: () {
return EditScaffold(
onCancelPressed: (context) => viewModel.onCancelPressed(context),
title: group.isNew ? localization.newGroup : localization.editGroup,
onSavePressed: (context) {
if (!_formKey.currentState.validate()) {
return;
}
viewModel.onSavePressed(context);
},
),
],
),
body: Form(
key: _formKey,
child: Builder(builder: (BuildContext context) {
child: Builder(
builder: (BuildContext context) {
return ListView(
children: <Widget>[
FormCard(
@ -129,7 +105,8 @@ class _GroupEditState extends State<GroupEdit> {
),
],
);
})),
},
),
),
);
}

View File

@ -46,7 +46,6 @@ class GroupEditVM {
@required this.origGroup,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.onBackPressed,
@required this.isLoading,
});
@ -64,12 +63,6 @@ class GroupEditVM {
onChanged: (GroupEntity group) {
store.dispatch(UpdateGroup(group));
},
onBackPressed: () {
if (state.uiState.currentRoute.contains(GroupSettingsScreen.route)) {
store.dispatch(UpdateCurrentRoute(
group.isNew ? GroupSettingsScreen.route : GroupViewScreen.route));
}
},
onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: GroupEntity(), force: true);
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
@ -104,7 +97,6 @@ class GroupEditVM {
final Function(GroupEntity) onChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final Function onBackPressed;
final bool isLoading;
final bool isSaving;
final GroupEntity origGroup;

View File

@ -50,7 +50,6 @@ class EntityViewVM {
@required this.onUploadDocument,
@required this.onDeleteDocument,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onClientPressed,
@required this.onPaymentsPressed,
@required this.onPaymentPressed,
@ -70,7 +69,6 @@ class EntityViewVM {
final Function(BuildContext) onPaymentsPressed;
final Function(BuildContext, PaymentEntity, [bool]) onPaymentPressed;
final Function(BuildContext) onRefreshed;
final Function onBackPressed;
final Function(BuildContext, String) onUploadDocument;
final Function(BuildContext, DocumentEntity) onDeleteDocument;
final Function(BuildContext, DocumentEntity) onViewExpense;
@ -90,7 +88,6 @@ class InvoiceViewVM extends EntityViewVM {
Function(BuildContext, PaymentEntity, [bool]) onPaymentPressed,
Function(BuildContext) onPaymentsPressed,
Function(BuildContext) onRefreshed,
Function onBackPressed,
Function(BuildContext, String) onUploadDocument,
Function(BuildContext, DocumentEntity) onDeleteDocument,
Function(BuildContext, DocumentEntity) onViewExpense,
@ -107,7 +104,6 @@ class InvoiceViewVM extends EntityViewVM {
onPaymentPressed: onPaymentPressed,
onPaymentsPressed: onPaymentsPressed,
onRefreshed: onRefreshed,
onBackPressed: onBackPressed,
onUploadDocument: onUploadDocument,
onDeleteDocument: onDeleteDocument,
onViewExpense: onViewExpense);
@ -140,11 +136,6 @@ class InvoiceViewVM extends EntityViewVM {
context, AppLocalization.of(context).updatedInvoice));
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(InvoiceScreen.route)) {
store.dispatch(UpdateCurrentRoute(InvoiceScreen.route));
}
},
onClientPressed: (BuildContext context, [bool longPress = false]) {
if (longPress) {
showEntityActionsDialog(

View File

@ -40,7 +40,6 @@ class ProductViewVM {
@required this.company,
@required this.onEntityAction,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
@ -83,11 +82,6 @@ class ProductViewVM {
onRefreshed: (context, loadActivities) =>
_handleRefresh(context, loadActivities),
*/
onBackPressed: () {
if (state.uiState.currentRoute.contains(ProductScreen.route)) {
store.dispatch(UpdateCurrentRoute(ProductScreen.route));
}
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleProductAction(context, [product], action),
);
@ -98,7 +92,6 @@ class ProductViewVM {
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function onBackPressed;
final Function(BuildContext, bool) onRefreshed;
final bool isSaving;
final bool isLoading;

View File

@ -42,7 +42,6 @@ class ProjectViewVM {
@required this.onEntityAction,
@required this.onTasksPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onAddTaskPressed,
@required this.onClientPressed,
@required this.onRefreshed,
@ -113,11 +112,6 @@ class ProjectViewVM {
..clientId = project.clientId),
force: true);
},
onBackPressed: () {
if (state.uiState.currentRoute.contains(ProjectScreen.route)) {
store.dispatch(UpdateCurrentRoute(ProjectScreen.route));
}
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleProjectAction(context, [project], action),
);
@ -130,7 +124,6 @@ class ProjectViewVM {
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function(BuildContext, [bool]) onClientPressed;
final Function onBackPressed;
final Function(BuildContext) onAddTaskPressed;
final Function(BuildContext, {bool longPress}) onTasksPressed;
final Function(BuildContext) onRefreshed;

View File

@ -54,7 +54,6 @@ class QuoteViewVM extends EntityViewVM {
Function(BuildContext) onPaymentsPressed,
Function(BuildContext, PaymentEntity) onPaymentPressed,
Function(BuildContext) onRefreshed,
Function onBackPressed,
Function(BuildContext, String) onUploadDocument,
Function(BuildContext, DocumentEntity) onDeleteDocument,
Function(BuildContext, DocumentEntity) onViewExpense,
@ -71,7 +70,6 @@ class QuoteViewVM extends EntityViewVM {
onPaymentsPressed: onPaymentsPressed,
onPaymentPressed: onPaymentPressed,
onRefreshed: onRefreshed,
onBackPressed: onBackPressed,
onUploadDocument: onUploadDocument,
onDeleteDocument: onDeleteDocument,
onViewExpense: onViewExpense,
@ -107,11 +105,6 @@ class QuoteViewVM extends EntityViewVM {
context, AppLocalization.of(context).updatedQuote));
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(QuoteScreen.route)) {
store.dispatch(UpdateCurrentRoute(QuoteScreen.route));
}
},
onClientPressed: (BuildContext context, [bool longPress = false]) {
if (longPress) {
showEntityActionsDialog(

View File

@ -47,7 +47,6 @@ class TaskViewVM {
@required this.state,
@required this.onEntityAction,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onRefreshed,
@required this.onClientPressed,
@required this.onProjectPressed,
@ -157,11 +156,6 @@ class TaskViewVM {
*/
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(TaskScreen.route)) {
store.dispatch(UpdateCurrentRoute(TaskScreen.route));
}
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleTaskAction(context, [task], action),
);
@ -174,7 +168,6 @@ class TaskViewVM {
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext, [TaskTime]) onEditPressed;
final Function onBackPressed;
final Function(BuildContext) onFabPressed;
final Function(BuildContext) onRefreshed;
final Function(BuildContext, [bool]) onClientPressed;

View File

@ -46,7 +46,6 @@ class TaxRateEditVM {
@required this.origTaxRate,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.onBackPressed,
@required this.isLoading,
});
@ -68,13 +67,6 @@ class TaxRateEditVM {
createEntity(context: context, entity: TaxRateEntity(), force: true);
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
onBackPressed: () {
if (state.uiState.currentRoute.contains(TaxRateSettingsScreen.route)) {
store.dispatch(UpdateCurrentRoute(taxRate.isNew
? TaxRateSettingsScreen.route
: TaxRateViewScreen.route));
}
},
onSavePressed: (BuildContext context) {
final Completer<TaxRateEntity> completer =
new Completer<TaxRateEntity>();

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart';
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
@ -108,40 +109,16 @@ class _UserEditState extends State<UserEdit> {
final user = viewModel.user;
final userCompany = user.userCompany;
return WillPopScope(
onWillPop: () async {
viewModel.onBackPressed();
return true;
},
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: isMobile(context),
title: Text(viewModel.user.isNew
? localization.newUser
: localization.editUser),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionFlatButton(
tooltip: localization.save,
isVisible: user.isActive,
isDirty: user.isNew || user != viewModel.origUser,
isSaving: viewModel.isSaving,
onPressed: () {
return EditScaffold(
title:
viewModel.user.isNew ? localization.newUser : localization.editUser,
onCancelPressed: (context) => viewModel.onCancelPressed(context),
onSavePressed: (context) {
if (!_formKey.currentState.validate()) {
return;
}
viewModel.onSavePressed(context);
},
),
],
),
body: AppForm(
focusNode: _focusNode,
formKey: _formKey,
@ -219,8 +196,7 @@ class _UserEditState extends State<UserEdit> {
onChanged: (value) =>
_togglePermission(kPermissionCreateAll),
),
onTap: () =>
_togglePermission(kPermissionCreateAll)),
onTap: () => _togglePermission(kPermissionCreateAll)),
DataCell(
_PermissionCheckbox(
userCompany: userCompany,
@ -245,8 +221,7 @@ class _UserEditState extends State<UserEdit> {
EntityType.payment,
EntityType.quote,
].map((EntityType type) {
final createPermission =
'create_' + toSnakeCase('$type');
final createPermission = 'create_' + toSnakeCase('$type');
final editPermission = 'edit_' + toSnakeCase('$type');
final viewPermission = 'view_' + toSnakeCase('$type');
return DataRow(cells: [
@ -298,7 +273,6 @@ class _UserEditState extends State<UserEdit> {
)
],
),
),
);
}
}

View File

@ -47,7 +47,6 @@ class UserEditVM {
@required this.origUser,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.onBackPressed,
@required this.isLoading,
});
@ -66,12 +65,6 @@ class UserEditVM {
onUserChanged: (UserEntity user) {
store.dispatch(UpdateUser(user));
},
onBackPressed: () {
if (state.uiState.currentRoute.contains(UserScreen.route)) {
store.dispatch(UpdateCurrentRoute(
user.isNew ? UserScreen.route : UserViewScreen.route));
}
},
onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: UserEntity(), force: true);
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
@ -107,7 +100,6 @@ class UserEditVM {
final Function(UserEntity) onUserChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final Function onBackPressed;
final bool isLoading;
final bool isSaving;
final UserEntity origUser;

View File

@ -43,7 +43,6 @@ class VendorViewVM {
@required this.onEntityAction,
@required this.onEntityPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@ -77,11 +76,6 @@ class VendorViewVM {
context, AppLocalization.of(context).updatedVendor));
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(VendorScreen.route)) {
store.dispatch(UpdateCurrentRoute(VendorScreen.route));
}
},
onEntityPressed: (BuildContext context, EntityType entityType,
[longPress = false]) {
switch (entityType) {
@ -115,7 +109,6 @@ class VendorViewVM {
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function(BuildContext, EntityType, [bool]) onEntityPressed;
final Function onBackPressed;
final Function(BuildContext) onRefreshed;
final Function(BuildContext) onAddExpensePressed;
final bool isSaving;

View File

@ -41,7 +41,6 @@ class StubViewVM {
@required this.company,
@required this.onEntityAction,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@ -75,11 +74,6 @@ class StubViewVM {
context, AppLocalization.of(context).updatedStub));
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(StubScreen.route)) {
store.dispatch(UpdateCurrentRoute(StubScreen.route));
}
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleStubAction(context, stub, action),
);
@ -90,7 +84,6 @@ class StubViewVM {
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function onBackPressed;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;