Starter...

This commit is contained in:
Hillel Coren 2020-03-02 21:41:03 +02:00
parent b6a2c51153
commit e895d00981
8 changed files with 183 additions and 145 deletions

View File

@ -68,6 +68,10 @@ abstract class CreditUIState extends Object
@nullable
InvoiceEntity get editing;
@nullable
@BuiltValueField(serialize: false)
int get editingItemIndex;
@override
bool get isCreatingNew => editing.isNew;

View File

@ -255,6 +255,8 @@ class _$CreditUIState extends CreditUIState {
@override
final InvoiceEntity editing;
@override
final int editingItemIndex;
@override
final ListUIState listUIState;
@override
final String selectedId;
@ -268,6 +270,7 @@ class _$CreditUIState extends CreditUIState {
_$CreditUIState._(
{this.editing,
this.editingItemIndex,
this.listUIState,
this.selectedId,
this.saveCompleter,
@ -290,6 +293,7 @@ class _$CreditUIState extends CreditUIState {
if (identical(other, this)) return true;
return other is CreditUIState &&
editing == other.editing &&
editingItemIndex == other.editingItemIndex &&
listUIState == other.listUIState &&
selectedId == other.selectedId &&
saveCompleter == other.saveCompleter &&
@ -300,7 +304,9 @@ class _$CreditUIState extends CreditUIState {
int get hashCode {
return $jf($jc(
$jc(
$jc($jc($jc(0, editing.hashCode), listUIState.hashCode),
$jc(
$jc($jc($jc(0, editing.hashCode), editingItemIndex.hashCode),
listUIState.hashCode),
selectedId.hashCode),
saveCompleter.hashCode),
cancelCompleter.hashCode));
@ -310,6 +316,7 @@ class _$CreditUIState extends CreditUIState {
String toString() {
return (newBuiltValueToStringHelper('CreditUIState')
..add('editing', editing)
..add('editingItemIndex', editingItemIndex)
..add('listUIState', listUIState)
..add('selectedId', selectedId)
..add('saveCompleter', saveCompleter)
@ -327,6 +334,11 @@ class CreditUIStateBuilder
_$this._editing ??= new InvoiceEntityBuilder();
set editing(InvoiceEntityBuilder editing) => _$this._editing = editing;
int _editingItemIndex;
int get editingItemIndex => _$this._editingItemIndex;
set editingItemIndex(int editingItemIndex) =>
_$this._editingItemIndex = editingItemIndex;
ListUIStateBuilder _listUIState;
ListUIStateBuilder get listUIState =>
_$this._listUIState ??= new ListUIStateBuilder();
@ -352,6 +364,7 @@ class CreditUIStateBuilder
CreditUIStateBuilder get _$this {
if (_$v != null) {
_editing = _$v.editing?.toBuilder();
_editingItemIndex = _$v.editingItemIndex;
_listUIState = _$v.listUIState?.toBuilder();
_selectedId = _$v.selectedId;
_saveCompleter = _$v.saveCompleter;
@ -381,6 +394,7 @@ class CreditUIStateBuilder
_$result = _$v ??
new _$CreditUIState._(
editing: _editing?.build(),
editingItemIndex: editingItemIndex,
listUIState: listUIState.build(),
selectedId: selectedId,
saveCompleter: saveCompleter,
@ -390,6 +404,7 @@ class CreditUIStateBuilder
try {
_$failedField = 'editing';
_editing?.build();
_$failedField = 'listUIState';
listUIState.build();
} catch (e) {

View File

@ -2,20 +2,21 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/credit/credit_screen.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/credit/edit/credit_edit.dart';
import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/credit/view/credit_view_vm.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/credit/view/credit_view_vm.dart';
import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart';
import 'package:invoiceninja_flutter/data/models/credit_model.dart';
import 'package:invoiceninja_flutter/ui/credit/edit/credit_edit.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class CreditEditScreen extends StatelessWidget {
const CreditEditScreen({Key key}) : super(key: key);
static const String route = '/credit/edit';
@override
@ -27,60 +28,59 @@ class CreditEditScreen extends StatelessWidget {
builder: (context, viewModel) {
return CreditEdit(
viewModel: viewModel,
key: ValueKey(viewModel.credit.id),
);
},
);
}
}
class CreditEditVM {
class CreditEditVM extends EntityEditVM {
CreditEditVM({
@required this.state,
@required this.credit,
@required this.company,
@required this.onChanged,
@required this.isSaving,
@required this.origCredit,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.isLoading,
});
AppState state,
CompanyEntity company,
InvoiceEntity invoice,
int invoiceItemIndex,
InvoiceEntity origInvoice,
Function(BuildContext) onSavePressed,
Function(List<InvoiceItemEntity>, String) onItemsAdded,
bool isSaving,
Function(BuildContext) onCancelPressed,
}) : super(
state: state,
company: company,
invoice: invoice,
invoiceItemIndex: invoiceItemIndex,
origInvoice: origInvoice,
onSavePressed: onSavePressed,
onItemsAdded: onItemsAdded,
isSaving: isSaving,
onCancelPressed: onCancelPressed,
);
factory CreditEditVM.fromStore(Store<AppState> store) {
final state = store.state;
final AppState state = store.state;
final credit = state.creditUIState.editing;
return CreditEditVM(
state: state,
isLoading: state.isLoading,
company: state.company,
isSaving: state.isSaving,
origCredit: state.creditState.map[credit.id],
credit: credit,
company: state.selectedCompany,
onChanged: (InvoiceEntity credit) {
store.dispatch(UpdateCredit(credit));
},
onCancelPressed: (BuildContext context) {
store.dispatch(
EditCredit(credit: InvoiceEntity(), context: context, force: true));
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
invoice: credit,
invoiceItemIndex: state.creditUIState.editingItemIndex,
origInvoice: store.state.creditState.map[credit.id],
onSavePressed: (BuildContext context) {
final Completer<InvoiceEntity> completer = new Completer<InvoiceEntity>();
final Completer<InvoiceEntity> completer = Completer<InvoiceEntity>();
store.dispatch(SaveCreditRequest(completer: completer, credit: credit));
return completer.future.then((savedCredit) {
if (isMobile(context)) {
store.dispatch(UpdateCurrentRoute(CreditViewScreen.route));
if (credit.isNew) {
Navigator.of(context)
.pushReplacementNamed(CreditViewScreen.route);
Navigator.of(context).pushReplacementNamed(CreditViewScreen.route);
} else {
Navigator.of(context).pop(savedCredit);
}
} else {
store.dispatch(ViewCredit(
context: context, creditId: savedCredit.id, force: true));
viewEntity(context: context, entity: savedCredit, force: true);
}
}).catchError((Object error) {
showDialog<ErrorDialog>(
@ -90,16 +90,16 @@ class CreditEditVM {
});
});
},
onItemsAdded: (items, clientId) {
if (items.length == 1) {
store.dispatch(EditCreditItem(credit.lineItems.length));
}
store.dispatch(AddCreditItems(items));
},
onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: InvoiceEntity(), force: true);
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
);
}
final InvoiceEntity credit;
final CompanyEntity company;
final Function(InvoiceEntity) onChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final bool isLoading;
final bool isSaving;
final InvoiceEntity origCredit;
final AppState state;
}

View File

@ -1,51 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/edit_icon_button.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/ui/credit/view/credit_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_state_title.dart';
class CreditView extends StatefulWidget {
const CreditView({
Key key,
@required this.viewModel,
}) : super(key: key);
final CreditViewVM viewModel;
@override
_CreditViewState createState() => new _CreditViewState();
}
class _CreditViewState extends State<CreditView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final userCompany = viewModel.state.userCompany;
final credit = viewModel.credit;
return Scaffold(
appBar: AppBar(
title: EntityStateTitle(entity: credit),
actions: [
userCompany.canEditEntity(credit)
? EditIconButton(
isVisible: !credit.isDeleted,
onPressed: () => viewModel.onEditPressed(context),
)
: Container(),
ActionMenuButton(
entityActions: credit.getActions(userCompany: userCompany),
isSaving: viewModel.isSaving,
entity: credit,
onSelected: viewModel.onEntityAction,
)
],
),
body: FormCard(children: [
// STARTER: widgets - do not remove comment
]),
);
}
}

View File

@ -1,54 +1,84 @@
import 'dart:async';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.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/utils/completers.dart';
import 'package:invoiceninja_flutter/ui/credit/credit_screen.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/credit/credit_actions.dart';
import 'package:invoiceninja_flutter/data/models/credit_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/credit/view/credit_view.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class CreditViewScreen extends StatelessWidget {
const CreditViewScreen({Key key}) : super(key: key);
static const String route = '/credit/view';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, CreditViewVM>(
//distinct: true,
converter: (Store<AppState> store) {
return CreditViewVM.fromStore(store);
},
builder: (context, vm) {
return CreditView(
viewModel: vm,
builder: (context, viewModel) {
return InvoiceView(
viewModel: viewModel,
);
},
);
}
}
class CreditViewVM {
class CreditViewVM extends EntityViewVM {
CreditViewVM({
@required this.state,
@required this.credit,
@required this.company,
@required this.onEntityAction,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
});
AppState state,
CompanyEntity company,
InvoiceEntity invoice,
ClientEntity client,
bool isSaving,
bool isDirty,
Function(BuildContext, EntityAction) onEntityAction,
Function(BuildContext, [int]) onEditPressed,
Function(BuildContext, [bool]) onClientPressed,
Function(BuildContext) onPaymentsPressed,
Function(BuildContext, PaymentEntity) onPaymentPressed,
Function(BuildContext) onRefreshed,
Function(BuildContext, String) onUploadDocument,
Function(BuildContext, DocumentEntity) onDeleteDocument,
Function(BuildContext, DocumentEntity) onViewExpense,
}) : super(
state: state,
company: company,
invoice: invoice,
client: client,
isSaving: isSaving,
isDirty: isDirty,
onActionSelected: onEntityAction,
onEditPressed: onEditPressed,
onClientPressed: onClientPressed,
onPaymentsPressed: onPaymentsPressed,
onPaymentPressed: onPaymentPressed,
onRefreshed: onRefreshed,
onUploadDocument: onUploadDocument,
onDeleteDocument: onDeleteDocument,
onViewExpense: onViewExpense,
);
factory CreditViewVM.fromStore(Store<AppState> store) {
final state = store.state;
final credit = state.creditState.map[state.creditUIState.selectedId] ??
InvoiceEntity(id: state.creditUIState.selectedId);
final client = store.state.clientState.map[credit.clientId] ??
ClientEntity(id: credit.clientId);
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter<Null>(
@ -59,23 +89,58 @@ class CreditViewVM {
return CreditViewVM(
state: state,
company: state.selectedCompany,
company: state.company,
isSaving: state.isSaving,
isLoading: state.isLoading,
isDirty: credit.isNew,
credit: credit,
invoice: credit,
client: client,
onEditPressed: (BuildContext context, [int index]) {
editEntity(
context: context,
entity: credit,
subIndex: index,
completer: snackBarCompleter<ClientEntity>(
context, AppLocalization.of(context).updatedCredit));
},
onRefreshed: (context) => _handleRefresh(context),
onClientPressed: (BuildContext context, [bool longPress = false]) {
if (longPress) {
showEntityActionsDialog(
context: context,
entities: [client],
);
} else {
viewEntity(context: context, entity: client);
}
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleCreditAction(context, credit, action),
handleCreditAction(context, [credit], action),
onUploadDocument: (BuildContext context, String path) {
final Completer<DocumentEntity> completer = Completer<DocumentEntity>();
final document = DocumentEntity().rebuild((b) => b
..invoiceId = credit.id
..path = path);
store.dispatch(
SaveDocumentRequest(document: document, completer: completer));
completer.future.then((client) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: AppLocalization.of(context).uploadedDocument,
)));
}).catchError((Object error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
},
onDeleteDocument: (BuildContext context, DocumentEntity document) {
store.dispatch(DeleteDocumentRequest(
snackBarCompleter<Null>(
context, AppLocalization.of(context).deletedDocument),
[document.id]));
},
);
}
final AppState state;
final InvoiceEntity credit;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;
final bool isDirty;
}

View File

@ -223,8 +223,8 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
validator: (String val) => val.trim().isEmpty
? AppLocalization.of(context).pleaseSelectADate
: null,
labelText: widget.isQuote
? localization.quoteDate
labelText: widget.entityType == EntityType.credit ? localization.creditDate :
widget.entityType == EntityType.quote ? localization.quoteDate
: localization.invoiceDate,
selectedDate: invoice.date,
onSelected: (date) {

View File

@ -15,6 +15,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
'credit_date': 'Credit Date',
'credit': 'Credit',
'credits': 'Credits',
'new_credit': 'New Credit',
@ -32772,15 +32773,19 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get appUpdated => _localizedValues[localeCode]['app_updated'];
// STARTER: lang field - do not remove comment
String get credit => _localizedValues[localeCode][' credit'];
String get credits => _localizedValues[localeCode][' credits'];
String get newCredit => _localizedValues[localeCode]['new_ credit'];
String get createdCredit => _localizedValues[localeCode]['created_ credit'];
String get updatedCredit => _localizedValues[localeCode]['updated_ credit'];
String get archivedCredit => _localizedValues[localeCode]['archived_ credit'];
String get deletedCredit => _localizedValues[localeCode]['deleted_ credit'];
String get restoredCredit => _localizedValues[localeCode]['restored_ credit'];
String get editCredit => _localizedValues[localeCode]['edit_ credit'];
String get newCredit => _localizedValues[localeCode]['new_credit'];
String get createdCredit => _localizedValues[localeCode]['created_credit'];
String get updatedCredit => _localizedValues[localeCode]['updated_credit'];
String get archivedCredit => _localizedValues[localeCode]['archived_credit'];
String get deletedCredit => _localizedValues[localeCode]['deleted_credit'];
String get restoredCredit => _localizedValues[localeCode]['restored_credit'];
String get creditDate => _localizedValues[localeCode]['credit_date'];
String lookup(String key) {
final lookupKey = toSnakeCase(key);

View File

@ -431,7 +431,7 @@ else
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/utils/i18n.dart
comment="STARTER: lang field - do not remove comment"
code="String get ${module_camel} => _localizedValues[localeCode][' ${module_snake}']; String get ${module_camel}s => _localizedValues[localeCode][' ${module_snake}s']; String get new${Module} => _localizedValues[localeCode]['new_ ${module_snake}']; String get created${Module} => _localizedValues[localeCode]['created_ ${module_snake}']; String get updated${Module} => _localizedValues[localeCode]['updated_ ${module_snake}']; String get archived${Module} => _localizedValues[localeCode]['archived_ ${module_snake}']; String get deleted${Module} => _localizedValues[localeCode]['deleted_ ${module_snake}']; String get restored${Module} => _localizedValues[localeCode]['restored_ ${module_snake}']; String get edit${Module} => _localizedValues[localeCode]['edit_ ${module_snake}'];${lineBreak}"
code="String get ${module_camel} => _localizedValues[localeCode][' ${module_snake}']; String get ${module_camel}s => _localizedValues[localeCode]['${module_snake}s']; String get new${Module} => _localizedValues[localeCode]['new_${module_snake}']; String get created${Module} => _localizedValues[localeCode]['created_${module_snake}']; String get updated${Module} => _localizedValues[localeCode]['updated_${module_snake}']; String get archived${Module} => _localizedValues[localeCode]['archived_${module_snake}']; String get deleted${Module} => _localizedValues[localeCode]['deleted_${module_snake}']; String get restored${Module} => _localizedValues[localeCode]['restored_${module_snake}']; String get edit${Module} => _localizedValues[localeCode]['edit_${module_snake}'];${lineBreak}"
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/utils/i18n.dart
echo "Generating built files.."