Refactor entity actions

This commit is contained in:
Hillel Coren 2019-06-16 14:39:03 +03:00
parent c3237fd659
commit ccb07c4373
54 changed files with 958 additions and 1421 deletions

View File

@ -106,8 +106,6 @@ class ExpenseStatusColors {
};
}
const List<int> kPaymentTerms = [0, -1, 7, 10, 14, 15, 30, 60, 90];
const String kDesignCustom1 = 'Custom 1';

View File

@ -68,7 +68,11 @@ abstract class ExpenseEntity extends Object
with BaseEntity, SelectableEntity, BelongsToClient
implements Built<ExpenseEntity, ExpenseEntityBuilder> {
factory ExpenseEntity(
{int id, CompanyEntity company, UIState uiState, VendorEntity vendor, ClientEntity client}) {
{int id,
CompanyEntity company,
UIState uiState,
VendorEntity vendor,
ClientEntity client}) {
return _$ExpenseEntity._(
id: id ?? --ExpenseEntity.counter,
privateNotes: '',

View File

@ -120,8 +120,6 @@ abstract class CurrencyEntity extends Object
@override
double get listDisplayAmount => null;
static Serializer<CurrencyEntity> get serializer =>
_$currencyEntitySerializer;
}

View File

@ -311,7 +311,8 @@ Middleware<AppState> _createAccountLoaded() {
};
}
Middleware<AppState> _createPersistStatic(PersistenceRepository staticRepository) {
Middleware<AppState> _createPersistStatic(
PersistenceRepository staticRepository) {
return (Store<AppState> store, dynamic action, NextDispatcher next) {
// first process the action so the data is in the state
next(action);

View File

@ -13,7 +13,6 @@ var memoizedDropdownExpenseCategoriesList = memo2(
List<int> dropdownExpenseCategoriesSelector(
BuiltMap<int, ExpenseCategoryEntity> categoryMap,
BuiltList<ExpenseCategoryEntity> categoryList) {
final list = categoryList
//.where((category) => category.isActive)
.map((category) => category.id)

View File

@ -3,6 +3,13 @@ import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_selectors.dart';
class ViewExpenseList implements PersistUI {
ViewExpenseList(this.context);
@ -227,3 +234,47 @@ class FilterExpensesByEntity implements PersistUI {
final int entityId;
final EntityType entityType;
}
void handleExpenseAction(
BuildContext context, ExpenseEntity expense, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.selectedCompany;
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditExpense(context: context, expense: expense));
break;
case EntityAction.clone:
store.dispatch(EditExpense(context: context, expense: expense.clone));
break;
case EntityAction.newInvoice:
final item = convertExpenseToInvoiceItem(expense: expense);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: company).rebuild((b) => b
..hasExpenses = true
..clientId = expense.clientId
..invoiceItems.add(item)),
context: context));
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(invoiceId: expense.invoiceId, context: context));
break;
case EntityAction.restore:
store.dispatch(RestoreExpenseRequest(
snackBarCompleter(context, localization.restoredExpense),
expense.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveExpenseRequest(
snackBarCompleter(context, localization.archivedExpense),
expense.id));
break;
case EntityAction.delete:
store.dispatch(DeleteExpenseRequest(
snackBarCompleter(context, localization.deletedExpense), expense.id));
break;
}
}

View File

@ -89,13 +89,13 @@ ListUIState _filterExpensesByState(
ListUIState _filterExpensesByStatus(
ListUIState expenseListState, FilterExpensesByStatus action) {
if (expenseListState.statusFilters.contains(action.status)) {
return expenseListState.rebuild((b) => b..statusFilters.remove(action.status));
return expenseListState
.rebuild((b) => b..statusFilters.remove(action.status));
} else {
return expenseListState.rebuild((b) => b..statusFilters.add(action.status));
}
}
ListUIState _filterExpenses(
ListUIState expenseListState, FilterExpenses action) {
return expenseListState.rebuild((b) => b..filter = action.filter);

View File

@ -1,9 +1,17 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/utils/pdf.dart';
import 'package:url_launcher/url_launcher.dart';
class ViewInvoiceList implements PersistUI {
ViewInvoiceList(this.context);
@ -302,3 +310,63 @@ class FilterInvoicesByCustom2 implements PersistUI {
final String value;
}
void handleInvoiceAction(
BuildContext context, InvoiceEntity invoice, EntityAction action) async {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.selectedCompany;
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditInvoice(context: context, invoice: invoice));
break;
case EntityAction.pdf:
viewPdf(invoice, context);
break;
case EntityAction.clientPortal:
if (await canLaunch(invoice.invitationSilentLink)) {
await launch(invoice.invitationSilentLink,
forceSafariVC: false, forceWebView: false);
}
break;
case EntityAction.markSent:
store.dispatch(MarkSentInvoiceRequest(
snackBarCompleter(context, localization.markedInvoiceAsSent),
invoice.id));
break;
case EntityAction.sendEmail:
store.dispatch(ShowEmailInvoice(
completer: snackBarCompleter(context, localization.emailedInvoice),
invoice: invoice,
context: context));
break;
case EntityAction.cloneToInvoice:
store.dispatch(
EditInvoice(context: context, invoice: invoice.cloneToInvoice));
break;
case EntityAction.cloneToQuote:
store.dispatch(EditQuote(context: context, quote: invoice.cloneToQuote));
break;
case EntityAction.enterPayment:
store.dispatch(EditPayment(
context: context,
payment: invoice.createPayment(company)));
break;
case EntityAction.restore:
store.dispatch(RestoreInvoiceRequest(
snackBarCompleter(context, localization.restoredInvoice),
invoice.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveInvoiceRequest(
snackBarCompleter(context, localization.archivedInvoice),
invoice.id));
break;
case EntityAction.delete:
store.dispatch(DeleteInvoiceRequest(
snackBarCompleter(context, localization.deletedInvoice), invoice.id));
break;
}
}

View File

@ -77,7 +77,8 @@ InvoiceEntity _addInvoiceItem(InvoiceEntity invoice, AddInvoiceItem action) {
InvoiceEntity _addInvoiceItems(InvoiceEntity invoice, AddInvoiceItems action) {
return invoice.rebuild((b) => b
..hasTasks = action.invoiceItems.where((item) => item.isTask).isNotEmpty
..hasExpenses = action.invoiceItems.where((item) => item.isExpense).isNotEmpty
..hasExpenses =
action.invoiceItems.where((item) => item.isExpense).isNotEmpty
..invoiceItems.addAll(action.invoiceItems));
}

View File

@ -3,6 +3,10 @@ import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class ViewPaymentList implements PersistUI {
ViewPaymentList(this.context);
@ -236,3 +240,33 @@ class FilterPaymentsByEntity implements PersistUI {
final int entityId;
final EntityType entityType;
}
void handlePaymentAction(
BuildContext context, PaymentEntity payment, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditPayment(context: context, payment: payment));
break;
case EntityAction.sendEmail:
store.dispatch(EmailPaymentRequest(
snackBarCompleter(context, localization.emailedPayment), payment));
break;
case EntityAction.restore:
store.dispatch(RestorePaymentRequest(
snackBarCompleter(context, localization.restoredPayment),
payment.id));
break;
case EntityAction.archive:
store.dispatch(ArchivePaymentRequest(
snackBarCompleter(context, localization.archivedPayment),
payment.id));
break;
case EntityAction.delete:
store.dispatch(DeletePaymentRequest(
snackBarCompleter(context, localization.deletedPayment), payment.id));
break;
}
}

View File

@ -10,7 +10,6 @@ import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class ViewProductList implements PersistUI {
ViewProductList(this.context);
@ -179,7 +178,6 @@ class FilterProductDropdown {
final String filter;
}
void handleProductAction(
BuildContext context, ProductEntity product, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
@ -199,8 +197,7 @@ void handleProductAction(
store.dispatch(EditProduct(context: context, product: product));
break;
case EntityAction.clone:
store.dispatch(
EditProduct(context: context, product: product.clone));
store.dispatch(EditProduct(context: context, product: product.clone));
break;
case EntityAction.restore:
store.dispatch(RestoreProductRequest(
@ -214,8 +211,7 @@ void handleProductAction(
break;
case EntityAction.delete:
store.dispatch(DeleteProductRequest(
snackBarCompleter(context, localization.deletedProduct),
product.id));
snackBarCompleter(context, localization.deletedProduct), product.id));
break;
}
}

View File

@ -3,6 +3,13 @@ import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/project/project_selectors.dart';
class ViewProjectList implements PersistUI {
ViewProjectList(this.context);
@ -221,3 +228,47 @@ class FilterProjectsByEntity implements PersistUI {
final int entityId;
final EntityType entityType;
}
void handleProjectAction(
BuildContext context, ProjectEntity project, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.selectedCompany;
switch (action) {
case EntityAction.edit:
store.dispatch(EditProject(context: context, project: project));
break;
case EntityAction.newInvoice:
final items =
convertProjectToInvoiceItem(project: project, context: context);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: company).rebuild((b) => b
..hasTasks = true
..clientId = project.clientId
..invoiceItems.addAll(items)),
context: context));
break;
case EntityAction.clone:
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;
}
}

View File

@ -1,9 +1,16 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/pdf.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:flutter/material.dart';
class ViewQuoteList implements PersistUI {
ViewQuoteList(this.context);
@ -322,3 +329,65 @@ class ConvertQuoteFailure implements StopSaving {
final dynamic error;
}
Future handleQuoteAction(
BuildContext context, InvoiceEntity quote, EntityAction action) async {
final store = StoreProvider.of<AppState>(context);
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditQuote(context: context, quote: quote));
break;
case EntityAction.pdf:
viewPdf(quote, context);
break;
case EntityAction.clientPortal:
if (await canLaunch(quote.invitationSilentLink)) {
await launch(quote.invitationSilentLink,
forceSafariVC: false, forceWebView: false);
}
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(context: context, invoiceId: quote.quoteInvoiceId));
break;
case EntityAction.convert:
final Completer<InvoiceEntity> completer = Completer<InvoiceEntity>();
store.dispatch(ConvertQuote(completer, quote.id));
completer.future.then((InvoiceEntity invoice) {
store.dispatch(ViewInvoice(invoiceId: invoice.id, context: context));
});
break;
case EntityAction.markSent:
store.dispatch(MarkSentQuoteRequest(
snackBarCompleter(context, localization.markedQuoteAsSent),
quote.id));
break;
case EntityAction.sendEmail:
store.dispatch(ShowEmailQuote(
completer: snackBarCompleter(context, localization.emailedQuote),
quote: quote,
context: context));
break;
case EntityAction.cloneToInvoice:
store.dispatch(
EditInvoice(context: context, invoice: quote.cloneToInvoice));
break;
case EntityAction.cloneToQuote:
store.dispatch(EditQuote(context: context, quote: quote.cloneToQuote));
break;
case EntityAction.restore:
store.dispatch(RestoreQuoteRequest(
snackBarCompleter(context, localization.restoredQuote), quote.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveQuoteRequest(
snackBarCompleter(context, localization.archivedQuote), quote.id));
break;
case EntityAction.delete:
store.dispatch(DeleteQuoteRequest(
snackBarCompleter(context, localization.deletedQuote), quote.id));
break;
}
}

View File

@ -3,6 +3,15 @@ import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/task/task_selectors.dart';
class ViewTaskList implements PersistUI {
ViewTaskList(this.context);
@ -259,3 +268,73 @@ class FilterTasksByEntity implements PersistUI {
final int entityId;
final EntityType entityType;
}
void handleTaskAction(
BuildContext context, TaskEntity task, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.selectedCompany;
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditTask(context: context, task: task));
break;
case EntityAction.start:
case EntityAction.stop:
case EntityAction.resume:
final Completer<TaskEntity> completer = new Completer<TaskEntity>();
final localization = AppLocalization.of(context);
store
.dispatch(SaveTaskRequest(completer: completer, task: task.toggle()));
completer.future.then((savedTask) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: savedTask.isRunning
? (savedTask.duration > 0
? localization.resumedTask
: localization.startedTask)
: localization.stoppedTask,
)));
}).catchError((Object error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
break;
case EntityAction.newInvoice:
final item = convertTaskToInvoiceItem(task: task, context: context);
store.dispatch(EditInvoice(
invoice:
InvoiceEntity(company: company).rebuild((b) => b
..hasTasks = true
..clientId = task.clientId
..invoiceItems.add(item)),
context: context));
break;
case EntityAction.viewInvoice:
store.dispatch(ViewInvoice(invoiceId: task.invoiceId, context: context));
break;
case EntityAction.clone:
store.dispatch(EditTask(context: context, task: task.clone));
break;
case EntityAction.restore:
store.dispatch(RestoreTaskRequest(
snackBarCompleter(context, localization.restoredTask),
task.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveTaskRequest(
snackBarCompleter(context, localization.archivedTask),
task.id));
break;
case EntityAction.delete:
store.dispatch(DeleteTaskRequest(
snackBarCompleter(context, localization.deletedTask),
task.id));
break;
}
}

View File

@ -3,6 +3,11 @@ import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_actions.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
class ViewVendorList implements PersistUI {
ViewVendorList(this.context);
@ -251,3 +256,34 @@ class FilterVendorsByEntity implements PersistUI {
final int entityId;
final EntityType entityType;
}
void handleVendorAction(
BuildContext context, VendorEntity vendor, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.selectedCompany;
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditVendor(context: context, vendor: vendor));
break;
case EntityAction.newExpense:
store.dispatch(EditExpense(
expense: ExpenseEntity(company: company, vendor: vendor),
context: context));
break;
case EntityAction.restore:
store.dispatch(RestoreVendorRequest(
snackBarCompleter(context, localization.restoredVendor), vendor.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveVendorRequest(
snackBarCompleter(context, localization.archivedVendor), vendor.id));
break;
case EntityAction.delete:
store.dispatch(DeleteVendorRequest(
snackBarCompleter(context, localization.deletedVendor), vendor.id));
break;
}
}

View File

@ -47,27 +47,26 @@ class ClientList extends StatelessWidget {
final clientId = viewModel.clientList[index];
final client = viewModel.clientMap[clientId];
final user = viewModel.user;
void showDialog() => showEntityActionsDialog(
entity: client,
context: context,
user: user,
onEntityAction: viewModel.onEntityAction);
return ClientListItem(
user: viewModel.user,
filter: viewModel.filter,
client: client,
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
showEntityActionsDialog(
entity: client,
context: context,
user: user,
onEntityAction: viewModel.onEntityAction);
showDialog();
} else {
viewModel.onEntityAction(context, client, action);
}
},
onTap: () => viewModel.onClientTap(context, client),
onLongPress: () => showEntityActionsDialog(
entity: client,
context: context,
user: user,
onEntityAction: viewModel.onEntityAction),
onLongPress: () => showDialog(),
);
}),
);

View File

@ -59,11 +59,13 @@ class ClientListItem extends StatelessWidget {
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
filterMatch != null ? Text(
filterMatch != null
? Text(
filterMatch,
maxLines: 3,
overflow: TextOverflow.ellipsis,
) : SizedBox(),
)
: SizedBox(),
EntityStateLabel(client),
],
),

View File

@ -290,7 +290,7 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
user: viewModel.company.user,
isSaving: viewModel.isSaving,
entity: client,
onSelected: viewModel.onActionSelected,
onSelected: viewModel.onEntityAction,
entityActions: viewModel.client.getActions(user: user),
)
],

View File

@ -145,8 +145,8 @@ class ClientOverview extends StatelessWidget {
title: localization.expenses,
onTap: () =>
viewModel.onEntityPressed(context, EntityType.expense),
onLongPress: () =>
viewModel.onEntityPressed(context, EntityType.expense, true),
onLongPress: () => viewModel.onEntityPressed(
context, EntityType.expense, true),
subtitle: memoizedExpenseStatsForClient(
client.id,
state.expenseState.map,

View File

@ -44,7 +44,7 @@ class ClientViewVM {
ClientViewVM({
@required this.client,
@required this.company,
@required this.onActionSelected,
@required this.onEntityAction,
@required this.onEntityPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@ -173,14 +173,14 @@ class ClientViewVM {
store.dispatch(UpdateCurrentRoute(ClientScreen.route));
}
},
onActionSelected: (BuildContext context, EntityAction action) =>
onEntityAction: (BuildContext context, EntityAction action) =>
handleClientAction(context, client, action),
);
}
final ClientEntity client;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onActionSelected;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function onBackPressed;
final Function(BuildContext, EntityType, [bool]) onEntityPressed;

View File

@ -20,8 +20,7 @@ class ExpenseEditDocumentsState extends State<ExpenseEditDocuments> {
@override
void didChangeDependencies() {
final List<TextEditingController> _controllers = [
];
final List<TextEditingController> _controllers = [];
_controllers
.forEach((dynamic controller) => controller.removeListener(_onChanged));
@ -71,8 +70,7 @@ class ExpenseEditDocumentsState extends State<ExpenseEditDocuments> {
viewModel.onChanged(
expense.rebuild((b) => b..invoiceDocuments = value));
viewModel.onAddDocumentsChanged(value);
}
)
})
],
),
],

View File

@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
@ -17,41 +18,6 @@ class ExpenseList extends StatelessWidget {
final ExpenseListVM viewModel;
void _showMenu(BuildContext context, ExpenseEntity expense) async {
if (expense == null) {
return;
}
final user = viewModel.user;
final message = await showDialog<String>(
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: expense
.getActions(user: user, includeEdit: true)
.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, expense, entityAction);
},
);
}
}).toList()));
if (message != null) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: message,
)));
}
}
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
@ -119,12 +85,21 @@ class ExpenseList extends StatelessWidget {
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.expenseList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final expenseId = viewModel.expenseList[index];
final expense = viewModel.expenseMap[expenseId];
final client =
viewModel.state.clientState.map[expense.clientId];
final vendor =
viewModel.state.vendorState.map[expense.vendorId];
void showDialog() => showEntityActionsDialog(
entity: expense,
context: context,
user: user,
client: client,
onEntityAction: viewModel.onEntityAction);
return ExpenseListItem(
user: viewModel.user,
filter: viewModel.filter,
@ -134,13 +109,13 @@ class ExpenseList extends StatelessWidget {
onTap: () => viewModel.onExpenseTap(context, expense),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, expense);
showDialog();
} else {
viewModel.onEntityAction(
context, expense, action);
}
},
onLongPress: () => _showMenu(context, expense),
onLongPress: () => showDialog(),
);
},
),

View File

@ -1,5 +1,4 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
import 'package:redux/redux.dart';
import 'package:flutter/material.dart';
@ -92,49 +91,9 @@ class ExpenseListVM {
onExpenseTap: (context, expense) {
store.dispatch(ViewExpense(expenseId: expense.id, context: context));
},
onEntityAction: (context, expense, action) {
switch (action) {
case EntityAction.edit:
store.dispatch(EditExpense(context: context, expense: expense));
break;
case EntityAction.clone:
store.dispatch(
EditExpense(context: context, expense: expense.clone));
break;
case EntityAction.newInvoice:
final item = convertExpenseToInvoiceItem(expense: expense);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: state.selectedCompany)
.rebuild((b) => b
..hasExpenses = true
..clientId = expense.clientId
..invoiceItems.add(item)),
context: context));
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(invoiceId: expense.invoiceId, context: context));
break;
case EntityAction.restore:
store.dispatch(RestoreExpenseRequest(
snackBarCompleter(
context, AppLocalization.of(context).restoredExpense),
expense.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveExpenseRequest(
snackBarCompleter(
context, AppLocalization.of(context).archivedExpense),
expense.id));
break;
case EntityAction.delete:
store.dispatch(DeleteExpenseRequest(
snackBarCompleter(
context, AppLocalization.of(context).deletedExpense),
expense.id));
break;
}
},
onEntityAction:
(BuildContext context, BaseEntity expense, EntityAction action) =>
handleExpenseAction(context, expense, action),
onRefreshed: (context) => _handleRefresh(context),
);
}

View File

@ -157,7 +157,7 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
user: viewModel.company.user,
isSaving: viewModel.isSaving,
entity: expense,
onSelected: viewModel.onActionSelected,
onSelected: viewModel.onEntityAction,
entityActions: viewModel.expense.getActions(user: user),
)
],

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_selectors.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
@ -42,7 +41,7 @@ class ExpenseViewVM {
@required this.state,
@required this.expense,
@required this.company,
@required this.onActionSelected,
@required this.onEntityAction,
@required this.onEntityPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@ -120,50 +119,17 @@ class ExpenseViewVM {
break;
}
},
onActionSelected: (BuildContext context, EntityAction action) {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.clone:
store.dispatch(
EditExpense(context: context, expense: expense.clone));
break;
case EntityAction.newInvoice:
final item = convertExpenseToInvoiceItem(expense: expense);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: state.selectedCompany)
.rebuild((b) => b
..hasExpenses = true
..clientId = expense.clientId
..invoiceItems.add(item)),
context: context));
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(invoiceId: expense.invoiceId, context: context));
break;
case EntityAction.archive:
store.dispatch(ArchiveExpenseRequest(
popCompleter(context, localization.archivedExpense),
expense.id));
break;
case EntityAction.delete:
store.dispatch(DeleteExpenseRequest(
popCompleter(context, localization.deletedExpense),
expense.id));
break;
case EntityAction.restore:
store.dispatch(RestoreExpenseRequest(
snackBarCompleter(context, localization.restoredExpense),
expense.id));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handleExpenseAction(context, expense, action),
);
}
final AppState state;
final ExpenseEntity expense;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onActionSelected;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext, EntityType, [bool]) onEntityPressed;
final Function(BuildContext) onEditPressed;
final Function onBackPressed;

View File

@ -1,13 +1,11 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_list_item.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_list_vm.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class InvoiceList extends StatelessWidget {
@ -18,43 +16,6 @@ class InvoiceList extends StatelessWidget {
final EntityListVM viewModel;
void _showMenu(
BuildContext context, InvoiceEntity invoice, ClientEntity client) async {
if (invoice == null || client == null) {
return;
}
final user = viewModel.user;
final message = await showDialog<String>(
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: invoice
.getActions(
user: user, client: client, includeEdit: true)
.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, invoice, entityAction);
},
);
}
}).toList()));
if (message != null) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: message,
)));
}
}
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
@ -117,11 +78,20 @@ class InvoiceList extends StatelessWidget {
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.invoiceList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final invoiceId = viewModel.invoiceList[index];
final invoice = viewModel.invoiceMap[invoiceId];
final client =
viewModel.clientMap[invoice.clientId] ??
ClientEntity();
void showDialog() => showEntityActionsDialog(
entity: invoice,
context: context,
user: user,
client: client,
onEntityAction: viewModel.onEntityAction);
return InvoiceListItem(
user: viewModel.user,
filter: viewModel.filter,
@ -132,14 +102,13 @@ class InvoiceList extends StatelessWidget {
viewModel.onInvoiceTap(context, invoice),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, invoice, client);
showDialog();
} else {
viewModel.onEntityAction(
context, invoice, action);
}
},
onLongPress: () =>
_showMenu(context, invoice, client),
onLongPress: () => showDialog(),
);
},
),

View File

@ -6,18 +6,14 @@ import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/pdf.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_list.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:url_launcher/url_launcher.dart';
class InvoiceListBuilder extends StatelessWidget {
const InvoiceListBuilder({Key key}) : super(key: key);
@ -136,63 +132,9 @@ class InvoiceListVM extends EntityListVM {
ViewClient(
clientId: state.invoiceListState.filterEntityId,
context: context)),
onEntityAction: (context, invoice, action) async {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditInvoice(context: context, invoice: invoice));
break;
case EntityAction.pdf:
viewPdf(invoice, context);
break;
case EntityAction.clientPortal:
if (await canLaunch(invoice.invitationSilentLink)) {
await launch(invoice.invitationSilentLink,
forceSafariVC: false, forceWebView: false);
}
break;
case EntityAction.markSent:
store.dispatch(MarkSentInvoiceRequest(
snackBarCompleter(context, localization.markedInvoiceAsSent),
invoice.id));
break;
case EntityAction.sendEmail:
store.dispatch(ShowEmailInvoice(
completer:
snackBarCompleter(context, localization.emailedInvoice),
invoice: invoice,
context: context));
break;
case EntityAction.cloneToInvoice:
store.dispatch(
EditInvoice(context: context, invoice: invoice.cloneToInvoice));
break;
case EntityAction.cloneToQuote:
store.dispatch(
EditQuote(context: context, quote: invoice.cloneToQuote));
break;
case EntityAction.enterPayment:
store.dispatch(EditPayment(
context: context,
payment: invoice.createPayment(state.selectedCompany)));
break;
case EntityAction.restore:
store.dispatch(RestoreInvoiceRequest(
snackBarCompleter(context, localization.restoredInvoice),
invoice.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveInvoiceRequest(
snackBarCompleter(context, localization.archivedInvoice),
invoice.id));
break;
case EntityAction.delete:
store.dispatch(DeleteInvoiceRequest(
snackBarCompleter(context, localization.deletedInvoice),
invoice.id));
break;
}
},
onEntityAction:
(BuildContext context, BaseEntity invoice, EntityAction action) =>
handleInvoiceAction(context, invoice, action),
);
}
}

View File

@ -309,8 +309,7 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
: Container(),
ActionMenuButton(
user: user,
entityActions:
invoice.getActions(client: client, user: user),
entityActions: invoice.getActions(client: client, user: user),
isSaving: viewModel.isSaving,
entity: invoice,
onSelected: viewModel.onActionSelected,

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:redux/redux.dart';
import 'package:flutter/foundation.dart';
@ -11,13 +10,11 @@ import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_screen.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/pdf.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/invoice/view/invoice_view.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:url_launcher/url_launcher.dart';
class InvoiceViewScreen extends StatelessWidget {
const InvoiceViewScreen({Key key}) : super(key: key);
@ -93,7 +90,7 @@ class InvoiceViewVM extends EntityViewVM {
ClientEntity client,
bool isSaving,
bool isDirty,
Function(BuildContext, EntityAction) onActionSelected,
Function(BuildContext, EntityAction) onEntityAction,
Function(BuildContext, [InvoiceItemEntity]) onEditPressed,
Function(BuildContext, [bool]) onClientPressed,
Function(BuildContext, PaymentEntity, [bool]) onPaymentPressed,
@ -106,7 +103,7 @@ class InvoiceViewVM extends EntityViewVM {
client: client,
isSaving: isSaving,
isDirty: isDirty,
onActionSelected: onActionSelected,
onActionSelected: onEntityAction,
onEditPressed: onEditPressed,
onClientPressed: onClientPressed,
onPaymentPressed: onPaymentPressed,
@ -179,61 +176,8 @@ class InvoiceViewVM extends EntityViewVM {
entityId: invoice.id, entityType: EntityType.invoice));
store.dispatch(ViewPaymentList(context));
},
onActionSelected: (BuildContext context, EntityAction action) async {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.pdf:
viewPdf(invoice, context);
break;
case EntityAction.clientPortal:
if (await canLaunch(invoice.invitationSilentLink)) {
await launch(invoice.invitationSilentLink,
forceSafariVC: false, forceWebView: false);
}
break;
case EntityAction.markSent:
store.dispatch(MarkSentInvoiceRequest(
snackBarCompleter(context, localization.markedInvoiceAsSent),
invoice.id));
break;
case EntityAction.sendEmail:
store.dispatch(ShowEmailInvoice(
completer:
snackBarCompleter(context, localization.emailedInvoice),
invoice: invoice,
context: context));
break;
case EntityAction.archive:
store.dispatch(ArchiveInvoiceRequest(
popCompleter(context, localization.archivedInvoice),
invoice.id));
break;
case EntityAction.delete:
store.dispatch(DeleteInvoiceRequest(
popCompleter(context, localization.deletedInvoice),
invoice.id));
break;
case EntityAction.restore:
store.dispatch(RestoreInvoiceRequest(
snackBarCompleter(context, localization.restoredInvoice),
invoice.id));
break;
case EntityAction.cloneToInvoice:
Navigator.of(context).pop();
store.dispatch(EditInvoice(
context: context, invoice: invoice.cloneToInvoice));
break;
case EntityAction.cloneToQuote:
Navigator.of(context).pop();
store.dispatch(
EditQuote(context: context, quote: invoice.cloneToQuote));
break;
case EntityAction.enterPayment:
store.dispatch(EditPayment(
context: context,
payment: invoice.createPayment(state.selectedCompany)));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handleInvoiceAction(context, invoice, action),
);
}
}

View File

@ -1,16 +1,14 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/payment_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:invoiceninja_flutter/ui/payment/payment_list_item.dart';
import 'package:invoiceninja_flutter/ui/payment/payment_list_vm.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class PaymentList extends StatelessWidget {
@ -21,43 +19,6 @@ class PaymentList extends StatelessWidget {
final PaymentListVM viewModel;
void _showMenu(
BuildContext context, PaymentEntity payment, ClientEntity client) async {
if (payment == null || client == null) {
return;
}
final user = viewModel.user;
final message = await showDialog<String>(
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: payment
.getActions(
user: user, client: client, includeEdit: true)
.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, payment, entityAction);
},
);
}
}).toList()));
if (message != null) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: message,
)));
}
}
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
@ -134,10 +95,19 @@ class PaymentList extends StatelessWidget {
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.paymentList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final paymentId = viewModel.paymentList[index];
final payment = state.paymentState.map[paymentId];
final client =
paymentClientSelector(paymentId, state);
void showDialog() => showEntityActionsDialog(
entity: payment,
context: context,
user: user,
client: client,
onEntityAction: viewModel.onEntityAction);
return PaymentListItem(
user: viewModel.user,
filter: viewModel.filter,
@ -146,14 +116,13 @@ class PaymentList extends StatelessWidget {
viewModel.onPaymentTap(context, payment),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, payment, client);
showDialog();
} else {
viewModel.onEntityAction(
context, payment, action);
}
},
onLongPress: () =>
_showMenu(context, payment, client),
onLongPress: () => showDialog(),
);
},
),

View File

@ -79,34 +79,9 @@ class PaymentListVM {
onPaymentTap: (context, payment) {
store.dispatch(ViewPayment(paymentId: payment.id, context: context));
},
onEntityAction: (context, payment, action) {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditPayment(context: context, payment: payment));
break;
case EntityAction.sendEmail:
store.dispatch(EmailPaymentRequest(
snackBarCompleter(context, localization.emailedPayment),
payment));
break;
case EntityAction.restore:
store.dispatch(RestorePaymentRequest(
snackBarCompleter(context, localization.restoredPayment),
payment.id));
break;
case EntityAction.archive:
store.dispatch(ArchivePaymentRequest(
snackBarCompleter(context, localization.archivedPayment),
payment.id));
break;
case EntityAction.delete:
store.dispatch(DeletePaymentRequest(
snackBarCompleter(context, localization.deletedPayment),
payment.id));
break;
}
},
onEntityAction:
(BuildContext context, BaseEntity payment, EntityAction action) =>
handlePaymentAction(context, payment, action),
onClearEntityFilterPressed: () =>
store.dispatch(FilterPaymentsByEntity()),
onViewClientFilterPressed: (BuildContext context) {

View File

@ -70,7 +70,7 @@ class _PaymentViewState extends State<PaymentView> {
user: viewModel.company.user,
isSaving: viewModel.isSaving,
entity: payment,
onSelected: viewModel.onActionSelected,
onSelected: viewModel.onEntityAction,
entityActions: viewModel.payment.getActions(
user: viewModel.company.user, client: client),
)

View File

@ -3,8 +3,6 @@ import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_selectors.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
@ -37,7 +35,7 @@ class PaymentViewVM {
PaymentViewVM({
@required this.payment,
@required this.company,
@required this.onActionSelected,
@required this.onEntityAction,
@required this.onEditPressed,
@required this.onClientPressed,
@required this.onInvoicePressed,
@ -71,35 +69,14 @@ class PaymentViewVM {
invoice: state.invoiceState.map[payment.invoiceId],
context: context)
: ViewInvoice(invoiceId: payment.invoiceId, context: context)),
onActionSelected: (BuildContext context, EntityAction action) {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.sendEmail:
store.dispatch(EmailPaymentRequest(
popCompleter(context, localization.emailedPayment), payment));
break;
case EntityAction.archive:
store.dispatch(ArchivePaymentRequest(
popCompleter(context, localization.archivedClient),
payment.id));
break;
case EntityAction.delete:
store.dispatch(DeletePaymentRequest(
popCompleter(context, localization.deletedClient),
payment.id));
break;
case EntityAction.restore:
store.dispatch(RestorePaymentRequest(
snackBarCompleter(context, localization.restoredClient),
payment.id));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handlePaymentAction(context, payment, action),
);
}
final PaymentEntity payment;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onActionSelected;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function(BuildContext, [bool]) onInvoicePressed;
final Function(BuildContext, [bool]) onClientPressed;

View File

@ -71,8 +71,18 @@ class ProductEditVM {
: AppLocalization.of(context).updatedProduct),
product: product));
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleProductAction(context, product, action),
onEntityAction: (BuildContext context, EntityAction action) {
// TODO Add view page for products
// Prevent duplicate global key error
if (action == EntityAction.clone) {
Navigator.pop(context);
WidgetsBinding.instance.addPostFrameCallback((duration) {
handleProductAction(context, product, action);
});
} else {
handleProductAction(context, product, action);
}
},
);
}

View File

@ -46,27 +46,26 @@ class ProductList extends StatelessWidget {
itemBuilder: (BuildContext context, index) {
final productId = viewModel.productList[index];
final product = viewModel.productMap[productId];
void showDialog() => showEntityActionsDialog(
entity: product,
context: context,
user: viewModel.user,
onEntityAction: viewModel.onEntityAction);
return ProductListItem(
user: viewModel.user,
filter: viewModel.filter,
product: product,
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
showEntityActionsDialog(
entity: product,
context: context,
user: viewModel.user,
onEntityAction: viewModel.onEntityAction);
showDialog();
} else {
viewModel.onEntityAction(context, product, action);
}
},
onTap: () => viewModel.onProductTap(context, product),
onLongPress: () => showEntityActionsDialog(
entity: product,
context: context,
user: viewModel.user,
onEntityAction: viewModel.onEntityAction),
onLongPress: () => showDialog(),
);
}),
);

View File

@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
@ -17,43 +18,6 @@ class ProjectList extends StatelessWidget {
final ProjectListVM viewModel;
void _showMenu(
BuildContext context, ProjectEntity project, ClientEntity client) async {
if (project == null || client == null) {
return;
}
final user = viewModel.user;
final message = await showDialog<String>(
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: project
.getActions(
user: user, client: client, includeEdit: true)
.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(
message: message,
)));
}
}
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
@ -116,30 +80,37 @@ class ProjectList extends StatelessWidget {
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.projectList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final projectId = viewModel.projectList[index];
final project = viewModel.projectMap[projectId];
final client =
viewModel.clientMap[project.clientId] ??
ClientEntity(id: project.clientId);
void showDialog() => showEntityActionsDialog(
entity: project,
context: context,
user: user,
client: client,
onEntityAction: viewModel.onEntityAction);
return ProjectListItem(
user: viewModel.user,
filter: viewModel.filter,
project: project,
client:
viewModel.clientMap[project.clientId] ??
client: viewModel.clientMap[project.clientId] ??
ClientEntity(),
onTap: () =>
viewModel.onProjectTap(context, project),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, project, client);
showDialog();
} else {
viewModel.onEntityAction(
context, project, action);
}
},
onLongPress: () =>
_showMenu(context, project, client),
onLongPress: () => showDialog(),
);
},
),

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:redux/redux.dart';
import 'package:flutter/material.dart';
@ -84,46 +83,9 @@ class ProjectListVM {
onProjectTap: (context, project) {
store.dispatch(ViewProject(projectId: project.id, context: context));
},
onEntityAction: (context, project, action) {
switch (action) {
case EntityAction.edit:
store.dispatch(EditProject(context: context, project: project));
break;
case EntityAction.newInvoice:
final items =
convertProjectToInvoiceItem(project: project, context: context);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: state.selectedCompany)
.rebuild((b) => b
..hasTasks = true
..clientId = project.clientId
..invoiceItems.addAll(items)),
context: context));
break;
case EntityAction.clone:
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;
}
},
onEntityAction:
(BuildContext context, BaseEntity project, EntityAction action) =>
handleProjectAction(context, project, action),
onRefreshed: (context) => _handleRefresh(context),
);
}

View File

@ -187,11 +187,11 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
: Container(),
ActionMenuButton(
user: user,
entityActions: project.getActions(
client: viewModel.client, user: user),
entityActions:
project.getActions(client: viewModel.client, user: user),
isSaving: viewModel.isSaving,
entity: project,
onSelected: viewModel.onActionSelected,
onSelected: viewModel.onEntityAction,
)
],
);

View File

@ -1,8 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/project/project_selectors.dart';
import 'package:invoiceninja_flutter/redux/task/task_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/project/project_screen.dart';
@ -41,7 +39,7 @@ class ProjectViewVM {
@required this.project,
@required this.client,
@required this.company,
@required this.onActionSelected,
@required this.onEntityAction,
@required this.onTasksPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@ -99,48 +97,17 @@ class ProjectViewVM {
store.dispatch(UpdateCurrentRoute(ProjectScreen.route));
}
},
onActionSelected: (BuildContext context, EntityAction action) {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.newInvoice:
final items = convertProjectToInvoiceItem(
project: project, context: context);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: state.selectedCompany)
.rebuild((b) => b
..hasTasks = true
..clientId = project.clientId
..invoiceItems.addAll(items)),
context: context));
break;
case EntityAction.clone:
store.dispatch(
EditProject(context: context, project: project.clone));
break;
case EntityAction.archive:
store.dispatch(ArchiveProjectRequest(
popCompleter(context, localization.archivedProject),
project.id));
break;
case EntityAction.delete:
store.dispatch(DeleteProjectRequest(
popCompleter(context, localization.deletedProject),
project.id));
break;
case EntityAction.restore:
store.dispatch(RestoreProjectRequest(
snackBarCompleter(context, localization.restoredProject),
project.id));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handleProjectAction(context, project, action),
);
}
final AppState state;
final ProjectEntity project;
final ClientEntity client;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onActionSelected;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function(BuildContext, [bool]) onClientPressed;
final Function onBackPressed;

View File

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_selectors.dart';
import 'package:flutter/material.dart';
@ -13,11 +12,9 @@ import 'package:invoiceninja_flutter/ui/invoice/invoice_list.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_list_vm.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/pdf.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:url_launcher/url_launcher.dart';
class QuoteListBuilder extends StatelessWidget {
const QuoteListBuilder({Key key}) : super(key: key);
@ -99,71 +96,9 @@ class QuoteListVM extends EntityListVM {
onViewEntityFilterPressed: (BuildContext context) => store.dispatch(
ViewClient(
clientId: state.quoteListState.filterEntityId, context: context)),
onEntityAction: (context, quote, action) async {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditQuote(context: context, quote: quote));
break;
case EntityAction.pdf:
viewPdf(quote, context);
break;
case EntityAction.clientPortal:
if (await canLaunch(quote.invitationSilentLink)) {
await launch(quote.invitationSilentLink,
forceSafariVC: false, forceWebView: false);
}
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(context: context, invoiceId: quote.quoteInvoiceId));
break;
case EntityAction.convert:
final Completer<InvoiceEntity> completer =
Completer<InvoiceEntity>();
store.dispatch(ConvertQuote(completer, quote.id));
completer.future.then((InvoiceEntity invoice) {
store.dispatch(
ViewInvoice(invoiceId: invoice.id, context: context));
});
break;
case EntityAction.markSent:
store.dispatch(MarkSentQuoteRequest(
snackBarCompleter(context, localization.markedQuoteAsSent),
quote.id));
break;
case EntityAction.sendEmail:
store.dispatch(ShowEmailQuote(
completer:
snackBarCompleter(context, localization.emailedQuote),
quote: quote,
context: context));
break;
case EntityAction.cloneToInvoice:
store.dispatch(
EditInvoice(context: context, invoice: quote.cloneToInvoice));
break;
case EntityAction.cloneToQuote:
store.dispatch(
EditQuote(context: context, quote: quote.cloneToQuote));
break;
case EntityAction.restore:
store.dispatch(RestoreQuoteRequest(
snackBarCompleter(context, localization.restoredQuote),
quote.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveQuoteRequest(
snackBarCompleter(context, localization.archivedQuote),
quote.id));
break;
case EntityAction.delete:
store.dispatch(DeleteQuoteRequest(
snackBarCompleter(context, localization.deletedQuote),
quote.id));
break;
}
},
onEntityAction:
(BuildContext context, BaseEntity quote, EntityAction action) =>
handleQuoteAction(context, quote, action),
);
}
}

View File

@ -3,20 +3,17 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/invoice/view/invoice_view.dart';
import 'package:invoiceninja_flutter/ui/invoice/view/invoice_view_vm.dart';
import 'package:invoiceninja_flutter/ui/quote/quote_screen.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/pdf.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:url_launcher/url_launcher.dart';
class QuoteViewScreen extends StatelessWidget {
const QuoteViewScreen({Key key}) : super(key: key);
@ -46,7 +43,7 @@ class QuoteViewVM extends EntityViewVM {
ClientEntity client,
bool isSaving,
bool isDirty,
Function(BuildContext, EntityAction) onActionSelected,
Function(BuildContext, EntityAction) onEntityAction,
Function(BuildContext, [InvoiceItemEntity]) onEditPressed,
Function(BuildContext, [bool]) onClientPressed,
Function(BuildContext) onPaymentsPressed,
@ -59,7 +56,7 @@ class QuoteViewVM extends EntityViewVM {
client: client,
isSaving: isSaving,
isDirty: isDirty,
onActionSelected: onActionSelected,
onActionSelected: onEntityAction,
onEditPressed: onEditPressed,
onClientPressed: onClientPressed,
onPaymentsPressed: onPaymentsPressed,
@ -113,67 +110,9 @@ class QuoteViewVM extends EntityViewVM {
store.dispatch(longPress
? EditClient(client: client, context: context)
: ViewClient(clientId: client.id, context: context)),
onActionSelected: (BuildContext context, EntityAction action) async {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.pdf:
viewPdf(quote, context);
break;
case EntityAction.clientPortal:
if (await canLaunch(quote.invitationSilentLink)) {
await launch(quote.invitationSilentLink,
forceSafariVC: false, forceWebView: false);
}
break;
case EntityAction.viewInvoice:
store.dispatch(ViewInvoice(
context: context, invoiceId: quote.quoteInvoiceId));
break;
case EntityAction.convert:
final Completer<InvoiceEntity> completer =
Completer<InvoiceEntity>();
store.dispatch(ConvertQuote(completer, quote.id));
completer.future.then((InvoiceEntity invoice) {
store.dispatch(
ViewInvoice(invoiceId: invoice.id, context: context));
});
break;
case EntityAction.markSent:
store.dispatch(MarkSentQuoteRequest(
snackBarCompleter(context, localization.markedQuoteAsSent),
quote.id));
break;
case EntityAction.sendEmail:
store.dispatch(ShowEmailQuote(
completer:
snackBarCompleter(context, localization.emailedQuote),
quote: quote,
context: context));
break;
case EntityAction.archive:
store.dispatch(ArchiveQuoteRequest(
popCompleter(context, localization.archivedQuote), quote.id));
break;
case EntityAction.delete:
store.dispatch(DeleteQuoteRequest(
popCompleter(context, localization.deletedQuote), quote.id));
break;
case EntityAction.restore:
store.dispatch(RestoreQuoteRequest(
snackBarCompleter(context, localization.restoredQuote),
quote.id));
break;
case EntityAction.cloneToInvoice:
Navigator.of(context).pop();
store.dispatch(
EditInvoice(context: context, invoice: quote.cloneToInvoice));
break;
case EntityAction.cloneToQuote:
Navigator.of(context).pop();
store.dispatch(
EditQuote(context: context, quote: quote.cloneToQuote));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handleQuoteAction(context, quote, action),
);
}
}

View File

@ -1,12 +1,11 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:invoiceninja_flutter/ui/task/task_list_item.dart';
import 'package:invoiceninja_flutter/ui/task/task_list_vm.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class TaskList extends StatelessWidget {
@ -17,43 +16,6 @@ class TaskList extends StatelessWidget {
final TaskListVM viewModel;
void _showMenu(
BuildContext context, TaskEntity task, ClientEntity client) async {
if (task == null || client == null) {
return;
}
final user = viewModel.user;
final message = await showDialog<String>(
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: task
.getActions(
user: user, client: client, includeEdit: true)
.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, task, entityAction);
},
);
}
}).toList()));
if (message != null) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: message,
)));
}
}
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
@ -127,10 +89,19 @@ class TaskList extends StatelessWidget {
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.taskList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final taskId = viewModel.taskList[index];
final task = viewModel.taskMap[taskId];
final client = viewModel.clientMap[task.clientId] ??
ClientEntity();
void showDialog() => showEntityActionsDialog(
entity: task,
context: context,
user: user,
client: client,
onEntityAction: viewModel.onEntityAction);
return TaskListItem(
user: viewModel.user,
filter: viewModel.filter,
@ -139,18 +110,16 @@ class TaskList extends StatelessWidget {
ClientEntity(),
project: viewModel
.state.projectState.map[task.projectId],
onTap: () =>
viewModel.onTaskTap(context, task),
onTap: () => viewModel.onTaskTap(context, task),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, task, client);
showDialog();
} else {
viewModel.onEntityAction(
context, task, action);
}
},
onLongPress: () =>
_showMenu(context, task, client),
onLongPress: () => showDialog(),
);
},
),

View File

@ -1,8 +1,5 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/project/project_actions.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:redux/redux.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
@ -99,73 +96,9 @@ class TaskListVM {
onTaskTap: (context, task) {
store.dispatch(ViewTask(taskId: task.id, context: context));
},
onEntityAction: (context, task, action) {
switch (action) {
case EntityAction.edit:
store.dispatch(EditTask(context: context, task: task));
break;
case EntityAction.start:
case EntityAction.stop:
case EntityAction.resume:
final Completer<TaskEntity> completer = new Completer<TaskEntity>();
final localization = AppLocalization.of(context);
store.dispatch(
SaveTaskRequest(completer: completer, task: task.toggle()));
completer.future.then((savedTask) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: savedTask.isRunning
? (savedTask.duration > 0
? localization.resumedTask
: localization.startedTask)
: localization.stoppedTask,
)));
}).catchError((Object error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
break;
case EntityAction.newInvoice:
final item = convertTaskToInvoiceItem(task: task, context: context);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: state.selectedCompany)
.rebuild((b) => b
..hasTasks = true
..clientId = task.clientId
..invoiceItems.add(item)),
context: context));
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(invoiceId: task.invoiceId, context: context));
break;
case EntityAction.clone:
store.dispatch(EditTask(context: context, task: task.clone));
break;
case EntityAction.restore:
store.dispatch(RestoreTaskRequest(
snackBarCompleter(
context, AppLocalization.of(context).restoredTask),
task.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveTaskRequest(
snackBarCompleter(
context, AppLocalization.of(context).archivedTask),
task.id));
break;
case EntityAction.delete:
store.dispatch(DeleteTaskRequest(
snackBarCompleter(
context, AppLocalization.of(context).deletedTask),
task.id));
break;
}
},
onEntityAction:
(BuildContext context, BaseEntity task, EntityAction action) =>
handleTaskAction(context, task, action),
onRefreshed: (context) => _handleRefresh(context),
);
}

View File

@ -250,7 +250,7 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
task.getActions(client: viewModel.client, user: user),
isSaving: viewModel.isSaving,
entity: task,
onSelected: viewModel.onActionSelected,
onSelected: viewModel.onEntityAction,
)
],
);

View File

@ -1,12 +1,10 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
import 'package:invoiceninja_flutter/redux/project/project_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/redux/task/task_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
@ -47,7 +45,7 @@ class TaskViewVM {
@required this.project,
@required this.company,
@required this.state,
@required this.onActionSelected,
@required this.onEntityAction,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onRefreshed,
@ -151,47 +149,11 @@ class TaskViewVM {
store.dispatch(UpdateCurrentRoute(TaskScreen.route));
}
},
onActionSelected: (BuildContext context, EntityAction action) {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.resume:
case EntityAction.start:
case EntityAction.stop:
_toggleTask(context);
break;
case EntityAction.newInvoice:
final item =
convertTaskToInvoiceItem(task: task, context: context);
store.dispatch(EditInvoice(
invoice: InvoiceEntity(company: state.selectedCompany)
.rebuild((b) => b
..hasTasks = true
..clientId = task.clientId
..invoiceItems.add(item)),
context: context));
break;
case EntityAction.clone:
store.dispatch(EditTask(context: context, task: task.clone));
break;
case EntityAction.viewInvoice:
store.dispatch(
ViewInvoice(invoiceId: task.invoiceId, context: context));
break;
case EntityAction.archive:
store.dispatch(ArchiveTaskRequest(
popCompleter(context, localization.archivedTask), task.id));
break;
case EntityAction.delete:
store.dispatch(DeleteTaskRequest(
popCompleter(context, localization.deletedTask), task.id));
break;
case EntityAction.restore:
store.dispatch(RestoreTaskRequest(
snackBarCompleter(context, localization.restoredTask),
task.id));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handleTaskAction(context, task, action),
);
}
final AppState state;
@ -199,7 +161,7 @@ class TaskViewVM {
final ClientEntity client;
final ProjectEntity project;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onActionSelected;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext, [TaskTime]) onEditPressed;
final Function onBackPressed;
final Function(BuildContext) onFabPressed;

View File

@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
@ -17,41 +18,6 @@ class VendorList extends StatelessWidget {
final VendorListVM viewModel;
void _showMenu(BuildContext context, VendorEntity vendor) async {
if (vendor == null) {
return;
}
final user = viewModel.user;
final message = await showDialog<String>(
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: vendor
.getActions(user: user, includeEdit: true)
.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, vendor, entityAction);
},
);
}
}).toList()));
if (message != null) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: message,
)));
}
}
@override
Widget build(BuildContext context) {
return Column(
@ -78,8 +44,16 @@ class VendorList extends StatelessWidget {
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.vendorList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final vendorId = viewModel.vendorList[index];
final vendor = viewModel.vendorMap[vendorId];
void showDialog() => showEntityActionsDialog(
entity: vendor,
context: context,
user: user,
onEntityAction: viewModel.onEntityAction);
return VendorListItem(
user: viewModel.user,
filter: viewModel.filter,
@ -88,13 +62,13 @@ class VendorList extends StatelessWidget {
viewModel.onVendorTap(context, vendor),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, vendor);
showDialog();
} else {
viewModel.onEntityAction(
context, vendor, action);
}
},
onLongPress: () => _showMenu(context, vendor),
onLongPress: () => showDialog(),
);
},
),

View File

@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_actions.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
@ -78,37 +77,9 @@ class VendorListVM {
onVendorTap: (context, vendor) {
store.dispatch(ViewVendor(vendorId: vendor.id, context: context));
},
onEntityAction: (context, vendor, action) {
switch (action) {
case EntityAction.edit:
store.dispatch(EditVendor(context: context, vendor: vendor));
break;
case EntityAction.newExpense:
store.dispatch(EditExpense(
expense: ExpenseEntity(
company: state.selectedCompany, vendor: vendor),
context: context));
break;
case EntityAction.restore:
store.dispatch(RestoreVendorRequest(
snackBarCompleter(
context, AppLocalization.of(context).restoredVendor),
vendor.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveVendorRequest(
snackBarCompleter(
context, AppLocalization.of(context).archivedVendor),
vendor.id));
break;
case EntityAction.delete:
store.dispatch(DeleteVendorRequest(
snackBarCompleter(
context, AppLocalization.of(context).deletedVendor),
vendor.id));
break;
}
},
onEntityAction:
(BuildContext context, BaseEntity vendor, EntityAction action) =>
handleVendorAction(context, vendor, action),
onRefreshed: (context) => _handleRefresh(context),
);
}

View File

@ -147,7 +147,7 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
user: viewModel.company.user,
isSaving: viewModel.isSaving,
entity: vendor,
onSelected: viewModel.onActionSelected,
onSelected: viewModel.onEntityAction,
entityActions: viewModel.vendor.getActions(user: user),
)
],

View File

@ -40,7 +40,7 @@ class VendorViewVM {
@required this.vendor,
@required this.company,
@required this.onAddExpensePressed,
@required this.onActionSelected,
@required this.onEntityAction,
@required this.onEntityPressed,
@required this.onEditPressed,
@required this.onBackPressed,
@ -107,38 +107,16 @@ class VendorViewVM {
onAddExpensePressed: (context) => store.dispatch(EditExpense(
expense: ExpenseEntity(company: company, vendor: vendor),
context: context)),
onActionSelected: (BuildContext context, EntityAction action) {
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.newExpense:
store.dispatch(EditExpense(
expense: ExpenseEntity(
company: state.selectedCompany, vendor: vendor),
context: context));
break;
case EntityAction.archive:
store.dispatch(ArchiveVendorRequest(
popCompleter(context, localization.archivedVendor),
vendor.id));
break;
case EntityAction.delete:
store.dispatch(DeleteVendorRequest(
popCompleter(context, localization.deletedVendor),
vendor.id));
break;
case EntityAction.restore:
store.dispatch(RestoreVendorRequest(
snackBarCompleter(context, localization.restoredVendor),
vendor.id));
break;
}
});
onEntityAction: (BuildContext context, EntityAction action) =>
handleVendorAction(context, vendor, action),
);
}
final AppState state;
final VendorEntity vendor;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onActionSelected;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function(BuildContext, EntityType, [bool]) onEntityPressed;
final Function onBackPressed;

View File

@ -1,7 +1,6 @@
import 'package:invoiceninja_flutter/utils/strings.dart';
abstract class LocaleCodeAware {
LocaleCodeAware(this.localeCode);
final String localeCode;
@ -13,7 +12,6 @@ abstract class LocaleCodeAware {
/// It should be used by a [LocaleCodeAware] to get the i18n strings for
/// a specified locale.
mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
'expense_date': 'Expense Date',
@ -11415,17 +11413,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
},
};
String get createdProject =>
_localizedValues[localeCode]['created_project'];
String get createdProject => _localizedValues[localeCode]['created_project'];
String get updatedProject =>
_localizedValues[localeCode]['updated_project'];
String get updatedProject => _localizedValues[localeCode]['updated_project'];
String get archivedProject =>
_localizedValues[localeCode]['archived_project'];
String get deletedProject =>
_localizedValues[localeCode]['deleted_project'];
String get deletedProject => _localizedValues[localeCode]['deleted_project'];
String get restoredProject =>
_localizedValues[localeCode]['restored_project'];
@ -11435,8 +11430,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get thankYouForUsingOurApp =>
_localizedValues[localeCode]['thank_you_for_using_our_app'];
String get ifYouLikeIt =>
_localizedValues[localeCode]['if_you_like_it'];
String get ifYouLikeIt => _localizedValues[localeCode]['if_you_like_it'];
String get clickHere => _localizedValues[localeCode]['click_here'];
@ -11451,8 +11445,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get locked => _localizedValues[localeCode]['locked'];
String get authenticate =>
_localizedValues[localeCode]['authenticate'];
String get authenticate => _localizedValues[localeCode]['authenticate'];
String get pleaseAuthenticate =>
_localizedValues[localeCode]['please_authenticate'];
@ -11466,8 +11459,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get hostedLogin => _localizedValues[localeCode]['hosted_login'];
String get selfhostLogin =>
_localizedValues[localeCode]['selfhost_login'];
String get selfhostLogin => _localizedValues[localeCode]['selfhost_login'];
String get googleLogin => _localizedValues[localeCode]['google_login'];
@ -11481,17 +11473,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get previous => _localizedValues[localeCode]['previous'];
String get currentPeriod =>
_localizedValues[localeCode]['current_period'];
String get currentPeriod => _localizedValues[localeCode]['current_period'];
String get comparisonPeriod =>
_localizedValues[localeCode]['comparison_period'];
String get previousPeriod =>
_localizedValues[localeCode]['previous_period'];
String get previousPeriod => _localizedValues[localeCode]['previous_period'];
String get previousYear =>
_localizedValues[localeCode]['previous_year'];
String get previousYear => _localizedValues[localeCode]['previous_year'];
String get compareTo => _localizedValues[localeCode]['compare_to'];
@ -11511,11 +11500,9 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get custom => _localizedValues[localeCode]['custom'];
String get cloneToInvoice =>
_localizedValues[localeCode]['clone_to_invoice'];
String get cloneToInvoice => _localizedValues[localeCode]['clone_to_invoice'];
String get cloneToQuote =>
_localizedValues[localeCode]['clone_to_quote'];
String get cloneToQuote => _localizedValues[localeCode]['clone_to_quote'];
String get viewInvoice => _localizedValues[localeCode]['view_invoice'];
@ -11552,25 +11539,20 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get editRecurringQuote =>
_localizedValues[localeCode]['edit_recurring_quote'];
String get billingAddress =>
_localizedValues[localeCode]['billing_address'];
String get billingAddress => _localizedValues[localeCode]['billing_address'];
String get shippingAddress =>
_localizedValues[localeCode]['shipping_address'];
String get totalRevenue =>
_localizedValues[localeCode]['total_revenue'];
String get totalRevenue => _localizedValues[localeCode]['total_revenue'];
String get averageInvoice =>
_localizedValues[localeCode]['average_invoice'];
String get averageInvoice => _localizedValues[localeCode]['average_invoice'];
String get outstanding => _localizedValues[localeCode]['outstanding'];
String get invoicesSent =>
_localizedValues[localeCode]['invoices_sent'];
String get invoicesSent => _localizedValues[localeCode]['invoices_sent'];
String get activeClients =>
_localizedValues[localeCode]['active_clients'];
String get activeClients => _localizedValues[localeCode]['active_clients'];
String get close => _localizedValues[localeCode]['close'];
@ -11657,8 +11639,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get error => _localizedValues[localeCode]['error'];
String get couldNotLaunch =>
_localizedValues[localeCode]['could_not_launch'];
String get couldNotLaunch => _localizedValues[localeCode]['could_not_launch'];
String get contacts => _localizedValues[localeCode]['contacts'];
@ -11678,8 +11659,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get remove => _localizedValues[localeCode]['remove'];
String get emailIsInvalid =>
_localizedValues[localeCode]['email_is_invalid'];
String get emailIsInvalid => _localizedValues[localeCode]['email_is_invalid'];
String get product => _localizedValues[localeCode]['product'];
@ -11687,51 +11667,40 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get newProduct => _localizedValues[localeCode]['new_product'];
String get createdProduct =>
_localizedValues[localeCode]['created_product'];
String get createdProduct => _localizedValues[localeCode]['created_product'];
String get updatedProduct =>
_localizedValues[localeCode]['updated_product'];
String get updatedProduct => _localizedValues[localeCode]['updated_product'];
String get archivedProduct =>
_localizedValues[localeCode]['archived_product'];
String get deletedProduct =>
_localizedValues[localeCode]['deleted_product'];
String get deletedProduct => _localizedValues[localeCode]['deleted_product'];
String get restoredProduct =>
_localizedValues[localeCode]['restored_product'];
String get newVendor => _localizedValues[localeCode]['new_vendor'];
String get createdVendor =>
_localizedValues[localeCode]['created_vendor'];
String get createdVendor => _localizedValues[localeCode]['created_vendor'];
String get updatedVendor =>
_localizedValues[localeCode]['updated_vendor'];
String get updatedVendor => _localizedValues[localeCode]['updated_vendor'];
String get archivedVendor =>
_localizedValues[localeCode]['archived_vendor'];
String get archivedVendor => _localizedValues[localeCode]['archived_vendor'];
String get deletedVendor =>
_localizedValues[localeCode]['deleted_vendor'];
String get deletedVendor => _localizedValues[localeCode]['deleted_vendor'];
String get restoredVendor =>
_localizedValues[localeCode]['restored_vendor'];
String get restoredVendor => _localizedValues[localeCode]['restored_vendor'];
String get newExpense => _localizedValues[localeCode]['new_expense'];
String get createdExpense =>
_localizedValues[localeCode]['created_expense'];
String get createdExpense => _localizedValues[localeCode]['created_expense'];
String get updatedExpense =>
_localizedValues[localeCode]['updated_expense'];
String get updatedExpense => _localizedValues[localeCode]['updated_expense'];
String get archivedExpense =>
_localizedValues[localeCode]['archived_expense'];
String get deletedExpense =>
_localizedValues[localeCode]['deleted_expense'];
String get deletedExpense => _localizedValues[localeCode]['deleted_expense'];
String get restoredExpense =>
_localizedValues[localeCode]['restored_expense'];
@ -11748,20 +11717,15 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get newClient => _localizedValues[localeCode]['new_client'];
String get createdClient =>
_localizedValues[localeCode]['created_client'];
String get createdClient => _localizedValues[localeCode]['created_client'];
String get updatedClient =>
_localizedValues[localeCode]['updated_client'];
String get updatedClient => _localizedValues[localeCode]['updated_client'];
String get archivedClient =>
_localizedValues[localeCode]['archived_client'];
String get archivedClient => _localizedValues[localeCode]['archived_client'];
String get deletedClient =>
_localizedValues[localeCode]['deleted_client'];
String get deletedClient => _localizedValues[localeCode]['deleted_client'];
String get restoredClient =>
_localizedValues[localeCode]['restored_client'];
String get restoredClient => _localizedValues[localeCode]['restored_client'];
String get address1 => _localizedValues[localeCode]['address1'];
@ -11781,31 +11745,25 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get newInvoice => _localizedValues[localeCode]['new_invoice'];
String get createdInvoice =>
_localizedValues[localeCode]['created_invoice'];
String get createdInvoice => _localizedValues[localeCode]['created_invoice'];
String get updatedInvoice =>
_localizedValues[localeCode]['updated_invoice'];
String get updatedInvoice => _localizedValues[localeCode]['updated_invoice'];
String get archivedInvoice =>
_localizedValues[localeCode]['archived_invoice'];
String get deletedInvoice =>
_localizedValues[localeCode]['deleted_invoice'];
String get deletedInvoice => _localizedValues[localeCode]['deleted_invoice'];
String get restoredInvoice =>
_localizedValues[localeCode]['restored_invoice'];
String get emailedInvoice =>
_localizedValues[localeCode]['emailed_invoice'];
String get emailedInvoice => _localizedValues[localeCode]['emailed_invoice'];
String get emailedPayment =>
_localizedValues[localeCode]['emailed_payment'];
String get emailedPayment => _localizedValues[localeCode]['emailed_payment'];
String get amount => _localizedValues[localeCode]['amount'];
String get invoiceNumber =>
_localizedValues[localeCode]['invoice_number'];
String get invoiceNumber => _localizedValues[localeCode]['invoice_number'];
String get invoiceDate => _localizedValues[localeCode]['invoice_date'];
@ -11817,8 +11775,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get publicNotes => _localizedValues[localeCode]['public_notes'];
String get privateNotes =>
_localizedValues[localeCode]['private_notes'];
String get privateNotes => _localizedValues[localeCode]['private_notes'];
String get frequency => _localizedValues[localeCode]['frequency'];
@ -11834,8 +11791,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get items => _localizedValues[localeCode]['items'];
String get partialDeposit =>
_localizedValues[localeCode]['partial_deposit'];
String get partialDeposit => _localizedValues[localeCode]['partial_deposit'];
String get description => _localizedValues[localeCode]['description'];
@ -11855,16 +11811,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get dueDate => _localizedValues[localeCode]['due_date'];
String get partialDueDate =>
_localizedValues[localeCode]['partial_due_date'];
String get partialDueDate => _localizedValues[localeCode]['partial_due_date'];
String get status => _localizedValues[localeCode]['status'];
String get invoiceStatusId =>
_localizedValues[localeCode]['invoice_status_id'];
String get quoteStatusId =>
_localizedValues[localeCode]['quote_status'];
String get quoteStatusId => _localizedValues[localeCode]['quote_status'];
String get clickPlusToAddItem =>
_localizedValues[localeCode]['click_plus_to_add_item'];
@ -11872,8 +11826,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get clickPlusToAddTime =>
_localizedValues[localeCode]['click_plus_to_add_time'];
String get countSelected =>
_localizedValues[localeCode]['count_selected'];
String get countSelected => _localizedValues[localeCode]['count_selected'];
String get total => _localizedValues[localeCode]['total'];
@ -11928,23 +11881,17 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get paid => _localizedValues[localeCode]['paid'];
String get invoiceStatus1 =>
_localizedValues[localeCode]['invoice_status_1'];
String get invoiceStatus1 => _localizedValues[localeCode]['invoice_status_1'];
String get invoiceStatus2 =>
_localizedValues[localeCode]['invoice_status_2'];
String get invoiceStatus2 => _localizedValues[localeCode]['invoice_status_2'];
String get invoiceStatus3 =>
_localizedValues[localeCode]['invoice_status_3'];
String get invoiceStatus3 => _localizedValues[localeCode]['invoice_status_3'];
String get invoiceStatus4 =>
_localizedValues[localeCode]['invoice_status_4'];
String get invoiceStatus4 => _localizedValues[localeCode]['invoice_status_4'];
String get invoiceStatus5 =>
_localizedValues[localeCode]['invoice_status_5'];
String get invoiceStatus5 => _localizedValues[localeCode]['invoice_status_5'];
String get invoiceStatus6 =>
_localizedValues[localeCode]['invoice_status_6'];
String get invoiceStatus6 => _localizedValues[localeCode]['invoice_status_6'];
String get markSent => _localizedValues[localeCode]['mark_sent'];
@ -11954,8 +11901,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get done => _localizedValues[localeCode]['done'];
String get pleaseEnterAClientOrContactName =>
_localizedValues[localeCode]
['please_enter_a_client_or_contact_name'];
_localizedValues[localeCode]['please_enter_a_client_or_contact_name'];
String get darkMode => _localizedValues[localeCode]['dark_mode'];
@ -11964,13 +11910,11 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get refreshData => _localizedValues[localeCode]['refresh_data'];
String get blankContact =>
_localizedValues[localeCode]['blank_contact'];
String get blankContact => _localizedValues[localeCode]['blank_contact'];
String get activity => _localizedValues[localeCode]['activity'];
String get noRecordsFound =>
_localizedValues[localeCode]['no_records_found'];
String get noRecordsFound => _localizedValues[localeCode]['no_records_found'];
String get clone => _localizedValues[localeCode]['clone'];
@ -11980,39 +11924,31 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get size => _localizedValues[localeCode]['size'];
String get paymentTerms =>
_localizedValues[localeCode]['payment_terms'];
String get paymentTerms => _localizedValues[localeCode]['payment_terms'];
String get paymentDate => _localizedValues[localeCode]['payment_date'];
String get paymentStatus =>
_localizedValues[localeCode]['payment_status'];
String get paymentStatus => _localizedValues[localeCode]['payment_status'];
String get net => _localizedValues[localeCode]['net'];
String get clientPortal =>
_localizedValues[localeCode]['client_portal'];
String get clientPortal => _localizedValues[localeCode]['client_portal'];
String get showTasks => _localizedValues[localeCode]['show_tasks'];
String get emailReminders =>
_localizedValues[localeCode]['email_reminders'];
String get emailReminders => _localizedValues[localeCode]['email_reminders'];
String get enabled => _localizedValues[localeCode]['enabled'];
String get recipients => _localizedValues[localeCode]['recipients'];
String get initialEmail =>
_localizedValues[localeCode]['initial_email'];
String get initialEmail => _localizedValues[localeCode]['initial_email'];
String get firstReminder =>
_localizedValues[localeCode]['first_reminder'];
String get firstReminder => _localizedValues[localeCode]['first_reminder'];
String get secondReminder =>
_localizedValues[localeCode]['second_reminder'];
String get secondReminder => _localizedValues[localeCode]['second_reminder'];
String get thirdReminder =>
_localizedValues[localeCode]['third_reminder'];
String get thirdReminder => _localizedValues[localeCode]['third_reminder'];
String get template => _localizedValues[localeCode]['template'];
@ -12024,8 +11960,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get sendEmail => _localizedValues[localeCode]['send_email'];
String get emailReceipt =>
_localizedValues[localeCode]['email_receipt'];
String get emailReceipt => _localizedValues[localeCode]['email_receipt'];
String get documents => _localizedValues[localeCode]['documents'];
@ -12050,20 +11985,16 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get transactionReference =>
_localizedValues[localeCode]['transaction_reference'];
String get enterPayment =>
_localizedValues[localeCode]['enter_payment'];
String get enterPayment => _localizedValues[localeCode]['enter_payment'];
String get createdPayment =>
_localizedValues[localeCode]['created_payment'];
String get createdPayment => _localizedValues[localeCode]['created_payment'];
String get updatedPayment =>
_localizedValues[localeCode]['updated_payment'];
String get updatedPayment => _localizedValues[localeCode]['updated_payment'];
String get archivedPayment =>
_localizedValues[localeCode]['archived_payment'];
String get deletedPayment =>
_localizedValues[localeCode]['deleted_payment'];
String get deletedPayment => _localizedValues[localeCode]['deleted_payment'];
String get restoredPayment =>
_localizedValues[localeCode]['restored_payment'];
@ -12074,20 +12005,15 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get newQuote => _localizedValues[localeCode]['new_quote'];
String get createdQuote =>
_localizedValues[localeCode]['created_quote'];
String get createdQuote => _localizedValues[localeCode]['created_quote'];
String get updatedQuote =>
_localizedValues[localeCode]['updated_quote'];
String get updatedQuote => _localizedValues[localeCode]['updated_quote'];
String get archivedQuote =>
_localizedValues[localeCode]['archived_quote'];
String get archivedQuote => _localizedValues[localeCode]['archived_quote'];
String get deletedQuote =>
_localizedValues[localeCode]['deleted_quote'];
String get deletedQuote => _localizedValues[localeCode]['deleted_quote'];
String get restoredQuote =>
_localizedValues[localeCode]['restored_quote'];
String get restoredQuote => _localizedValues[localeCode]['restored_quote'];
String get expense => _localizedValues[localeCode]['expense'];
@ -12202,16 +12128,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get oneTimePassword =>
_localizedValues[localeCode]['one_time_password'];
String get emailedQuote =>
_localizedValues[localeCode]['emailed_quote'];
String get emailedQuote => _localizedValues[localeCode]['emailed_quote'];
String get markedQuoteAsSent =>
_localizedValues[localeCode]['marked_quote_as_sent'];
String get expired => _localizedValues[localeCode]['expired'];
String get budgetedHours =>
_localizedValues[localeCode]['budgeted_hours'];
String get budgetedHours => _localizedValues[localeCode]['budgeted_hours'];
String get pleaseEnterAName =>
_localizedValues[localeCode]['please_enter_a_name'];
@ -12220,13 +12144,11 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get updatedTask => _localizedValues[localeCode]['updated_task'];
String get archivedTask =>
_localizedValues[localeCode]['archived_task'];
String get archivedTask => _localizedValues[localeCode]['archived_task'];
String get deletedTask => _localizedValues[localeCode]['deleted_task'];
String get restoredTask =>
_localizedValues[localeCode]['restored_task'];
String get restoredTask => _localizedValues[localeCode]['restored_task'];
String get newTask => _localizedValues[localeCode]['new_task'];
@ -12246,8 +12168,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get manual => _localizedValues[localeCode]['manual'];
String get autoStartTasks =>
_localizedValues[localeCode]['auto_start_tasks'];
String get autoStartTasks => _localizedValues[localeCode]['auto_start_tasks'];
String get now => _localizedValues[localeCode]['now'];
@ -12279,8 +12200,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get design => _localizedValues[localeCode]['design'];
String get copyShipping =>
_localizedValues[localeCode]['copy_shipping'];
String get copyShipping => _localizedValues[localeCode]['copy_shipping'];
String get copyBilling => _localizedValues[localeCode]['copy_billing'];
@ -12288,44 +12208,34 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get category => _localizedValues[localeCode]['category'];
String get markBillable =>
_localizedValues[localeCode]['mark_billable'];
String get markBillable => _localizedValues[localeCode]['mark_billable'];
String get markPaid => _localizedValues[localeCode]['mark_paid'];
String get convertCurrency =>
_localizedValues[localeCode]['convert_currency'];
String get exchangeRate =>
_localizedValues[localeCode]['exchange_rate'];
String get exchangeRate => _localizedValues[localeCode]['exchange_rate'];
String get addDocumentsToInvoice =>
_localizedValues[localeCode]['add_documents_to_invoice'];
String get pending =>
_localizedValues[localeCode]['pending'];
String get pending => _localizedValues[localeCode]['pending'];
String get converted =>
_localizedValues[localeCode]['converted'];
String get converted => _localizedValues[localeCode]['converted'];
String get expenseStatus1 =>
_localizedValues[localeCode]['expense_status_1'];
String get expenseStatus1 => _localizedValues[localeCode]['expense_status_1'];
String get expenseStatus2 =>
_localizedValues[localeCode]['expense_status_2'];
String get expenseStatus2 => _localizedValues[localeCode]['expense_status_2'];
String get expenseStatus3 =>
_localizedValues[localeCode]['expense_status_3'];
String get expenseDate =>
_localizedValues[localeCode]['expense_date'];
String get expenseStatus3 => _localizedValues[localeCode]['expense_status_3'];
String get expenseDate => _localizedValues[localeCode]['expense_date'];
String lookup(String key) {
final lookupKey = toSnakeCase(key);
return _localizedValues[localeCode][lookupKey] ??
_localizedValues[localeCode]
[lookupKey.replaceFirst('_id', '')] ??
_localizedValues[localeCode][lookupKey.replaceFirst('_id', '')] ??
key;
}
}

View File

@ -18,8 +18,6 @@ class AppLocalization extends LocaleCodeAware with LocalizationsProvider {
static AppLocalization of(BuildContext context) {
return Localizations.of<AppLocalization>(context, AppLocalization);
}
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalization> {