Null safety

This commit is contained in:
Hillel Coren 2023-09-20 11:08:59 +03:00
parent b328d56c23
commit 96fea81865
18 changed files with 114 additions and 77 deletions

View File

@ -599,7 +599,7 @@ class _AccountOverview extends StatelessWidget {
context: context, context: context,
callback: (password, idToken) { callback: (password, idToken) {
viewModel.onPurgeData( viewModel.onPurgeData(
context, password, idToken); context, password ?? '', idToken ?? '');
}); });
}); });
}, },
@ -648,10 +648,10 @@ class _AccountOverview extends StatelessWidget {
); );
viewModel.onCompanyDelete( viewModel.onCompanyDelete(
navigatorKey.currentContext, navigatorKey.currentContext!,
'', '',
credentials.identityToken, credentials.identityToken ?? '',
reason, reason ?? '',
); );
} else { } else {
passwordCallback( passwordCallback(
@ -660,9 +660,9 @@ class _AccountOverview extends StatelessWidget {
callback: (password, idToken) { callback: (password, idToken) {
viewModel.onCompanyDelete( viewModel.onCompanyDelete(
context, context,
password, password ?? '',
idToken, idToken ?? '',
reason, reason ?? '',
); );
}); });
} }

View File

@ -65,7 +65,7 @@ class AccountManagementVM {
store.dispatch(UpdateCompany(company: company)), store.dispatch(UpdateCompany(company: company)),
onCompanyDelete: (context, password, idToken, reason) { onCompanyDelete: (context, password, idToken, reason) {
showDialog<AlertDialog>( showDialog<AlertDialog>(
context: context, context: context!,
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) => SimpleDialog( builder: (BuildContext context) => SimpleDialog(
children: <Widget>[LoadingDialog()], children: <Widget>[LoadingDialog()],
@ -74,7 +74,7 @@ class AccountManagementVM {
final companyLength = state.companies.length; final companyLength = state.companies.length;
final deleteCompleter = Completer<Null>() final deleteCompleter = Completer<Null>()
..future ..future
.then((value) { .then<Null>(() {
final context = navigatorKey.currentContext; final context = navigatorKey.currentContext;
final state = store.state; final state = store.state;
if (companyLength == 1) { if (companyLength == 1) {
@ -87,7 +87,7 @@ class AccountManagementVM {
final index = selectedCompanyIndex == 0 ? 1 : 0; final index = selectedCompanyIndex == 0 ? 1 : 0;
store.dispatch(SelectCompany(companyIndex: index)); store.dispatch(SelectCompany(companyIndex: index));
final refreshCompleter = Completer<Null>() final refreshCompleter = Completer<Null>()
..future.then((value) { ..future.then<Null>(() {
store.dispatch(SelectCompany(companyIndex: 0)); store.dispatch(SelectCompany(companyIndex: 0));
store.dispatch(ViewDashboard()); store.dispatch(ViewDashboard());
AppBuilder.of(navigatorKey.currentContext!)!.rebuild(); AppBuilder.of(navigatorKey.currentContext!)!.rebuild();
@ -99,7 +99,7 @@ class AccountManagementVM {
store.dispatch( store.dispatch(
RefreshData(clearData: true, completer: refreshCompleter)); RefreshData(clearData: true, completer: refreshCompleter));
} }
} as FutureOr<_> Function(Null)) } as FutureOr<Null> Function(Null))
.catchError((Object error) { .catchError((Object error) {
if (Navigator.of(navigatorKey.currentContext!).canPop()) { if (Navigator.of(navigatorKey.currentContext!).canPop()) {
Navigator.of(navigatorKey.currentContext!).pop(); Navigator.of(navigatorKey.currentContext!).pop();
@ -151,7 +151,7 @@ class AccountManagementVM {
final CompanyEntity company; final CompanyEntity company;
final Function(BuildContext) onSetPrimaryCompany; final Function(BuildContext) onSetPrimaryCompany;
final Function(CompanyEntity) onCompanyChanged; final Function(CompanyEntity) onCompanyChanged;
final Function(BuildContext?, String?, String?, String?) onCompanyDelete; final Function(BuildContext, String, String, String) onCompanyDelete;
final Function(BuildContext, String?, String?) onPurgeData; final Function(BuildContext, String, String) onPurgeData;
final Function onAppliedLicense; final Function onAppliedLicense;
} }

View File

@ -1,4 +1,6 @@
// Flutter imports: // Flutter imports:
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -80,7 +82,7 @@ class ClientPortalVM {
final oldSubdomain = state.company!.subdomain; final oldSubdomain = state.company!.subdomain;
final newSubdomain = settingsUIState.company.subdomain; final newSubdomain = settingsUIState.company.subdomain;
if (oldSubdomain != newSubdomain) { if (oldSubdomain != newSubdomain) {
completer.future.then((value) { completer.future.then<Null>(() {
showRefreshDataDialog( showRefreshDataDialog(
context: navigatorKey.currentContext!); context: navigatorKey.currentContext!);
} as FutureOr<Null> Function(Null)); } as FutureOr<Null> Function(Null));

View File

@ -560,7 +560,7 @@ class _CompanyDetailsState extends State<CompanyDetails>
if (multipartFiles != null && if (multipartFiles != null &&
multipartFiles.isNotEmpty) { multipartFiles.isNotEmpty) {
viewModel.onUploadLogo( viewModel.onUploadLogo(
navigatorKey.currentContext, navigatorKey.currentContext!,
multipartFiles.first); multipartFiles.first);
} }
}, },

View File

@ -174,7 +174,7 @@ class CompanyDetailsVM {
final Function(SettingsEntity) onSettingsChanged; final Function(SettingsEntity) onSettingsChanged;
final Function(CompanyEntity) onCompanyChanged; final Function(CompanyEntity) onCompanyChanged;
final Function(BuildContext) onSavePressed; final Function(BuildContext) onSavePressed;
final Function(BuildContext?, MultipartFile) onUploadLogo; final Function(BuildContext, MultipartFile) onUploadLogo;
final Function(BuildContext) onDeleteLogo; final Function(BuildContext) onDeleteLogo;
final Function(BuildContext) onConfigurePaymentTermsPressed; final Function(BuildContext) onConfigurePaymentTermsPressed;
final Function(BuildContext, List<MultipartFile>, bool) onUploadDocuments; final Function(BuildContext, List<MultipartFile>, bool) onUploadDocuments;

View File

@ -120,7 +120,7 @@ class _DeviceSettingsState extends State<DeviceSettings>
value: prefState.appLayout == AppLayout.mobile, value: prefState.appLayout == AppLayout.mobile,
onChanged: (value) { onChanged: (value) {
viewModel.onLayoutChanged(context, viewModel.onLayoutChanged(context,
value ? AppLayout.mobile : AppLayout.desktop); value == true ? AppLayout.mobile : AppLayout.desktop);
}, },
enabledLabel: localization.mobile, enabledLabel: localization.mobile,
disabledLabel: localization.desktop, disabledLabel: localization.desktop,
@ -132,7 +132,7 @@ class _DeviceSettingsState extends State<DeviceSettings>
onChanged: (value) { onChanged: (value) {
viewModel.onMenuModeChanged( viewModel.onMenuModeChanged(
context, context,
value value == true
? AppSidebarMode.float ? AppSidebarMode.float
: AppSidebarMode.collapse, : AppSidebarMode.collapse,
); );
@ -147,7 +147,9 @@ class _DeviceSettingsState extends State<DeviceSettings>
onChanged: (value) { onChanged: (value) {
viewModel.onHistoryModeChanged( viewModel.onHistoryModeChanged(
context, context,
value ? AppSidebarMode.float : AppSidebarMode.visible, value == true
? AppSidebarMode.float
: AppSidebarMode.visible,
); );
}, },
enabledLabel: localization.float, enabledLabel: localization.float,
@ -159,7 +161,7 @@ class _DeviceSettingsState extends State<DeviceSettings>
label: localization.clickSelected, label: localization.clickSelected,
value: prefState.tapSelectedToEdit, value: prefState.tapSelectedToEdit,
onChanged: (value) { onChanged: (value) {
viewModel.onTapSelectedChanged(context, value); viewModel.onTapSelectedChanged(context, value == true);
}, },
enabledLabel: localization.editRecord, enabledLabel: localization.editRecord,
disabledLabel: localization.hidePreview, disabledLabel: localization.hidePreview,
@ -168,7 +170,8 @@ class _DeviceSettingsState extends State<DeviceSettings>
label: localization.afterSaving, label: localization.afterSaving,
value: prefState.editAfterSaving, value: prefState.editAfterSaving,
onChanged: (value) { onChanged: (value) {
viewModel.onEditAfterSavingChanged(context, value); viewModel.onEditAfterSavingChanged(
context, value == true);
}, },
enabledLabel: localization.editRecord, enabledLabel: localization.editRecord,
disabledLabel: localization.viewRecord, disabledLabel: localization.viewRecord,
@ -179,7 +182,7 @@ class _DeviceSettingsState extends State<DeviceSettings>
value: !prefState.longPressSelectionIsDefault, value: !prefState.longPressSelectionIsDefault,
onChanged: (value) { onChanged: (value) {
viewModel.onLongPressSelectionIsDefault( viewModel.onLongPressSelectionIsDefault(
context, !value); context, value == false);
}, },
enabledLabel: localization.showActions, enabledLabel: localization.showActions,
disabledLabel: localization.startMultiselect, disabledLabel: localization.startMultiselect,
@ -213,7 +216,8 @@ class _DeviceSettingsState extends State<DeviceSettings>
label: localization.previewLocation, label: localization.previewLocation,
value: prefState.showPdfPreviewSideBySide, value: prefState.showPdfPreviewSideBySide,
onChanged: (value) { onChanged: (value) {
viewModel.onShowPdfSideBySideChanged(context, value); viewModel.onShowPdfSideBySideChanged(
context, value == true);
}, },
disabledLabel: localization.bottom, disabledLabel: localization.bottom,
enabledLabel: localization.side, enabledLabel: localization.side,

View File

@ -185,7 +185,7 @@ class _ImportExportState extends State<ImportExport> {
} }
}, },
onImportTypeChanged: (importType) => onImportTypeChanged: (importType) =>
setState(() => _importFormat = importType), setState(() => _importFormat = importType!),
) )
else else
_FileMapper( _FileMapper(

View File

@ -575,8 +575,8 @@ class _InvoiceDesignState extends State<InvoiceDesign>
value: !(settings.hideEmptyColumnsOnPdf ?? false), value: !(settings.hideEmptyColumnsOnPdf ?? false),
iconData: MdiIcons.table, iconData: MdiIcons.table,
onChanged: (value) => viewModel.onSettingsChanged( onChanged: (value) => viewModel.onSettingsChanged(
settings.rebuild( settings.rebuild((b) =>
(b) => b..hideEmptyColumnsOnPdf = !value), b..hideEmptyColumnsOnPdf = value == false),
), ),
enabledLabel: localization.show, enabledLabel: localization.show,
disabledLabel: localization.hide, disabledLabel: localization.hide,

View File

@ -1,4 +1,5 @@
// Dart imports: // Dart imports:
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
// Flutter imports: // Flutter imports:
@ -82,7 +83,7 @@ class InvoiceDesignVM {
case EntityType.company: case EntityType.company:
final completer = snackBarCompleter<Null>( final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context)!.savedSettings) context, AppLocalization.of(context)!.savedSettings)
..future.then((value) { ..future.then<Null>(() {
final webClient = WebClient(); final webClient = WebClient();
final credentials = state.credentials; final credentials = state.credentials;
final url = '${credentials.url}/designs/set/default'; final url = '${credentials.url}/designs/set/default';

View File

@ -419,7 +419,7 @@ class _AddCompanyDialogState extends State<_AddCompanyDialog> {
entityList: memoizedCountryList(state.staticState.countryMap), entityList: memoizedCountryList(state.staticState.countryMap),
labelText: localization.country, labelText: localization.country,
onSelected: (SelectableEntity? country) { onSelected: (SelectableEntity? country) {
_countryId = country.id; _countryId = country?.id ?? '';
}, },
), ),
); );

View File

@ -147,16 +147,16 @@ class _SettingsWizardState extends State<SettingsWizard> {
final localization = AppLocalization.of(context); final localization = AppLocalization.of(context);
final completer = Completer<Null>(); final completer = Completer<Null>();
completer.future completer.future
.then((value) { .then<Null>(() {
final toastCompleter = final toastCompleter =
snackBarCompleter<Null>(context, localization!.savedSettings); snackBarCompleter<Null>(context, localization!.savedSettings);
toastCompleter.future toastCompleter.future
.then((value) { .then<Null>(() {
setState(() { setState(() {
_isSaving = false; _isSaving = false;
_showLogo = true; _showLogo = true;
}); });
} as FutureOr<_> Function(Null)) } as FutureOr<Null> Function(Null))
.catchError((Object error) { .catchError((Object error) {
setState(() { setState(() {
_isSaving = false; _isSaving = false;
@ -174,7 +174,7 @@ class _SettingsWizardState extends State<SettingsWizard> {
), ),
), ),
); );
} as FutureOr<_> Function(Null)) } as FutureOr<Null> Function(Null))
.catchError((Object error) { .catchError((Object error) {
setState(() => _isSaving = false); setState(() => _isSaving = false);
}); });
@ -237,7 +237,7 @@ class _SettingsWizardState extends State<SettingsWizard> {
labelText: localization.currency, labelText: localization.currency,
entityId: _currencyId, entityId: _currencyId,
onSelected: (SelectableEntity? currency) => onSelected: (SelectableEntity? currency) =>
setState(() => _currencyId = currency?.id), setState(() => _currencyId = currency?.id ?? ''),
validator: (dynamic value) => validator: (dynamic value) =>
value.isEmpty ? localization.pleaseEnterAValue : null, value.isEmpty ? localization.pleaseEnterAValue : null,
); );
@ -248,7 +248,7 @@ class _SettingsWizardState extends State<SettingsWizard> {
labelText: localization.language, labelText: localization.language,
entityId: _languageId, entityId: _languageId,
onSelected: (SelectableEntity? language) { onSelected: (SelectableEntity? language) {
setState(() => _languageId = language?.id); setState(() => _languageId = language?.id ?? '');
store.dispatch(UpdateCompanyLanguage(languageId: language?.id)); store.dispatch(UpdateCompanyLanguage(languageId: language?.id));
AppBuilder.of(context)!.rebuild(); AppBuilder.of(context)!.rebuild();
}, },

View File

@ -96,8 +96,8 @@ class TemplatesAndRemindersVM {
case EntityType.company: case EntityType.company:
final completer = snackBarCompleter<Null>( final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context)!.savedSettings); context, AppLocalization.of(context)!.savedSettings);
completer.future.then( completer.future.then<Null>(
((value) => callback()) as FutureOr<Null> Function(Null)); (() => callback()) as FutureOr<Null> Function(Null));
store.dispatch(SaveCompanyRequest( store.dispatch(SaveCompanyRequest(
completer: completer, company: settingsUIState.company)); completer: completer, company: settingsUIState.company));
break; break;

View File

@ -315,7 +315,7 @@ class UserDetailsVM {
final appBuilder = AppBuilder.of(context); final appBuilder = AppBuilder.of(context);
final origUserSettings = state.userCompany!.settings; final origUserSettings = state.userCompany!.settings;
completer.future.then((_) async { completer.future.then<Null>(() async {
final newUserSettings = store.state.userCompany!.settings!; final newUserSettings = store.state.userCompany!.settings!;
if (origUserSettings!.includeDeletedClients != if (origUserSettings!.includeDeletedClients !=
newUserSettings.includeDeletedClients || newUserSettings.includeDeletedClients ||

View File

@ -252,15 +252,18 @@ class _SubscriptionEditState extends State<SubscriptionEdit>
entityMap: state.productState.map, entityMap: state.productState.map,
labelText: localization.oneTimeProducts, labelText: localization.oneTimeProducts,
onSelected: (value) { onSelected: (value) {
if (value != null) {
final parts = subscription.productIds.split(','); final parts = subscription.productIds.split(',');
viewModel.onChanged(subscription.rebuild((b) => b viewModel.onChanged(subscription.rebuild((b) => b
..productIds = <String>[...parts, value.id] ..productIds = <String>[...parts, value.id]
.where((part) => part.isNotEmpty) .where((part) => part.isNotEmpty)
.join(','))); .join(',')));
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance
.addPostFrameCallback((duration) {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
}); });
}
}, },
), ),
SizedBox( SizedBox(
@ -338,15 +341,19 @@ class _SubscriptionEditState extends State<SubscriptionEdit>
entityMap: state.productState.map, entityMap: state.productState.map,
labelText: localization.optionalOneTimeProducts, labelText: localization.optionalOneTimeProducts,
onSelected: (value) { onSelected: (value) {
final parts = subscription.optionalProductIds.split(','); if (value != null) {
final parts =
subscription.optionalProductIds.split(',');
viewModel.onChanged(subscription.rebuild((b) => b viewModel.onChanged(subscription.rebuild((b) => b
..optionalProductIds = <String>[...parts, value.id] ..optionalProductIds = <String>[...parts, value.id]
.where((part) => part.isNotEmpty) .where((part) => part.isNotEmpty)
.join(','))); .join(',')));
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance
.addPostFrameCallback((duration) {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
}); });
}
}, },
), ),
SizedBox( SizedBox(
@ -380,6 +387,7 @@ class _SubscriptionEditState extends State<SubscriptionEdit>
entityMap: state.productState.map, entityMap: state.productState.map,
labelText: localization.optionalRecurringProducts, labelText: localization.optionalRecurringProducts,
onSelected: (value) { onSelected: (value) {
if (value != null) {
final parts = final parts =
subscription.optionalRecurringProductIds.split(','); subscription.optionalRecurringProductIds.split(',');
viewModel.onChanged(subscription.rebuild((b) => b viewModel.onChanged(subscription.rebuild((b) => b
@ -388,9 +396,11 @@ class _SubscriptionEditState extends State<SubscriptionEdit>
value.id value.id
].where((part) => part.isNotEmpty).join(','))); ].where((part) => part.isNotEmpty).join(',')));
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance
.addPostFrameCallback((duration) {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
}); });
}
}, },
), ),
SizedBox( SizedBox(

View File

@ -332,11 +332,13 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
labelText: settings.showTaskItemDescription! labelText: settings.showTaskItemDescription!
? localization.startDate ? localization.startDate
: null, : null,
selectedDate: taskTimes[index]!.startDate == selectedDate:
null taskTimes[index]!.startDate == null
? null ? null
: convertDateTimeToSqlDate( : convertDateTimeToSqlDate(
taskTimes[index]!.startDate!.toLocal()), taskTimes[index]!
.startDate!
.toLocal()),
onSelected: (date, _) { onSelected: (date, _) {
final taskTime = taskTimes[index]! final taskTime = taskTimes[index]!
.copyWithStartDate(date, .copyWithStartDate(date,
@ -363,6 +365,10 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
: null, : null,
selectedDateTime: taskTimes[index]!.startDate, selectedDateTime: taskTimes[index]!.startDate,
onSelected: (timeOfDay) { onSelected: (timeOfDay) {
if (timeOfDay == null) {
return;
}
final taskTime = taskTimes[index]! final taskTime = taskTimes[index]!
.copyWithStartTime(timeOfDay); .copyWithStartTime(timeOfDay);
viewModel.onUpdatedTaskTime( viewModel.onUpdatedTaskTime(
@ -386,11 +392,13 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
labelText: settings.showTaskItemDescription! labelText: settings.showTaskItemDescription!
? localization.endDate ? localization.endDate
: null, : null,
selectedDate: taskTimes[index]!.endDate == selectedDate:
null taskTimes[index]!.endDate == null
? null ? null
: convertDateTimeToSqlDate( : convertDateTimeToSqlDate(
taskTimes[index]!.endDate!.toLocal()), taskTimes[index]!
.endDate!
.toLocal()),
onSelected: (date, _) { onSelected: (date, _) {
final taskTime = taskTimes[index]! final taskTime = taskTimes[index]!
.copyWithEndDate(date); .copyWithEndDate(date);
@ -417,6 +425,10 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
selectedDateTime: taskTimes[index]!.endDate, selectedDateTime: taskTimes[index]!.endDate,
isEndTime: true, isEndTime: true,
onSelected: (timeOfDay) { onSelected: (timeOfDay) {
if (timeOfDay == null) {
return;
}
final taskTime = taskTimes[index]! final taskTime = taskTimes[index]!
.copyWithEndTime(timeOfDay); .copyWithEndTime(timeOfDay);
viewModel.onUpdatedTaskTime( viewModel.onUpdatedTaskTime(

View File

@ -145,8 +145,8 @@ class TimeEditDetailsState extends State<TimeEditDetails> {
: convertDateTimeToSqlDate(_taskTime!.startDate!.toLocal()), : convertDateTimeToSqlDate(_taskTime!.startDate!.toLocal()),
onSelected: (date, _) { onSelected: (date, _) {
setState(() { setState(() {
_taskTime = _taskTime!.copyWithStartDate(date, _taskTime = _taskTime!
syncDates: !showEndDate); .copyWithStartDate(date, syncDates: !showEndDate);
viewModel.onUpdatedTaskTime(_taskTime, widget.index); viewModel.onUpdatedTaskTime(_taskTime, widget.index);
_startDateUpdatedAt = DateTime.now().millisecondsSinceEpoch; _startDateUpdatedAt = DateTime.now().millisecondsSinceEpoch;
}); });
@ -157,6 +157,10 @@ class TimeEditDetailsState extends State<TimeEditDetails> {
labelText: localization.startTime, labelText: localization.startTime,
selectedDateTime: _taskTime!.startDate, selectedDateTime: _taskTime!.startDate,
onSelected: (timeOfDay) { onSelected: (timeOfDay) {
if (timeOfDay == null) {
return;
}
setState(() { setState(() {
_taskTime = _taskTime!.copyWithStartTime(timeOfDay); _taskTime = _taskTime!.copyWithStartTime(timeOfDay);
viewModel.onUpdatedTaskTime(_taskTime, widget.index); viewModel.onUpdatedTaskTime(_taskTime, widget.index);
@ -188,6 +192,10 @@ class TimeEditDetailsState extends State<TimeEditDetails> {
isEndTime: true, isEndTime: true,
onSelected: (timeOfDay) { onSelected: (timeOfDay) {
setState(() { setState(() {
if (timeOfDay == null) {
return;
}
_taskTime = _taskTime!.copyWithEndTime(timeOfDay); _taskTime = _taskTime!.copyWithEndTime(timeOfDay);
viewModel.onUpdatedTaskTime(_taskTime, widget.index); viewModel.onUpdatedTaskTime(_taskTime, widget.index);
_endTimeUpdatedAt = DateTime.now().millisecondsSinceEpoch; _endTimeUpdatedAt = DateTime.now().millisecondsSinceEpoch;

View File

@ -160,7 +160,7 @@ class TaskEditVM {
final int? taskTimeIndex; final int? taskTimeIndex;
final CompanyEntity? company; final CompanyEntity? company;
final Function(BuildContext, [EntityAction?]) onSavePressed; final Function(BuildContext, [EntityAction?]) onSavePressed;
final Function(BuildContext?) onCancelPressed; final Function(BuildContext) onCancelPressed;
final Function onFabPressed; final Function onFabPressed;
final bool isLoading; final bool isLoading;
final bool isSaving; final bool isSaving;

View File

@ -61,7 +61,7 @@ class _TaskOverviewState extends State<TaskOverview> {
final company = viewModel.company!; final company = viewModel.company!;
final invoice = viewModel.state.invoiceState.map[task.invoiceId]; final invoice = viewModel.state.invoiceState.map[task.invoiceId];
final user = viewModel.state.userState.map[task.assignedUserId]; final user = viewModel.state.userState.map[task.assignedUserId];
final group = state.groupState.get(client?.groupId); final group = state.groupState.get(client?.groupId ?? '');
final status = state.taskStatusState.get(task.statusId); final status = state.taskStatusState.get(task.statusId);
final Map<String, String?> fields = { final Map<String, String?> fields = {