Null safety

This commit is contained in:
Hillel Coren 2023-09-20 16:37:03 +03:00
parent 96fea81865
commit 7b5bd7b68c
30 changed files with 99 additions and 68 deletions

View File

@ -34,7 +34,8 @@ class EntityListTile extends StatefulWidget {
final BaseEntity? entity;
final bool isFilter;
final ClientEntity? client;
final Function(BuildContext, BaseEntity?, EntityAction)? onEntityActionSelected;
final Function(BuildContext, BaseEntity?, EntityAction)?
onEntityActionSelected;
@override
_EntityListTileState createState() => _EntityListTileState();
@ -64,8 +65,9 @@ class _EntityListTileState extends State<EntityListTile> {
_isHovered;
final leading = ActionMenuButton(
iconData:
isHovered ? Icons.more_vert : getEntityIcon(widget.entity!.entityType),
iconData: isHovered
? Icons.more_vert
: getEntityIcon(widget.entity!.entityType),
iconSize: isHovered ? null : 18,
entityActions: widget.entity!.getActions(
userCompany: state.userCompany,
@ -146,7 +148,7 @@ class _EntityListTileState extends State<EntityListTile> {
onLongPress: () =>
inspectEntity(entity: widget.entity, longPress: true),
title: Text(
EntityPresenter().initialize(widget.entity, context).title()!,
EntityPresenter().initialize(widget.entity!, context).title()!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@ -166,8 +168,8 @@ class _EntityListTileState extends State<EntityListTile> {
: null,
leading: leading,
trailing: trailing,
isThreeLine:
(widget.subtitle ?? '').isNotEmpty && !widget.entity!.isActive,
isThreeLine: (widget.subtitle ?? '').isNotEmpty &&
!widget.entity!.isActive,
),
),
ListDivider(),

View File

@ -115,7 +115,8 @@ class EntityTopFilter extends StatelessWidget {
constraints: BoxConstraints(maxWidth: 220),
child: Text(
EntityPresenter()
.initialize(filterEntity as BaseEntity?, context)
.initialize(
filterEntity as BaseEntity, context)
.title()!,
style: TextStyle(
fontSize: 17,
@ -153,7 +154,8 @@ class EntityTopFilter extends StatelessWidget {
onPressed: () {
viewEntitiesByType(
entityType: relatedTypes[i],
filterEntity: filterEntity as BaseEntity?,
filterEntity:
filterEntity as BaseEntity?,
);
},
onLongPress: () {
@ -206,7 +208,8 @@ class EntityTopFilter extends StatelessWidget {
} else {
viewEntitiesByType(
entityType: value,
filterEntity: filterEntity as BaseEntity?,
filterEntity:
filterEntity as BaseEntity?,
);
}
},

View File

@ -91,7 +91,7 @@ class _TaxRateDropdownState extends State<TaxRateDropdown> {
value: taxRate,
isExpanded: true,
isDense: true,
onChanged: widget.onSelected,
onChanged: (rate) => widget.onSelected(rate!),
items: [
if (!taxRate.isEmpty)
DropdownMenuItem(

View File

@ -12,7 +12,10 @@ import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class EntityPresenter {
EntityPresenter initialize(BaseEntity? entity, BuildContext context) {
EntityPresenter initialize(
BaseEntity entity,
BuildContext context,
) {
this.entity = entity;
this.context = context;

View File

@ -54,7 +54,7 @@ class EntityDataTableSource extends AppDataTableSource {
DataRow getRow(int index) {
final state = StoreProvider.of<AppState>(context).state;
final prefState = state.prefState;
final entity = entityMap![entityList[index]];
final entity = entityMap![entityList[index]]!;
entityPresenter!.initialize(entity, context);
final listState = state.getListState(entityType);

View File

@ -30,7 +30,7 @@ class ViewScaffold extends StatelessWidget {
});
final bool isFilter;
final BaseEntity? entity;
final BaseEntity entity;
final Widget body;
final Function? onBackPressed;
final Widget? appBarBottom;
@ -105,7 +105,7 @@ class ViewScaffold extends StatelessWidget {
child: Text(appBarTitle!),
),
bottom: appBarBottom as PreferredSizeWidget?,
actions: entity!.isNew
actions: entity.isNew
? []
: [
if (isSettings && isDesktop(context) && !isFilter)

View File

@ -101,8 +101,10 @@ class CompanyGatewayEditVM {
store.dispatch(SaveCompanyRequest(
completer: Completer<Null>(),
company: company.rebuild((b) => b
..settings.companyGatewayIds +=
',' + savedCompanyGateway.id)));
..settings.companyGatewayIds =
company.settings.companyGatewayIds! +
',' +
savedCompanyGateway.id)));
}
if (state.prefState.isMobile) {

View File

@ -57,8 +57,8 @@ class CreditEditDetailsVM extends EntityEditDetailsVM {
CompanyEntity? company,
InvoiceEntity? invoice,
Function(InvoiceEntity)? onChanged,
Function(BuildContext, InvoiceEntity, ClientEntity)? onClientChanged,
Function(BuildContext, InvoiceEntity, VendorEntity)? onVendorChanged,
Function(BuildContext, InvoiceEntity, ClientEntity?)? onClientChanged,
Function(BuildContext, InvoiceEntity, VendorEntity?)? onVendorChanged,
BuiltMap<String?, ClientEntity?>? clientMap,
BuiltList<String>? clientList,
Function(BuildContext context, Completer<SelectableEntity> completer)?
@ -91,7 +91,9 @@ class CreditEditDetailsVM extends EntityEditDetailsVM {
clientMap: state.clientState.map,
clientList: state.clientState.list,
onClientChanged: (context, credit, client) {
if (client != null) {
store.dispatch(UpdateCredit(credit.applyClient(state, client)));
}
store.dispatch(UpdateCreditClient(client: client));
},
onAddClientPressed: (context, completer) {

View File

@ -52,8 +52,8 @@ class CreditEditVM extends AbstractInvoiceEditVM {
InvoiceEntity? invoice,
int? invoiceItemIndex,
InvoiceEntity? origInvoice,
Function(BuildContext, [EntityAction])? onSavePressed,
Function(List<InvoiceItemEntity>, String, String)? onItemsAdded,
Function(BuildContext, [EntityAction?])? onSavePressed,
Function(List<InvoiceItemEntity>, String?, String?)? onItemsAdded,
bool? isSaving,
Function(BuildContext)? onCancelPressed,
Function(BuildContext, List<MultipartFile>, bool?)? onUploadDocuments,

View File

@ -61,7 +61,7 @@ class AbstractExpenseViewVM {
});
final AppState? state;
final ExpenseEntity? expense;
final ExpenseEntity expense;
final CompanyEntity? company;
final Function(BuildContext, EntityAction)? onEntityAction;
final Function(BuildContext)? onRefreshed;
@ -73,8 +73,8 @@ class AbstractExpenseViewVM {
class ExpenseViewVM extends AbstractExpenseViewVM {
ExpenseViewVM({
required ExpenseEntity expense,
AppState? state,
ExpenseEntity? expense,
CompanyEntity? company,
Function(BuildContext, EntityAction)? onEntityAction,
Function(BuildContext)? onRefreshed,

View File

@ -330,7 +330,7 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
EntityPresenter()
.initialize(
invoice.isPurchaseOrder
? vendor
? vendor!
: client,
context)
.title()!,

View File

@ -46,7 +46,7 @@ class _InvoiceEditItemsState extends State<InvoiceEditItems> {
viewModel: viewModel,
entityViewModel: widget.entityViewModel,
key: ValueKey('__${lineItemIndex}__'),
invoiceItem: invoice.lineItems[lineItemIndex!],
invoiceItem: invoice.lineItems[lineItemIndex!]!,
index: lineItemIndex,
);
});
@ -97,8 +97,8 @@ class ItemEditDetails extends StatefulWidget {
required this.entityViewModel,
}) : super(key: key);
final int? index;
final InvoiceItemEntity? invoiceItem;
final int index;
final InvoiceItemEntity invoiceItem;
final EntityEditItemsVM viewModel;
final AbstractInvoiceEditVM entityViewModel;

View File

@ -1,4 +1,6 @@
// Flutter imports:
import 'dart:async';
import 'package:flutter/material.dart';
// Package imports:
@ -676,8 +678,10 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
return <ProductEntity>[];
}
return options as FutureOr<Iterable<ProductEntity>>;
} as FutureOr<Iterable<ProductEntity>> Function(TextEditingValue),
return options
as FutureOr<Iterable<ProductEntity>>;
} as FutureOr<Iterable<ProductEntity>> Function(
TextEditingValue),
displayStringForOption: (product) =>
product.productKey,
onSelected: (product) {
@ -818,8 +822,8 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
.cardColor,
child:
EntityAutocompleteListTile(
onTap: (entity) =>
onSelected(entity as ProductEntity),
onTap: (entity) => onSelected(
entity as ProductEntity),
overrideSuggestedAmount:
(entity) {
final product =
@ -1162,6 +1166,8 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
),
),
);
} else {
return SizedBox();
}
}).toList(),
Padding(

View File

@ -78,8 +78,8 @@ class InvoiceEditVM extends AbstractInvoiceEditVM {
InvoiceEntity? invoice,
int? invoiceItemIndex,
InvoiceEntity? origInvoice,
Function(BuildContext, [EntityAction])? onSavePressed,
Function(List<InvoiceItemEntity>, String, String)? onItemsAdded,
Function(BuildContext, [EntityAction?])? onSavePressed,
Function(List<InvoiceItemEntity>, String?, String?)? onItemsAdded,
bool? isSaving,
Function(BuildContext)? onCancelPressed,
Function(BuildContext, List<MultipartFile>, bool?)? onUploadDocuments,
@ -202,7 +202,7 @@ class InvoiceEditVM extends AbstractInvoiceEditVM {
},
onItemsAdded: (items, clientId, projectId) {
if ((clientId ?? '').isNotEmpty || (projectId ?? '').isNotEmpty) {
final client = state.clientState.get(clientId);
final client = state.clientState.get(clientId!);
store.dispatch(UpdateInvoice(invoice.rebuild((b) => b
..clientId = clientId ?? ''
..projectId = projectId ?? ''

View File

@ -1,4 +1,6 @@
// Flutter imports:
import 'dart:async';
import 'package:flutter/material.dart';
// Package imports:
@ -111,7 +113,7 @@ class EmailInvoiceVM extends EmailEntityVM {
context, AppLocalization.of(context)!.emailedInvoice,
shouldPop: isMobile(context));
if (!isMobile(context)) {
completer.future.then((value) {
completer.future.then<Null>(() {
viewEntity(entity: invoice);
} as FutureOr<Null> Function(Null));
}

View File

@ -85,8 +85,8 @@ class ProjectViewVM {
client: client,
onRefreshed: (context) => _handleRefresh(context),
onEntityPressed: (BuildContext context, EntityType entityType,
{bool longPress = false}) {
if (longPress && project.isActive && client.isActive) {
{bool? longPress = false}) {
if (longPress == true && project.isActive && client.isActive) {
handleProjectAction(
context, [project], EntityAction.newEntityType(entityType));
} else {

View File

@ -52,8 +52,8 @@ class PurchaseOrderEditVM extends AbstractInvoiceEditVM {
InvoiceEntity? purchaseOrder,
int? invoiceItemIndex,
InvoiceEntity? origInvoice,
Function(BuildContext, [EntityAction])? onSavePressed,
Function(List<InvoiceItemEntity>, String, String)? onItemsAdded,
Function(BuildContext, [EntityAction?])? onSavePressed,
Function(List<InvoiceItemEntity>, String?, String?)? onItemsAdded,
bool? isSaving,
Function(BuildContext)? onCancelPressed,
Function(BuildContext, List<MultipartFile>, bool?)? onUploadDocuments,
@ -116,7 +116,8 @@ class PurchaseOrderEditVM extends AbstractInvoiceEditVM {
store.dispatch(
UpdateCurrentRoute(PurchaseOrderViewScreen.route));
if (purchaseOrder.isNew) {
navigator!.pushReplacementNamed(PurchaseOrderViewScreen.route);
navigator!
.pushReplacementNamed(PurchaseOrderViewScreen.route);
} else {
navigator!.pop(savedPurchaseOrder);
}

View File

@ -90,7 +90,9 @@ class QuoteEditDetailsVM extends EntityEditDetailsVM {
clientMap: state.clientState.map,
clientList: state.clientState.list,
onClientChanged: (context, quote, client) {
if (client != null) {
store.dispatch(UpdateQuote(quote.applyClient(state, client)));
}
store.dispatch(UpdateQuoteClient(client: client));
},
onAddClientPressed: (context, completer) {

View File

@ -52,8 +52,8 @@ class QuoteEditVM extends AbstractInvoiceEditVM {
InvoiceEntity? invoice,
int? invoiceItemIndex,
InvoiceEntity? origInvoice,
Function(BuildContext, [EntityAction])? onSavePressed,
Function(List<InvoiceItemEntity>, String, String)? onItemsAdded,
Function(BuildContext, [EntityAction?])? onSavePressed,
Function(List<InvoiceItemEntity>, String?, String?)? onItemsAdded,
bool? isSaving,
Function(BuildContext)? onCancelPressed,
Function(BuildContext, List<MultipartFile>, bool?)? onUploadDocument,

View File

@ -93,7 +93,7 @@ class RecurringExpenseEditVM extends AbstractExpenseEditVM {
..future.then<Null>(() {
store.dispatch(
UpdateCurrentRoute(RecurringExpenseEditScreen.route));
} as FutureOr<_> Function(Null)));
} as FutureOr<Null> Function(Null)));
completer.future.then((SelectableEntity client) {
store.dispatch(UpdateCurrentRoute(RecurringExpenseEditScreen.route));
});

View File

@ -49,8 +49,8 @@ class RecurringExpenseViewScreen extends StatelessWidget {
class RecurringExpenseViewVM extends AbstractExpenseViewVM {
RecurringExpenseViewVM({
required ExpenseEntity expense,
AppState? state,
ExpenseEntity? expense,
CompanyEntity? company,
Function(BuildContext, EntityAction)? onEntityAction,
Function(BuildContext)? onRefreshed,

View File

@ -92,8 +92,10 @@ class RecurringInvoiceEditDetailsVM extends EntityEditDetailsVM {
clientMap: state.clientState.map,
clientList: state.clientState.list,
onClientChanged: (context, invoice, client) {
if (client != null) {
store.dispatch(
UpdateRecurringInvoice(invoice.applyClient(state, client)));
}
store.dispatch(UpdateRecurringInvoiceClient(client: client));
},
onAddClientPressed: (context, completer) {

View File

@ -53,7 +53,7 @@ class RecurringInvoiceEditVM extends AbstractInvoiceEditVM {
int? invoiceItemIndex,
InvoiceEntity? origInvoice,
Function(BuildContext, [EntityAction?])? onSavePressed,
Function(List<InvoiceItemEntity>, String, String)? onItemsAdded,
Function(List<InvoiceItemEntity>, String?, String?)? onItemsAdded,
bool? isSaving,
Function(BuildContext)? onCancelPressed,
Function(BuildContext, List<MultipartFile>, bool)? onUploadDocuments,

View File

@ -46,7 +46,7 @@ ReportResult documentReport(
BuiltMap<String?, UserEntity?> userMap,
) {
final List<List<ReportElement>> data = [];
final List<BaseEntity?> entities = [];
final List<BaseEntity> entities = [];
BuiltList<DocumentReportFields> columns;
final localization =
@ -144,13 +144,13 @@ ReportResult documentReport(
if (!skip) {
data.add(row);
entities.add(document);
entities.add(document!);
}
});
final selectedColumns = columns.map((item) => EnumUtils.parse(item)).toList();
data.sort((rowA, rowB) =>
sortReportTableRows(rowA, rowB, documentReportSettings, selectedColumns)!);
data.sort((rowA, rowB) => sortReportTableRows(
rowA, rowB, documentReportSettings, selectedColumns)!);
return ReportResult(
allColumns:

View File

@ -1,4 +1,5 @@
// Flutter imports:
import 'package:charts_flutter/flutter.dart';
import 'package:flutter/material.dart';
// Package imports:
@ -71,8 +72,8 @@ class ReportCharts extends StatelessWidget {
data: viewModel.groupTotals.rows!.map((key) {
return {
'name': key,
'value': viewModel.groupTotals.totals![key]!
[reportState.chart]
'value':
viewModel.groupTotals.totals![key]![reportState.chart]
};
}).toList()) as Series<dynamic, String>
],
@ -98,8 +99,8 @@ class ReportCharts extends StatelessWidget {
data: keys.map((key) {
return {
'name': key,
'value': viewModel.groupTotals.totals![key]!
[reportState.chart]
'value':
viewModel.groupTotals.totals![key]![reportState.chart]
};
}).toList()) as Series<dynamic, DateTime>
],

View File

@ -1,4 +1,6 @@
// Flutter imports:
import 'dart:async';
import 'package:collection/collection.dart' show IterableNullableExtension;
import 'package:flutter/material.dart' hide DataRow, DataCell, DataColumn;
import 'package:flutter/material.dart' as mt;
@ -961,7 +963,7 @@ class ReportResult {
}
static bool matchDateTime({
String? filter,
required String filter,
required String value,
required UserCompanyEntity userCompany,
required ReportsUIState reportsUIState,
@ -1165,7 +1167,7 @@ class ReportResult {
showBlank: true,
blankValue: null,
value: (reportState.filters[column] ?? '').isNotEmpty
? DateRange.valueOf(reportState.filters[column])
? DateRange.valueOf(reportState.filters[column]!)
: null,
onChanged: (dynamic value) {
if (value == null) {
@ -1213,7 +1215,7 @@ class ReportResult {
focusNode: textEditingFocusNodes![column],
optionsBuilder: (TextEditingValue textEditingValue) {
final filter = textEditingValue.text.toLowerCase();
final index = columns.indexOf(column);
final index = columns.indexOf(column!);
final options = data
.where((row) =>
row[index]
@ -1327,7 +1329,7 @@ class ReportResult {
final row = data[index - 1];
final cells = <DataCell>[];
for (var j = 0; j < row.length; j++) {
final index = columns.indexOf(sorted[j]);
final index = columns.indexOf(sorted[j]!);
final cell = row[index];
final column = sorted[j];
cells.add(
@ -1534,13 +1536,14 @@ class ReportResult {
totals[currencyId] = {'count': 0};
}
if (!countedRow) {
totals[currencyId]!['count']++;
totals[currencyId]!['count'] = totals[currencyId]!['count']! + 1;
countedRow = true;
}
if (!totals[currencyId]!.containsKey(column)) {
totals[currencyId]![column] = 0;
}
totals[currencyId]![column] += cell.doubleValue!;
totals[currencyId]![column] =
totals[currencyId]![column]! + cell.doubleValue!;
}
}
}

View File

@ -61,7 +61,7 @@ class TransactionViewVM {
transactionIds = [state.transactionUIState.selectedId];
}
transactionIds.forEach((transactionId) {
transactionIds.forEach((String transactionId) {
transactions.add(state.transactionState.map[transactionId] ??
TransactionEntity(id: transactionId));
} as void Function(String?));
@ -118,14 +118,14 @@ class TransactionViewVM {
ConvertTransactionsToExpensesRequest(
snackBarCompleter<Null>(
context, AppLocalization.of(context)!.convertedTransaction)
..future.then((value) {
..future.then<Null>(() {
if (state.transactionListState.isInMultiselect()) {
store.dispatch(ClearTransactionMultiselect());
if (store.state.prefState.isPreviewVisible) {
store.dispatch(TogglePreviewSidebar());
}
}
} as FutureOr<_> Function(Null)),
} as FutureOr<Null> Function(Null)),
transactionIds,
vendorId,
categoryId,

View File

@ -502,6 +502,7 @@ class _ExampleEditorState extends State<ExampleEditor> {
onCutPressed: _cut,
onCopyPressed: _copy,
onPastePressed: _paste,
focalPoint: _overlayController.toolbarTopAnchor!,
),
overlayController: _overlayController,
),

View File

@ -84,7 +84,7 @@ class WebUtils {
final loginRequest = PopupRequest()..scopes = ['user.read'];
publicClientApp.loginPopup(loginRequest).then((result) {
succesCallback(result?.idToken, result?.accessToken);
succesCallback(result?.idToken ?? '', result?.accessToken ?? '');
}).catchError((dynamic error) {
failureCallback(error);
});

View File

@ -243,7 +243,7 @@ class ContactForm extends StatefulWidget {
}) : super(key: key);
final ContactEntity contact;
final Function(GlobalKey<ContactFormState>?) onRemovePressed;
final Function(GlobalKey<ContactFormState>) onRemovePressed;
@override
ContactFormState createState() => ContactFormState();
@ -274,7 +274,8 @@ class ContactFormState extends State<ContactForm> {
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: TextButton(
onPressed: () => widget.onRemovePressed(widget.key as GlobalKey<ContactFormState>?),
onPressed: () => widget
.onRemovePressed(widget.key as GlobalKey<ContactFormState>),
child: Text(
'Delete',
style: TextStyle(