Recurring invoices
This commit is contained in:
parent
4c7293b4ce
commit
4c14f5cb6e
|
|
@ -91,6 +91,7 @@ abstract class CompanyEntity extends Object
|
|||
clients: BuiltList<ClientEntity>(),
|
||||
products: BuiltList<ProductEntity>(),
|
||||
invoices: BuiltList<InvoiceEntity>(),
|
||||
recurringInvoices: BuiltList<InvoiceEntity>(),
|
||||
payments: BuiltList<PaymentEntity>(),
|
||||
quotes: BuiltList<InvoiceEntity>(),
|
||||
credits: BuiltList<InvoiceEntity>(),
|
||||
|
|
@ -215,6 +216,9 @@ abstract class CompanyEntity extends Object
|
|||
|
||||
BuiltList<InvoiceEntity> get invoices;
|
||||
|
||||
@BuiltValueField(wireName: 'recurring_invoices')
|
||||
BuiltList<InvoiceEntity> get recurringInvoices;
|
||||
|
||||
BuiltList<PaymentEntity> get payments;
|
||||
|
||||
BuiltList<InvoiceEntity> get quotes;
|
||||
|
|
@ -407,7 +411,6 @@ abstract class CompanyEntity extends Object
|
|||
bool isModuleEnabled(EntityType entityType) {
|
||||
// TODO remove this
|
||||
if ([
|
||||
EntityType.recurringInvoice,
|
||||
EntityType.project,
|
||||
EntityType.task,
|
||||
EntityType.expense,
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
|
|||
serializers.serialize(object.invoices,
|
||||
specifiedType:
|
||||
const FullType(BuiltList, const [const FullType(InvoiceEntity)])),
|
||||
'recurring_invoices',
|
||||
serializers.serialize(object.recurringInvoices,
|
||||
specifiedType:
|
||||
const FullType(BuiltList, const [const FullType(InvoiceEntity)])),
|
||||
'payments',
|
||||
serializers.serialize(object.payments,
|
||||
specifiedType:
|
||||
|
|
@ -455,6 +459,12 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
|
|||
BuiltList, const [const FullType(InvoiceEntity)]))
|
||||
as BuiltList<Object>);
|
||||
break;
|
||||
case 'recurring_invoices':
|
||||
result.recurringInvoices.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(
|
||||
BuiltList, const [const FullType(InvoiceEntity)]))
|
||||
as BuiltList<Object>);
|
||||
break;
|
||||
case 'payments':
|
||||
result.payments.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(
|
||||
|
|
@ -2762,6 +2772,8 @@ class _$CompanyEntity extends CompanyEntity {
|
|||
@override
|
||||
final BuiltList<InvoiceEntity> invoices;
|
||||
@override
|
||||
final BuiltList<InvoiceEntity> recurringInvoices;
|
||||
@override
|
||||
final BuiltList<PaymentEntity> payments;
|
||||
@override
|
||||
final BuiltList<InvoiceEntity> quotes;
|
||||
|
|
@ -2853,6 +2865,7 @@ class _$CompanyEntity extends CompanyEntity {
|
|||
this.clients,
|
||||
this.products,
|
||||
this.invoices,
|
||||
this.recurringInvoices,
|
||||
this.payments,
|
||||
this.quotes,
|
||||
this.credits,
|
||||
|
|
@ -2995,6 +3008,9 @@ class _$CompanyEntity extends CompanyEntity {
|
|||
if (invoices == null) {
|
||||
throw new BuiltValueNullFieldError('CompanyEntity', 'invoices');
|
||||
}
|
||||
if (recurringInvoices == null) {
|
||||
throw new BuiltValueNullFieldError('CompanyEntity', 'recurringInvoices');
|
||||
}
|
||||
if (payments == null) {
|
||||
throw new BuiltValueNullFieldError('CompanyEntity', 'payments');
|
||||
}
|
||||
|
|
@ -3102,6 +3118,7 @@ class _$CompanyEntity extends CompanyEntity {
|
|||
clients == other.clients &&
|
||||
products == other.products &&
|
||||
invoices == other.invoices &&
|
||||
recurringInvoices == other.recurringInvoices &&
|
||||
payments == other.payments &&
|
||||
quotes == other.quotes &&
|
||||
credits == other.credits &&
|
||||
|
|
@ -3150,7 +3167,7 @@ class _$CompanyEntity extends CompanyEntity {
|
|||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, enableCustomSurchargeTaxes1.hashCode), enableCustomSurchargeTaxes2.hashCode), enableCustomSurchargeTaxes3.hashCode), enableCustomSurchargeTaxes4.hashCode), sizeId.hashCode), industryId.hashCode), subdomain.hashCode), portalMode.hashCode), portalDomain.hashCode), updateProducts.hashCode), convertProductExchangeRate.hashCode), fillProducts.hashCode), enableProductCost.hashCode), enableProductQuantity.hashCode), defaultQuantity.hashCode), showProductDetails.hashCode), clientCanRegister.hashCode), isLarge.hashCode), enableShopApi.hashCode), plan.hashCode), companyKey.hashCode), firstDayOfWeek.hashCode), firstMonthOfYear.hashCode), numberOfInvoiceTaxRates.hashCode), numberOfItemTaxRates.hashCode), groups.hashCode), activities.hashCode), taxRates.hashCode), taskStatuses.hashCode), taskStatusMap.hashCode), companyGateways.hashCode), expenseCategories.hashCode), expenseCategoryMap.hashCode), users.hashCode), clients.hashCode), products.hashCode), invoices.hashCode), payments.hashCode), quotes.hashCode), credits.hashCode), tasks.hashCode), projects.hashCode), expenses.hashCode),
|
||||
$jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, enableCustomSurchargeTaxes1.hashCode), enableCustomSurchargeTaxes2.hashCode), enableCustomSurchargeTaxes3.hashCode), enableCustomSurchargeTaxes4.hashCode), sizeId.hashCode), industryId.hashCode), subdomain.hashCode), portalMode.hashCode), portalDomain.hashCode), updateProducts.hashCode), convertProductExchangeRate.hashCode), fillProducts.hashCode), enableProductCost.hashCode), enableProductQuantity.hashCode), defaultQuantity.hashCode), showProductDetails.hashCode), clientCanRegister.hashCode), isLarge.hashCode), enableShopApi.hashCode), plan.hashCode), companyKey.hashCode), firstDayOfWeek.hashCode), firstMonthOfYear.hashCode), numberOfInvoiceTaxRates.hashCode), numberOfItemTaxRates.hashCode), groups.hashCode), activities.hashCode), taxRates.hashCode), taskStatuses.hashCode), taskStatusMap.hashCode), companyGateways.hashCode), expenseCategories.hashCode), expenseCategoryMap.hashCode), users.hashCode), clients.hashCode), products.hashCode), invoices.hashCode), recurringInvoices.hashCode), payments.hashCode), quotes.hashCode), credits.hashCode), tasks.hashCode), projects.hashCode), expenses.hashCode),
|
||||
vendors.hashCode),
|
||||
designs.hashCode),
|
||||
tokens.hashCode),
|
||||
|
|
@ -3212,6 +3229,7 @@ class _$CompanyEntity extends CompanyEntity {
|
|||
..add('clients', clients)
|
||||
..add('products', products)
|
||||
..add('invoices', invoices)
|
||||
..add('recurringInvoices', recurringInvoices)
|
||||
..add('payments', payments)
|
||||
..add('quotes', quotes)
|
||||
..add('credits', credits)
|
||||
|
|
@ -3432,6 +3450,12 @@ class CompanyEntityBuilder
|
|||
set invoices(ListBuilder<InvoiceEntity> invoices) =>
|
||||
_$this._invoices = invoices;
|
||||
|
||||
ListBuilder<InvoiceEntity> _recurringInvoices;
|
||||
ListBuilder<InvoiceEntity> get recurringInvoices =>
|
||||
_$this._recurringInvoices ??= new ListBuilder<InvoiceEntity>();
|
||||
set recurringInvoices(ListBuilder<InvoiceEntity> recurringInvoices) =>
|
||||
_$this._recurringInvoices = recurringInvoices;
|
||||
|
||||
ListBuilder<PaymentEntity> _payments;
|
||||
ListBuilder<PaymentEntity> get payments =>
|
||||
_$this._payments ??= new ListBuilder<PaymentEntity>();
|
||||
|
|
@ -3597,6 +3621,7 @@ class CompanyEntityBuilder
|
|||
_clients = _$v.clients?.toBuilder();
|
||||
_products = _$v.products?.toBuilder();
|
||||
_invoices = _$v.invoices?.toBuilder();
|
||||
_recurringInvoices = _$v.recurringInvoices?.toBuilder();
|
||||
_payments = _$v.payments?.toBuilder();
|
||||
_quotes = _$v.quotes?.toBuilder();
|
||||
_credits = _$v.credits?.toBuilder();
|
||||
|
|
@ -3683,6 +3708,7 @@ class CompanyEntityBuilder
|
|||
clients: clients.build(),
|
||||
products: products.build(),
|
||||
invoices: invoices.build(),
|
||||
recurringInvoices: recurringInvoices.build(),
|
||||
payments: payments.build(),
|
||||
quotes: quotes.build(),
|
||||
credits: credits.build(),
|
||||
|
|
@ -3735,6 +3761,8 @@ class CompanyEntityBuilder
|
|||
products.build();
|
||||
_$failedField = 'invoices';
|
||||
invoices.build();
|
||||
_$failedField = 'recurringInvoices';
|
||||
recurringInvoices.build();
|
||||
_$failedField = 'payments';
|
||||
payments.build();
|
||||
_$failedField = 'quotes';
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class EntityType extends EnumClass {
|
|||
static const EntityType gatewayToken = _$gatewayToken;
|
||||
static const EntityType invoiceItem = _$invoiceItem;
|
||||
static const EntityType design = _$design;
|
||||
|
||||
// STARTER: entity type - do not remove comment
|
||||
static const EntityType webhook = _$webhook;
|
||||
static const EntityType token = _$token;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ import 'package:invoiceninja_flutter/redux/task/task_state.dart';
|
|||
import 'package:invoiceninja_flutter/redux/project/project_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment/payment_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/quote/quote_state.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/webhook_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/token_model.dart';
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
|
|||
..add(ProjectUIState.serializer)
|
||||
..add(QuoteState.serializer)
|
||||
..add(QuoteUIState.serializer)
|
||||
..add(RecurringInvoiceState.serializer)
|
||||
..add(RecurringInvoiceUIState.serializer)
|
||||
..add(ReportSettingsEntity.serializer)
|
||||
..add(ReportsUIState.serializer)
|
||||
..add(SettingsEntity.serializer)
|
||||
|
|
@ -337,6 +339,9 @@ Serializers _$serializers = (new Serializers().toBuilder()
|
|||
..addBuilderFactory(
|
||||
const FullType(BuiltList, const [const FullType(InvoiceEntity)]),
|
||||
() => new ListBuilder<InvoiceEntity>())
|
||||
..addBuilderFactory(
|
||||
const FullType(BuiltList, const [const FullType(InvoiceEntity)]),
|
||||
() => new ListBuilder<InvoiceEntity>())
|
||||
..addBuilderFactory(
|
||||
const FullType(BuiltList, const [const FullType(PaymentEntity)]),
|
||||
() => new ListBuilder<PaymentEntity>())
|
||||
|
|
@ -386,9 +391,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
|
|||
..addBuilderFactory(
|
||||
const FullType(BuiltList, const [const FullType(InvoiceEntity)]),
|
||||
() => new ListBuilder<InvoiceEntity>())
|
||||
..addBuilderFactory(
|
||||
const FullType(BuiltList, const [const FullType(InvoiceItemEntity)]),
|
||||
() => new ListBuilder<InvoiceItemEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(InvoiceItemEntity)]), () => new ListBuilder<InvoiceItemEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(InvitationEntity)]), () => new ListBuilder<InvitationEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(DocumentEntity)]), () => new ListBuilder<DocumentEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(InvoiceHistoryEntity)]), () => new ListBuilder<InvoiceHistoryEntity>())
|
||||
|
|
@ -461,6 +464,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
|
|||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
|
||||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(InvoiceEntity)]), () => new MapBuilder<String, InvoiceEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
|
||||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(InvoiceEntity)]), () => new MapBuilder<String, InvoiceEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
|
||||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(PaymentEntity)]), () => new MapBuilder<String, PaymentEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
|
||||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(PaymentTermEntity)]), () => new MapBuilder<String, PaymentTermEntity>())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:core';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/serializers.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/data/web_client.dart';
|
||||
|
||||
class RecurringInvoiceRepository {
|
||||
const RecurringInvoiceRepository({
|
||||
this.webClient = const WebClient(),
|
||||
});
|
||||
|
||||
final WebClient webClient;
|
||||
|
||||
Future<InvoiceEntity> loadItem(
|
||||
Credentials credentials, String entityId) async {
|
||||
final dynamic response = await webClient.get(
|
||||
'${credentials.url}/recurring_invoices/$entityId', credentials.token);
|
||||
|
||||
final InvoiceItemResponse recurringInvoiceResponse = serializers
|
||||
.deserializeWith(InvoiceItemResponse.serializer, response);
|
||||
|
||||
return recurringInvoiceResponse.data;
|
||||
}
|
||||
|
||||
Future<BuiltList<InvoiceEntity>> loadList(
|
||||
Credentials credentials) async {
|
||||
final String url = credentials.url + '/recurring_invoices?';
|
||||
|
||||
final dynamic response = await webClient.get(url, credentials.token);
|
||||
|
||||
final InvoiceListResponse recurringInvoiceResponse = serializers
|
||||
.deserializeWith(InvoiceListResponse.serializer, response);
|
||||
|
||||
return recurringInvoiceResponse.data;
|
||||
}
|
||||
|
||||
Future<List<InvoiceEntity>> bulkAction(
|
||||
Credentials credentials, List<String> ids, EntityAction action) async {
|
||||
final url = credentials.url + '/recurring_invoices/bulk';
|
||||
final dynamic response = await webClient.post(url, credentials.token,
|
||||
data: json.encode({'ids': ids, 'action': action.toApiParam()}));
|
||||
|
||||
final InvoiceListResponse recurringInvoiceResponse = serializers
|
||||
.deserializeWith(InvoiceListResponse.serializer, response);
|
||||
|
||||
return recurringInvoiceResponse.data.toList();
|
||||
}
|
||||
|
||||
Future<InvoiceEntity> saveData(
|
||||
Credentials credentials, InvoiceEntity recurringInvoice) async {
|
||||
final data = serializers.serializeWith(
|
||||
InvoiceEntity.serializer, recurringInvoice);
|
||||
dynamic response;
|
||||
|
||||
if (recurringInvoice.isNew) {
|
||||
response = await webClient.post(
|
||||
credentials.url + '/recurring_invoices', credentials.token,
|
||||
data: json.encode(data));
|
||||
} else {
|
||||
final url =
|
||||
'${credentials.url}/recurring_invoices/${recurringInvoice.id}';
|
||||
response =
|
||||
await webClient.put(url, credentials.token, data: json.encode(data));
|
||||
}
|
||||
|
||||
final InvoiceItemResponse recurringInvoiceResponse = serializers
|
||||
.deserializeWith(InvoiceItemResponse.serializer, response);
|
||||
|
||||
return recurringInvoiceResponse.data;
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,8 @@ import 'package:invoiceninja_flutter/utils/web_stub.dart'
|
|||
if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_middleware.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_middleware.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_middleware.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_middleware.dart';
|
||||
|
|
@ -71,6 +73,7 @@ void main({bool isTesting = false}) async {
|
|||
..addAll(createStoreSettingsMiddleware())
|
||||
..addAll(createStoreReportsMiddleware())
|
||||
// STARTER: middleware - do not remove comment
|
||||
..addAll(createStoreRecurringInvoicesMiddleware())
|
||||
..addAll(createStoreWebhooksMiddleware())
|
||||
..addAll(createStoreTokensMiddleware())
|
||||
..addAll(createStorePaymentTermsMiddleware())
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ import 'package:local_auth/local_auth.dart';
|
|||
import 'package:redux/redux.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_screen.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/edit/recurring_invoice_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/view/recurring_invoice_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_screen_vm.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/ui/webhook/webhook_screen.dart';
|
||||
import 'package:invoiceninja_flutter/ui/webhook/edit/webhook_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/webhook/view/webhook_view_vm.dart';
|
||||
|
|
@ -281,6 +286,13 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
|||
QuoteEditScreen.route: (context) => QuoteEditScreen(),
|
||||
QuoteEmailScreen.route: (context) => QuoteEmailScreen(),
|
||||
// STARTER: routes - do not remove comment
|
||||
RecurringInvoiceScreen.route: (context) =>
|
||||
RecurringInvoiceScreenBuilder(),
|
||||
RecurringInvoiceViewScreen.route: (context) =>
|
||||
RecurringInvoiceViewScreen(),
|
||||
RecurringInvoiceEditScreen.route: (context) =>
|
||||
RecurringInvoiceEditScreen(),
|
||||
|
||||
WebhookScreen.route: (context) => WebhookScreenBuilder(),
|
||||
WebhookViewScreen.route: (context) => WebhookViewScreen(),
|
||||
WebhookEditScreen.route: (context) => WebhookEditScreen(),
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
|||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart';
|
||||
|
|
@ -297,6 +299,10 @@ void viewEntitiesByType({
|
|||
action = ViewGroupList(navigator: navigator);
|
||||
break;
|
||||
// STARTER: view list - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
store.dispatch(ViewRecurringInvoiceList(navigator: navigator));
|
||||
break;
|
||||
|
||||
case EntityType.webhook:
|
||||
store.dispatch(ViewWebhookList(navigator: navigator));
|
||||
break;
|
||||
|
|
@ -471,6 +477,14 @@ void viewEntityById({
|
|||
));
|
||||
break;
|
||||
// STARTER: view - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
store.dispatch(ViewRecurringInvoice(
|
||||
recurringInvoiceId: entityId,
|
||||
navigator: navigator,
|
||||
force: force,
|
||||
));
|
||||
break;
|
||||
|
||||
case EntityType.webhook:
|
||||
store.dispatch(ViewWebhook(
|
||||
webhookId: entityId,
|
||||
|
|
@ -636,6 +650,14 @@ void createEntityByType(
|
|||
));
|
||||
break;
|
||||
// STARTER: create type - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
store.dispatch(EditRecurringInvoice(
|
||||
navigator: navigator,
|
||||
force: force,
|
||||
recurringInvoice: InvoiceEntity(state: state),
|
||||
));
|
||||
break;
|
||||
|
||||
case EntityType.webhook:
|
||||
store.dispatch(EditWebhook(
|
||||
navigator: navigator,
|
||||
|
|
@ -826,6 +848,15 @@ void createEntity({
|
|||
));
|
||||
break;
|
||||
// STARTER: create - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
store.dispatch(EditRecurringInvoice(
|
||||
navigator: navigator,
|
||||
recurringInvoice: entity,
|
||||
force: force,
|
||||
completer: completer,
|
||||
));
|
||||
break;
|
||||
|
||||
case EntityType.webhook:
|
||||
store.dispatch(EditWebhook(
|
||||
navigator: navigator,
|
||||
|
|
@ -1059,6 +1090,19 @@ void editEntity(
|
|||
));
|
||||
break;
|
||||
// STARTER: edit - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
store.dispatch(EditRecurringInvoice(
|
||||
recurringInvoice: entity,
|
||||
navigator: navigator,
|
||||
completer: completer ??
|
||||
snackBarCompleter<InvoiceEntity>(
|
||||
context,
|
||||
entity.isNew
|
||||
? localization.createdRecurringInvoice
|
||||
: localization.updatedRecurringInvoice),
|
||||
));
|
||||
break;
|
||||
|
||||
case EntityType.webhook:
|
||||
store.dispatch(EditWebhook(
|
||||
webhook: entity,
|
||||
|
|
@ -1220,6 +1264,10 @@ void handleEntitiesActions(
|
|||
handleDocumentAction(context, entities, action);
|
||||
break;
|
||||
// STARTER: actions - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
handleRecurringInvoiceAction(context, entities, action);
|
||||
break;
|
||||
|
||||
case EntityType.webhook:
|
||||
handleWebhookAction(context, entities, action);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import 'package:invoiceninja_flutter/redux/company/company_reducer.dart';
|
|||
import 'package:invoiceninja_flutter/redux/static/static_reducer.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart';
|
||||
|
|
@ -93,6 +95,10 @@ final lastErrorReducer = combineReducers<String>([
|
|||
return '${action.error}';
|
||||
}),
|
||||
// STARTER: errors - do not remove comment
|
||||
TypedReducer<String, LoadRecurringInvoicesFailure>((state, action) {
|
||||
return '${action.error}';
|
||||
}),
|
||||
|
||||
TypedReducer<String, LoadWebhooksFailure>((state, action) {
|
||||
return '${action.error}';
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart';
|
|||
import 'package:invoiceninja_flutter/ui/product/edit/product_edit_vm.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_state.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/edit/recurring_invoice_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_selectors.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
|
||||
import 'package:invoiceninja_flutter/ui/webhook/edit/webhook_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_selectors.dart';
|
||||
|
|
@ -217,6 +221,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
case EntityType.invoice:
|
||||
return invoiceState.map;
|
||||
// STARTER: states switch map - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
return recurringInvoiceState.map;
|
||||
|
||||
case EntityType.webhook:
|
||||
return webhookState.map;
|
||||
case EntityType.token:
|
||||
|
|
@ -284,6 +291,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
case EntityType.invoice:
|
||||
return invoiceState.list;
|
||||
// STARTER: states switch list - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
return recurringInvoiceState.list;
|
||||
|
||||
case EntityType.webhook:
|
||||
return webhookState.list;
|
||||
case EntityType.token:
|
||||
|
|
@ -330,6 +340,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
case EntityType.invoice:
|
||||
return invoiceUIState;
|
||||
// STARTER: states switch - do not remove comment
|
||||
case EntityType.recurringInvoice:
|
||||
return recurringInvoiceUIState;
|
||||
|
||||
case EntityType.webhook:
|
||||
return webhookUIState;
|
||||
|
||||
|
|
@ -393,6 +406,13 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
ListUIState get invoiceListState => uiState.invoiceUIState.listUIState;
|
||||
|
||||
// STARTER: state getters - do not remove comment
|
||||
RecurringInvoiceState get recurringInvoiceState =>
|
||||
userCompanyState.recurringInvoiceState;
|
||||
ListUIState get recurringInvoiceListState =>
|
||||
uiState.recurringInvoiceUIState.listUIState;
|
||||
RecurringInvoiceUIState get recurringInvoiceUIState =>
|
||||
uiState.recurringInvoiceUIState;
|
||||
|
||||
WebhookState get webhookState => userCompanyState.webhookState;
|
||||
|
||||
ListUIState get webhookListState => uiState.webhookUIState.listUIState;
|
||||
|
|
@ -525,6 +545,10 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
case CreditEditScreen.route:
|
||||
return hasCreditChanges(creditUIState.editing, creditState.map);
|
||||
// STARTER: has changes - do not remove comment
|
||||
case RecurringInvoiceEditScreen.route:
|
||||
return hasRecurringInvoiceChanges(
|
||||
recurringInvoiceUIState.editing, recurringInvoiceState.map);
|
||||
|
||||
case WebhookEditScreen.route:
|
||||
return hasWebhookChanges(webhookUIState.editing, webhookState.map);
|
||||
case TokenEditScreen.route:
|
||||
|
|
|
|||
|
|
@ -201,16 +201,15 @@ Middleware<AppState> _createRefreshRequest(AuthRepository repository) {
|
|||
}
|
||||
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final url = formatApiUrl(
|
||||
prefs.getString(kSharedPrefUrl) ?? state.authState.url);
|
||||
final url =
|
||||
formatApiUrl(prefs.getString(kSharedPrefUrl) ?? state.authState.url);
|
||||
final token =
|
||||
TokenEntity.unobscureToken(prefs.getString(kSharedPrefToken)) ??
|
||||
'TOKEN';
|
||||
|
||||
final updatedAt = action.clearData
|
||||
? 0
|
||||
: ((state.userCompanyState.lastUpdated -
|
||||
kMillisecondsToRefreshData) /
|
||||
: ((state.userCompanyState.lastUpdated - kMillisecondsToRefreshData) /
|
||||
1000)
|
||||
.round();
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import 'package:invoiceninja_flutter/redux/payment/payment_reducer.dart';
|
|||
import 'package:invoiceninja_flutter/redux/quote/quote_reducer.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_reducer.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_reducer.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_reducer.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_reducer.dart';
|
||||
|
|
@ -44,6 +46,8 @@ UserCompanyState companyReducer(UserCompanyState state, dynamic action) {
|
|||
..vendorState.replace(vendorsReducer(state.vendorState, action))
|
||||
..taskState.replace(tasksReducer(state.taskState, action))
|
||||
// STARTER: reducer - do not remove comment
|
||||
..recurringInvoiceState
|
||||
.replace(recurringInvoicesReducer(state.recurringInvoiceState, action))
|
||||
..webhookState.replace(webhooksReducer(state.webhookState, action))
|
||||
..tokenState.replace(tokensReducer(state.tokenState, action))
|
||||
..paymentTermState
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import 'package:built_value/built_value.dart';
|
|||
import 'package:built_value/serializer.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart';
|
||||
|
|
@ -44,6 +46,8 @@ abstract class UserCompanyState
|
|||
paymentState: PaymentState(),
|
||||
quoteState: QuoteState(),
|
||||
// STARTER: constructor - do not remove comment
|
||||
recurringInvoiceState: RecurringInvoiceState(),
|
||||
|
||||
webhookState: WebhookState(),
|
||||
tokenState: TokenState(),
|
||||
paymentTermState: PaymentTermState(),
|
||||
|
|
@ -88,6 +92,8 @@ abstract class UserCompanyState
|
|||
QuoteState get quoteState;
|
||||
|
||||
// STARTER: fields - do not remove comment
|
||||
RecurringInvoiceState get recurringInvoiceState;
|
||||
|
||||
WebhookState get webhookState;
|
||||
|
||||
TokenState get tokenState;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ class _$UserCompanyStateSerializer
|
|||
'quoteState',
|
||||
serializers.serialize(object.quoteState,
|
||||
specifiedType: const FullType(QuoteState)),
|
||||
'recurringInvoiceState',
|
||||
serializers.serialize(object.recurringInvoiceState,
|
||||
specifiedType: const FullType(RecurringInvoiceState)),
|
||||
'webhookState',
|
||||
serializers.serialize(object.webhookState,
|
||||
specifiedType: const FullType(WebhookState)),
|
||||
|
|
@ -153,6 +156,11 @@ class _$UserCompanyStateSerializer
|
|||
result.quoteState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(QuoteState)) as QuoteState);
|
||||
break;
|
||||
case 'recurringInvoiceState':
|
||||
result.recurringInvoiceState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(RecurringInvoiceState))
|
||||
as RecurringInvoiceState);
|
||||
break;
|
||||
case 'webhookState':
|
||||
result.webhookState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(WebhookState)) as WebhookState);
|
||||
|
|
@ -359,6 +367,8 @@ class _$UserCompanyState extends UserCompanyState {
|
|||
@override
|
||||
final QuoteState quoteState;
|
||||
@override
|
||||
final RecurringInvoiceState recurringInvoiceState;
|
||||
@override
|
||||
final WebhookState webhookState;
|
||||
@override
|
||||
final TokenState tokenState;
|
||||
|
|
@ -394,6 +404,7 @@ class _$UserCompanyState extends UserCompanyState {
|
|||
this.projectState,
|
||||
this.paymentState,
|
||||
this.quoteState,
|
||||
this.recurringInvoiceState,
|
||||
this.webhookState,
|
||||
this.tokenState,
|
||||
this.paymentTermState,
|
||||
|
|
@ -437,6 +448,10 @@ class _$UserCompanyState extends UserCompanyState {
|
|||
if (quoteState == null) {
|
||||
throw new BuiltValueNullFieldError('UserCompanyState', 'quoteState');
|
||||
}
|
||||
if (recurringInvoiceState == null) {
|
||||
throw new BuiltValueNullFieldError(
|
||||
'UserCompanyState', 'recurringInvoiceState');
|
||||
}
|
||||
if (webhookState == null) {
|
||||
throw new BuiltValueNullFieldError('UserCompanyState', 'webhookState');
|
||||
}
|
||||
|
|
@ -492,6 +507,7 @@ class _$UserCompanyState extends UserCompanyState {
|
|||
projectState == other.projectState &&
|
||||
paymentState == other.paymentState &&
|
||||
quoteState == other.quoteState &&
|
||||
recurringInvoiceState == other.recurringInvoiceState &&
|
||||
webhookState == other.webhookState &&
|
||||
tokenState == other.tokenState &&
|
||||
paymentTermState == other.paymentTermState &&
|
||||
|
|
@ -524,17 +540,17 @@ class _$UserCompanyState extends UserCompanyState {
|
|||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc($jc($jc(0, lastUpdated.hashCode), userCompany.hashCode),
|
||||
documentState.hashCode),
|
||||
productState.hashCode),
|
||||
clientState.hashCode),
|
||||
invoiceState.hashCode),
|
||||
expenseState.hashCode),
|
||||
vendorState.hashCode),
|
||||
taskState.hashCode),
|
||||
projectState.hashCode),
|
||||
paymentState.hashCode),
|
||||
quoteState.hashCode),
|
||||
$jc($jc($jc($jc(0, lastUpdated.hashCode), userCompany.hashCode), documentState.hashCode),
|
||||
productState.hashCode),
|
||||
clientState.hashCode),
|
||||
invoiceState.hashCode),
|
||||
expenseState.hashCode),
|
||||
vendorState.hashCode),
|
||||
taskState.hashCode),
|
||||
projectState.hashCode),
|
||||
paymentState.hashCode),
|
||||
quoteState.hashCode),
|
||||
recurringInvoiceState.hashCode),
|
||||
webhookState.hashCode),
|
||||
tokenState.hashCode),
|
||||
paymentTermState.hashCode),
|
||||
|
|
@ -561,6 +577,7 @@ class _$UserCompanyState extends UserCompanyState {
|
|||
..add('projectState', projectState)
|
||||
..add('paymentState', paymentState)
|
||||
..add('quoteState', quoteState)
|
||||
..add('recurringInvoiceState', recurringInvoiceState)
|
||||
..add('webhookState', webhookState)
|
||||
..add('tokenState', tokenState)
|
||||
..add('paymentTermState', paymentTermState)
|
||||
|
|
@ -647,6 +664,13 @@ class UserCompanyStateBuilder
|
|||
set quoteState(QuoteStateBuilder quoteState) =>
|
||||
_$this._quoteState = quoteState;
|
||||
|
||||
RecurringInvoiceStateBuilder _recurringInvoiceState;
|
||||
RecurringInvoiceStateBuilder get recurringInvoiceState =>
|
||||
_$this._recurringInvoiceState ??= new RecurringInvoiceStateBuilder();
|
||||
set recurringInvoiceState(
|
||||
RecurringInvoiceStateBuilder recurringInvoiceState) =>
|
||||
_$this._recurringInvoiceState = recurringInvoiceState;
|
||||
|
||||
WebhookStateBuilder _webhookState;
|
||||
WebhookStateBuilder get webhookState =>
|
||||
_$this._webhookState ??= new WebhookStateBuilder();
|
||||
|
|
@ -716,6 +740,7 @@ class UserCompanyStateBuilder
|
|||
_projectState = _$v.projectState?.toBuilder();
|
||||
_paymentState = _$v.paymentState?.toBuilder();
|
||||
_quoteState = _$v.quoteState?.toBuilder();
|
||||
_recurringInvoiceState = _$v.recurringInvoiceState?.toBuilder();
|
||||
_webhookState = _$v.webhookState?.toBuilder();
|
||||
_tokenState = _$v.tokenState?.toBuilder();
|
||||
_paymentTermState = _$v.paymentTermState?.toBuilder();
|
||||
|
|
@ -761,6 +786,7 @@ class UserCompanyStateBuilder
|
|||
projectState: projectState.build(),
|
||||
paymentState: paymentState.build(),
|
||||
quoteState: quoteState.build(),
|
||||
recurringInvoiceState: recurringInvoiceState.build(),
|
||||
webhookState: webhookState.build(),
|
||||
tokenState: tokenState.build(),
|
||||
paymentTermState: paymentTermState.build(),
|
||||
|
|
@ -795,6 +821,8 @@ class UserCompanyStateBuilder
|
|||
paymentState.build();
|
||||
_$failedField = 'quoteState';
|
||||
quoteState.build();
|
||||
_$failedField = 'recurringInvoiceState';
|
||||
recurringInvoiceState.build();
|
||||
_$failedField = 'webhookState';
|
||||
webhookState.build();
|
||||
_$failedField = 'tokenState';
|
||||
|
|
|
|||
|
|
@ -151,12 +151,13 @@ List<String> filteredInvoicesSelector(
|
|||
|
||||
list.sort((invoiceAId, invoiceBId) {
|
||||
return invoiceMap[invoiceAId].compareTo(
|
||||
invoice: invoiceMap[invoiceBId],
|
||||
sortField: invoiceListState.sortField,
|
||||
sortAscending: invoiceListState.sortAscending,
|
||||
clientMap: clientMap,
|
||||
staticState: staticState,
|
||||
userMap: userMap);
|
||||
invoice: invoiceMap[invoiceBId],
|
||||
sortField: invoiceListState.sortField,
|
||||
sortAscending: invoiceListState.sortAscending,
|
||||
clientMap: clientMap,
|
||||
staticState: staticState,
|
||||
userMap: userMap,
|
||||
);
|
||||
});
|
||||
|
||||
return list;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,330 @@
|
|||
import 'dart:async';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:flutter/widgets.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/ui/app/entities/entity_actions_dialog.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
class ViewRecurringInvoiceList extends AbstractNavigatorAction
|
||||
implements PersistUI, StopLoading {
|
||||
ViewRecurringInvoiceList({
|
||||
@required NavigatorState navigator,
|
||||
this.force = false,
|
||||
}) : super(navigator: navigator);
|
||||
|
||||
final bool force;
|
||||
}
|
||||
|
||||
class ViewRecurringInvoice extends AbstractNavigatorAction
|
||||
implements PersistUI, PersistPrefs {
|
||||
ViewRecurringInvoice({
|
||||
@required NavigatorState navigator,
|
||||
@required this.recurringInvoiceId,
|
||||
this.force = false,
|
||||
}) : super(navigator: navigator);
|
||||
|
||||
final String recurringInvoiceId;
|
||||
final bool force;
|
||||
}
|
||||
|
||||
class EditRecurringInvoice extends AbstractNavigatorAction
|
||||
implements PersistUI, PersistPrefs {
|
||||
EditRecurringInvoice(
|
||||
{@required this.recurringInvoice,
|
||||
@required NavigatorState navigator,
|
||||
this.completer,
|
||||
this.cancelCompleter,
|
||||
this.force = false})
|
||||
: super(navigator: navigator);
|
||||
|
||||
final InvoiceEntity recurringInvoice;
|
||||
final Completer completer;
|
||||
final Completer cancelCompleter;
|
||||
final bool force;
|
||||
}
|
||||
|
||||
class UpdateRecurringInvoice implements PersistUI {
|
||||
UpdateRecurringInvoice(this.recurringInvoice);
|
||||
|
||||
final InvoiceEntity recurringInvoice;
|
||||
}
|
||||
|
||||
class LoadRecurringInvoice {
|
||||
LoadRecurringInvoice({this.completer, this.recurringInvoiceId});
|
||||
|
||||
final Completer completer;
|
||||
final String recurringInvoiceId;
|
||||
}
|
||||
|
||||
class LoadRecurringInvoiceActivity {
|
||||
LoadRecurringInvoiceActivity({this.completer, this.recurringInvoiceId});
|
||||
|
||||
final Completer completer;
|
||||
final String recurringInvoiceId;
|
||||
}
|
||||
|
||||
class LoadRecurringInvoices {
|
||||
LoadRecurringInvoices({this.completer});
|
||||
|
||||
final Completer completer;
|
||||
}
|
||||
|
||||
class LoadRecurringInvoiceRequest implements StartLoading {}
|
||||
|
||||
class LoadRecurringInvoiceFailure implements StopLoading {
|
||||
LoadRecurringInvoiceFailure(this.error);
|
||||
|
||||
final dynamic error;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadRecurringInvoiceFailure{error: $error}';
|
||||
}
|
||||
}
|
||||
|
||||
class LoadRecurringInvoiceSuccess implements StopLoading, PersistData {
|
||||
LoadRecurringInvoiceSuccess(this.recurringInvoice);
|
||||
|
||||
final InvoiceEntity recurringInvoice;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadRecurringInvoiceSuccess{recurringInvoice: $recurringInvoice}';
|
||||
}
|
||||
}
|
||||
|
||||
class LoadRecurringInvoicesRequest implements StartLoading {}
|
||||
|
||||
class LoadRecurringInvoicesFailure implements StopLoading {
|
||||
LoadRecurringInvoicesFailure(this.error);
|
||||
|
||||
final dynamic error;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadRecurringInvoicesFailure{error: $error}';
|
||||
}
|
||||
}
|
||||
|
||||
class LoadRecurringInvoicesSuccess implements StopLoading {
|
||||
LoadRecurringInvoicesSuccess(this.recurringInvoices);
|
||||
|
||||
final BuiltList<InvoiceEntity> recurringInvoices;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadRecurringInvoicesSuccess{recurringInvoices: $recurringInvoices}';
|
||||
}
|
||||
}
|
||||
|
||||
class SaveRecurringInvoiceRequest implements StartSaving {
|
||||
SaveRecurringInvoiceRequest({this.completer, this.recurringInvoice});
|
||||
|
||||
final Completer completer;
|
||||
final InvoiceEntity recurringInvoice;
|
||||
}
|
||||
|
||||
class SaveRecurringInvoiceSuccess
|
||||
implements StopSaving, PersistData, PersistUI {
|
||||
SaveRecurringInvoiceSuccess(this.recurringInvoice);
|
||||
|
||||
final InvoiceEntity recurringInvoice;
|
||||
}
|
||||
|
||||
class AddRecurringInvoiceSuccess implements StopSaving, PersistData, PersistUI {
|
||||
AddRecurringInvoiceSuccess(this.recurringInvoice);
|
||||
|
||||
final InvoiceEntity recurringInvoice;
|
||||
}
|
||||
|
||||
class SaveRecurringInvoiceFailure implements StopSaving {
|
||||
SaveRecurringInvoiceFailure(this.error);
|
||||
|
||||
final Object error;
|
||||
}
|
||||
|
||||
class ArchiveRecurringInvoicesRequest implements StartSaving {
|
||||
ArchiveRecurringInvoicesRequest(this.completer, this.recurringInvoiceIds);
|
||||
|
||||
final Completer completer;
|
||||
final List<String> recurringInvoiceIds;
|
||||
}
|
||||
|
||||
class ArchiveRecurringInvoicesSuccess implements StopSaving, PersistData {
|
||||
ArchiveRecurringInvoicesSuccess(this.recurringInvoices);
|
||||
|
||||
final List<InvoiceEntity> recurringInvoices;
|
||||
}
|
||||
|
||||
class ArchiveRecurringInvoicesFailure implements StopSaving {
|
||||
ArchiveRecurringInvoicesFailure(this.recurringInvoices);
|
||||
|
||||
final List<InvoiceEntity> recurringInvoices;
|
||||
}
|
||||
|
||||
class DeleteRecurringInvoicesRequest implements StartSaving {
|
||||
DeleteRecurringInvoicesRequest(this.completer, this.recurringInvoiceIds);
|
||||
|
||||
final Completer completer;
|
||||
final List<String> recurringInvoiceIds;
|
||||
}
|
||||
|
||||
class DeleteRecurringInvoicesSuccess implements StopSaving, PersistData {
|
||||
DeleteRecurringInvoicesSuccess(this.recurringInvoices);
|
||||
|
||||
final List<InvoiceEntity> recurringInvoices;
|
||||
}
|
||||
|
||||
class DeleteRecurringInvoicesFailure implements StopSaving {
|
||||
DeleteRecurringInvoicesFailure(this.recurringInvoices);
|
||||
|
||||
final List<InvoiceEntity> recurringInvoices;
|
||||
}
|
||||
|
||||
class RestoreRecurringInvoicesRequest implements StartSaving {
|
||||
RestoreRecurringInvoicesRequest(this.completer, this.recurringInvoiceIds);
|
||||
|
||||
final Completer completer;
|
||||
final List<String> recurringInvoiceIds;
|
||||
}
|
||||
|
||||
class RestoreRecurringInvoicesSuccess implements StopSaving, PersistData {
|
||||
RestoreRecurringInvoicesSuccess(this.recurringInvoices);
|
||||
|
||||
final List<InvoiceEntity> recurringInvoices;
|
||||
}
|
||||
|
||||
class RestoreRecurringInvoicesFailure implements StopSaving {
|
||||
RestoreRecurringInvoicesFailure(this.recurringInvoices);
|
||||
|
||||
final List<InvoiceEntity> recurringInvoices;
|
||||
}
|
||||
|
||||
class FilterRecurringInvoices implements PersistUI {
|
||||
FilterRecurringInvoices(this.filter);
|
||||
|
||||
final String filter;
|
||||
}
|
||||
|
||||
class SortRecurringInvoices implements PersistUI {
|
||||
SortRecurringInvoices(this.field);
|
||||
|
||||
final String field;
|
||||
}
|
||||
|
||||
class FilterRecurringInvoicesByState implements PersistUI {
|
||||
FilterRecurringInvoicesByState(this.state);
|
||||
|
||||
final EntityState state;
|
||||
}
|
||||
|
||||
class FilterRecurringInvoicesByCustom1 implements PersistUI {
|
||||
FilterRecurringInvoicesByCustom1(this.value);
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
class FilterRecurringInvoicesByCustom2 implements PersistUI {
|
||||
FilterRecurringInvoicesByCustom2(this.value);
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
class FilterRecurringInvoicesByCustom3 implements PersistUI {
|
||||
FilterRecurringInvoicesByCustom3(this.value);
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
class FilterRecurringInvoicesByCustom4 implements PersistUI {
|
||||
FilterRecurringInvoicesByCustom4(this.value);
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
void handleRecurringInvoiceAction(BuildContext context,
|
||||
List<BaseEntity> recurringInvoices, EntityAction action) {
|
||||
if (recurringInvoices.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final localization = AppLocalization.of(context);
|
||||
final recurringInvoice = recurringInvoices.first as InvoiceEntity;
|
||||
final recurringInvoiceIds =
|
||||
recurringInvoices.map((recurringInvoice) => recurringInvoice.id).toList();
|
||||
|
||||
switch (action) {
|
||||
case EntityAction.edit:
|
||||
editEntity(context: context, entity: recurringInvoice);
|
||||
break;
|
||||
case EntityAction.restore:
|
||||
store.dispatch(RestoreRecurringInvoicesRequest(
|
||||
snackBarCompleter<Null>(
|
||||
context, localization.restoredRecurringInvoice),
|
||||
recurringInvoiceIds));
|
||||
break;
|
||||
case EntityAction.archive:
|
||||
store.dispatch(ArchiveRecurringInvoicesRequest(
|
||||
snackBarCompleter<Null>(
|
||||
context, localization.archivedRecurringInvoice),
|
||||
recurringInvoiceIds));
|
||||
break;
|
||||
case EntityAction.delete:
|
||||
store.dispatch(DeleteRecurringInvoicesRequest(
|
||||
snackBarCompleter<Null>(
|
||||
context, localization.deletedRecurringInvoice),
|
||||
recurringInvoiceIds));
|
||||
break;
|
||||
case EntityAction.toggleMultiselect:
|
||||
if (!store.state.recurringInvoiceListState.isInMultiselect()) {
|
||||
store.dispatch(StartRecurringInvoiceMultiselect());
|
||||
}
|
||||
|
||||
if (recurringInvoices.isEmpty) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (final recurringInvoice in recurringInvoices) {
|
||||
if (!store.state.recurringInvoiceListState
|
||||
.isSelected(recurringInvoice.id)) {
|
||||
store.dispatch(
|
||||
AddToRecurringInvoiceMultiselect(entity: recurringInvoice));
|
||||
} else {
|
||||
store.dispatch(
|
||||
RemoveFromRecurringInvoiceMultiselect(entity: recurringInvoice));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EntityAction.more:
|
||||
showEntityActionsDialog(
|
||||
entities: [recurringInvoice],
|
||||
context: context,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class StartRecurringInvoiceMultiselect {
|
||||
StartRecurringInvoiceMultiselect();
|
||||
}
|
||||
|
||||
class AddToRecurringInvoiceMultiselect {
|
||||
AddToRecurringInvoiceMultiselect({@required this.entity});
|
||||
|
||||
final BaseEntity entity;
|
||||
}
|
||||
|
||||
class RemoveFromRecurringInvoiceMultiselect {
|
||||
RemoveFromRecurringInvoiceMultiselect({@required this.entity});
|
||||
|
||||
final BaseEntity entity;
|
||||
}
|
||||
|
||||
class ClearRecurringInvoiceMultiselect {
|
||||
ClearRecurringInvoiceMultiselect();
|
||||
}
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_screen.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/edit/recurring_invoice_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/view/recurring_invoice_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/repositories/recurring_invoice_repository.dart';
|
||||
|
||||
List<Middleware<AppState>> createStoreRecurringInvoicesMiddleware([
|
||||
RecurringInvoiceRepository repository = const RecurringInvoiceRepository(),
|
||||
]) {
|
||||
final viewRecurringInvoiceList = _viewRecurringInvoiceList();
|
||||
final viewRecurringInvoice = _viewRecurringInvoice();
|
||||
final editRecurringInvoice = _editRecurringInvoice();
|
||||
final loadRecurringInvoices = _loadRecurringInvoices(repository);
|
||||
final loadRecurringInvoice = _loadRecurringInvoice(repository);
|
||||
final saveRecurringInvoice = _saveRecurringInvoice(repository);
|
||||
final archiveRecurringInvoice = _archiveRecurringInvoice(repository);
|
||||
final deleteRecurringInvoice = _deleteRecurringInvoice(repository);
|
||||
final restoreRecurringInvoice = _restoreRecurringInvoice(repository);
|
||||
|
||||
return [
|
||||
TypedMiddleware<AppState, ViewRecurringInvoiceList>(
|
||||
viewRecurringInvoiceList),
|
||||
TypedMiddleware<AppState, ViewRecurringInvoice>(viewRecurringInvoice),
|
||||
TypedMiddleware<AppState, EditRecurringInvoice>(editRecurringInvoice),
|
||||
TypedMiddleware<AppState, LoadRecurringInvoices>(loadRecurringInvoices),
|
||||
TypedMiddleware<AppState, LoadRecurringInvoice>(loadRecurringInvoice),
|
||||
TypedMiddleware<AppState, SaveRecurringInvoiceRequest>(
|
||||
saveRecurringInvoice),
|
||||
TypedMiddleware<AppState, ArchiveRecurringInvoicesRequest>(
|
||||
archiveRecurringInvoice),
|
||||
TypedMiddleware<AppState, DeleteRecurringInvoicesRequest>(
|
||||
deleteRecurringInvoice),
|
||||
TypedMiddleware<AppState, RestoreRecurringInvoicesRequest>(
|
||||
restoreRecurringInvoice),
|
||||
];
|
||||
}
|
||||
|
||||
Middleware<AppState> _editRecurringInvoice() {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as EditRecurringInvoice;
|
||||
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(RecurringInvoiceEditScreen.route));
|
||||
|
||||
if (isMobile(action.context)) {
|
||||
action.navigator.pushNamed(RecurringInvoiceEditScreen.route);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _viewRecurringInvoice() {
|
||||
return (Store<AppState> store, dynamic dynamicAction,
|
||||
NextDispatcher next) async {
|
||||
final action = dynamicAction as ViewRecurringInvoice;
|
||||
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(RecurringInvoiceViewScreen.route));
|
||||
|
||||
if (isMobile(action.context)) {
|
||||
Navigator.of(action.context).pushNamed(RecurringInvoiceViewScreen.route);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _viewRecurringInvoiceList() {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as ViewRecurringInvoiceList;
|
||||
|
||||
next(action);
|
||||
|
||||
if (store.state.staticState.isStale) {
|
||||
store.dispatch(RefreshData());
|
||||
}
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(RecurringInvoiceScreen.route));
|
||||
|
||||
if (isMobile(action.context)) {
|
||||
Navigator.of(action.context).pushNamedAndRemoveUntil(
|
||||
RecurringInvoiceScreen.route, (Route<dynamic> route) => false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _archiveRecurringInvoice(
|
||||
RecurringInvoiceRepository repository) {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as ArchiveRecurringInvoicesRequest;
|
||||
final prevRecurringInvoices = action.recurringInvoiceIds
|
||||
.map((id) => store.state.recurringInvoiceState.map[id])
|
||||
.toList();
|
||||
repository
|
||||
.bulkAction(store.state.credentials, action.recurringInvoiceIds,
|
||||
EntityAction.archive)
|
||||
.then((List<InvoiceEntity> recurringInvoices) {
|
||||
store.dispatch(ArchiveRecurringInvoicesSuccess(recurringInvoices));
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(ArchiveRecurringInvoicesFailure(prevRecurringInvoices));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _deleteRecurringInvoice(
|
||||
RecurringInvoiceRepository repository) {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as DeleteRecurringInvoicesRequest;
|
||||
final prevRecurringInvoices = action.recurringInvoiceIds
|
||||
.map((id) => store.state.recurringInvoiceState.map[id])
|
||||
.toList();
|
||||
repository
|
||||
.bulkAction(store.state.credentials, action.recurringInvoiceIds,
|
||||
EntityAction.delete)
|
||||
.then((List<InvoiceEntity> recurringInvoices) {
|
||||
store.dispatch(DeleteRecurringInvoicesSuccess(recurringInvoices));
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(DeleteRecurringInvoicesFailure(prevRecurringInvoices));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _restoreRecurringInvoice(
|
||||
RecurringInvoiceRepository repository) {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as RestoreRecurringInvoicesRequest;
|
||||
final prevRecurringInvoices = action.recurringInvoiceIds
|
||||
.map((id) => store.state.recurringInvoiceState.map[id])
|
||||
.toList();
|
||||
repository
|
||||
.bulkAction(store.state.credentials, action.recurringInvoiceIds,
|
||||
EntityAction.restore)
|
||||
.then((List<InvoiceEntity> recurringInvoices) {
|
||||
store.dispatch(RestoreRecurringInvoicesSuccess(recurringInvoices));
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(RestoreRecurringInvoicesFailure(prevRecurringInvoices));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _saveRecurringInvoice(
|
||||
RecurringInvoiceRepository repository) {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as SaveRecurringInvoiceRequest;
|
||||
repository
|
||||
.saveData(store.state.credentials, action.recurringInvoice)
|
||||
.then((InvoiceEntity recurringInvoice) {
|
||||
if (action.recurringInvoice.isNew) {
|
||||
store.dispatch(AddRecurringInvoiceSuccess(recurringInvoice));
|
||||
} else {
|
||||
store.dispatch(SaveRecurringInvoiceSuccess(recurringInvoice));
|
||||
}
|
||||
|
||||
action.completer.complete(recurringInvoice);
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(SaveRecurringInvoiceFailure(error));
|
||||
action.completer.completeError(error);
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _loadRecurringInvoice(
|
||||
RecurringInvoiceRepository repository) {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as LoadRecurringInvoice;
|
||||
final AppState state = store.state;
|
||||
|
||||
store.dispatch(LoadRecurringInvoiceRequest());
|
||||
repository
|
||||
.loadItem(state.credentials, action.recurringInvoiceId)
|
||||
.then((recurringInvoice) {
|
||||
store.dispatch(LoadRecurringInvoiceSuccess(recurringInvoice));
|
||||
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(LoadRecurringInvoiceFailure(error));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _loadRecurringInvoices(
|
||||
RecurringInvoiceRepository repository) {
|
||||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as LoadRecurringInvoices;
|
||||
final AppState state = store.state;
|
||||
|
||||
store.dispatch(LoadRecurringInvoicesRequest());
|
||||
repository.loadList(state.credentials).then((data) {
|
||||
store.dispatch(LoadRecurringInvoicesSuccess(data));
|
||||
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
/*
|
||||
if (state.productState.isStale) {
|
||||
store.dispatch(LoadProducts());
|
||||
}
|
||||
*/
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(LoadRecurringInvoicesFailure(error));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
||||
|
||||
EntityUIState recurringInvoiceUIReducer(
|
||||
RecurringInvoiceUIState state, dynamic action) {
|
||||
return state.rebuild((b) => b
|
||||
..listUIState
|
||||
.replace(recurringInvoiceListReducer(state.listUIState, action))
|
||||
..editing.replace(editingReducer(state.editing, action))
|
||||
..selectedId = selectedIdReducer(state.selectedId, action));
|
||||
}
|
||||
|
||||
Reducer<String> selectedIdReducer = combineReducers([
|
||||
TypedReducer<String, ViewRecurringInvoice>(
|
||||
(String selectedId, dynamic action) => action.recurringInvoiceId),
|
||||
TypedReducer<String, AddRecurringInvoiceSuccess>(
|
||||
(String selectedId, dynamic action) => action.recurringInvoice.id),
|
||||
TypedReducer<String, SelectCompany>(
|
||||
(selectedId, action) => action.clearSelection ? '' : selectedId),
|
||||
TypedReducer<String, DeleteRecurringInvoicesSuccess>(
|
||||
(selectedId, action) => ''),
|
||||
TypedReducer<String, ArchiveRecurringInvoicesSuccess>(
|
||||
(selectedId, action) => ''),
|
||||
TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''),
|
||||
TypedReducer<String, FilterByEntity>((selectedId, action) =>
|
||||
action.clearSelection
|
||||
? ''
|
||||
: action.entityType == EntityType.recurringInvoice
|
||||
? action.entityId
|
||||
: selectedId),
|
||||
]);
|
||||
|
||||
final editingReducer = combineReducers<InvoiceEntity>([
|
||||
TypedReducer<InvoiceEntity, SaveRecurringInvoiceSuccess>(_updateEditing),
|
||||
TypedReducer<InvoiceEntity, AddRecurringInvoiceSuccess>(_updateEditing),
|
||||
TypedReducer<InvoiceEntity, RestoreRecurringInvoicesSuccess>(
|
||||
(recurringInvoices, action) {
|
||||
return action.recurringInvoices[0];
|
||||
}),
|
||||
TypedReducer<InvoiceEntity, ArchiveRecurringInvoicesSuccess>(
|
||||
(recurringInvoices, action) {
|
||||
return action.recurringInvoices[0];
|
||||
}),
|
||||
TypedReducer<InvoiceEntity, DeleteRecurringInvoicesSuccess>(
|
||||
(recurringInvoices, action) {
|
||||
return action.recurringInvoices[0];
|
||||
}),
|
||||
TypedReducer<InvoiceEntity, EditRecurringInvoice>(_updateEditing),
|
||||
TypedReducer<InvoiceEntity, UpdateRecurringInvoice>(
|
||||
(recurringInvoice, action) {
|
||||
return action.recurringInvoice.rebuild((b) => b..isChanged = true);
|
||||
}),
|
||||
TypedReducer<InvoiceEntity, DiscardChanges>(_clearEditing),
|
||||
]);
|
||||
|
||||
InvoiceEntity _clearEditing(InvoiceEntity recurringInvoice, dynamic action) {
|
||||
return InvoiceEntity();
|
||||
}
|
||||
|
||||
InvoiceEntity _updateEditing(InvoiceEntity recurringInvoice, dynamic action) {
|
||||
return action.recurringInvoice;
|
||||
}
|
||||
|
||||
final recurringInvoiceListReducer = combineReducers<ListUIState>([
|
||||
TypedReducer<ListUIState, SortRecurringInvoices>(_sortRecurringInvoices),
|
||||
TypedReducer<ListUIState, FilterRecurringInvoicesByState>(
|
||||
_filterRecurringInvoicesByState),
|
||||
TypedReducer<ListUIState, FilterRecurringInvoices>(_filterRecurringInvoices),
|
||||
TypedReducer<ListUIState, FilterRecurringInvoicesByCustom1>(
|
||||
_filterRecurringInvoicesByCustom1),
|
||||
TypedReducer<ListUIState, FilterRecurringInvoicesByCustom2>(
|
||||
_filterRecurringInvoicesByCustom2),
|
||||
TypedReducer<ListUIState, StartRecurringInvoiceMultiselect>(
|
||||
_startListMultiselect),
|
||||
TypedReducer<ListUIState, AddToRecurringInvoiceMultiselect>(
|
||||
_addToListMultiselect),
|
||||
TypedReducer<ListUIState, RemoveFromRecurringInvoiceMultiselect>(
|
||||
_removeFromListMultiselect),
|
||||
TypedReducer<ListUIState, ClearRecurringInvoiceMultiselect>(
|
||||
_clearListMultiselect),
|
||||
]);
|
||||
|
||||
ListUIState _filterRecurringInvoicesByCustom1(
|
||||
ListUIState recurringInvoiceListState,
|
||||
FilterRecurringInvoicesByCustom1 action) {
|
||||
if (recurringInvoiceListState.custom1Filters.contains(action.value)) {
|
||||
return recurringInvoiceListState
|
||||
.rebuild((b) => b..custom1Filters.remove(action.value));
|
||||
} else {
|
||||
return recurringInvoiceListState
|
||||
.rebuild((b) => b..custom1Filters.add(action.value));
|
||||
}
|
||||
}
|
||||
|
||||
ListUIState _filterRecurringInvoicesByCustom2(
|
||||
ListUIState recurringInvoiceListState,
|
||||
FilterRecurringInvoicesByCustom2 action) {
|
||||
if (recurringInvoiceListState.custom2Filters.contains(action.value)) {
|
||||
return recurringInvoiceListState
|
||||
.rebuild((b) => b..custom2Filters.remove(action.value));
|
||||
} else {
|
||||
return recurringInvoiceListState
|
||||
.rebuild((b) => b..custom2Filters.add(action.value));
|
||||
}
|
||||
}
|
||||
|
||||
ListUIState _filterRecurringInvoicesByState(
|
||||
ListUIState recurringInvoiceListState,
|
||||
FilterRecurringInvoicesByState action) {
|
||||
if (recurringInvoiceListState.stateFilters.contains(action.state)) {
|
||||
return recurringInvoiceListState
|
||||
.rebuild((b) => b..stateFilters.remove(action.state));
|
||||
} else {
|
||||
return recurringInvoiceListState
|
||||
.rebuild((b) => b..stateFilters.add(action.state));
|
||||
}
|
||||
}
|
||||
|
||||
ListUIState _filterRecurringInvoices(
|
||||
ListUIState recurringInvoiceListState, FilterRecurringInvoices action) {
|
||||
return recurringInvoiceListState.rebuild((b) => b
|
||||
..filter = action.filter
|
||||
..filterClearedAt = action.filter == null
|
||||
? DateTime.now().millisecondsSinceEpoch
|
||||
: recurringInvoiceListState.filterClearedAt);
|
||||
}
|
||||
|
||||
ListUIState _sortRecurringInvoices(
|
||||
ListUIState recurringInvoiceListState, SortRecurringInvoices action) {
|
||||
return recurringInvoiceListState.rebuild((b) => b
|
||||
..sortAscending = b.sortField != action.field || !b.sortAscending
|
||||
..sortField = action.field);
|
||||
}
|
||||
|
||||
ListUIState _startListMultiselect(
|
||||
ListUIState productListState, StartRecurringInvoiceMultiselect action) {
|
||||
return productListState.rebuild((b) => b..selectedIds = ListBuilder());
|
||||
}
|
||||
|
||||
ListUIState _addToListMultiselect(
|
||||
ListUIState productListState, AddToRecurringInvoiceMultiselect action) {
|
||||
return productListState.rebuild((b) => b..selectedIds.add(action.entity.id));
|
||||
}
|
||||
|
||||
ListUIState _removeFromListMultiselect(ListUIState productListState,
|
||||
RemoveFromRecurringInvoiceMultiselect action) {
|
||||
return productListState
|
||||
.rebuild((b) => b..selectedIds.remove(action.entity.id));
|
||||
}
|
||||
|
||||
ListUIState _clearListMultiselect(
|
||||
ListUIState productListState, ClearRecurringInvoiceMultiselect action) {
|
||||
return productListState.rebuild((b) => b..selectedIds = null);
|
||||
}
|
||||
|
||||
final recurringInvoicesReducer = combineReducers<RecurringInvoiceState>([
|
||||
TypedReducer<RecurringInvoiceState, SaveRecurringInvoiceSuccess>(
|
||||
_updateRecurringInvoice),
|
||||
TypedReducer<RecurringInvoiceState, AddRecurringInvoiceSuccess>(
|
||||
_addRecurringInvoice),
|
||||
TypedReducer<RecurringInvoiceState, LoadRecurringInvoicesSuccess>(
|
||||
_setLoadedRecurringInvoices),
|
||||
TypedReducer<RecurringInvoiceState, LoadRecurringInvoiceSuccess>(
|
||||
_setLoadedRecurringInvoice),
|
||||
TypedReducer<RecurringInvoiceState, LoadCompanySuccess>(_setLoadedCompany),
|
||||
TypedReducer<RecurringInvoiceState, ArchiveRecurringInvoicesSuccess>(
|
||||
_archiveRecurringInvoiceSuccess),
|
||||
TypedReducer<RecurringInvoiceState, DeleteRecurringInvoicesSuccess>(
|
||||
_deleteRecurringInvoiceSuccess),
|
||||
TypedReducer<RecurringInvoiceState, RestoreRecurringInvoicesSuccess>(
|
||||
_restoreRecurringInvoiceSuccess),
|
||||
]);
|
||||
|
||||
RecurringInvoiceState _archiveRecurringInvoiceSuccess(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
ArchiveRecurringInvoicesSuccess action) {
|
||||
return recurringInvoiceState.rebuild((b) {
|
||||
for (final recurringInvoice in action.recurringInvoices) {
|
||||
b.map[recurringInvoice.id] = recurringInvoice;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RecurringInvoiceState _deleteRecurringInvoiceSuccess(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
DeleteRecurringInvoicesSuccess action) {
|
||||
return recurringInvoiceState.rebuild((b) {
|
||||
for (final recurringInvoice in action.recurringInvoices) {
|
||||
b.map[recurringInvoice.id] = recurringInvoice;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RecurringInvoiceState _restoreRecurringInvoiceSuccess(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
RestoreRecurringInvoicesSuccess action) {
|
||||
return recurringInvoiceState.rebuild((b) {
|
||||
for (final recurringInvoice in action.recurringInvoices) {
|
||||
b.map[recurringInvoice.id] = recurringInvoice;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RecurringInvoiceState _addRecurringInvoice(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
AddRecurringInvoiceSuccess action) {
|
||||
return recurringInvoiceState.rebuild((b) => b
|
||||
..map[action.recurringInvoice.id] = action.recurringInvoice
|
||||
..list.add(action.recurringInvoice.id));
|
||||
}
|
||||
|
||||
RecurringInvoiceState _updateRecurringInvoice(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
SaveRecurringInvoiceSuccess action) {
|
||||
return recurringInvoiceState.rebuild(
|
||||
(b) => b..map[action.recurringInvoice.id] = action.recurringInvoice);
|
||||
}
|
||||
|
||||
RecurringInvoiceState _setLoadedRecurringInvoice(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
LoadRecurringInvoiceSuccess action) {
|
||||
return recurringInvoiceState.rebuild(
|
||||
(b) => b..map[action.recurringInvoice.id] = action.recurringInvoice);
|
||||
}
|
||||
|
||||
RecurringInvoiceState _setLoadedRecurringInvoices(
|
||||
RecurringInvoiceState recurringInvoiceState,
|
||||
LoadRecurringInvoicesSuccess action) =>
|
||||
recurringInvoiceState.loadRecurringInvoices(action.recurringInvoices);
|
||||
|
||||
RecurringInvoiceState _setLoadedCompany(
|
||||
RecurringInvoiceState recurringInvoiceState, LoadCompanySuccess action) {
|
||||
final company = action.userCompany.company;
|
||||
return recurringInvoiceState.loadRecurringInvoices(company.recurringInvoices);
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/static/static_state.dart';
|
||||
import 'package:memoize/memoize.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
|
||||
var memoizedFilteredRecurringInvoiceList = memo8((
|
||||
String filterEntityId,
|
||||
EntityType filterEntityType,
|
||||
BuiltMap<String, InvoiceEntity> recurringInvoiceMap,
|
||||
BuiltMap<String, ClientEntity> clientMap,
|
||||
BuiltList<String> recurringInvoiceList,
|
||||
ListUIState recurringInvoiceListState,
|
||||
StaticState staticState,
|
||||
BuiltMap<String, UserEntity> userMap,
|
||||
) =>
|
||||
filteredRecurringInvoicesSelector(
|
||||
filterEntityId,
|
||||
filterEntityType,
|
||||
recurringInvoiceMap,
|
||||
clientMap,
|
||||
recurringInvoiceList,
|
||||
recurringInvoiceListState,
|
||||
staticState,
|
||||
userMap,
|
||||
));
|
||||
|
||||
List<String> filteredRecurringInvoicesSelector(
|
||||
String filterEntityId,
|
||||
EntityType filterEntityType,
|
||||
BuiltMap<String, InvoiceEntity> recurringInvoiceMap,
|
||||
BuiltMap<String, ClientEntity> clientMap,
|
||||
BuiltList<String> recurringInvoiceList,
|
||||
ListUIState recurringInvoiceListState,
|
||||
StaticState staticState,
|
||||
BuiltMap<String, UserEntity> userMap,
|
||||
) {
|
||||
final list = recurringInvoiceList.where((recurringInvoiceId) {
|
||||
final recurringInvoice = recurringInvoiceMap[recurringInvoiceId];
|
||||
if (filterEntityId != null && recurringInvoice.id != filterEntityId) {
|
||||
return false;
|
||||
} else {}
|
||||
|
||||
if (!recurringInvoice
|
||||
.matchesStates(recurringInvoiceListState.stateFilters)) {
|
||||
return false;
|
||||
}
|
||||
if (recurringInvoiceListState.custom1Filters.isNotEmpty &&
|
||||
!recurringInvoiceListState.custom1Filters
|
||||
.contains(recurringInvoice.customValue1)) {
|
||||
return false;
|
||||
}
|
||||
if (recurringInvoiceListState.custom2Filters.isNotEmpty &&
|
||||
!recurringInvoiceListState.custom2Filters
|
||||
.contains(recurringInvoice.customValue2)) {
|
||||
return false;
|
||||
}
|
||||
return recurringInvoice.matchesFilter(recurringInvoiceListState.filter);
|
||||
}).toList();
|
||||
|
||||
list.sort((recurringInvoiceAId, recurringInvoiceBId) {
|
||||
final recurringInvoiceA = recurringInvoiceMap[recurringInvoiceAId];
|
||||
final recurringInvoiceB = recurringInvoiceMap[recurringInvoiceBId];
|
||||
|
||||
return recurringInvoiceA.compareTo(
|
||||
invoice: recurringInvoiceB,
|
||||
sortField: recurringInvoiceListState.sortField,
|
||||
sortAscending: recurringInvoiceListState.sortAscending,
|
||||
clientMap: clientMap,
|
||||
staticState: staticState,
|
||||
userMap: userMap,
|
||||
);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
bool hasRecurringInvoiceChanges(InvoiceEntity recurringInvoice,
|
||||
BuiltMap<String, InvoiceEntity> recurringInvoiceMap) =>
|
||||
recurringInvoice.isNew
|
||||
? recurringInvoice.isChanged
|
||||
: recurringInvoice != recurringInvoiceMap[recurringInvoice.id];
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import 'dart:async';
|
||||
import 'package:built_value/built_value.dart';
|
||||
import 'package:built_value/serializer.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
|
||||
part 'recurring_invoice_state.g.dart';
|
||||
|
||||
abstract class RecurringInvoiceState
|
||||
implements Built<RecurringInvoiceState, RecurringInvoiceStateBuilder> {
|
||||
factory RecurringInvoiceState() {
|
||||
return _$RecurringInvoiceState._(
|
||||
map: BuiltMap<String, InvoiceEntity>(),
|
||||
list: BuiltList<String>(),
|
||||
);
|
||||
}
|
||||
|
||||
RecurringInvoiceState._();
|
||||
|
||||
@override
|
||||
@memoized
|
||||
int get hashCode;
|
||||
|
||||
BuiltMap<String, InvoiceEntity> get map;
|
||||
|
||||
BuiltList<String> get list;
|
||||
|
||||
RecurringInvoiceState loadRecurringInvoices(
|
||||
BuiltList<InvoiceEntity> clients) {
|
||||
final map = Map<String, InvoiceEntity>.fromIterable(
|
||||
clients,
|
||||
key: (dynamic item) => item.id,
|
||||
value: (dynamic item) => item,
|
||||
);
|
||||
|
||||
return rebuild((b) => b
|
||||
..map.addAll(map)
|
||||
..list.replace((map.keys.toList() + list.toList()).toSet().toList()));
|
||||
}
|
||||
|
||||
static Serializer<RecurringInvoiceState> get serializer =>
|
||||
_$recurringInvoiceStateSerializer;
|
||||
}
|
||||
|
||||
abstract class RecurringInvoiceUIState extends Object
|
||||
with EntityUIState
|
||||
implements Built<RecurringInvoiceUIState, RecurringInvoiceUIStateBuilder> {
|
||||
factory RecurringInvoiceUIState() {
|
||||
return _$RecurringInvoiceUIState._(
|
||||
listUIState: ListUIState(InvoiceFields.invoiceNumber),
|
||||
editing: InvoiceEntity(),
|
||||
selectedId: '',
|
||||
);
|
||||
}
|
||||
|
||||
RecurringInvoiceUIState._();
|
||||
|
||||
@override
|
||||
@memoized
|
||||
int get hashCode;
|
||||
|
||||
@nullable
|
||||
InvoiceEntity get editing;
|
||||
|
||||
@override
|
||||
bool get isCreatingNew => editing.isNew;
|
||||
|
||||
@override
|
||||
String get editingId => editing.id;
|
||||
|
||||
static Serializer<RecurringInvoiceUIState> get serializer =>
|
||||
_$recurringInvoiceUIStateSerializer;
|
||||
}
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'recurring_invoice_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// BuiltValueGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Serializer<RecurringInvoiceState> _$recurringInvoiceStateSerializer =
|
||||
new _$RecurringInvoiceStateSerializer();
|
||||
Serializer<RecurringInvoiceUIState> _$recurringInvoiceUIStateSerializer =
|
||||
new _$RecurringInvoiceUIStateSerializer();
|
||||
|
||||
class _$RecurringInvoiceStateSerializer
|
||||
implements StructuredSerializer<RecurringInvoiceState> {
|
||||
@override
|
||||
final Iterable<Type> types = const [
|
||||
RecurringInvoiceState,
|
||||
_$RecurringInvoiceState
|
||||
];
|
||||
@override
|
||||
final String wireName = 'RecurringInvoiceState';
|
||||
|
||||
@override
|
||||
Iterable<Object> serialize(
|
||||
Serializers serializers, RecurringInvoiceState object,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = <Object>[
|
||||
'map',
|
||||
serializers.serialize(object.map,
|
||||
specifiedType: const FullType(BuiltMap,
|
||||
const [const FullType(String), const FullType(InvoiceEntity)])),
|
||||
'list',
|
||||
serializers.serialize(object.list,
|
||||
specifiedType:
|
||||
const FullType(BuiltList, const [const FullType(String)])),
|
||||
];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
RecurringInvoiceState deserialize(
|
||||
Serializers serializers, Iterable<Object> serialized,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = new RecurringInvoiceStateBuilder();
|
||||
|
||||
final iterator = serialized.iterator;
|
||||
while (iterator.moveNext()) {
|
||||
final key = iterator.current as String;
|
||||
iterator.moveNext();
|
||||
final dynamic value = iterator.current;
|
||||
switch (key) {
|
||||
case 'map':
|
||||
result.map.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(BuiltMap, const [
|
||||
const FullType(String),
|
||||
const FullType(InvoiceEntity)
|
||||
])));
|
||||
break;
|
||||
case 'list':
|
||||
result.list.replace(serializers.deserialize(value,
|
||||
specifiedType:
|
||||
const FullType(BuiltList, const [const FullType(String)]))
|
||||
as BuiltList<Object>);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.build();
|
||||
}
|
||||
}
|
||||
|
||||
class _$RecurringInvoiceUIStateSerializer
|
||||
implements StructuredSerializer<RecurringInvoiceUIState> {
|
||||
@override
|
||||
final Iterable<Type> types = const [
|
||||
RecurringInvoiceUIState,
|
||||
_$RecurringInvoiceUIState
|
||||
];
|
||||
@override
|
||||
final String wireName = 'RecurringInvoiceUIState';
|
||||
|
||||
@override
|
||||
Iterable<Object> serialize(
|
||||
Serializers serializers, RecurringInvoiceUIState object,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = <Object>[
|
||||
'listUIState',
|
||||
serializers.serialize(object.listUIState,
|
||||
specifiedType: const FullType(ListUIState)),
|
||||
];
|
||||
if (object.editing != null) {
|
||||
result
|
||||
..add('editing')
|
||||
..add(serializers.serialize(object.editing,
|
||||
specifiedType: const FullType(InvoiceEntity)));
|
||||
}
|
||||
if (object.selectedId != null) {
|
||||
result
|
||||
..add('selectedId')
|
||||
..add(serializers.serialize(object.selectedId,
|
||||
specifiedType: const FullType(String)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
RecurringInvoiceUIState deserialize(
|
||||
Serializers serializers, Iterable<Object> serialized,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = new RecurringInvoiceUIStateBuilder();
|
||||
|
||||
final iterator = serialized.iterator;
|
||||
while (iterator.moveNext()) {
|
||||
final key = iterator.current as String;
|
||||
iterator.moveNext();
|
||||
final dynamic value = iterator.current;
|
||||
switch (key) {
|
||||
case 'editing':
|
||||
result.editing.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(InvoiceEntity)) as InvoiceEntity);
|
||||
break;
|
||||
case 'listUIState':
|
||||
result.listUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(ListUIState)) as ListUIState);
|
||||
break;
|
||||
case 'selectedId':
|
||||
result.selectedId = serializers.deserialize(value,
|
||||
specifiedType: const FullType(String)) as String;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.build();
|
||||
}
|
||||
}
|
||||
|
||||
class _$RecurringInvoiceState extends RecurringInvoiceState {
|
||||
@override
|
||||
final BuiltMap<String, InvoiceEntity> map;
|
||||
@override
|
||||
final BuiltList<String> list;
|
||||
|
||||
factory _$RecurringInvoiceState(
|
||||
[void Function(RecurringInvoiceStateBuilder) updates]) =>
|
||||
(new RecurringInvoiceStateBuilder()..update(updates)).build();
|
||||
|
||||
_$RecurringInvoiceState._({this.map, this.list}) : super._() {
|
||||
if (map == null) {
|
||||
throw new BuiltValueNullFieldError('RecurringInvoiceState', 'map');
|
||||
}
|
||||
if (list == null) {
|
||||
throw new BuiltValueNullFieldError('RecurringInvoiceState', 'list');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
RecurringInvoiceState rebuild(
|
||||
void Function(RecurringInvoiceStateBuilder) updates) =>
|
||||
(toBuilder()..update(updates)).build();
|
||||
|
||||
@override
|
||||
RecurringInvoiceStateBuilder toBuilder() =>
|
||||
new RecurringInvoiceStateBuilder()..replace(this);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(other, this)) return true;
|
||||
return other is RecurringInvoiceState &&
|
||||
map == other.map &&
|
||||
list == other.list;
|
||||
}
|
||||
|
||||
int __hashCode;
|
||||
@override
|
||||
int get hashCode {
|
||||
return __hashCode ??= $jf($jc($jc(0, map.hashCode), list.hashCode));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (newBuiltValueToStringHelper('RecurringInvoiceState')
|
||||
..add('map', map)
|
||||
..add('list', list))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringInvoiceStateBuilder
|
||||
implements Builder<RecurringInvoiceState, RecurringInvoiceStateBuilder> {
|
||||
_$RecurringInvoiceState _$v;
|
||||
|
||||
MapBuilder<String, InvoiceEntity> _map;
|
||||
MapBuilder<String, InvoiceEntity> get map =>
|
||||
_$this._map ??= new MapBuilder<String, InvoiceEntity>();
|
||||
set map(MapBuilder<String, InvoiceEntity> map) => _$this._map = map;
|
||||
|
||||
ListBuilder<String> _list;
|
||||
ListBuilder<String> get list => _$this._list ??= new ListBuilder<String>();
|
||||
set list(ListBuilder<String> list) => _$this._list = list;
|
||||
|
||||
RecurringInvoiceStateBuilder();
|
||||
|
||||
RecurringInvoiceStateBuilder get _$this {
|
||||
if (_$v != null) {
|
||||
_map = _$v.map?.toBuilder();
|
||||
_list = _$v.list?.toBuilder();
|
||||
_$v = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@override
|
||||
void replace(RecurringInvoiceState other) {
|
||||
if (other == null) {
|
||||
throw new ArgumentError.notNull('other');
|
||||
}
|
||||
_$v = other as _$RecurringInvoiceState;
|
||||
}
|
||||
|
||||
@override
|
||||
void update(void Function(RecurringInvoiceStateBuilder) updates) {
|
||||
if (updates != null) updates(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_$RecurringInvoiceState build() {
|
||||
_$RecurringInvoiceState _$result;
|
||||
try {
|
||||
_$result = _$v ??
|
||||
new _$RecurringInvoiceState._(map: map.build(), list: list.build());
|
||||
} catch (_) {
|
||||
String _$failedField;
|
||||
try {
|
||||
_$failedField = 'map';
|
||||
map.build();
|
||||
_$failedField = 'list';
|
||||
list.build();
|
||||
} catch (e) {
|
||||
throw new BuiltValueNestedFieldError(
|
||||
'RecurringInvoiceState', _$failedField, e.toString());
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
replace(_$result);
|
||||
return _$result;
|
||||
}
|
||||
}
|
||||
|
||||
class _$RecurringInvoiceUIState extends RecurringInvoiceUIState {
|
||||
@override
|
||||
final InvoiceEntity editing;
|
||||
@override
|
||||
final ListUIState listUIState;
|
||||
@override
|
||||
final String selectedId;
|
||||
@override
|
||||
final Completer<SelectableEntity> saveCompleter;
|
||||
@override
|
||||
final Completer<Null> cancelCompleter;
|
||||
|
||||
factory _$RecurringInvoiceUIState(
|
||||
[void Function(RecurringInvoiceUIStateBuilder) updates]) =>
|
||||
(new RecurringInvoiceUIStateBuilder()..update(updates)).build();
|
||||
|
||||
_$RecurringInvoiceUIState._(
|
||||
{this.editing,
|
||||
this.listUIState,
|
||||
this.selectedId,
|
||||
this.saveCompleter,
|
||||
this.cancelCompleter})
|
||||
: super._() {
|
||||
if (listUIState == null) {
|
||||
throw new BuiltValueNullFieldError(
|
||||
'RecurringInvoiceUIState', 'listUIState');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
RecurringInvoiceUIState rebuild(
|
||||
void Function(RecurringInvoiceUIStateBuilder) updates) =>
|
||||
(toBuilder()..update(updates)).build();
|
||||
|
||||
@override
|
||||
RecurringInvoiceUIStateBuilder toBuilder() =>
|
||||
new RecurringInvoiceUIStateBuilder()..replace(this);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(other, this)) return true;
|
||||
return other is RecurringInvoiceUIState &&
|
||||
editing == other.editing &&
|
||||
listUIState == other.listUIState &&
|
||||
selectedId == other.selectedId &&
|
||||
saveCompleter == other.saveCompleter &&
|
||||
cancelCompleter == other.cancelCompleter;
|
||||
}
|
||||
|
||||
int __hashCode;
|
||||
@override
|
||||
int get hashCode {
|
||||
return __hashCode ??= $jf($jc(
|
||||
$jc(
|
||||
$jc($jc($jc(0, editing.hashCode), listUIState.hashCode),
|
||||
selectedId.hashCode),
|
||||
saveCompleter.hashCode),
|
||||
cancelCompleter.hashCode));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (newBuiltValueToStringHelper('RecurringInvoiceUIState')
|
||||
..add('editing', editing)
|
||||
..add('listUIState', listUIState)
|
||||
..add('selectedId', selectedId)
|
||||
..add('saveCompleter', saveCompleter)
|
||||
..add('cancelCompleter', cancelCompleter))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringInvoiceUIStateBuilder
|
||||
implements
|
||||
Builder<RecurringInvoiceUIState, RecurringInvoiceUIStateBuilder> {
|
||||
_$RecurringInvoiceUIState _$v;
|
||||
|
||||
InvoiceEntityBuilder _editing;
|
||||
InvoiceEntityBuilder get editing =>
|
||||
_$this._editing ??= new InvoiceEntityBuilder();
|
||||
set editing(InvoiceEntityBuilder editing) => _$this._editing = editing;
|
||||
|
||||
ListUIStateBuilder _listUIState;
|
||||
ListUIStateBuilder get listUIState =>
|
||||
_$this._listUIState ??= new ListUIStateBuilder();
|
||||
set listUIState(ListUIStateBuilder listUIState) =>
|
||||
_$this._listUIState = listUIState;
|
||||
|
||||
String _selectedId;
|
||||
String get selectedId => _$this._selectedId;
|
||||
set selectedId(String selectedId) => _$this._selectedId = selectedId;
|
||||
|
||||
Completer<SelectableEntity> _saveCompleter;
|
||||
Completer<SelectableEntity> get saveCompleter => _$this._saveCompleter;
|
||||
set saveCompleter(Completer<SelectableEntity> saveCompleter) =>
|
||||
_$this._saveCompleter = saveCompleter;
|
||||
|
||||
Completer<Null> _cancelCompleter;
|
||||
Completer<Null> get cancelCompleter => _$this._cancelCompleter;
|
||||
set cancelCompleter(Completer<Null> cancelCompleter) =>
|
||||
_$this._cancelCompleter = cancelCompleter;
|
||||
|
||||
RecurringInvoiceUIStateBuilder();
|
||||
|
||||
RecurringInvoiceUIStateBuilder get _$this {
|
||||
if (_$v != null) {
|
||||
_editing = _$v.editing?.toBuilder();
|
||||
_listUIState = _$v.listUIState?.toBuilder();
|
||||
_selectedId = _$v.selectedId;
|
||||
_saveCompleter = _$v.saveCompleter;
|
||||
_cancelCompleter = _$v.cancelCompleter;
|
||||
_$v = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@override
|
||||
void replace(RecurringInvoiceUIState other) {
|
||||
if (other == null) {
|
||||
throw new ArgumentError.notNull('other');
|
||||
}
|
||||
_$v = other as _$RecurringInvoiceUIState;
|
||||
}
|
||||
|
||||
@override
|
||||
void update(void Function(RecurringInvoiceUIStateBuilder) updates) {
|
||||
if (updates != null) updates(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_$RecurringInvoiceUIState build() {
|
||||
_$RecurringInvoiceUIState _$result;
|
||||
try {
|
||||
_$result = _$v ??
|
||||
new _$RecurringInvoiceUIState._(
|
||||
editing: _editing?.build(),
|
||||
listUIState: listUIState.build(),
|
||||
selectedId: selectedId,
|
||||
saveCompleter: saveCompleter,
|
||||
cancelCompleter: cancelCompleter);
|
||||
} catch (_) {
|
||||
String _$failedField;
|
||||
try {
|
||||
_$failedField = 'editing';
|
||||
_editing?.build();
|
||||
_$failedField = 'listUIState';
|
||||
listUIState.build();
|
||||
} catch (e) {
|
||||
throw new BuiltValueNestedFieldError(
|
||||
'RecurringInvoiceUIState', _$failedField, e.toString());
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
replace(_$result);
|
||||
return _$result;
|
||||
}
|
||||
}
|
||||
|
||||
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new
|
||||
|
|
@ -23,6 +23,8 @@ import 'package:invoiceninja_flutter/redux/user/user_actions.dart';
|
|||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
|
||||
|
|
@ -322,6 +324,19 @@ Reducer<BuiltList<HistoryRecord>> historyReducer = combineReducers([
|
|||
_addToHistory(historyList,
|
||||
HistoryRecord(id: action.group.id, entityType: EntityType.group))),
|
||||
// STARTER: history - do not remove comment
|
||||
TypedReducer<BuiltList<HistoryRecord>, ViewRecurringInvoice>(
|
||||
(historyList, action) => _addToHistory(
|
||||
historyList,
|
||||
HistoryRecord(
|
||||
id: action.recurringInvoiceId,
|
||||
entityType: EntityType.recurringInvoice))),
|
||||
TypedReducer<BuiltList<HistoryRecord>, EditRecurringInvoice>(
|
||||
(historyList, action) => _addToHistory(
|
||||
historyList,
|
||||
HistoryRecord(
|
||||
id: action.recurringInvoice.id,
|
||||
entityType: EntityType.recurringInvoice))),
|
||||
|
||||
TypedReducer<BuiltList<HistoryRecord>, ViewWebhook>((historyList, action) =>
|
||||
_addToHistory(historyList,
|
||||
HistoryRecord(id: action.webhookId, entityType: EntityType.webhook))),
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import 'package:invoiceninja_flutter/redux/task/task_reducer.dart';
|
|||
import 'package:invoiceninja_flutter/redux/vendor/vendor_reducer.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_reducer.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_reducer.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_reducer.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_reducer.dart';
|
||||
|
|
@ -78,6 +80,8 @@ UIState uiReducer(UIState state, dynamic action) {
|
|||
.replace(dashboardUIReducer(state.dashboardUIState, action))
|
||||
..reportsUIState.replace(reportsUIReducer(state.reportsUIState, action))
|
||||
// STARTER: reducer - do not remove comment
|
||||
..recurringInvoiceUIState.replace(
|
||||
recurringInvoiceUIReducer(state.recurringInvoiceUIState, action))
|
||||
..webhookUIState.replace(webhookUIReducer(state.webhookUIState, action))
|
||||
..tokenUIState.replace(tokenUIReducer(state.tokenUIState, action))
|
||||
..paymentTermUIState
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ import 'package:invoiceninja_flutter/redux/quote/quote_state.dart';
|
|||
import 'package:invoiceninja_flutter/redux/task/task_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/token/token_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart';
|
||||
|
|
@ -40,6 +42,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
|
|||
clientUIState: ClientUIState(),
|
||||
invoiceUIState: InvoiceUIState(),
|
||||
// STARTER: constructor - do not remove comment
|
||||
recurringInvoiceUIState: RecurringInvoiceUIState(),
|
||||
|
||||
webhookUIState: WebhookUIState(),
|
||||
tokenUIState: TokenUIState(),
|
||||
paymentTermUIState: PaymentTermUIState(),
|
||||
|
|
@ -93,6 +97,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
|
|||
InvoiceUIState get invoiceUIState;
|
||||
|
||||
// STARTER: properties - do not remove comment
|
||||
RecurringInvoiceUIState get recurringInvoiceUIState;
|
||||
|
||||
WebhookUIState get webhookUIState;
|
||||
|
||||
TokenUIState get tokenUIState;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
|
|||
'invoiceUIState',
|
||||
serializers.serialize(object.invoiceUIState,
|
||||
specifiedType: const FullType(InvoiceUIState)),
|
||||
'recurringInvoiceUIState',
|
||||
serializers.serialize(object.recurringInvoiceUIState,
|
||||
specifiedType: const FullType(RecurringInvoiceUIState)),
|
||||
'webhookUIState',
|
||||
serializers.serialize(object.webhookUIState,
|
||||
specifiedType: const FullType(WebhookUIState)),
|
||||
|
|
@ -174,6 +177,11 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
|
|||
result.invoiceUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(InvoiceUIState)) as InvoiceUIState);
|
||||
break;
|
||||
case 'recurringInvoiceUIState':
|
||||
result.recurringInvoiceUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(RecurringInvoiceUIState))
|
||||
as RecurringInvoiceUIState);
|
||||
break;
|
||||
case 'webhookUIState':
|
||||
result.webhookUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(WebhookUIState)) as WebhookUIState);
|
||||
|
|
@ -281,6 +289,8 @@ class _$UIState extends UIState {
|
|||
@override
|
||||
final InvoiceUIState invoiceUIState;
|
||||
@override
|
||||
final RecurringInvoiceUIState recurringInvoiceUIState;
|
||||
@override
|
||||
final WebhookUIState webhookUIState;
|
||||
@override
|
||||
final TokenUIState tokenUIState;
|
||||
|
|
@ -332,6 +342,7 @@ class _$UIState extends UIState {
|
|||
this.productUIState,
|
||||
this.clientUIState,
|
||||
this.invoiceUIState,
|
||||
this.recurringInvoiceUIState,
|
||||
this.webhookUIState,
|
||||
this.tokenUIState,
|
||||
this.paymentTermUIState,
|
||||
|
|
@ -375,6 +386,9 @@ class _$UIState extends UIState {
|
|||
if (invoiceUIState == null) {
|
||||
throw new BuiltValueNullFieldError('UIState', 'invoiceUIState');
|
||||
}
|
||||
if (recurringInvoiceUIState == null) {
|
||||
throw new BuiltValueNullFieldError('UIState', 'recurringInvoiceUIState');
|
||||
}
|
||||
if (webhookUIState == null) {
|
||||
throw new BuiltValueNullFieldError('UIState', 'webhookUIState');
|
||||
}
|
||||
|
|
@ -453,6 +467,7 @@ class _$UIState extends UIState {
|
|||
productUIState == other.productUIState &&
|
||||
clientUIState == other.clientUIState &&
|
||||
invoiceUIState == other.invoiceUIState &&
|
||||
recurringInvoiceUIState == other.recurringInvoiceUIState &&
|
||||
webhookUIState == other.webhookUIState &&
|
||||
tokenUIState == other.tokenUIState &&
|
||||
paymentTermUIState == other.paymentTermUIState &&
|
||||
|
|
@ -494,8 +509,8 @@ class _$UIState extends UIState {
|
|||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, selectedCompanyIndex.hashCode), currentRoute.hashCode), previousRoute.hashCode), filterEntityId.hashCode), filterEntityType.hashCode), filter.hashCode), filterClearedAt.hashCode), dashboardUIState.hashCode), productUIState.hashCode), clientUIState.hashCode),
|
||||
invoiceUIState.hashCode),
|
||||
$jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, selectedCompanyIndex.hashCode), currentRoute.hashCode), previousRoute.hashCode), filterEntityId.hashCode), filterEntityType.hashCode), filter.hashCode), filterClearedAt.hashCode), dashboardUIState.hashCode), productUIState.hashCode), clientUIState.hashCode), invoiceUIState.hashCode),
|
||||
recurringInvoiceUIState.hashCode),
|
||||
webhookUIState.hashCode),
|
||||
tokenUIState.hashCode),
|
||||
paymentTermUIState.hashCode),
|
||||
|
|
@ -530,6 +545,7 @@ class _$UIState extends UIState {
|
|||
..add('productUIState', productUIState)
|
||||
..add('clientUIState', clientUIState)
|
||||
..add('invoiceUIState', invoiceUIState)
|
||||
..add('recurringInvoiceUIState', recurringInvoiceUIState)
|
||||
..add('webhookUIState', webhookUIState)
|
||||
..add('tokenUIState', tokenUIState)
|
||||
..add('paymentTermUIState', paymentTermUIState)
|
||||
|
|
@ -612,6 +628,13 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
set invoiceUIState(InvoiceUIStateBuilder invoiceUIState) =>
|
||||
_$this._invoiceUIState = invoiceUIState;
|
||||
|
||||
RecurringInvoiceUIStateBuilder _recurringInvoiceUIState;
|
||||
RecurringInvoiceUIStateBuilder get recurringInvoiceUIState =>
|
||||
_$this._recurringInvoiceUIState ??= new RecurringInvoiceUIStateBuilder();
|
||||
set recurringInvoiceUIState(
|
||||
RecurringInvoiceUIStateBuilder recurringInvoiceUIState) =>
|
||||
_$this._recurringInvoiceUIState = recurringInvoiceUIState;
|
||||
|
||||
WebhookUIStateBuilder _webhookUIState;
|
||||
WebhookUIStateBuilder get webhookUIState =>
|
||||
_$this._webhookUIState ??= new WebhookUIStateBuilder();
|
||||
|
|
@ -736,6 +759,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
_productUIState = _$v.productUIState?.toBuilder();
|
||||
_clientUIState = _$v.clientUIState?.toBuilder();
|
||||
_invoiceUIState = _$v.invoiceUIState?.toBuilder();
|
||||
_recurringInvoiceUIState = _$v.recurringInvoiceUIState?.toBuilder();
|
||||
_webhookUIState = _$v.webhookUIState?.toBuilder();
|
||||
_tokenUIState = _$v.tokenUIState?.toBuilder();
|
||||
_paymentTermUIState = _$v.paymentTermUIState?.toBuilder();
|
||||
|
|
@ -789,6 +813,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
productUIState: productUIState.build(),
|
||||
clientUIState: clientUIState.build(),
|
||||
invoiceUIState: invoiceUIState.build(),
|
||||
recurringInvoiceUIState: recurringInvoiceUIState.build(),
|
||||
webhookUIState: webhookUIState.build(),
|
||||
tokenUIState: tokenUIState.build(),
|
||||
paymentTermUIState: paymentTermUIState.build(),
|
||||
|
|
@ -818,6 +843,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
clientUIState.build();
|
||||
_$failedField = 'invoiceUIState';
|
||||
invoiceUIState.build();
|
||||
_$failedField = 'recurringInvoiceUIState';
|
||||
recurringInvoiceUIState.build();
|
||||
_$failedField = 'webhookUIState';
|
||||
webhookUIState.build();
|
||||
_$failedField = 'tokenUIState';
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ class AppButton extends StatelessWidget {
|
|||
final button = RaisedButton(
|
||||
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
||||
color: color ?? Theme.of(context).buttonColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
||||
child: iconData != null
|
||||
? IconText(
|
||||
icon: iconData,
|
||||
|
|
|
|||
|
|
@ -235,6 +235,13 @@ class MenuDrawer extends StatelessWidget {
|
|||
title: localization.invoices,
|
||||
iconTooltip: localization.newInvoice,
|
||||
),
|
||||
DrawerTile(
|
||||
company: company,
|
||||
entityType: EntityType.recurringInvoice,
|
||||
icon: getEntityIcon(EntityType.recurringInvoice),
|
||||
title: localization.recurringInvoices,
|
||||
iconTooltip: localization.newRecurringInvoice,
|
||||
),
|
||||
DrawerTile(
|
||||
company: company,
|
||||
entityType: EntityType.payment,
|
||||
|
|
|
|||
|
|
@ -54,68 +54,51 @@ class CompanyGatewayListItem extends StatelessWidget {
|
|||
trailing: onRemovePressed == null
|
||||
? null
|
||||
: FlatButton(
|
||||
child: Text(AppLocalization
|
||||
.of(context)
|
||||
.remove),
|
||||
onPressed: onRemovePressed,
|
||||
),
|
||||
child: Text(AppLocalization.of(context).remove),
|
||||
onPressed: onRemovePressed,
|
||||
),
|
||||
leading: showCheckbox
|
||||
? IgnorePointer(
|
||||
ignoring: listUIState.isInMultiselect(),
|
||||
child: Checkbox(
|
||||
value: isChecked,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: (value) => onCheckboxChanged(value),
|
||||
activeColor: Theme
|
||||
.of(context)
|
||||
.accentColor,
|
||||
),
|
||||
)
|
||||
ignoring: listUIState.isInMultiselect(),
|
||||
child: Checkbox(
|
||||
value: isChecked,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: (value) => onCheckboxChanged(value),
|
||||
activeColor: Theme.of(context).accentColor,
|
||||
),
|
||||
)
|
||||
: Icon(Icons.drag_handle),
|
||||
title: Container(
|
||||
width: MediaQuery
|
||||
.of(context)
|
||||
.size
|
||||
.width,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
companyGateway.label,
|
||||
style: Theme
|
||||
.of(context)
|
||||
.textTheme
|
||||
.headline6,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
companyGateway.label,
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
),
|
||||
Text(formatNumber(companyGateway.listDisplayAmount, context),
|
||||
style: Theme.of(context).textTheme.headline6),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (companyGateway.isTestMode) Text(localization.testMode),
|
||||
subtitle != null && subtitle.isNotEmpty
|
||||
? Text(
|
||||
subtitle,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: Container(),
|
||||
EntityStateLabel(companyGateway),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(formatNumber(companyGateway.listDisplayAmount, context),
|
||||
style: Theme
|
||||
.of(context)
|
||||
.textTheme
|
||||
.headline6),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (companyGateway.isTestMode)
|
||||
Text(localization.testMode),
|
||||
subtitle != null && subtitle.isNotEmpty
|
||||
? Text(
|
||||
subtitle,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: Container(),
|
||||
EntityStateLabel(companyGateway),
|
||||
]
|
||||
,
|
||||
)
|
||||
,
|
||||
)
|
||||
,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/edit/recurring_invoice_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
|
||||
class RecurringInvoiceEdit extends StatefulWidget {
|
||||
const RecurringInvoiceEdit({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final RecurringInvoiceEditVM viewModel;
|
||||
|
||||
@override
|
||||
_RecurringInvoiceEditState createState() => _RecurringInvoiceEditState();
|
||||
}
|
||||
|
||||
class _RecurringInvoiceEditState extends State<RecurringInvoiceEdit> {
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_recurringInvoiceEdit');
|
||||
final _debouncer = Debouncer();
|
||||
|
||||
// STARTER: controllers - do not remove comment
|
||||
|
||||
List<TextEditingController> _controllers = [];
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_controllers = [
|
||||
// STARTER: array - do not remove comment
|
||||
];
|
||||
|
||||
_controllers.forEach((controller) => controller.removeListener(_onChanged));
|
||||
|
||||
//final recurringInvoice = widget.viewModel.recurringInvoice;
|
||||
// STARTER: read value - do not remove comment
|
||||
|
||||
_controllers.forEach((controller) => controller.addListener(_onChanged));
|
||||
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controllers.forEach((controller) {
|
||||
controller.removeListener(_onChanged);
|
||||
controller.dispose();
|
||||
});
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onChanged() {
|
||||
_debouncer.run(() {
|
||||
final recurringInvoice =
|
||||
widget.viewModel.recurringInvoice.rebuild((b) => b
|
||||
// STARTER: set value - do not remove comment
|
||||
);
|
||||
if (recurringInvoice != widget.viewModel.recurringInvoice) {
|
||||
widget.viewModel.onChanged(recurringInvoice);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final viewModel = widget.viewModel;
|
||||
final localization = AppLocalization.of(context);
|
||||
final recurringInvoice = viewModel.recurringInvoice;
|
||||
|
||||
return EditScaffold(
|
||||
title: recurringInvoice.isNew
|
||||
? localization.newRecurringInvoice
|
||||
: localization.editRecurringInvoice,
|
||||
onCancelPressed: (context) => viewModel.onCancelPressed(context),
|
||||
onSavePressed: (context) {
|
||||
final bool isValid = _formKey.currentState.validate();
|
||||
|
||||
/*
|
||||
setState(() {
|
||||
_autoValidate = !isValid;
|
||||
});
|
||||
*/
|
||||
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewModel.onSavePressed(context);
|
||||
},
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
children: <Widget>[
|
||||
// STARTER: widgets - do not remove comment
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
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/ui/ui_actions.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/recurring_invoice/view/recurring_invoice_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/edit/recurring_invoice_edit.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class RecurringInvoiceEditScreen extends StatelessWidget {
|
||||
const RecurringInvoiceEditScreen({Key key}) : super(key: key);
|
||||
static const String route = '/recurring_invoice/edit';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, RecurringInvoiceEditVM>(
|
||||
converter: (Store<AppState> store) {
|
||||
return RecurringInvoiceEditVM.fromStore(store);
|
||||
},
|
||||
builder: (context, viewModel) {
|
||||
return RecurringInvoiceEdit(
|
||||
viewModel: viewModel,
|
||||
key: ValueKey(viewModel.recurringInvoice.id),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringInvoiceEditVM {
|
||||
RecurringInvoiceEditVM({
|
||||
@required this.state,
|
||||
@required this.recurringInvoice,
|
||||
@required this.company,
|
||||
@required this.onChanged,
|
||||
@required this.isSaving,
|
||||
@required this.origRecurringInvoice,
|
||||
@required this.onSavePressed,
|
||||
@required this.onCancelPressed,
|
||||
@required this.isLoading,
|
||||
});
|
||||
|
||||
factory RecurringInvoiceEditVM.fromStore(Store<AppState> store) {
|
||||
final state = store.state;
|
||||
final recurringInvoice = state.recurringInvoiceUIState.editing;
|
||||
|
||||
return RecurringInvoiceEditVM(
|
||||
state: state,
|
||||
isLoading: state.isLoading,
|
||||
isSaving: state.isSaving,
|
||||
origRecurringInvoice:
|
||||
state.recurringInvoiceState.map[recurringInvoice.id],
|
||||
recurringInvoice: recurringInvoice,
|
||||
company: state.company,
|
||||
onChanged: (InvoiceEntity recurringInvoice) {
|
||||
store.dispatch(UpdateRecurringInvoice(recurringInvoice));
|
||||
},
|
||||
onCancelPressed: (BuildContext context) {
|
||||
createEntity(
|
||||
context: context, entity: InvoiceEntity(), force: true);
|
||||
},
|
||||
onSavePressed: (BuildContext context) {
|
||||
final Completer<InvoiceEntity> completer =
|
||||
new Completer<InvoiceEntity>();
|
||||
store.dispatch(SaveRecurringInvoiceRequest(
|
||||
completer: completer, recurringInvoice: recurringInvoice));
|
||||
return completer.future.then((savedRecurringInvoice) {
|
||||
if (isMobile(context)) {
|
||||
store
|
||||
.dispatch(UpdateCurrentRoute(RecurringInvoiceViewScreen.route));
|
||||
if (recurringInvoice.isNew) {
|
||||
Navigator.of(context)
|
||||
.pushReplacementNamed(RecurringInvoiceViewScreen.route);
|
||||
} else {
|
||||
Navigator.of(context).pop(savedRecurringInvoice);
|
||||
}
|
||||
} else {
|
||||
viewEntity(
|
||||
context: context, entity: savedRecurringInvoice, force: true);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
showDialog<ErrorDialog>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ErrorDialog(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final InvoiceEntity recurringInvoice;
|
||||
final CompanyEntity company;
|
||||
final Function(InvoiceEntity) onChanged;
|
||||
final Function(BuildContext) onSavePressed;
|
||||
final Function(BuildContext) onCancelPressed;
|
||||
final bool isLoading;
|
||||
final bool isSaving;
|
||||
final InvoiceEntity origRecurringInvoice;
|
||||
final AppState state;
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/entity_state_label.dart';
|
||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/dismissible_entity.dart';
|
||||
|
||||
class RecurringInvoiceListItem extends StatelessWidget {
|
||||
const RecurringInvoiceListItem({
|
||||
@required this.user,
|
||||
@required this.recurringInvoice,
|
||||
@required this.filter,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.onCheckboxChanged,
|
||||
this.isChecked = false,
|
||||
});
|
||||
|
||||
final UserEntity user;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureTapCallback onLongPress;
|
||||
final InvoiceEntity recurringInvoice;
|
||||
final String filter;
|
||||
final Function(bool) onCheckboxChanged;
|
||||
final bool isChecked;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final state = store.state;
|
||||
final uiState = state.uiState;
|
||||
final recurringInvoiceUIState = uiState.recurringInvoiceUIState;
|
||||
final listUIState = recurringInvoiceUIState.listUIState;
|
||||
final isInMultiselect = listUIState.isInMultiselect();
|
||||
final showCheckbox = onCheckboxChanged != null || isInMultiselect;
|
||||
|
||||
final filterMatch = filter != null && filter.isNotEmpty
|
||||
? recurringInvoice.matchesFilterValue(filter)
|
||||
: null;
|
||||
final subtitle = filterMatch;
|
||||
|
||||
return DismissibleEntity(
|
||||
userCompany: state.userCompany,
|
||||
entity: recurringInvoice,
|
||||
isSelected: recurringInvoice.id ==
|
||||
(uiState.isEditing
|
||||
? recurringInvoiceUIState.editing.id
|
||||
: recurringInvoiceUIState.selectedId),
|
||||
child: ListTile(
|
||||
onTap: () => onTap != null
|
||||
? onTap()
|
||||
: selectEntity(entity: recurringInvoice, context: context),
|
||||
onLongPress: () => onLongPress != null
|
||||
? onLongPress()
|
||||
: selectEntity(
|
||||
entity: recurringInvoice, context: context, longPress: true),
|
||||
leading: showCheckbox
|
||||
? IgnorePointer(
|
||||
ignoring: listUIState.isInMultiselect(),
|
||||
child: Checkbox(
|
||||
value: isChecked,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: (value) => onCheckboxChanged(value),
|
||||
activeColor: Theme.of(context).accentColor,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
title: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
recurringInvoice.number,
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
),
|
||||
Text(formatNumber(recurringInvoice.listDisplayAmount, context),
|
||||
style: Theme.of(context).textTheme.headline6),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
subtitle != null && subtitle.isNotEmpty
|
||||
? Text(
|
||||
subtitle,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: Container(),
|
||||
EntityStateLabel(recurringInvoice),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import 'dart:async';
|
||||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/tables/entity_list.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_presenter.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_selectors.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
|
||||
class RecurringInvoiceListBuilder extends StatelessWidget {
|
||||
const RecurringInvoiceListBuilder({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, RecurringInvoiceListVM>(
|
||||
converter: RecurringInvoiceListVM.fromStore,
|
||||
builder: (context, viewModel) {
|
||||
return EntityList(
|
||||
entityType: EntityType.recurringInvoice,
|
||||
presenter: RecurringInvoicePresenter(),
|
||||
state: viewModel.state,
|
||||
entityList: viewModel.recurringInvoiceList,
|
||||
tableColumns: viewModel.tableColumns,
|
||||
onRefreshed: viewModel.onRefreshed,
|
||||
onSortColumn: viewModel.onSortColumn,
|
||||
onClearMultiselect: viewModel.onClearMultielsect,
|
||||
itemBuilder: (BuildContext context, index) {
|
||||
final state = viewModel.state;
|
||||
final recurringInvoiceId = viewModel.recurringInvoiceList[index];
|
||||
final recurringInvoice =
|
||||
viewModel.recurringInvoiceMap[recurringInvoiceId];
|
||||
final listState = state.getListState(EntityType.recurringInvoice);
|
||||
final isInMultiselect = listState.isInMultiselect();
|
||||
|
||||
return RecurringInvoiceListItem(
|
||||
user: viewModel.state.user,
|
||||
filter: viewModel.filter,
|
||||
recurringInvoice: recurringInvoice,
|
||||
isChecked: isInMultiselect &&
|
||||
listState.isSelected(recurringInvoice.id),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringInvoiceListVM {
|
||||
RecurringInvoiceListVM({
|
||||
@required this.state,
|
||||
@required this.userCompany,
|
||||
@required this.recurringInvoiceList,
|
||||
@required this.recurringInvoiceMap,
|
||||
@required this.filter,
|
||||
@required this.isLoading,
|
||||
@required this.listState,
|
||||
@required this.onRefreshed,
|
||||
@required this.onEntityAction,
|
||||
@required this.tableColumns,
|
||||
@required this.onSortColumn,
|
||||
@required this.onClearMultielsect,
|
||||
});
|
||||
|
||||
static RecurringInvoiceListVM fromStore(Store<AppState> store) {
|
||||
Future<Null> _handleRefresh(BuildContext context) {
|
||||
if (store.state.isLoading) {
|
||||
return Future<Null>(null);
|
||||
}
|
||||
final completer = snackBarCompleter<Null>(
|
||||
context, AppLocalization.of(context).refreshComplete);
|
||||
store.dispatch(RefreshData(completer: completer));
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
final state = store.state;
|
||||
|
||||
return RecurringInvoiceListVM(
|
||||
state: state,
|
||||
userCompany: state.userCompany,
|
||||
listState: state.recurringInvoiceListState,
|
||||
recurringInvoiceList: memoizedFilteredRecurringInvoiceList(
|
||||
state.uiState.filterEntityId,
|
||||
state.uiState.filterEntityType,
|
||||
state.recurringInvoiceState.map,
|
||||
state.clientState.map,
|
||||
state.recurringInvoiceState.list,
|
||||
state.recurringInvoiceListState,
|
||||
state.staticState,
|
||||
state.userState.map),
|
||||
recurringInvoiceMap: state.recurringInvoiceState.map,
|
||||
isLoading: state.isLoading,
|
||||
filter: state.recurringInvoiceUIState.listUIState.filter,
|
||||
onEntityAction: (BuildContext context, List<BaseEntity> recurringInvoices,
|
||||
EntityAction action) =>
|
||||
handleRecurringInvoiceAction(context, recurringInvoices, action),
|
||||
onRefreshed: (context) => _handleRefresh(context),
|
||||
tableColumns: state.userCompany.settings
|
||||
.getTableColumns(EntityType.recurringInvoice) ??
|
||||
RecurringInvoicePresenter.getDefaultTableFields(state.userCompany),
|
||||
onSortColumn: (field) => store.dispatch(SortRecurringInvoices(field)),
|
||||
onClearMultielsect: () =>
|
||||
store.dispatch(ClearRecurringInvoiceMultiselect()),
|
||||
);
|
||||
}
|
||||
|
||||
final AppState state;
|
||||
final UserCompanyEntity userCompany;
|
||||
final List<String> recurringInvoiceList;
|
||||
final BuiltMap<String, InvoiceEntity> recurringInvoiceMap;
|
||||
final ListUIState listState;
|
||||
final String filter;
|
||||
final bool isLoading;
|
||||
final Function(BuildContext) onRefreshed;
|
||||
final Function(BuildContext, List<BaseEntity>, EntityAction) onEntityAction;
|
||||
final List<String> tableColumns;
|
||||
final Function(String) onSortColumn;
|
||||
final Function onClearMultielsect;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
|
||||
|
||||
class RecurringInvoicePresenter extends EntityPresenter {
|
||||
static List<String> getDefaultTableFields(UserCompanyEntity userCompany) {
|
||||
return [];
|
||||
}
|
||||
|
||||
static List<String> getAllTableFields(UserCompanyEntity userCompany) {
|
||||
return [
|
||||
...getDefaultTableFields(userCompany),
|
||||
...EntityPresenter.getBaseFields(),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget getField({String field, BuildContext context}) {
|
||||
//final state = StoreProvider.of<AppState>(context).state;
|
||||
//final recurringInvoice = entity as InvoiceEntity;
|
||||
|
||||
switch (field) {
|
||||
}
|
||||
|
||||
return super.getField(field: field, context: context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
import 'package:flutter/material.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/recurring_invoice/recurring_invoice_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/app_bottom_bar.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/list_scaffold.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/list_filter.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_list_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/recurring_invoice_presenter.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
import 'recurring_invoice_screen_vm.dart';
|
||||
|
||||
class RecurringInvoiceScreen extends StatelessWidget {
|
||||
const RecurringInvoiceScreen({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
static const String route = '/recurring_invoice';
|
||||
|
||||
final RecurringInvoiceScreenVM viewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final state = store.state;
|
||||
final company = state.company;
|
||||
final userCompany = state.userCompany;
|
||||
final localization = AppLocalization.of(context);
|
||||
|
||||
return ListScaffold(
|
||||
entityType: EntityType.recurringInvoice,
|
||||
onHamburgerLongPress: () =>
|
||||
store.dispatch(StartRecurringInvoiceMultiselect()),
|
||||
appBarTitle: ListFilter(
|
||||
entityType: EntityType.recurringInvoice,
|
||||
entityIds: viewModel.recurringInvoiceList,
|
||||
filter: state.recurringInvoiceListState.filter,
|
||||
onFilterChanged: (value) {
|
||||
store.dispatch(FilterRecurringInvoices(value));
|
||||
},
|
||||
),
|
||||
body: RecurringInvoiceListBuilder(),
|
||||
bottomNavigationBar: AppBottomBar(
|
||||
entityType: EntityType.recurringInvoice,
|
||||
tableColumns: RecurringInvoicePresenter.getAllTableFields(userCompany),
|
||||
defaultTableColumns:
|
||||
RecurringInvoicePresenter.getDefaultTableFields(userCompany),
|
||||
onSelectedSortField: (value) {
|
||||
store.dispatch(SortRecurringInvoices(value));
|
||||
},
|
||||
sortFields: [
|
||||
InvoiceFields.invoiceNumber,
|
||||
],
|
||||
onSelectedState: (EntityState state, value) {
|
||||
store.dispatch(FilterRecurringInvoicesByState(state));
|
||||
},
|
||||
onCheckboxPressed: () {
|
||||
if (store.state.recurringInvoiceListState.isInMultiselect()) {
|
||||
store.dispatch(ClearRecurringInvoiceMultiselect());
|
||||
} else {
|
||||
store.dispatch(StartRecurringInvoiceMultiselect());
|
||||
}
|
||||
},
|
||||
customValues1: company.getCustomFieldValues(
|
||||
CustomFieldType.invoice1,
|
||||
excludeBlank: true),
|
||||
customValues2: company.getCustomFieldValues(
|
||||
CustomFieldType.invoice2,
|
||||
excludeBlank: true),
|
||||
customValues3: company.getCustomFieldValues(
|
||||
CustomFieldType.invoice3,
|
||||
excludeBlank: true),
|
||||
customValues4: company.getCustomFieldValues(
|
||||
CustomFieldType.invoice4,
|
||||
excludeBlank: true),
|
||||
onSelectedCustom1: (value) =>
|
||||
store.dispatch(FilterRecurringInvoicesByCustom1(value)),
|
||||
onSelectedCustom2: (value) =>
|
||||
store.dispatch(FilterRecurringInvoicesByCustom2(value)),
|
||||
onSelectedCustom3: (value) =>
|
||||
store.dispatch(FilterRecurringInvoicesByCustom3(value)),
|
||||
onSelectedCustom4: (value) =>
|
||||
store.dispatch(FilterRecurringInvoicesByCustom4(value)),
|
||||
),
|
||||
floatingActionButton: state.prefState.isMenuFloated &&
|
||||
userCompany.canCreate(EntityType.recurringInvoice)
|
||||
? FloatingActionButton(
|
||||
heroTag: 'recurring_invoice_fab',
|
||||
backgroundColor: Theme.of(context).primaryColorDark,
|
||||
onPressed: () {
|
||||
createEntityByType(
|
||||
context: context, entityType: EntityType.recurringInvoice);
|
||||
},
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
tooltip: localization.newRecurringInvoice,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/recurring_invoice/recurring_invoice_selectors.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
|
||||
import 'recurring_invoice_screen.dart';
|
||||
|
||||
class RecurringInvoiceScreenBuilder extends StatelessWidget {
|
||||
const RecurringInvoiceScreenBuilder({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, RecurringInvoiceScreenVM>(
|
||||
converter: RecurringInvoiceScreenVM.fromStore,
|
||||
builder: (context, vm) {
|
||||
return RecurringInvoiceScreen(
|
||||
viewModel: vm,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringInvoiceScreenVM {
|
||||
RecurringInvoiceScreenVM({
|
||||
@required this.isInMultiselect,
|
||||
@required this.recurringInvoiceList,
|
||||
@required this.userCompany,
|
||||
@required this.onEntityAction,
|
||||
@required this.recurringInvoiceMap,
|
||||
});
|
||||
|
||||
final bool isInMultiselect;
|
||||
final UserCompanyEntity userCompany;
|
||||
final List<String> recurringInvoiceList;
|
||||
final Function(BuildContext, List<BaseEntity>, EntityAction) onEntityAction;
|
||||
final BuiltMap<String, InvoiceEntity> recurringInvoiceMap;
|
||||
|
||||
static RecurringInvoiceScreenVM fromStore(Store<AppState> store) {
|
||||
final state = store.state;
|
||||
|
||||
return RecurringInvoiceScreenVM(
|
||||
recurringInvoiceMap: state.recurringInvoiceState.map,
|
||||
recurringInvoiceList: memoizedFilteredRecurringInvoiceList(
|
||||
state.uiState.filterEntityId,
|
||||
state.uiState.filterEntityType,
|
||||
state.recurringInvoiceState.map,
|
||||
state.clientState.map,
|
||||
state.recurringInvoiceState.list,
|
||||
state.recurringInvoiceListState,
|
||||
state.staticState,
|
||||
state.userState.map),
|
||||
userCompany: state.userCompany,
|
||||
isInMultiselect: state.recurringInvoiceListState.isInMultiselect(),
|
||||
onEntityAction: (BuildContext context, List<BaseEntity> recurringInvoices,
|
||||
EntityAction action) =>
|
||||
handleRecurringInvoiceAction(context, recurringInvoices, action),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/view/recurring_invoice_view_vm.dart';
|
||||
|
||||
class RecurringInvoiceView extends StatefulWidget {
|
||||
const RecurringInvoiceView({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
@required this.isFilter,
|
||||
}) : super(key: key);
|
||||
|
||||
final RecurringInvoiceViewVM viewModel;
|
||||
final bool isFilter;
|
||||
|
||||
@override
|
||||
_RecurringInvoiceViewState createState() => new _RecurringInvoiceViewState();
|
||||
}
|
||||
|
||||
class _RecurringInvoiceViewState extends State<RecurringInvoiceView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final viewModel = widget.viewModel;
|
||||
final recurringInvoice = viewModel.recurringInvoice;
|
||||
|
||||
return ViewScaffold(
|
||||
isFilter: widget.isFilter,
|
||||
entity: recurringInvoice,
|
||||
body: ListView(
|
||||
children: <Widget>[],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import 'dart:async';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.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/recurring_invoice/recurring_invoice_actions.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/recurring_invoice/view/recurring_invoice_view.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class RecurringInvoiceViewScreen extends StatelessWidget {
|
||||
const RecurringInvoiceViewScreen({
|
||||
Key key,
|
||||
this.isFilter = false,
|
||||
}) : super(key: key);
|
||||
static const String route = '/recurring_invoice/view';
|
||||
final bool isFilter;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, RecurringInvoiceViewVM>(
|
||||
converter: (Store<AppState> store) {
|
||||
return RecurringInvoiceViewVM.fromStore(store);
|
||||
},
|
||||
builder: (context, vm) {
|
||||
return RecurringInvoiceView(
|
||||
viewModel: vm,
|
||||
isFilter: isFilter,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringInvoiceViewVM {
|
||||
RecurringInvoiceViewVM({
|
||||
@required this.state,
|
||||
@required this.recurringInvoice,
|
||||
@required this.company,
|
||||
@required this.onEntityAction,
|
||||
@required this.onRefreshed,
|
||||
@required this.isSaving,
|
||||
@required this.isLoading,
|
||||
@required this.isDirty,
|
||||
});
|
||||
|
||||
factory RecurringInvoiceViewVM.fromStore(Store<AppState> store) {
|
||||
final state = store.state;
|
||||
final recurringInvoice = state.recurringInvoiceState
|
||||
.map[state.recurringInvoiceUIState.selectedId] ??
|
||||
InvoiceEntity(id: state.recurringInvoiceUIState.selectedId);
|
||||
|
||||
Future<Null> _handleRefresh(BuildContext context) {
|
||||
final completer = snackBarCompleter<Null>(
|
||||
context, AppLocalization.of(context).refreshComplete);
|
||||
store.dispatch(LoadRecurringInvoice(
|
||||
completer: completer, recurringInvoiceId: recurringInvoice.id));
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
return RecurringInvoiceViewVM(
|
||||
state: state,
|
||||
company: state.company,
|
||||
isSaving: state.isSaving,
|
||||
isLoading: state.isLoading,
|
||||
isDirty: recurringInvoice.isNew,
|
||||
recurringInvoice: recurringInvoice,
|
||||
onRefreshed: (context) => _handleRefresh(context),
|
||||
onEntityAction: (BuildContext context, EntityAction action) =>
|
||||
handleEntitiesActions(context, [recurringInvoice], action,
|
||||
autoPop: true),
|
||||
);
|
||||
}
|
||||
|
||||
final AppState state;
|
||||
final InvoiceEntity recurringInvoice;
|
||||
final CompanyEntity company;
|
||||
final Function(BuildContext, EntityAction) onEntityAction;
|
||||
final Function(BuildContext) onRefreshed;
|
||||
final bool isSaving;
|
||||
final bool isLoading;
|
||||
final bool isDirty;
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ class _AccountManagementState extends State<AccountManagement>
|
|||
// TODO change to kModules.keys
|
||||
children: [
|
||||
kModuleInvoices,
|
||||
kModuleRecurringInvoices,
|
||||
kModuleQuotes,
|
||||
kModuleCredits,
|
||||
].map((module) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,17 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
static final Map<String, Map<String, String>> _localizedValues = {
|
||||
'en': {
|
||||
// STARTER: lang key - do not remove comment
|
||||
'recurring_invoice': 'Recurring Invoice',
|
||||
'recurring_invoices': 'Recurring Invoices',
|
||||
'new_recurring_invoice': 'New Recurring Invoice',
|
||||
'edit_recurring_invoice': 'Edit Recurring Invoice',
|
||||
'created_recurring_invoice': 'Successfully created recurring invoice',
|
||||
'updated_recurring_invoice': 'Successfully updated recurring invoice',
|
||||
'archived_recurring_invoice': 'Successfully archived recurring invoice',
|
||||
'deleted_recurring_invoice': 'Successfully deleted recurring invoice',
|
||||
'removed_recurring_invoice': 'Successfully removed recurring invoice',
|
||||
'restored_recurring_invoice': 'Successfully restored recurring invoice',
|
||||
'search_recurring_invoice': 'Search Recurring Invoice',
|
||||
'send_date': 'Send Date',
|
||||
'auto_bill_on': 'Auto Bill On',
|
||||
'minimum_under_payment_amount': 'Minimum Under Payment Amount',
|
||||
|
|
@ -312,7 +323,6 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
'restored_design': 'Successfully restored design',
|
||||
'proposals': 'Proposals',
|
||||
'tickets': 'Tickets',
|
||||
'recurring_invoices': 'Recurring Invoices',
|
||||
'recurring_quotes': 'Recurring Quotes',
|
||||
'recurring_tasks': 'Recurring Tasks',
|
||||
'recurring_expenses': 'Recurring Expenses',
|
||||
|
|
@ -953,7 +963,6 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
'edit_expense': 'Edit Expense',
|
||||
'edit_vendor': 'Edit Vendor',
|
||||
'edit_project': 'Edit Project',
|
||||
'edit_recurring_invoice': 'Edit Recurring Invoice',
|
||||
'edit_recurring_expense': 'Edit Recurring Expense',
|
||||
'edit_recurring_quote': 'Edit Recurring Quote',
|
||||
'billing_address': 'Billing Address',
|
||||
|
|
@ -3628,6 +3637,33 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
String get appUpdated => _localizedValues[localeCode]['app_updated'] ?? '';
|
||||
|
||||
// STARTER: lang field - do not remove comment
|
||||
String get recurringInvoice =>
|
||||
_localizedValues[localeCode]['recurring_invoice'];
|
||||
|
||||
String get recurringInvoices =>
|
||||
_localizedValues[localeCode]['recurring_invoices'];
|
||||
|
||||
String get newRecurringInvoice =>
|
||||
_localizedValues[localeCode]['new_recurring_invoice'];
|
||||
|
||||
String get createdRecurringInvoice =>
|
||||
_localizedValues[localeCode]['created_recurring_invoice'];
|
||||
|
||||
String get updatedRecurringInvoice =>
|
||||
_localizedValues[localeCode]['updated_recurring_invoice'];
|
||||
|
||||
String get archivedRecurringInvoice =>
|
||||
_localizedValues[localeCode]['archived_recurring_invoice'];
|
||||
|
||||
String get deletedRecurringInvoice =>
|
||||
_localizedValues[localeCode]['deleted_recurring_invoice'];
|
||||
|
||||
String get restoredRecurringInvoice =>
|
||||
_localizedValues[localeCode]['restored_recurring_invoice'];
|
||||
|
||||
String get searchRecurringInvoice =>
|
||||
_localizedValues[localeCode]['search_recurring_invoice'];
|
||||
|
||||
String get webhook => _localizedValues[localeCode]['webhook'] ?? '';
|
||||
|
||||
String get webhooks => _localizedValues[localeCode]['webhooks'] ?? '';
|
||||
|
|
@ -3744,9 +3780,6 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
|
||||
String get tickets => _localizedValues[localeCode]['tickets'] ?? '';
|
||||
|
||||
String get recurringInvoices =>
|
||||
_localizedValues[localeCode]['recurring_invoices'] ?? '';
|
||||
|
||||
String get recurringQuotes =>
|
||||
_localizedValues[localeCode]['recurring_quotes'] ?? '';
|
||||
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ else
|
|||
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/redux/app/app_actions.dart
|
||||
|
||||
comment="STARTER: edit - do not remove comment"
|
||||
code="case EntityType.${module_camel}: store.dispatch(Edit${Module}(${module_camel}: map[entityId], navigator: navigator, completer: completer ?? snackBarCompleter<${Module}Entity>(context, entity.isNew ? localization.created${Module} : localization.updated${Module}),));break;${lineBreak}"
|
||||
code="case EntityType.${module_camel}: store.dispatch(Edit${Module}(${module_camel}: entity, navigator: navigator, completer: completer ?? snackBarCompleter<${Module}Entity>(context, entity.isNew ? localization.created${Module} : localization.updated${Module}),));break;${lineBreak}"
|
||||
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/redux/app/app_actions.dart
|
||||
|
||||
comment="STARTER: actions - do not remove comment"
|
||||
|
|
@ -431,7 +431,7 @@ else
|
|||
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/redux/app/app_actions.dart
|
||||
|
||||
comment="STARTER: lang key - do not remove comment"
|
||||
code="'${module_snake}': '${Module}', '${module_snake}s': '${Module}s', 'new_${module_snake}': 'New ${Module}', 'edit_${module_snake}': 'Edit ${Module}', 'created_${module_snake}': 'Successfully created ${module_snake}', 'updated_${module_snake}': 'Successfully updated ${module_snake}', 'archived_${module_snake}': 'Successfully archived ${module_snake}', 'deleted_${module_snake}': 'Successfully deleted ${module_snake}', 'removed_${module_snake}': 'Successfully removed ${module_snake}', 'restored_${module_snake}': 'Successfully restored ${module_snake}',${lineBreak}, 'search_${module_snake}': 'Search ${Module}'"
|
||||
code="'${module_snake}': '${Module}', '${module_snake}s': '${Module}s', 'new_${module_snake}': 'New ${Module}', 'edit_${module_snake}': 'Edit ${Module}', 'created_${module_snake}': 'Successfully created ${module_snake}', 'updated_${module_snake}': 'Successfully updated ${module_snake}', 'archived_${module_snake}': 'Successfully archived ${module_snake}', 'deleted_${module_snake}': 'Successfully deleted ${module_snake}', 'removed_${module_snake}': 'Successfully removed ${module_snake}', 'restored_${module_snake}': 'Successfully restored ${module_snake}', 'search_${module_snake}': 'Search ${Module}',${lineBreak}"
|
||||
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/utils/i18n.dart
|
||||
|
||||
comment="STARTER: lang field - do not remove comment"
|
||||
|
|
|
|||
|
|
@ -26,14 +26,8 @@ class StubRepository {
|
|||
return stubResponse.data;
|
||||
}
|
||||
|
||||
Future<BuiltList<StubEntity>> loadList(
|
||||
Credentials credentials, int updatedAt) async {
|
||||
String url = credentials.url + '/stubs?';
|
||||
|
||||
if (updatedAt > 0) {
|
||||
url += '&updated_at=${updatedAt - kUpdatedAtBufferSeconds}';
|
||||
}
|
||||
|
||||
Future<BuiltList<StubEntity>> loadList(Credentials credentials) async {
|
||||
final String url = credentials.url + '/stubs?';
|
||||
final dynamic response = await webClient.get(url, credentials.token);
|
||||
|
||||
final StubListResponse stubResponse =
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
|||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
|
||||
|
||||
class ViewStubList extends AbstractNavigatorAction implements PersistUI, StopLoading {
|
||||
ViewStubList({
|
||||
|
|
@ -245,6 +246,25 @@ class FilterStubsByCustom4 implements PersistUI {
|
|||
final String value;
|
||||
}
|
||||
|
||||
class StartStubMultiselect {
|
||||
StartStubMultiselect();
|
||||
}
|
||||
|
||||
class AddToStubMultiselect {
|
||||
AddToStubMultiselect({@required this.entity});
|
||||
|
||||
final BaseEntity entity;
|
||||
}
|
||||
|
||||
class RemoveFromStubMultiselect {
|
||||
RemoveFromStubMultiselect({@required this.entity});
|
||||
|
||||
final BaseEntity entity;
|
||||
}
|
||||
|
||||
class ClearStubMultiselect {
|
||||
ClearStubMultiselect();
|
||||
}
|
||||
|
||||
void handleStubAction(
|
||||
BuildContext context, List<BaseEntity> stubs, EntityAction action) {
|
||||
|
|
@ -254,6 +274,7 @@ void handleStubAction(
|
|||
}
|
||||
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final state = store.state;
|
||||
final localization = AppLocalization.of(context);
|
||||
final stub = stubs.first as StubEntity;
|
||||
final stubIds = stubs.map((stub) => stub.id).toList();
|
||||
|
|
@ -297,28 +318,7 @@ void handleStubAction(
|
|||
showEntityActionsDialog(
|
||||
entities: [stub],
|
||||
context: context,
|
||||
client: state.clientState.get(stub.clientId),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class StartStubMultiselect {
|
||||
StartStubMultiselect();
|
||||
}
|
||||
|
||||
class AddToStubMultiselect {
|
||||
AddToStubMultiselect({@required this.entity});
|
||||
|
||||
final BaseEntity entity;
|
||||
}
|
||||
|
||||
class RemoveFromStubMultiselect {
|
||||
RemoveFromStubMultiselect({@required this.entity});
|
||||
|
||||
final BaseEntity entity;
|
||||
}
|
||||
|
||||
class ClearStubMultiselect {
|
||||
ClearStubMultiselect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,11 +44,6 @@ Middleware<AppState> _editStub() {
|
|||
|
||||
final action = dynamicAction as EditStub;
|
||||
|
||||
if (!action.force && hasChanges(
|
||||
store: store, context: action.context, callback: () => store.dispatch(action))) {
|
||||
return;
|
||||
}
|
||||
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(StubEditScreen.route));
|
||||
|
|
@ -64,12 +59,6 @@ Middleware<AppState> _viewStub() {
|
|||
|
||||
final action = dynamicAction as ViewStub;
|
||||
|
||||
if (!action.force && hasChanges(
|
||||
store: store, context: action.context, callback: () => store.dispatch(action))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(StubViewScreen.route));
|
||||
|
|
@ -84,17 +73,10 @@ Middleware<AppState> _viewStubList() {
|
|||
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
|
||||
final action = dynamicAction as ViewStubList;
|
||||
|
||||
if (!action.force && hasChanges(
|
||||
store: store, context: action.context, callback: () => store.dispatch(action))) {
|
||||
return;
|
||||
}
|
||||
|
||||
next(action);
|
||||
|
||||
if (store.state.staticState.isStale) {
|
||||
store.dispatch(RefreshData());
|
||||
} else if (store.state.stubState.isStale) {
|
||||
store.dispatch(LoadStubs());
|
||||
}
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(StubScreen.route));
|
||||
|
|
@ -237,16 +219,10 @@ Middleware<AppState> _loadStubs(StubRepository repository) {
|
|||
final action = dynamicAction as LoadStubs;
|
||||
final AppState state = store.state;
|
||||
|
||||
if (!state.stubState.isStale && !action.force) {
|
||||
next(action);
|
||||
return;
|
||||
}
|
||||
|
||||
final int updatedAt = (state.stubState.lastUpdated / 1000).round();
|
||||
|
||||
store.dispatch(LoadStubsRequest());
|
||||
repository
|
||||
.loadList(state.credentials, updatedAt)
|
||||
.loadList(state.credentials)
|
||||
.then((data) {
|
||||
store.dispatch(LoadStubsSuccess(data));
|
||||
|
||||
|
|
|
|||
|
|
@ -72,11 +72,6 @@ final stubListReducer = combineReducers<ListUIState>([
|
|||
TypedReducer<ListUIState, RemoveFromStubMultiselect>(
|
||||
_removeFromListMultiselect),
|
||||
TypedReducer<ListUIState, ClearStubMultiselect>(_clearListMultiselect),
|
||||
TypedReducer<ListUIState, ClearEntityFilter>(
|
||||
(state, action) => state.rebuild((b) => b
|
||||
..filterEntityId = null
|
||||
..filterEntityType = null)),
|
||||
|
||||
]);
|
||||
|
||||
ListUIState _filterStubsByCustom1(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
import 'package:invoiceninja_flutter/data/models/stub_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/static/static_state.dart';
|
||||
import 'package:memoize/memoize.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
|
||||
var memoizedDropdownStubList = memo3(
|
||||
var memoizedDropdownStubList = memo5(
|
||||
(BuiltMap<String, StubEntity> stubMap, BuiltList<String> stubList,
|
||||
StaticState staticState,
|
||||
BuiltMap<String, UserEntity> userMap,
|
||||
String clientId) =>
|
||||
dropdownStubsSelector(stubMap, stubList, clientId));
|
||||
dropdownStubsSelector(stubMap, stubList, staticState, userMap, clientId));
|
||||
|
||||
List<String> dropdownStubsSelector(BuiltMap<String, StubEntity> stubMap,
|
||||
BuiltList<String> stubList, String clientId) {
|
||||
BuiltList<String> stubList,
|
||||
StaticState staticState,
|
||||
BuiltMap<String, UserEntity> userMap,
|
||||
String clientId) {
|
||||
final list = stubList.where((stubId) {
|
||||
final stub = stubMap[stubId];
|
||||
/*
|
||||
|
|
@ -30,16 +36,21 @@ List<String> dropdownStubsSelector(BuiltMap<String, StubEntity> stubMap,
|
|||
return list;
|
||||
}
|
||||
|
||||
var memoizedFilteredStubList = memo3((BuiltMap<String, StubEntity> stubMap,
|
||||
BuiltList<String> stubList, ListUIState stubListState) =>
|
||||
filteredStubsSelector(stubMap, stubList, stubListState));
|
||||
var memoizedFilteredStubList = memo7((BuiltMap<String, StubEntity> stubMap,
|
||||
BuiltList<String> stubList,
|
||||
StaticState staticState,
|
||||
BuiltMap<String, UserEntity> userMap,
|
||||
ListUIState stubListState) =>
|
||||
filteredStubsSelector(stubMap, stubList, staticState, userMap, stubListState));
|
||||
|
||||
List<String> filteredStubsSelector(BuiltMap<String, StubEntity> stubMap,
|
||||
BuiltList<String> stubList, ListUIState stubListState) {
|
||||
BuiltList<String> stubList,
|
||||
StaticState staticState,
|
||||
BuiltMap<String, UserEntity> userMap,
|
||||
ListUIState stubListState) {
|
||||
final list = stubList.where((stubId) {
|
||||
final stub = stubMap[stubId];
|
||||
if (stubListState.filterEntityId != null &&
|
||||
stub.id != stubListState.filterEntityId) {
|
||||
if (filterEntityId != null && stub.id != filterEntityId) {
|
||||
return false;
|
||||
} else {
|
||||
|
||||
|
|
@ -60,12 +71,17 @@ List<String> filteredStubsSelector(BuiltMap<String, StubEntity> stubMap,
|
|||
}).toList();
|
||||
|
||||
list.sort((stubAId, stubBId) {
|
||||
final stubA = stubMap[stubAId];
|
||||
final stubB = stubMap[stubBId];
|
||||
return stubA.compareTo(
|
||||
stubB, stubListState.sortField, stubListState.sortAscending);
|
||||
return stubMap[stubAId].compareTo(
|
||||
stub: stubMap[stubBId],
|
||||
sortField: stubListState.sortField,
|
||||
sortAscending: stubListState.sortAscending,
|
||||
//clientMap: clientMap,
|
||||
staticState: staticState,
|
||||
userMap: userMap,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import 'package:invoiceninja_flutter/ui/app/dismissible_entity.dart';
|
|||
class StubListItem extends StatelessWidget {
|
||||
const StubListItem({
|
||||
@required this.user,
|
||||
@required this.onEntityAction,
|
||||
@required this.stub,
|
||||
@required this.filter,
|
||||
this.onTap,
|
||||
|
|
@ -22,7 +21,6 @@ class StubListItem extends StatelessWidget {
|
|||
});
|
||||
|
||||
final UserEntity user;
|
||||
final Function(EntityAction) onEntityAction;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureTapCallback onLongPress;
|
||||
final StubEntity stub;
|
||||
|
|
@ -50,7 +48,6 @@ class StubListItem extends StatelessWidget {
|
|||
entity: stub,
|
||||
isSelected: stub.id ==
|
||||
(uiState.isEditing ? stubUIState.editing.id : stubUIState.selectedId),
|
||||
onEntityAction: onEntityAction,
|
||||
child: ListTile(
|
||||
onTap: () => onTap != null
|
||||
? onTap()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
|||
import 'package:invoiceninja_flutter/data/models/stub_model.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/tables/entity_list.dart';
|
||||
import 'package:invoiceninja_flutter/ui/webhook/stub_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/stub/stub_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/stub/stub_presenter.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
|
|
@ -18,7 +18,6 @@ import 'package:invoiceninja_flutter/redux/stub/stub_selectors.dart';
|
|||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/stub/stub_actions.dart';
|
||||
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
||||
|
||||
class StubListBuilder extends StatelessWidget {
|
||||
const StubListBuilder({Key key}) : super(key: key);
|
||||
|
|
@ -33,7 +32,6 @@ class StubListBuilder extends StatelessWidget {
|
|||
presenter: StubPresenter(),
|
||||
state: viewModel.state,
|
||||
entityList: viewModel.stubList,
|
||||
onEntityTap: viewModel.onStubTap,
|
||||
tableColumns: viewModel.tableColumns,
|
||||
onRefreshed: viewModel.onRefreshed,
|
||||
onSortColumn: viewModel.onSortColumn,
|
||||
|
|
@ -49,17 +47,6 @@ class StubListBuilder extends StatelessWidget {
|
|||
user: viewModel.state.user,
|
||||
filter: viewModel.filter,
|
||||
stub: stub,
|
||||
onEntityAction: (EntityAction action) {
|
||||
if (action == EntityAction.more) {
|
||||
showEntityActionsDialog(
|
||||
entities: [stub],
|
||||
context: context,
|
||||
);
|
||||
} else {
|
||||
handleStubAction(context, [stub], action);
|
||||
}
|
||||
},
|
||||
onTap: () => viewModel.onStubTap(context, stub),
|
||||
isChecked: isInMultiselect && listState.isSelected(stub.id),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ class StubScreen extends StatelessWidget {
|
|||
entityType: EntityType.stub,
|
||||
onHamburgerLongPress: () => store.dispatch(StartStubMultiselect()),
|
||||
appBarTitle: ListFilter(
|
||||
placeholder: localization.searchStubs,
|
||||
entityIds: viewModel.stubList,
|
||||
filter: state.stubListState.filter,
|
||||
onFilterChanged: (value) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/ui/stub/view/stub_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
|
||||
|
||||
class StubView extends StatefulWidget {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue