Tablet layout

This commit is contained in:
Hillel Coren 2019-08-19 13:59:58 +03:00
parent b72dac631a
commit d5ba4ac9f5
41 changed files with 199 additions and 115 deletions

View File

@ -325,7 +325,9 @@ abstract class ClientEntity extends Object
return true;
} else if (city.toLowerCase().contains(filter)) {
return true;
} else if (contacts.where((contact) => contact.matchesFilter(filter)).isNotEmpty) {
} else if (contacts
.where((contact) => contact.matchesFilter(filter))
.isNotEmpty) {
return true;
}
@ -340,7 +342,7 @@ abstract class ClientEntity extends Object
filter = filter.toLowerCase();
final contact = contacts.firstWhere(
(contact) => contact.matchesFilter(filter),
(contact) => contact.matchesFilter(filter),
orElse: () => null);
if (vatNumber.toLowerCase().contains(filter)) {

View File

@ -215,7 +215,9 @@ abstract class VendorEntity extends Object
return true;
} else if (city.toLowerCase().contains(filter)) {
return true;
} else if (contacts.where((contact) => contact.matchesFilter(filter)).isNotEmpty) {
} else if (contacts
.where((contact) => contact.matchesFilter(filter))
.isNotEmpty) {
return true;
}
@ -230,7 +232,7 @@ abstract class VendorEntity extends Object
filter = filter.toLowerCase();
final contact = contacts.firstWhere(
(contact) => contact.matchesFilter(filter),
(contact) => contact.matchesFilter(filter),
orElse: () => null);
if (vatNumber.toLowerCase().contains(filter)) {

View File

@ -130,7 +130,8 @@ List<CompanyEntity> companiesSelector(AppState state) {
}
String localeSelector(AppState state) {
final locale = state.staticState?.languageMap[state.selectedCompany?.languageId]?.locale ??
final locale = state.staticState
?.languageMap[state.selectedCompany?.languageId]?.locale ??
'en';
// https://github.com/flutter/flutter/issues/32090
@ -139,4 +140,4 @@ String localeSelector(AppState state) {
} else {
return locale;
}
}
}

View File

@ -38,7 +38,8 @@ List<Middleware<AppState>> createStoreDocumentsMiddleware([
}
Middleware<AppState> _editDocument() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditDocument;
next(action);
@ -54,7 +55,8 @@ Middleware<AppState> _editDocument() {
}
Middleware<AppState> _viewDocument() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewDocument;
next(action);

View File

@ -14,8 +14,7 @@ EntityUIState documentUIReducer(DocumentUIState state, dynamic action) {
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewDocument>(
(selectedId, action) => action.documentId),
TypedReducer<int, ViewDocument>((selectedId, action) => action.documentId),
TypedReducer<int, AddDocumentSuccess>(
(selectedId, action) => action.document.id),
]);

View File

@ -33,10 +33,10 @@ class ViewExpense implements PersistUI {
class EditExpense implements PersistUI {
EditExpense(
{@required this.expense,
@required this.context,
this.completer,
this.force = false,
this.trackRoute = true});
@required this.context,
this.completer,
this.force = false,
this.trackRoute = true});
final ExpenseEntity expense;
final BuildContext context;

View File

@ -41,7 +41,8 @@ List<Middleware<AppState>> createStoreExpensesMiddleware([
}
Middleware<AppState> _editExpense() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditExpense;
if (hasChanges(
@ -55,19 +56,18 @@ Middleware<AppState> _editExpense() {
if (isMobile(action.context)) {
final expense =
await Navigator.of(action.context).pushNamed(ExpenseEditScreen.route);
await Navigator.of(action.context).pushNamed(ExpenseEditScreen.route);
if (action.completer != null && expense != null) {
action.completer.complete(expense);
}
}
};
}
Middleware<AppState> _viewExpense() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewExpense;
next(action);

View File

@ -14,8 +14,7 @@ EntityUIState expenseUIReducer(ExpenseUIState state, dynamic action) {
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewExpense>(
(selectedId, action) => action.expenseId),
TypedReducer<int, ViewExpense>((selectedId, action) => action.expenseId),
TypedReducer<int, AddExpenseSuccess>(
(selectedId, action) => action.expense.id),
]);

View File

@ -70,7 +70,8 @@ Middleware<AppState> _viewInvoiceList() {
}
Middleware<AppState> _viewInvoice() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewInvoice;
if (hasChanges(
@ -89,7 +90,8 @@ Middleware<AppState> _viewInvoice() {
}
Middleware<AppState> _editInvoice() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditInvoice;
if (hasChanges(
@ -113,7 +115,8 @@ Middleware<AppState> _editInvoice() {
}
Middleware<AppState> _showEmailInvoice() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ShowEmailInvoice;
next(action);

View File

@ -35,8 +35,7 @@ String filterClientDropdownReducer(
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewInvoice>(
(selectedId, action) => action.invoiceId),
TypedReducer<int, ViewInvoice>((selectedId, action) => action.invoiceId),
TypedReducer<int, AddInvoiceSuccess>(
(selectedId, action) => action.invoice.id),
TypedReducer<int, ShowEmailInvoice>(

View File

@ -30,10 +30,10 @@ class ViewPayment implements PersistUI {
class EditPayment implements PersistUI {
EditPayment(
{@required this.payment,
@required this.context,
this.completer,
this.force = false,
this.trackRoute = true});
@required this.context,
this.completer,
this.force = false,
this.trackRoute = true});
final PaymentEntity payment;
final BuildContext context;

View File

@ -59,8 +59,7 @@ Middleware<AppState> _editPayment() {
}
Middleware<AppState> _viewPayment() {
return (Store<AppState> store, dynamic action,
NextDispatcher next) async {
return (Store<AppState> store, dynamic action, NextDispatcher next) async {
next(action);
store.dispatch(UpdateCurrentRoute(PaymentViewScreen.route));

View File

@ -14,8 +14,7 @@ EntityUIState paymentUIReducer(PaymentUIState state, dynamic action) {
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewPayment>(
(selectedId, action) => action.paymentId),
TypedReducer<int, ViewPayment>((selectedId, action) => action.paymentId),
TypedReducer<int, AddPaymentSuccess>(
(selectedId, action) => action.payment.id),
]);

View File

@ -27,7 +27,11 @@ class ViewProduct implements PersistUI {
}
class EditProduct implements PersistUI {
EditProduct({@required this.product, @required this.context, this.completer, this.force = false});
EditProduct(
{@required this.product,
@required this.context,
this.completer,
this.force = false});
final ProductEntity product;
final BuildContext context;

View File

@ -37,7 +37,8 @@ List<Middleware<AppState>> createStoreProductsMiddleware([
}
Middleware<AppState> _editProduct() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditProduct;
if (hasChanges(
@ -56,7 +57,8 @@ Middleware<AppState> _editProduct() {
}
Middleware<AppState> _viewProduct() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewProduct;
if (hasChanges(

View File

@ -42,8 +42,7 @@ ProductEntity _updateEditing(ProductEntity client, dynamic action) {
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewProduct>(
(selectedId, action) => action.productId),
TypedReducer<int, ViewProduct>((selectedId, action) => action.productId),
TypedReducer<int, AddProductSuccess>(
(selectedId, action) => action.product.id),
]);

View File

@ -34,10 +34,10 @@ class ViewProject implements PersistUI {
class EditProject implements PersistUI {
EditProject(
{@required this.project,
@required this.context,
this.completer,
this.force = false,
this.trackRoute = true});
@required this.context,
this.completer,
this.force = false,
this.trackRoute = true});
final ProjectEntity project;
final BuildContext context;

View File

@ -41,7 +41,8 @@ List<Middleware<AppState>> createStoreProjectsMiddleware([
}
Middleware<AppState> _editProject() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditProject;
if (hasChanges(
@ -55,18 +56,18 @@ Middleware<AppState> _editProject() {
if (isMobile(action.context)) {
final project =
await Navigator.of(action.context).pushNamed(ProjectEditScreen.route);
await Navigator.of(action.context).pushNamed(ProjectEditScreen.route);
if (action.completer != null && project != null) {
action.completer.complete(project);
}
}
};
}
Middleware<AppState> _viewProject() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewProject;
next(action);

View File

@ -14,8 +14,7 @@ EntityUIState projectUIReducer(ProjectUIState state, dynamic action) {
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewProject>(
(selectedId, action) => action.projectId),
TypedReducer<int, ViewProject>((selectedId, action) => action.projectId),
TypedReducer<int, AddProjectSuccess>(
(selectedId, action) => action.project.id),
]);

View File

@ -28,7 +28,12 @@ class ViewQuote implements PersistUI {
}
class EditQuote implements PersistUI {
EditQuote({this.quote, this.context, this.completer, this.quoteItem, this.force = false});
EditQuote(
{this.quote,
this.context,
this.completer,
this.quoteItem,
this.force = false});
final InvoiceEntity quote;
final InvoiceItemEntity quoteItem;

View File

@ -48,7 +48,8 @@ List<Middleware<AppState>> createStoreQuotesMiddleware([
}
Middleware<AppState> _viewQuote() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewQuote;
if (hasChanges(
@ -74,14 +75,13 @@ Middleware<AppState> _viewQuoteList() {
if (isMobile(action.context)) {
Navigator.of(action.context).pushNamedAndRemoveUntil(
QuoteScreen.route, (Route<dynamic> route) => false);
}
};
}
Middleware<AppState> _editQuote() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditQuote;
next(action);
@ -97,7 +97,8 @@ Middleware<AppState> _editQuote() {
}
Middleware<AppState> _showEmailQuote() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ShowEmailQuote;
next(action);

View File

@ -34,12 +34,9 @@ String filterClientDropdownReducer(
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewQuote>(
(selectedId, action) => action.quoteId),
TypedReducer<int, AddQuoteSuccess>(
(selectedId, action) => action.quote.id),
TypedReducer<int, ShowEmailQuote>(
(selectedId, action) => action.quote.id),
TypedReducer<int, ViewQuote>((selectedId, action) => action.quoteId),
TypedReducer<int, AddQuoteSuccess>((selectedId, action) => action.quote.id),
TypedReducer<int, ShowEmailQuote>((selectedId, action) => action.quote.id),
]);
final editingReducer = combineReducers<InvoiceEntity>([

View File

@ -24,10 +24,8 @@ TaskTime editTaskTime(TaskTime taskTime, dynamic action) {
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewTask>(
(selectedId, action) => action.taskId),
TypedReducer<int, AddTaskSuccess>(
(selectedId, action) => action.task.id),
TypedReducer<int, ViewTask>((selectedId, action) => action.taskId),
TypedReducer<int, AddTaskSuccess>((selectedId, action) => action.task.id),
]);
final editingReducer = combineReducers<TaskEntity>([

View File

@ -117,13 +117,13 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
String get mainRoute {
final parts =
currentRoute.split('/').where((part) => part.isNotEmpty).toList();
currentRoute.split('/').where((part) => part.isNotEmpty).toList();
return parts.isNotEmpty ? parts[0] : '';
}
String get subRoute {
final parts =
currentRoute.split('/').where((part) => part.isNotEmpty).toList();
currentRoute.split('/').where((part) => part.isNotEmpty).toList();
return parts.length > 1 ? parts[1] : '';
}

View File

@ -31,11 +31,11 @@ class ViewVendor implements PersistUI {
class EditVendor implements PersistUI {
EditVendor(
{@required this.vendor,
@required this.context,
this.contact,
this.completer,
this.force = false,
this.trackRoute = true});
@required this.context,
this.contact,
this.completer,
this.force = false,
this.trackRoute = true});
final VendorEntity vendor;
final VendorContactEntity contact;

View File

@ -26,10 +26,8 @@ VendorContactEntity editVendorContact(
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewVendor>(
(selectedId, action) => action.vendorId),
TypedReducer<int, AddVendorSuccess>(
(selectedId, action) => action.vendor.id),
TypedReducer<int, ViewVendor>((selectedId, action) => action.vendorId),
TypedReducer<int, AddVendorSuccess>((selectedId, action) => action.vendor.id),
]);
final editingReducer = combineReducers<VendorEntity>([

View File

@ -236,7 +236,8 @@ class AppDrawer extends StatelessWidget {
entityType: EntityType.payment,
icon: getEntityIcon(EntityType.payment),
title: localization.payments,
onTap: () => store.dispatch(ViewPaymentList(context: context)),
onTap: () =>
store.dispatch(ViewPaymentList(context: context)),
onCreateTap: () {
if (isMobile(context)) {
navigator.pop();
@ -251,7 +252,8 @@ class AppDrawer extends StatelessWidget {
entityType: EntityType.quote,
icon: getEntityIcon(EntityType.quote),
title: localization.quotes,
onTap: () => store.dispatch(ViewQuoteList(context: context)),
onTap: () =>
store.dispatch(ViewQuoteList(context: context)),
onCreateTap: () {
if (isMobile(context)) {
navigator.pop();
@ -266,7 +268,8 @@ class AppDrawer extends StatelessWidget {
entityType: EntityType.project,
icon: getEntityIcon(EntityType.project),
title: localization.projects,
onTap: () => store.dispatch(ViewProjectList(context: context)),
onTap: () =>
store.dispatch(ViewProjectList(context: context)),
onCreateTap: () {
if (isMobile(context)) {
navigator.pop();
@ -280,7 +283,8 @@ class AppDrawer extends StatelessWidget {
entityType: EntityType.task,
icon: getEntityIcon(EntityType.task),
title: localization.tasks,
onTap: () => store.dispatch(ViewTaskList(context: context)),
onTap: () =>
store.dispatch(ViewTaskList(context: context)),
onCreateTap: () {
if (isMobile(context)) {
navigator.pop();
@ -296,7 +300,8 @@ class AppDrawer extends StatelessWidget {
entityType: EntityType.vendor,
icon: getEntityIcon(EntityType.vendor),
title: localization.vendors,
onTap: () => store.dispatch(ViewVendorList(context: context)),
onTap: () =>
store.dispatch(ViewVendorList(context: context)),
onCreateTap: () {
if (isMobile(context)) {
navigator.pop();
@ -310,7 +315,8 @@ class AppDrawer extends StatelessWidget {
entityType: EntityType.expense,
icon: getEntityIcon(EntityType.expense),
title: localization.expenses,
onTap: () => store.dispatch(ViewExpenseList(context: context)),
onTap: () =>
store.dispatch(ViewExpenseList(context: context)),
onCreateTap: () {
if (isMobile(context)) {
navigator.pop();

View File

@ -78,6 +78,16 @@ class _DocumentEditState extends State<DocumentEdit> {
? localization.newDocument
: localization.editDocument),
actions: <Widget>[
/*
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
*/
ActionIconButton(
icon: Icons.cloud_upload,
tooltip: localization.save,

View File

@ -55,6 +55,14 @@ class _ExpenseEditState extends State<ExpenseEdit>
? localization.newExpense
: localization.editExpense),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionIconButton(
icon: Icons.cloud_upload,
tooltip: localization.save,

View File

@ -158,7 +158,8 @@ class InvoiceEditDetailsState extends State<InvoiceEditDetails> {
viewModel.onAddClientPressed(context, completer);
completer.future.then((client) {
final store = StoreProvider.of<AppState>(context);
store.dispatch(UpdateCurrentRoute(InvoiceEditScreen.route));
store.dispatch(
UpdateCurrentRoute(InvoiceEditScreen.route));
});
},
)

View File

@ -74,13 +74,14 @@ class InvoiceListItem extends StatelessWidget {
Expanded(
child: filterMatch == null
? Text((invoice.invoiceNumber +
'' +
formatDate(
invoice.dueDate.isNotEmpty
? invoice.dueDate
: invoice.invoiceDate,
context) +
(hasDocuments ? ' 📎' : '')).trim())
'' +
formatDate(
invoice.dueDate.isNotEmpty
? invoice.dueDate
: invoice.invoiceDate,
context) +
(hasDocuments ? ' 📎' : ''))
.trim())
: Text(
filterMatch,
maxLines: 3,

View File

@ -97,6 +97,14 @@ class _PaymentEditState extends State<PaymentEdit> {
? localization.enterPayment
: localization.editPayment),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
Builder(builder: (BuildContext context) {
return ActionIconButton(
icon: Icons.cloud_upload,

View File

@ -47,7 +47,8 @@ class _PaymentViewState extends State<PaymentView> {
formatDate(payment.paymentDate, context);
}
if (payment.paymentTypeId > 0) {
final paymentType = state.staticState.paymentTypeMap[payment.paymentTypeId];
final paymentType =
state.staticState.paymentTypeMap[payment.paymentTypeId];
if (paymentType != null) {
fields[PaymentFields.paymentTypeId] = paymentType.name;
}

View File

@ -106,6 +106,14 @@ class _ProductEditState extends State<ProductEdit> {
? localization.newProduct
: localization.editProduct),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
Builder(builder: (BuildContext context) {
if (!user.canEditEntity(product)) {
return Container();

View File

@ -113,6 +113,14 @@ class _ProjectEditState extends State<ProjectEdit> {
? localization.newProject
: localization.editProject),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
Builder(builder: (BuildContext context) {
return ActionIconButton(
icon: Icons.cloud_upload,

View File

@ -62,27 +62,27 @@ class QuoteScreen extends StatelessWidget {
},
statuses: [
InvoiceStatusEntity().rebuild(
(b) => b
(b) => b
..id = 1
..name = localization.draft,
),
InvoiceStatusEntity().rebuild(
(b) => b
(b) => b
..id = 2
..name = localization.sent,
),
InvoiceStatusEntity().rebuild(
(b) => b
(b) => b
..id = 3
..name = localization.viewed,
),
InvoiceStatusEntity().rebuild(
(b) => b
(b) => b
..id = 4
..name = localization.approved,
),
InvoiceStatusEntity().rebuild(
(b) => b
(b) => b
..id = -1
..name = localization.expired,
),
@ -90,21 +90,21 @@ class QuoteScreen extends StatelessWidget {
),
floatingActionButton: user.canCreate(EntityType.quote)
? FloatingActionButton(
backgroundColor: Theme.of(context).primaryColorDark,
onPressed: () {
store.dispatch(EditQuote(
quote: InvoiceEntity(company: company, isQuote: true)
.rebuild((b) => b
..clientId =
store.state.quoteListState.filterEntityId ?? 0),
context: context));
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newQuote,
)
backgroundColor: Theme.of(context).primaryColorDark,
onPressed: () {
store.dispatch(EditQuote(
quote: InvoiceEntity(company: company, isQuote: true)
.rebuild((b) => b
..clientId =
store.state.quoteListState.filterEntityId ?? 0),
context: context));
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newQuote,
)
: null,
);
}

View File

@ -72,6 +72,14 @@ class _TaskEditState extends State<TaskEdit>
title:
Text(task.isNew ? localization.newTask : localization.editTask),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionIconButton(
icon: Icons.cloud_upload,
tooltip: localization.save,

View File

@ -66,8 +66,8 @@ class TaskEditVM {
}
},
onCancelPressed: (BuildContext context) {
store.dispatch(EditTask(
task: TaskEntity(), context: context, force: true));
store.dispatch(
EditTask(task: TaskEntity(), context: context, force: true));
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
onFabPressed: () {

View File

@ -55,6 +55,14 @@ class _VendorEditState extends State<VendorEdit>
title: Text(
vendor.isNew ? localization.newVendor : localization.editVendor),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionIconButton(
icon: Icons.cloud_upload,
tooltip: localization.save,

View File

@ -68,8 +68,8 @@ class VendorEditVM {
}
},
onCancelPressed: (BuildContext context) {
store.dispatch(EditVendor(
vendor: VendorEntity(), context: context, force: true));
store.dispatch(
EditVendor(vendor: VendorEntity(), context: context, force: true));
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
onSavePressed: (BuildContext context) {

View File

@ -78,6 +78,14 @@ class _StubEditState extends State<StubEdit> {
? localization.newStub
: localization.editStub),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionIconButton(
icon: Icons.cloud_upload,
tooltip: localization.save,