// Dart imports: import 'dart:math'; // Package imports: import 'package:built_collection/built_collection.dart'; import 'package:redux/redux.dart'; // Project imports: import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company_gateway/company_gateway_actions.dart'; import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart'; import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart'; import 'package:invoiceninja_flutter/redux/design/design_actions.dart'; import 'package:invoiceninja_flutter/redux/expense/expense_actions.dart'; import 'package:invoiceninja_flutter/redux/expense_category/expense_category_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart'; import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart'; import 'package:invoiceninja_flutter/redux/product/product_actions.dart'; import 'package:invoiceninja_flutter/redux/project/project_actions.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart'; import 'package:invoiceninja_flutter/redux/recurring_expense/recurring_expense_actions.dart'; import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart'; import 'package:invoiceninja_flutter/redux/reports/reports_actions.dart'; import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart'; import 'package:invoiceninja_flutter/redux/subscription/subscription_actions.dart'; import 'package:invoiceninja_flutter/redux/task/task_actions.dart'; import 'package:invoiceninja_flutter/redux/task_status/task_status_actions.dart'; import 'package:invoiceninja_flutter/redux/tax_rate/tax_rate_actions.dart'; import 'package:invoiceninja_flutter/redux/token/token_actions.dart'; import 'package:invoiceninja_flutter/redux/ui/pref_state.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart'; import 'package:invoiceninja_flutter/redux/user/user_actions.dart'; import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart'; import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart'; // STARTER: import - do not remove comment import 'package:invoiceninja_flutter/redux/transaction_rule/transaction_rule_actions.dart'; import 'package:invoiceninja_flutter/redux/transaction/transaction_actions.dart'; import 'package:invoiceninja_flutter/redux/bank_account/bank_account_actions.dart'; import 'package:invoiceninja_flutter/redux/purchase_order/purchase_order_actions.dart'; PrefState prefReducer( PrefState state, dynamic action, String selectedCompanyId) { return state.rebuild((b) => b ..companyPrefs[selectedCompanyId] = companyPrefReducer(state.companyPrefs[selectedCompanyId], action) ..appLayout = layoutReducer(state.appLayout, action) ..rowsPerPage = rowsPerPageReducer(state.rowsPerPage, action) ..moduleLayout = moduleLayoutReducer(state.moduleLayout, action) ..isPreviewVisible = isPreviewVisibleReducer(state.isPreviewVisible, action) ..menuSidebarMode = manuSidebarReducer(state.menuSidebarMode, action) ..historySidebarMode = historySidebarReducer(state.historySidebarMode, action) ..hideDesktopWarning = hideDesktopWarningReducer(state.hideDesktopWarning, action) ..hideGatewayWarning = hideGatewayWarningReducer(state.hideGatewayWarning, action) ..hideReviewApp = hideReviewAppReducer(state.hideReviewApp, action) ..textScaleFactor = textScaleFactorReducer(state.textScaleFactor, action) ..isMenuVisible = menuVisibleReducer(state.isMenuVisible, action) ..isHistoryVisible = historyVisibleReducer(state.isHistoryVisible, action) ..enableDarkMode = darkModeReducer(state.enableDarkMode, action) ..enableJSPDF = enableJspdfReducer(state.enableJSPDF, action) ..enableTooltips = enableTooltipsReducer(state.enableTooltips, action) ..enableFlexibleSearch = enableFlexibleSearchReducer(state.enableFlexibleSearch, action) ..persistData = persistDataReducer(state.persistData, action) ..persistUI = persistUIReducer(state.persistUI, action) ..showKanban = showKanbanReducer(state.showKanban, action) ..isFilterVisible = isFilterVisibleReducer(state.isFilterVisible, action) ..longPressSelectionIsDefault = longPressReducer(state.longPressSelectionIsDefault, action) ..tapSelectedToEdit = tapSelectedToEditReducer(state.tapSelectedToEdit, action) ..requireAuthentication = requireAuthenticationReducer(state.requireAuthentication, action) ..colorTheme = colorThemeReducer(state.colorTheme, action) ..customColors.replace(customColorsReducer(state.customColors, action)) ..useSidebarEditor .replace(sidebarEditorReducer(state.useSidebarEditor, action)) ..useSidebarViewer .replace(sidebarViewerReducer(state.useSidebarViewer, action)) ..sortFields.replace(sortFieldsReducer(state.sortFields, action)) ..editAfterSaving = editAfterSavingReducer(state.editAfterSaving, action) ..enableTouchEvents = enableTouchEventsReducer(state.enableTouchEvents, action) ..showPdfPreview = showPdfPreviewReducer(state.showPdfPreview, action) ..showPdfPreviewSideBySide = showPdfPreviewSideBySideReducer( state.showPdfPreviewSideBySide, action)); } BuiltMap _resortFields( BuiltMap value, EntityType entityType, String field) { final sortField = value[entityType] ?? PrefStateSortField(field, field != 'number'); final directon = sortField.rebuild((b) => b ..ascending = sortField.field != field || !sortField.ascending ..field = field); return value.rebuild((b) => b..[entityType] = directon); } Reducer> sortFieldsReducer = combineReducers([ TypedReducer, SortClients>( (value, action) => _resortFields(value, EntityType.client, action.field)), TypedReducer, SortProducts>( (value, action) => _resortFields(value, EntityType.product, action.field)), TypedReducer, SortInvoices>( (value, action) => _resortFields(value, EntityType.invoice, action.field)), TypedReducer, SortPayments>( (value, action) => _resortFields(value, EntityType.payment, action.field)), TypedReducer, SortRecurringInvoices>( (value, action) => _resortFields(value, EntityType.recurringInvoice, action.field)), TypedReducer, SortQuotes>( (value, action) => _resortFields(value, EntityType.quote, action.field)), TypedReducer, SortCredits>( (value, action) => _resortFields(value, EntityType.credit, action.field)), TypedReducer, SortProjects>( (value, action) => _resortFields(value, EntityType.project, action.field)), TypedReducer, SortTasks>( (value, action) => _resortFields(value, EntityType.task, action.field)), TypedReducer, SortVendors>( (value, action) => _resortFields(value, EntityType.vendor, action.field)), TypedReducer, SortExpenses>( (value, action) => _resortFields(value, EntityType.expense, action.field)), TypedReducer, SortPaymentTerms>( (value, action) => _resortFields(value, EntityType.payment, action.field)), TypedReducer, SortTaxRates>( (value, action) => _resortFields(value, EntityType.taxRate, action.field)), TypedReducer, SortCompanyGateways>( (value, action) => _resortFields(value, EntityType.companyGateway, action.field)), TypedReducer, SortUsers>( (value, action) => _resortFields(value, EntityType.user, action.field)), TypedReducer, SortGroups>( (value, action) => _resortFields(value, EntityType.group, action.field)), TypedReducer, SortDesigns>( (value, action) => _resortFields(value, EntityType.design, action.field)), TypedReducer, SortTokens>( (value, action) => _resortFields(value, EntityType.token, action.field)), TypedReducer, SortWebhooks>( (value, action) => _resortFields(value, EntityType.webhook, action.field)), TypedReducer, SortExpenseCategories>( (value, action) => _resortFields(value, EntityType.expenseCategory, action.field)), TypedReducer, SortTaskStatuses>( (value, action) => _resortFields(value, EntityType.taskStatus, action.field)), TypedReducer, SortSubscriptions>( (value, action) => _resortFields(value, EntityType.subscription, action.field)), // TODO add to starter.sh ]); Reducer> sidebarEditorReducer = combineReducers([ TypedReducer, ToggleEditorLayout>((value, action) { final entityType = action.entityType.baseType; if (value.containsKey(entityType)) { return value.rebuild((b) => b..[entityType] = !value[entityType]); } else { return value.rebuild((b) => b..[entityType] = true); } }), ]); Reducer> sidebarViewerReducer = combineReducers([ TypedReducer, ToggleViewerLayout>((value, action) { final entityType = action.entityType.baseType; if (value.containsKey(entityType)) { return value.rebuild((b) => b..[entityType] = !value[entityType]); } else { return value.rebuild((b) => b..[entityType] = true); } }), ]); Reducer menuVisibleReducer = combineReducers([ TypedReducer((value, action) { return action.sidebar == AppSidebar.menu ? !value : value; }), TypedReducer((value, action) { switch (action.menuMode) { case AppSidebarMode.visible: return true; case AppSidebarMode.collapse: case AppSidebarMode.float: return false; default: return value; } }), ]); Reducer textScaleFactorReducer = combineReducers([ TypedReducer((value, action) { return action.textScaleFactor ?? value; }), ]); Reducer historyVisibleReducer = combineReducers([ TypedReducer((value, action) { return action.sidebar == AppSidebar.history ? !value : value; }), TypedReducer((value, action) { return action.historyMode == AppSidebarMode.visible ? true : action.historyMode == AppSidebarMode.float ? false : value; }), ]); Reducer filterReducer = combineReducers([ TypedReducer((filter, action) { return action.filter; }), ]); Reducer hideDesktopWarningReducer = combineReducers([ TypedReducer((filter, action) { return true; }), ]); Reducer hideGatewayWarningReducer = combineReducers([ TypedReducer((filter, action) { return true; }), ]); Reducer hideReviewAppReducer = combineReducers([ TypedReducer((filter, action) { return true; }), ]); Reducer filterClearedAtReducer = combineReducers([ TypedReducer((filterClearedAt, action) { return action.filter == null ? DateTime.now().millisecondsSinceEpoch : filterClearedAt; }), ]); Reducer layoutReducer = combineReducers([ TypedReducer((layout, action) { return action.appLayout ?? layout; }), ]); Reducer moduleLayoutReducer = combineReducers([ TypedReducer((moduleLayout, action) { if (action.moduleLayout != null) { return action.moduleLayout; } else if (action.appLayout != null) { return (action.appLayout == AppLayout.desktop) ? ModuleLayout.table : ModuleLayout.list; } return moduleLayout; }), TypedReducer((moduleLayout, action) { if (moduleLayout == ModuleLayout.list) { return ModuleLayout.table; } else { return ModuleLayout.list; } }), ]); Reducer rowsPerPageReducer = combineReducers([ TypedReducer((numRows, action) { return action.rowsPerPage ?? numRows; }), ]); Reducer manuSidebarReducer = combineReducers([ TypedReducer((mode, action) { return action.menuMode ?? mode; }), ]); Reducer historySidebarReducer = combineReducers([ TypedReducer((mode, action) { return action.historyMode ?? mode; }), ]); Reducer darkModeReducer = combineReducers([ TypedReducer((enableDarkMode, action) { return action.enableDarkMode ?? enableDarkMode; }), ]); Reducer enableJspdfReducer = combineReducers([ TypedReducer((enableJSPDF, action) { return action.enableJSPDF ?? enableJSPDF; }), ]); Reducer enableTooltipsReducer = combineReducers([ TypedReducer((enableTooltips, action) { return action.enableTooltips ?? enableTooltips; }), ]); Reducer enableFlexibleSearchReducer = combineReducers([ TypedReducer((enableFlexibleSearch, action) { return action.flexibleSearch ?? enableFlexibleSearch; }), ]); Reducer persistDataReducer = combineReducers([ TypedReducer((persistData, action) { return action.persistData ?? persistData; }), ]); Reducer persistUIReducer = combineReducers([ TypedReducer((persistUI, action) { return action.persistUi ?? persistUI; }), ]); Reducer showKanbanReducer = combineReducers([ TypedReducer((showKanban, action) { return action.showKanban ?? showKanban; }), ]); Reducer isFilterVisibleReducer = combineReducers([ TypedReducer((value, action) { return action.isFilterVisible ?? value; }), ]); Reducer longPressReducer = combineReducers([ TypedReducer( (longPressSelectionIsDefault, action) { return action.longPressSelectionIsDefault ?? longPressSelectionIsDefault; }), ]); Reducer tapSelectedToEditReducer = combineReducers([ TypedReducer((tapSelectedToEdit, action) { return action.tapSelectedToEdit ?? tapSelectedToEdit; }), ]); Reducer isPreviewVisibleReducer = combineReducers([ TypedReducer((value, action) { return !value; }), TypedReducer((isPreviewEnabled, action) { return action.isPreviewVisible ?? isPreviewEnabled; }), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer( (value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer((value, action) => false), TypedReducer( (value, action) => false), TypedReducer((value, action) => true), // TODO add to starter.sh ]); Reducer requireAuthenticationReducer = combineReducers([ TypedReducer((requireAuthentication, action) { return action.requireAuthentication ?? requireAuthentication; }), ]); Reducer colorThemeReducer = combineReducers([ TypedReducer((currentColorTheme, action) { return action.colorTheme ?? currentColorTheme; }), ]); Reducer showPdfPreviewReducer = combineReducers([ TypedReducer((value, action) { return action.showPdfPreview ?? value; }), ]); Reducer showPdfPreviewSideBySideReducer = combineReducers([ TypedReducer((value, action) { return action.showPdfPreviewSideBySide ?? value; }), ]); Reducer editAfterSavingReducer = combineReducers([ TypedReducer((value, action) { return action.editAfterSaving ?? value; }), ]); Reducer enableTouchEventsReducer = combineReducers([ TypedReducer((value, action) { return action.enableTouchEvents ?? value; }), ]); Reducer> customColorsReducer = combineReducers([ TypedReducer, UpdateUserPreferences>( (customColors, action) { return action.customColors ?? customColors; }), ]); Reducer currentRouteReducer = combineReducers([ TypedReducer((currentRoute, action) { return action.route; }), ]); Reducer previousRouteReducer = combineReducers([ TypedReducer((currentRoute, action) { return currentRoute; }), ]); Reducer selectedCompanyIndexReducer = combineReducers([ TypedReducer((selectedCompanyIndex, action) { return action.companyIndex; }), ]); CompanyPrefState companyPrefReducer(CompanyPrefState state, dynamic action) { state ??= CompanyPrefState(); return state.rebuild( (b) => b..historyList.replace(historyReducer(state.historyList, action))); } Reducer> historyReducer = combineReducers([ TypedReducer, PurgeDataSuccess>( (historyList, action) { return BuiltList(); }), TypedReducer, PopLastHistory>( (historyList, action) { if (historyList.isEmpty) { return historyList; } else { return historyList.rebuild((b) => b..removeAt(0)); } }, ), TypedReducer, ViewDashboard>((historyList, action) => _addToHistory( historyList, HistoryRecord(entityType: EntityType.dashboard))), TypedReducer, ViewReports>((historyList, action) => _addToHistory( historyList, HistoryRecord(entityType: EntityType.reports))), TypedReducer, ViewSettings>((historyList, action) => _addToHistory( historyList, HistoryRecord( entityType: EntityType.settings, id: action.section ?? kSettingsCompanyDetails))), TypedReducer, ViewClient>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.clientId, entityType: EntityType.client))), TypedReducer, EditClient>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.client.id, entityType: EntityType.client))), TypedReducer, ViewProduct>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.productId, entityType: EntityType.product))), TypedReducer, EditProduct>((historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.product.id, entityType: EntityType.product))), TypedReducer, ViewInvoice>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.invoiceId, entityType: EntityType.invoice))), TypedReducer, EditInvoice>((historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.invoice.id, entityType: EntityType.invoice))), TypedReducer, ViewPayment>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.paymentId, entityType: EntityType.payment))), TypedReducer, EditPayment>((historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.payment.id, entityType: EntityType.payment))), TypedReducer, ViewQuote>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.quoteId, entityType: EntityType.quote))), TypedReducer, EditQuote>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.quote.id, entityType: EntityType.quote))), TypedReducer, ViewTask>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.taskId, entityType: EntityType.task))), TypedReducer, EditTask>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.task.id, entityType: EntityType.task))), TypedReducer, ViewProject>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.projectId, entityType: EntityType.project))), TypedReducer, EditProject>((historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.project.id, entityType: EntityType.project))), TypedReducer, ViewVendor>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.vendorId, entityType: EntityType.vendor))), TypedReducer, EditVendor>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.vendor.id, entityType: EntityType.vendor))), TypedReducer, ViewExpense>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.expenseId, entityType: EntityType.expense))), TypedReducer, EditExpense>((historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.expense.id, entityType: EntityType.expense))), TypedReducer, ViewCompanyGateway>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.companyGatewayId, entityType: EntityType.companyGateway))), TypedReducer, EditCompanyGateway>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.companyGateway.id, entityType: EntityType.companyGateway))), TypedReducer, ViewUser>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.userId, entityType: EntityType.user))), TypedReducer, EditUser>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.user.id, entityType: EntityType.user))), TypedReducer, ViewGroup>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.groupId, entityType: EntityType.group))), TypedReducer, EditGroup>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.group.id, entityType: EntityType.group))), // STARTER: history - do not remove comment TypedReducer, ViewTransactionRule>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.transactionRuleId, entityType: EntityType.transactionRule))), TypedReducer, EditTransactionRule>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.transactionRule.id, entityType: EntityType.transactionRule))), TypedReducer, ViewTransaction>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.transactionId, entityType: EntityType.transaction))), TypedReducer, EditTransaction>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.transaction.id, entityType: EntityType.transaction))), TypedReducer, ViewBankAccount>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.bankAccountId, entityType: EntityType.bankAccount))), TypedReducer, ViewPurchaseOrder>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.purchaseOrderId, entityType: EntityType.purchaseOrder))), TypedReducer, EditPurchaseOrder>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.purchaseOrder.id, entityType: EntityType.purchaseOrder))), TypedReducer, ViewRecurringExpense>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.recurringExpenseId, entityType: EntityType.recurringExpense))), TypedReducer, EditRecurringExpense>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.recurringExpense.id, entityType: EntityType.recurringExpense))), TypedReducer, ViewSubscription>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.subscriptionId, entityType: EntityType.subscription))), TypedReducer, EditSubscription>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.subscription.id, entityType: EntityType.subscription))), TypedReducer, ViewTaskStatus>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.taskStatusId, entityType: EntityType.taskStatus))), TypedReducer, EditTaskStatus>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.taskStatus.id, entityType: EntityType.taskStatus))), TypedReducer, ViewExpenseCategory>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.expenseCategoryId, entityType: EntityType.expenseCategory))), TypedReducer, EditExpenseCategory>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.expenseCategory.id, entityType: EntityType.expenseCategory))), TypedReducer, ViewRecurringInvoice>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.recurringInvoiceId, entityType: EntityType.recurringInvoice))), TypedReducer, EditRecurringInvoice>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.recurringInvoice.id, entityType: EntityType.recurringInvoice))), TypedReducer, ViewWebhook>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.webhookId, entityType: EntityType.webhook))), TypedReducer, EditWebhook>((historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.webhook.id, entityType: EntityType.webhook))), TypedReducer, ViewToken>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.tokenId, entityType: EntityType.token))), TypedReducer, EditToken>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.token.id, entityType: EntityType.token))), TypedReducer, ViewPaymentTerm>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.paymentTermId, entityType: EntityType.paymentTerm))), TypedReducer, EditPaymentTerm>( (historyList, action) => _addToHistory( historyList, HistoryRecord( id: action.paymentTerm.id, entityType: EntityType.paymentTerm))), TypedReducer, EditDesign>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.design.id, entityType: EntityType.design))), TypedReducer, ViewCredit>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.creditId, entityType: EntityType.credit))), TypedReducer, EditCredit>((historyList, action) => _addToHistory(historyList, HistoryRecord(id: action.credit.id, entityType: EntityType.credit))), TypedReducer, FilterByEntity>((historyList, action) { if (action.clearSelection) { return historyList; } return _addToHistory(historyList, HistoryRecord(id: action.entityId, entityType: action.entityType)); }), ]); BuiltList _addToHistory( BuiltList list, HistoryRecord record) { // don't track new records if (record.id != null && record.id.startsWith('-')) { return list; } if (record.entityType == EntityType.settings) { if ((record.id ?? '').endsWith('/edit')) { return list; } } final old = list.firstWhere((item) => item.matchesRecord(record), orElse: () => null); if (old != null) { return list.rebuild((b) => b ..remove(old) ..insert(0, record)); } else { return list.rebuild((b) => b ..insert(0, record) ..sublist(0, min(kMaxNumberOfHistory, list.length + 1))); } }