Webhooks UI

This commit is contained in:
Hillel Coren 2020-07-05 16:41:48 +03:00
parent 6eaa0c246f
commit 3ac62453c3
43 changed files with 4556 additions and 1108 deletions

View File

@ -99,6 +99,7 @@ abstract class CompanyEntity extends Object
designs: BuiltList<DesignEntity>(), designs: BuiltList<DesignEntity>(),
paymentTerms: BuiltList<PaymentTermEntity>(), paymentTerms: BuiltList<PaymentTermEntity>(),
tokens: BuiltList<TokenEntity>(), tokens: BuiltList<TokenEntity>(),
webhooks: BuiltList<WebhookEntity>(),
); );
} }
@ -224,6 +225,8 @@ abstract class CompanyEntity extends Object
BuiltList<TokenEntity> get tokens; BuiltList<TokenEntity> get tokens;
BuiltList<WebhookEntity> get webhooks;
@BuiltValueField(wireName: 'payment_terms') @BuiltValueField(wireName: 'payment_terms')
BuiltList<PaymentTermEntity> get paymentTerms; BuiltList<PaymentTermEntity> get paymentTerms;

View File

@ -185,6 +185,10 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
serializers.serialize(object.tokens, serializers.serialize(object.tokens,
specifiedType: specifiedType:
const FullType(BuiltList, const [const FullType(TokenEntity)])), const FullType(BuiltList, const [const FullType(TokenEntity)])),
'webhooks',
serializers.serialize(object.webhooks,
specifiedType:
const FullType(BuiltList, const [const FullType(WebhookEntity)])),
'payment_terms', 'payment_terms',
serializers.serialize(object.paymentTerms, serializers.serialize(object.paymentTerms,
specifiedType: const FullType( specifiedType: const FullType(
@ -495,6 +499,12 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
BuiltList, const [const FullType(TokenEntity)])) BuiltList, const [const FullType(TokenEntity)]))
as BuiltList<Object>); as BuiltList<Object>);
break; break;
case 'webhooks':
result.webhooks.replace(serializers.deserialize(value,
specifiedType: const FullType(
BuiltList, const [const FullType(WebhookEntity)]))
as BuiltList<Object>);
break;
case 'payment_terms': case 'payment_terms':
result.paymentTerms.replace(serializers.deserialize(value, result.paymentTerms.replace(serializers.deserialize(value,
specifiedType: const FullType( specifiedType: const FullType(
@ -2703,6 +2713,8 @@ class _$CompanyEntity extends CompanyEntity {
@override @override
final BuiltList<TokenEntity> tokens; final BuiltList<TokenEntity> tokens;
@override @override
final BuiltList<WebhookEntity> webhooks;
@override
final BuiltList<PaymentTermEntity> paymentTerms; final BuiltList<PaymentTermEntity> paymentTerms;
@override @override
final BuiltMap<String, UserEntity> userMap; final BuiltMap<String, UserEntity> userMap;
@ -2783,6 +2795,7 @@ class _$CompanyEntity extends CompanyEntity {
this.vendors, this.vendors,
this.designs, this.designs,
this.tokens, this.tokens,
this.webhooks,
this.paymentTerms, this.paymentTerms,
this.userMap, this.userMap,
this.customFields, this.customFields,
@ -2937,6 +2950,9 @@ class _$CompanyEntity extends CompanyEntity {
if (tokens == null) { if (tokens == null) {
throw new BuiltValueNullFieldError('CompanyEntity', 'tokens'); throw new BuiltValueNullFieldError('CompanyEntity', 'tokens');
} }
if (webhooks == null) {
throw new BuiltValueNullFieldError('CompanyEntity', 'webhooks');
}
if (paymentTerms == null) { if (paymentTerms == null) {
throw new BuiltValueNullFieldError('CompanyEntity', 'paymentTerms'); throw new BuiltValueNullFieldError('CompanyEntity', 'paymentTerms');
} }
@ -3024,6 +3040,7 @@ class _$CompanyEntity extends CompanyEntity {
vendors == other.vendors && vendors == other.vendors &&
designs == other.designs && designs == other.designs &&
tokens == other.tokens && tokens == other.tokens &&
webhooks == other.webhooks &&
paymentTerms == other.paymentTerms && paymentTerms == other.paymentTerms &&
userMap == other.userMap && userMap == other.userMap &&
customFields == other.customFields && customFields == other.customFields &&
@ -3063,10 +3080,10 @@ 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($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), 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(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), 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), vendors.hashCode),
vendors.hashCode), designs.hashCode),
designs.hashCode), tokens.hashCode),
tokens.hashCode), webhooks.hashCode),
paymentTerms.hashCode), paymentTerms.hashCode),
userMap.hashCode), userMap.hashCode),
customFields.hashCode), customFields.hashCode),
@ -3132,6 +3149,7 @@ class _$CompanyEntity extends CompanyEntity {
..add('vendors', vendors) ..add('vendors', vendors)
..add('designs', designs) ..add('designs', designs)
..add('tokens', tokens) ..add('tokens', tokens)
..add('webhooks', webhooks)
..add('paymentTerms', paymentTerms) ..add('paymentTerms', paymentTerms)
..add('userMap', userMap) ..add('userMap', userMap)
..add('customFields', customFields) ..add('customFields', customFields)
@ -3382,6 +3400,12 @@ class CompanyEntityBuilder
_$this._tokens ??= new ListBuilder<TokenEntity>(); _$this._tokens ??= new ListBuilder<TokenEntity>();
set tokens(ListBuilder<TokenEntity> tokens) => _$this._tokens = tokens; set tokens(ListBuilder<TokenEntity> tokens) => _$this._tokens = tokens;
ListBuilder<WebhookEntity> _webhooks;
ListBuilder<WebhookEntity> get webhooks =>
_$this._webhooks ??= new ListBuilder<WebhookEntity>();
set webhooks(ListBuilder<WebhookEntity> webhooks) =>
_$this._webhooks = webhooks;
ListBuilder<PaymentTermEntity> _paymentTerms; ListBuilder<PaymentTermEntity> _paymentTerms;
ListBuilder<PaymentTermEntity> get paymentTerms => ListBuilder<PaymentTermEntity> get paymentTerms =>
_$this._paymentTerms ??= new ListBuilder<PaymentTermEntity>(); _$this._paymentTerms ??= new ListBuilder<PaymentTermEntity>();
@ -3506,6 +3530,7 @@ class CompanyEntityBuilder
_vendors = _$v.vendors?.toBuilder(); _vendors = _$v.vendors?.toBuilder();
_designs = _$v.designs?.toBuilder(); _designs = _$v.designs?.toBuilder();
_tokens = _$v.tokens?.toBuilder(); _tokens = _$v.tokens?.toBuilder();
_webhooks = _$v.webhooks?.toBuilder();
_paymentTerms = _$v.paymentTerms?.toBuilder(); _paymentTerms = _$v.paymentTerms?.toBuilder();
_userMap = _$v.userMap?.toBuilder(); _userMap = _$v.userMap?.toBuilder();
_customFields = _$v.customFields?.toBuilder(); _customFields = _$v.customFields?.toBuilder();
@ -3590,6 +3615,7 @@ class CompanyEntityBuilder
vendors: vendors.build(), vendors: vendors.build(),
designs: designs.build(), designs: designs.build(),
tokens: tokens.build(), tokens: tokens.build(),
webhooks: webhooks.build(),
paymentTerms: paymentTerms.build(), paymentTerms: paymentTerms.build(),
userMap: userMap.build(), userMap: userMap.build(),
customFields: customFields.build(), customFields: customFields.build(),
@ -3651,6 +3677,8 @@ class CompanyEntityBuilder
designs.build(); designs.build();
_$failedField = 'tokens'; _$failedField = 'tokens';
tokens.build(); tokens.build();
_$failedField = 'webhooks';
webhooks.build();
_$failedField = 'paymentTerms'; _$failedField = 'paymentTerms';
paymentTerms.build(); paymentTerms.build();
_$failedField = 'userMap'; _$failedField = 'userMap';

View File

@ -39,6 +39,8 @@ class EntityType extends EnumClass {
static const EntityType design = _$design; static const EntityType design = _$design;
// STARTER: entity type - do not remove comment // STARTER: entity type - do not remove comment
static const EntityType webhook = _$webhook;
static const EntityType token = _$token; static const EntityType token = _$token;
static const EntityType paymentTerm = _$paymentTerm; static const EntityType paymentTerm = _$paymentTerm;

View File

@ -30,6 +30,7 @@ const EntityType _$gateway = const EntityType._('gateway');
const EntityType _$gatewayToken = const EntityType._('gatewayToken'); const EntityType _$gatewayToken = const EntityType._('gatewayToken');
const EntityType _$invoiceItem = const EntityType._('invoiceItem'); const EntityType _$invoiceItem = const EntityType._('invoiceItem');
const EntityType _$design = const EntityType._('design'); const EntityType _$design = const EntityType._('design');
const EntityType _$webhook = const EntityType._('webhook');
const EntityType _$token = const EntityType._('token'); const EntityType _$token = const EntityType._('token');
const EntityType _$paymentTerm = const EntityType._('paymentTerm'); const EntityType _$paymentTerm = const EntityType._('paymentTerm');
const EntityType _$quoteItem = const EntityType._('quoteItem'); const EntityType _$quoteItem = const EntityType._('quoteItem');
@ -97,6 +98,8 @@ EntityType _$typeValueOf(String name) {
return _$invoiceItem; return _$invoiceItem;
case 'design': case 'design':
return _$design; return _$design;
case 'webhook':
return _$webhook;
case 'token': case 'token':
return _$token; return _$token;
case 'paymentTerm': case 'paymentTerm':
@ -160,6 +163,7 @@ final BuiltSet<EntityType> _$typeValues =
_$gatewayToken, _$gatewayToken,
_$invoiceItem, _$invoiceItem,
_$design, _$design,
_$webhook,
_$token, _$token,
_$paymentTerm, _$paymentTerm,
_$quoteItem, _$quoteItem,

View File

@ -316,10 +316,12 @@ abstract class ExpenseEntity extends Object
.compareTo(vendorB.listDisplayName.toLowerCase()); .compareTo(vendorB.listDisplayName.toLowerCase());
break; break;
case EntityFields.state: case EntityFields.state:
final stateA = EntityState.valueOf(expenseA.entityState) ?? EntityState.active; final stateA =
final stateB = EntityState.valueOf(expenseB.entityState) ?? EntityState.active; EntityState.valueOf(expenseA.entityState) ?? EntityState.active;
response = stateA.name.toLowerCase() final stateB =
.compareTo(stateB.name.toLowerCase()); EntityState.valueOf(expenseB.entityState) ?? EntityState.active;
response =
stateA.name.toLowerCase().compareTo(stateB.name.toLowerCase());
break; break;
case ExpenseFields.publicNotes: case ExpenseFields.publicNotes:
response = expenseA.publicNotes response = expenseA.publicNotes

View File

@ -10,6 +10,7 @@ export 'package:invoiceninja_flutter/data/models/document_model.dart';
export 'package:invoiceninja_flutter/data/models/entities.dart'; export 'package:invoiceninja_flutter/data/models/entities.dart';
export 'package:invoiceninja_flutter/data/models/expense_model.dart'; export 'package:invoiceninja_flutter/data/models/expense_model.dart';
export 'package:invoiceninja_flutter/data/models/token_model.dart'; export 'package:invoiceninja_flutter/data/models/token_model.dart';
export 'package:invoiceninja_flutter/data/models/webhook_model.dart';
export 'package:invoiceninja_flutter/data/models/invoice_model.dart'; export 'package:invoiceninja_flutter/data/models/invoice_model.dart';
export 'package:invoiceninja_flutter/data/models/payment_model.dart'; export 'package:invoiceninja_flutter/data/models/payment_model.dart';
export 'package:invoiceninja_flutter/data/models/product_model.dart'; export 'package:invoiceninja_flutter/data/models/product_model.dart';

View File

@ -36,11 +36,11 @@ import 'package:invoiceninja_flutter/redux/task/task_state.dart';
import 'package:invoiceninja_flutter/redux/project/project_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/payment/payment_state.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_state.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_state.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
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'; import 'package:invoiceninja_flutter/data/models/token_model.dart';
import 'package:invoiceninja_flutter/redux/token/token_state.dart'; import 'package:invoiceninja_flutter/redux/token/token_state.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart';
import 'package:invoiceninja_flutter/data/models/design_model.dart'; import 'package:invoiceninja_flutter/data/models/design_model.dart';
import 'package:invoiceninja_flutter/redux/design/design_state.dart'; import 'package:invoiceninja_flutter/redux/design/design_state.dart';
@ -116,8 +116,12 @@ part 'serializers.g.dart';
TaxRateItemResponse, TaxRateItemResponse,
TaxRateListResponse, TaxRateListResponse,
// STARTER: serializers - do not remove comment // STARTER: serializers - do not remove comment
TokenEntity, TokenListResponse, TokenItemResponse, WebhookEntity,
WebhookListResponse,
WebhookItemResponse,
TokenEntity,
TokenListResponse,
TokenItemResponse,
PaymentTermEntity, PaymentTermEntity,
PaymentTermListResponse, PaymentTermListResponse,
PaymentTermItemResponse, PaymentTermItemResponse,

View File

@ -169,6 +169,11 @@ Serializers _$serializers = (new Serializers().toBuilder()
..add(VendorListResponse.serializer) ..add(VendorListResponse.serializer)
..add(VendorState.serializer) ..add(VendorState.serializer)
..add(VendorUIState.serializer) ..add(VendorUIState.serializer)
..add(WebhookEntity.serializer)
..add(WebhookItemResponse.serializer)
..add(WebhookListResponse.serializer)
..add(WebhookState.serializer)
..add(WebhookUIState.serializer)
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(ClientEntity)]), const FullType(BuiltList, const [const FullType(ClientEntity)]),
() => new ListBuilder<ClientEntity>()) () => new ListBuilder<ClientEntity>())
@ -303,8 +308,10 @@ Serializers _$serializers = (new Serializers().toBuilder()
BuiltList, const [const FullType(ExpenseCategoryEntity)]), BuiltList, const [const FullType(ExpenseCategoryEntity)]),
() => new ListBuilder<ExpenseCategoryEntity>()) () => new ListBuilder<ExpenseCategoryEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltMap, const FullType(BuiltMap, const [
const [const FullType(String), const FullType(ExpenseCategoryEntity)]), const FullType(String),
const FullType(ExpenseCategoryEntity)
]),
() => new MapBuilder<String, ExpenseCategoryEntity>()) () => new MapBuilder<String, ExpenseCategoryEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(UserEntity)]), const FullType(BuiltList, const [const FullType(UserEntity)]),
@ -345,6 +352,9 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(TokenEntity)]), const FullType(BuiltList, const [const FullType(TokenEntity)]),
() => new ListBuilder<TokenEntity>()) () => new ListBuilder<TokenEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(WebhookEntity)]),
() => new ListBuilder<WebhookEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(PaymentTermEntity)]), const FullType(BuiltList, const [const FullType(PaymentTermEntity)]),
() => new ListBuilder<PaymentTermEntity>()) () => new ListBuilder<PaymentTermEntity>())
@ -366,10 +376,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
const FullType(BuiltList, const [const FullType(InvoiceEntity)]), const FullType(BuiltList, const [const FullType(InvoiceEntity)]),
() => new ListBuilder<InvoiceEntity>()) () => new ListBuilder<InvoiceEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(InvoiceEntity)]), const FullType(BuiltList, const [const FullType(InvoiceEntity)]), () => new ListBuilder<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(InvitationEntity)]), () => new ListBuilder<InvitationEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(DocumentEntity)]), () => new ListBuilder<DocumentEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(DocumentEntity)]), () => new ListBuilder<DocumentEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(LanguageEntity)]), () => new ListBuilder<LanguageEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(LanguageEntity)]), () => new ListBuilder<LanguageEntity>())
@ -392,6 +400,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserEntity)]), () => new ListBuilder<UserEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserEntity)]), () => new ListBuilder<UserEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(VendorContactEntity)]), () => new ListBuilder<VendorContactEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(VendorContactEntity)]), () => new ListBuilder<VendorContactEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(VendorEntity)]), () => new ListBuilder<VendorEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(VendorEntity)]), () => new ListBuilder<VendorEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(WebhookEntity)]), () => new ListBuilder<WebhookEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltMap, const [ const FullType(BuiltMap, const [
const FullType(String), const FullType(String),
@ -461,6 +470,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(UserEntity)]), () => new MapBuilder<String, UserEntity>()) ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(UserEntity)]), () => new MapBuilder<String, UserEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(VendorEntity)]), () => new MapBuilder<String, VendorEntity>()) ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(VendorEntity)]), () => new MapBuilder<String, VendorEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(WebhookEntity)]), () => new MapBuilder<String, WebhookEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>()))
.build(); .build();

View File

@ -99,7 +99,6 @@ abstract class TokenEntity extends Object
return utf8.decode(base64Decode(value)); return utf8.decode(base64Decode(value));
} }
@override @override
String get listDisplayName { String get listDisplayName {
return name; return name;

View File

@ -0,0 +1,185 @@
import 'dart:convert';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
part 'webhook_model.g.dart';
abstract class WebhookListResponse
implements Built<WebhookListResponse, WebhookListResponseBuilder> {
factory WebhookListResponse([void updates(WebhookListResponseBuilder b)]) =
_$WebhookListResponse;
WebhookListResponse._();
@override
@memoized
int get hashCode;
BuiltList<WebhookEntity> get data;
static Serializer<WebhookListResponse> get serializer =>
_$webhookListResponseSerializer;
}
abstract class WebhookItemResponse
implements Built<WebhookItemResponse, WebhookItemResponseBuilder> {
factory WebhookItemResponse([void updates(WebhookItemResponseBuilder b)]) =
_$WebhookItemResponse;
WebhookItemResponse._();
@override
@memoized
int get hashCode;
WebhookEntity get data;
static Serializer<WebhookItemResponse> get serializer =>
_$webhookItemResponseSerializer;
}
class WebhookFields {
static const String name = 'name';
static const String custom1 = 'custom1';
static const String custom2 = 'custom2';
}
abstract class WebhookEntity extends Object
with BaseEntity, SelectableEntity
implements Built<WebhookEntity, WebhookEntityBuilder> {
factory WebhookEntity({String id, AppState state}) {
return _$WebhookEntity._(
id: id ?? BaseEntity.nextId,
isChanged: false,
name: '',
webhook: '',
updatedAt: 0,
archivedAt: 0,
isDeleted: false,
createdAt: 0,
assignedUserId: '',
createdUserId: '',
);
}
WebhookEntity._();
@override
@memoized
int get hashCode;
@override
EntityType get entityType {
return EntityType.webhook;
}
// TODO remove this
@override
@nullable
String get id;
String get webhook;
String get name;
String get obscuredWebhook => base64Encode(utf8.encode(webhook));
static String unobscureWebhook(String value) {
if (value == null || value.isEmpty) {
return null;
}
return utf8.decode(base64Decode(value));
}
@override
String get listDisplayName {
return name;
}
int compareTo(WebhookEntity webhook, String sortField, bool sortAscending) {
int response = 0;
final WebhookEntity webhookA = sortAscending ? this : webhook;
final WebhookEntity webhookB = sortAscending ? webhook : this;
switch (sortField) {
case WebhookFields.name:
response =
webhookA.name.toLowerCase().compareTo(webhookB.name.toLowerCase());
break;
default:
print('## ERROR: sort by webhook.$sortField is not implemented');
break;
}
return response;
}
@override
bool matchesFilter(String filter) {
if (filter == null || filter.isEmpty) {
return true;
}
filter = filter.toLowerCase();
if (name.toLowerCase().contains(filter)) {
return true;
}
return false;
}
@override
String matchesFilterValue(String filter) {
if (filter == null || filter.isEmpty) {
return null;
}
return null;
}
@override
List<EntityAction> getActions(
{UserCompanyEntity userCompany,
ClientEntity client,
bool includeEdit = false,
bool multiselect = false}) {
final actions = <EntityAction>[];
// TODO remove ??
if (!(isDeleted ?? false)) {
if (includeEdit && userCompany.canEditEntity(this)) {
actions.add(EntityAction.edit);
}
if (userCompany.canEditEntity(this)) {
actions.add(EntityAction.settings);
}
if (userCompany.canCreate(EntityType.client)) {
actions.add(EntityAction.newClient);
}
}
if (actions.isNotEmpty) {
actions.add(null);
}
return actions..addAll(super.getActions(userCompany: userCompany));
}
@override
double get listDisplayAmount => null;
@override
FormatNumberType get listDisplayAmountType => null;
static Serializer<WebhookEntity> get serializer => _$webhookEntitySerializer;
}

View File

@ -0,0 +1,631 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'webhook_model.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<WebhookListResponse> _$webhookListResponseSerializer =
new _$WebhookListResponseSerializer();
Serializer<WebhookItemResponse> _$webhookItemResponseSerializer =
new _$WebhookItemResponseSerializer();
Serializer<WebhookEntity> _$webhookEntitySerializer =
new _$WebhookEntitySerializer();
class _$WebhookListResponseSerializer
implements StructuredSerializer<WebhookListResponse> {
@override
final Iterable<Type> types = const [
WebhookListResponse,
_$WebhookListResponse
];
@override
final String wireName = 'WebhookListResponse';
@override
Iterable<Object> serialize(
Serializers serializers, WebhookListResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType:
const FullType(BuiltList, const [const FullType(WebhookEntity)])),
];
return result;
}
@override
WebhookListResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new WebhookListResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'data':
result.data.replace(serializers.deserialize(value,
specifiedType: const FullType(
BuiltList, const [const FullType(WebhookEntity)]))
as BuiltList<Object>);
break;
}
}
return result.build();
}
}
class _$WebhookItemResponseSerializer
implements StructuredSerializer<WebhookItemResponse> {
@override
final Iterable<Type> types = const [
WebhookItemResponse,
_$WebhookItemResponse
];
@override
final String wireName = 'WebhookItemResponse';
@override
Iterable<Object> serialize(
Serializers serializers, WebhookItemResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType: const FullType(WebhookEntity)),
];
return result;
}
@override
WebhookItemResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new WebhookItemResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'data':
result.data.replace(serializers.deserialize(value,
specifiedType: const FullType(WebhookEntity)) as WebhookEntity);
break;
}
}
return result.build();
}
}
class _$WebhookEntitySerializer implements StructuredSerializer<WebhookEntity> {
@override
final Iterable<Type> types = const [WebhookEntity, _$WebhookEntity];
@override
final String wireName = 'WebhookEntity';
@override
Iterable<Object> serialize(Serializers serializers, WebhookEntity object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'webhook',
serializers.serialize(object.webhook,
specifiedType: const FullType(String)),
'name',
serializers.serialize(object.name, specifiedType: const FullType(String)),
'created_at',
serializers.serialize(object.createdAt,
specifiedType: const FullType(int)),
'updated_at',
serializers.serialize(object.updatedAt,
specifiedType: const FullType(int)),
'archived_at',
serializers.serialize(object.archivedAt,
specifiedType: const FullType(int)),
];
if (object.id != null) {
result
..add('id')
..add(serializers.serialize(object.id,
specifiedType: const FullType(String)));
}
if (object.isChanged != null) {
result
..add('isChanged')
..add(serializers.serialize(object.isChanged,
specifiedType: const FullType(bool)));
}
if (object.isDeleted != null) {
result
..add('is_deleted')
..add(serializers.serialize(object.isDeleted,
specifiedType: const FullType(bool)));
}
if (object.createdUserId != null) {
result
..add('user_id')
..add(serializers.serialize(object.createdUserId,
specifiedType: const FullType(String)));
}
if (object.assignedUserId != null) {
result
..add('assigned_user_id')
..add(serializers.serialize(object.assignedUserId,
specifiedType: const FullType(String)));
}
return result;
}
@override
WebhookEntity deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new WebhookEntityBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'id':
result.id = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'webhook':
result.webhook = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'name':
result.name = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'isChanged':
result.isChanged = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
case 'created_at':
result.createdAt = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'updated_at':
result.updatedAt = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'archived_at':
result.archivedAt = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'is_deleted':
result.isDeleted = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
case 'user_id':
result.createdUserId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'assigned_user_id':
result.assignedUserId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$WebhookListResponse extends WebhookListResponse {
@override
final BuiltList<WebhookEntity> data;
factory _$WebhookListResponse(
[void Function(WebhookListResponseBuilder) updates]) =>
(new WebhookListResponseBuilder()..update(updates)).build();
_$WebhookListResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('WebhookListResponse', 'data');
}
}
@override
WebhookListResponse rebuild(
void Function(WebhookListResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
WebhookListResponseBuilder toBuilder() =>
new WebhookListResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is WebhookListResponse && data == other.data;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('WebhookListResponse')
..add('data', data))
.toString();
}
}
class WebhookListResponseBuilder
implements Builder<WebhookListResponse, WebhookListResponseBuilder> {
_$WebhookListResponse _$v;
ListBuilder<WebhookEntity> _data;
ListBuilder<WebhookEntity> get data =>
_$this._data ??= new ListBuilder<WebhookEntity>();
set data(ListBuilder<WebhookEntity> data) => _$this._data = data;
WebhookListResponseBuilder();
WebhookListResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(WebhookListResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$WebhookListResponse;
}
@override
void update(void Function(WebhookListResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$WebhookListResponse build() {
_$WebhookListResponse _$result;
try {
_$result = _$v ?? new _$WebhookListResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'WebhookListResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$WebhookItemResponse extends WebhookItemResponse {
@override
final WebhookEntity data;
factory _$WebhookItemResponse(
[void Function(WebhookItemResponseBuilder) updates]) =>
(new WebhookItemResponseBuilder()..update(updates)).build();
_$WebhookItemResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('WebhookItemResponse', 'data');
}
}
@override
WebhookItemResponse rebuild(
void Function(WebhookItemResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
WebhookItemResponseBuilder toBuilder() =>
new WebhookItemResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is WebhookItemResponse && data == other.data;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('WebhookItemResponse')
..add('data', data))
.toString();
}
}
class WebhookItemResponseBuilder
implements Builder<WebhookItemResponse, WebhookItemResponseBuilder> {
_$WebhookItemResponse _$v;
WebhookEntityBuilder _data;
WebhookEntityBuilder get data => _$this._data ??= new WebhookEntityBuilder();
set data(WebhookEntityBuilder data) => _$this._data = data;
WebhookItemResponseBuilder();
WebhookItemResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(WebhookItemResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$WebhookItemResponse;
}
@override
void update(void Function(WebhookItemResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$WebhookItemResponse build() {
_$WebhookItemResponse _$result;
try {
_$result = _$v ?? new _$WebhookItemResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'WebhookItemResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$WebhookEntity extends WebhookEntity {
@override
final String id;
@override
final String webhook;
@override
final String name;
@override
final bool isChanged;
@override
final int createdAt;
@override
final int updatedAt;
@override
final int archivedAt;
@override
final bool isDeleted;
@override
final String createdUserId;
@override
final String assignedUserId;
factory _$WebhookEntity([void Function(WebhookEntityBuilder) updates]) =>
(new WebhookEntityBuilder()..update(updates)).build();
_$WebhookEntity._(
{this.id,
this.webhook,
this.name,
this.isChanged,
this.createdAt,
this.updatedAt,
this.archivedAt,
this.isDeleted,
this.createdUserId,
this.assignedUserId})
: super._() {
if (webhook == null) {
throw new BuiltValueNullFieldError('WebhookEntity', 'webhook');
}
if (name == null) {
throw new BuiltValueNullFieldError('WebhookEntity', 'name');
}
if (createdAt == null) {
throw new BuiltValueNullFieldError('WebhookEntity', 'createdAt');
}
if (updatedAt == null) {
throw new BuiltValueNullFieldError('WebhookEntity', 'updatedAt');
}
if (archivedAt == null) {
throw new BuiltValueNullFieldError('WebhookEntity', 'archivedAt');
}
}
@override
WebhookEntity rebuild(void Function(WebhookEntityBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
WebhookEntityBuilder toBuilder() => new WebhookEntityBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is WebhookEntity &&
id == other.id &&
webhook == other.webhook &&
name == other.name &&
isChanged == other.isChanged &&
createdAt == other.createdAt &&
updatedAt == other.updatedAt &&
archivedAt == other.archivedAt &&
isDeleted == other.isDeleted &&
createdUserId == other.createdUserId &&
assignedUserId == other.assignedUserId;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf($jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc($jc($jc(0, id.hashCode), webhook.hashCode),
name.hashCode),
isChanged.hashCode),
createdAt.hashCode),
updatedAt.hashCode),
archivedAt.hashCode),
isDeleted.hashCode),
createdUserId.hashCode),
assignedUserId.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('WebhookEntity')
..add('id', id)
..add('webhook', webhook)
..add('name', name)
..add('isChanged', isChanged)
..add('createdAt', createdAt)
..add('updatedAt', updatedAt)
..add('archivedAt', archivedAt)
..add('isDeleted', isDeleted)
..add('createdUserId', createdUserId)
..add('assignedUserId', assignedUserId))
.toString();
}
}
class WebhookEntityBuilder
implements Builder<WebhookEntity, WebhookEntityBuilder> {
_$WebhookEntity _$v;
String _id;
String get id => _$this._id;
set id(String id) => _$this._id = id;
String _webhook;
String get webhook => _$this._webhook;
set webhook(String webhook) => _$this._webhook = webhook;
String _name;
String get name => _$this._name;
set name(String name) => _$this._name = name;
bool _isChanged;
bool get isChanged => _$this._isChanged;
set isChanged(bool isChanged) => _$this._isChanged = isChanged;
int _createdAt;
int get createdAt => _$this._createdAt;
set createdAt(int createdAt) => _$this._createdAt = createdAt;
int _updatedAt;
int get updatedAt => _$this._updatedAt;
set updatedAt(int updatedAt) => _$this._updatedAt = updatedAt;
int _archivedAt;
int get archivedAt => _$this._archivedAt;
set archivedAt(int archivedAt) => _$this._archivedAt = archivedAt;
bool _isDeleted;
bool get isDeleted => _$this._isDeleted;
set isDeleted(bool isDeleted) => _$this._isDeleted = isDeleted;
String _createdUserId;
String get createdUserId => _$this._createdUserId;
set createdUserId(String createdUserId) =>
_$this._createdUserId = createdUserId;
String _assignedUserId;
String get assignedUserId => _$this._assignedUserId;
set assignedUserId(String assignedUserId) =>
_$this._assignedUserId = assignedUserId;
WebhookEntityBuilder();
WebhookEntityBuilder get _$this {
if (_$v != null) {
_id = _$v.id;
_webhook = _$v.webhook;
_name = _$v.name;
_isChanged = _$v.isChanged;
_createdAt = _$v.createdAt;
_updatedAt = _$v.updatedAt;
_archivedAt = _$v.archivedAt;
_isDeleted = _$v.isDeleted;
_createdUserId = _$v.createdUserId;
_assignedUserId = _$v.assignedUserId;
_$v = null;
}
return this;
}
@override
void replace(WebhookEntity other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$WebhookEntity;
}
@override
void update(void Function(WebhookEntityBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$WebhookEntity build() {
final _$result = _$v ??
new _$WebhookEntity._(
id: id,
webhook: webhook,
name: name,
isChanged: isChanged,
createdAt: createdAt,
updatedAt: updatedAt,
archivedAt: archivedAt,
isDeleted: isDeleted,
createdUserId: createdUserId,
assignedUserId: assignedUserId);
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

View File

@ -0,0 +1,78 @@
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'package:invoiceninja_flutter/.env.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/constants.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 WebhookRepository {
const WebhookRepository({
this.webClient = const WebClient(),
});
final WebClient webClient;
Future<WebhookEntity> loadItem(
Credentials credentials, String entityId) async {
final dynamic response = await webClient.get(
'${credentials.url}/webhooks/$entityId', credentials.token);
final WebhookItemResponse webhookResponse =
serializers.deserializeWith(WebhookItemResponse.serializer, response);
return webhookResponse.data;
}
Future<BuiltList<WebhookEntity>> loadList(
Credentials credentials, int updatedAt) async {
String url = credentials.url + '/webhooks?';
if (updatedAt > 0) {
url += '&updated_at=${updatedAt - kUpdatedAtBufferSeconds}';
}
final dynamic response = await webClient.get(url, credentials.token);
final WebhookListResponse webhookResponse =
serializers.deserializeWith(WebhookListResponse.serializer, response);
return webhookResponse.data;
}
Future<List<WebhookEntity>> bulkAction(
Credentials credentials, List<String> ids, EntityAction action) async {
final url = credentials.url + '/webhooks/bulk';
final dynamic response = await webClient.post(url, credentials.token,
data: json.encode({'ids': ids, 'action': '$action'}));
final WebhookListResponse webhookResponse =
serializers.deserializeWith(WebhookListResponse.serializer, response);
return webhookResponse.data.toList();
}
Future<WebhookEntity> saveData(
Credentials credentials, WebhookEntity webhook) async {
final data = serializers.serializeWith(WebhookEntity.serializer, webhook);
dynamic response;
if (webhook.isNew) {
response = await webClient.post(
credentials.url + '/webhooks', credentials.token,
data: json.encode(data));
} else {
var url = '${credentials.url}/webhooks/${webhook.id}';
response =
await webClient.put(url, credentials.token, data: json.encode(data));
}
final WebhookItemResponse webhookResponse =
serializers.deserializeWith(WebhookItemResponse.serializer, response);
return webhookResponse.data;
}
}

View File

@ -39,6 +39,13 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:invoiceninja_flutter/utils/web_stub.dart' import 'package:invoiceninja_flutter/utils/web_stub.dart'
if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart'; if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
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';
import 'package:invoiceninja_flutter/ui/webhook/webhook_screen_vm.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_middleware.dart';
import 'package:invoiceninja_flutter/redux/token/token_middleware.dart'; import 'package:invoiceninja_flutter/redux/token/token_middleware.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_middleware.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_middleware.dart';
@ -70,6 +77,7 @@ void main({bool isTesting = false}) async {
..addAll(createStoreSettingsMiddleware()) ..addAll(createStoreSettingsMiddleware())
..addAll(createStoreReportsMiddleware()) ..addAll(createStoreReportsMiddleware())
// STARTER: middleware - do not remove comment // STARTER: middleware - do not remove comment
..addAll(createStoreWebhooksMiddleware())
..addAll(createStoreTokensMiddleware()) ..addAll(createStoreTokensMiddleware())
..addAll(createStorePaymentTermsMiddleware()) ..addAll(createStorePaymentTermsMiddleware())
..addAll(createStoreDesignsMiddleware()) ..addAll(createStoreDesignsMiddleware())

View File

@ -51,6 +51,11 @@ import 'package:local_auth/local_auth.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
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';
import 'package:invoiceninja_flutter/ui/webhook/webhook_screen_vm.dart';
import 'package:invoiceninja_flutter/ui/token/token_screen.dart'; import 'package:invoiceninja_flutter/ui/token/token_screen.dart';
import 'package:invoiceninja_flutter/ui/token/edit/token_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/token/edit/token_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/token/view/token_view_vm.dart'; import 'package:invoiceninja_flutter/ui/token/view/token_view_vm.dart';
@ -255,6 +260,10 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
QuoteEditScreen.route: (context) => QuoteEditScreen(), QuoteEditScreen.route: (context) => QuoteEditScreen(),
QuoteEmailScreen.route: (context) => QuoteEmailScreen(), QuoteEmailScreen.route: (context) => QuoteEmailScreen(),
// STARTER: routes - do not remove comment // STARTER: routes - do not remove comment
WebhookScreen.route: (context) => WebhookScreenBuilder(),
WebhookViewScreen.route: (context) => WebhookViewScreen(),
WebhookEditScreen.route: (context) => WebhookEditScreen(),
TokenScreen.route: (context) => TokenScreenBuilder(), TokenScreen.route: (context) => TokenScreenBuilder(),
TokenViewScreen.route: (context) => TokenViewScreen(), TokenViewScreen.route: (context) => TokenViewScreen(),
TokenEditScreen.route: (context) => TokenEditScreen(), TokenEditScreen.route: (context) => TokenEditScreen(),

View File

@ -33,6 +33,8 @@ import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/token/token_actions.dart'; import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart';
@ -256,6 +258,10 @@ void viewEntitiesByType({
action = ViewGroupList(navigator: navigator); action = ViewGroupList(navigator: navigator);
break; break;
// STARTER: view list - do not remove comment // STARTER: view list - do not remove comment
case EntityType.webhook:
store.dispatch(ViewWebhookList(navigator: navigator));
break;
case EntityType.token: case EntityType.token:
store.dispatch(ViewTokenList(navigator: navigator)); store.dispatch(ViewTokenList(navigator: navigator));
break; break;
@ -400,6 +406,14 @@ void viewEntityById({
)); ));
break; break;
// STARTER: view - do not remove comment // STARTER: view - do not remove comment
case EntityType.webhook:
store.dispatch(ViewWebhook(
webhookId: entityId,
navigator: navigator,
force: force,
));
break;
case EntityType.token: case EntityType.token:
store.dispatch(ViewToken( store.dispatch(ViewToken(
tokenId: entityId, tokenId: entityId,
@ -546,6 +560,14 @@ void createEntityByType(
)); ));
break; break;
// STARTER: create type - do not remove comment // STARTER: create type - do not remove comment
case EntityType.webhook:
store.dispatch(EditWebhook(
navigator: navigator,
force: force,
webhook: WebhookEntity(state: state),
));
break;
case EntityType.token: case EntityType.token:
store.dispatch(EditToken( store.dispatch(EditToken(
navigator: navigator, navigator: navigator,
@ -722,6 +744,15 @@ void createEntity({
)); ));
break; break;
// STARTER: create - do not remove comment // STARTER: create - do not remove comment
case EntityType.webhook:
store.dispatch(EditWebhook(
navigator: navigator,
webhook: entity,
force: force,
completer: completer,
));
break;
case EntityType.token: case EntityType.token:
store.dispatch(EditToken( store.dispatch(EditToken(
navigator: navigator, navigator: navigator,
@ -943,6 +974,19 @@ void editEntityById(
)); ));
break; break;
// STARTER: edit - do not remove comment // STARTER: edit - do not remove comment
case EntityType.webhook:
store.dispatch(EditWebhook(
webhook: map[entityId],
navigator: navigator,
completer: completer ??
snackBarCompleter<WebhookEntity>(
context,
entity.isNew
? localization.createdWebhook
: localization.updatedWebhook),
));
break;
case EntityType.token: case EntityType.token:
store.dispatch(EditToken( store.dispatch(EditToken(
token: map[entityId], token: map[entityId],
@ -1072,6 +1116,10 @@ void handleEntitiesActions(
handleDocumentAction(context, entities, action); handleDocumentAction(context, entities, action);
break; break;
// STARTER: actions - do not remove comment // STARTER: actions - do not remove comment
case EntityType.webhook:
handleWebhookAction(context, entities, action);
break;
case EntityType.token: case EntityType.token:
handleTokenAction(context, entities, action); handleTokenAction(context, entities, action);
break; break;

View File

@ -22,6 +22,8 @@ import 'package:invoiceninja_flutter/redux/company/company_reducer.dart';
import 'package:invoiceninja_flutter/redux/static/static_reducer.dart'; import 'package:invoiceninja_flutter/redux/static/static_reducer.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/token/token_actions.dart'; import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart';
@ -93,6 +95,10 @@ final lastErrorReducer = combineReducers<String>([
return '${action.error}'; return '${action.error}';
}), }),
// STARTER: errors - do not remove comment // STARTER: errors - do not remove comment
TypedReducer<String, LoadWebhooksFailure>((state, action) {
return '${action.error}';
}),
TypedReducer<String, LoadTokensFailure>((state, action) { TypedReducer<String, LoadTokensFailure>((state, action) {
return '${action.error}'; return '${action.error}';
}), }),

View File

@ -46,6 +46,12 @@ import 'package:invoiceninja_flutter/ui/design/edit/design_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/product/edit/product_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/product/edit/product_edit_vm.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
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_state.dart';
import 'package:invoiceninja_flutter/ui/webhook/edit/webhook_edit_vm.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_selectors.dart';
import 'package:invoiceninja_flutter/redux/token/token_state.dart'; import 'package:invoiceninja_flutter/redux/token/token_state.dart';
import 'package:invoiceninja_flutter/ui/token/edit/token_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/token/edit/token_edit_vm.dart';
import 'package:invoiceninja_flutter/redux/token/token_selectors.dart'; import 'package:invoiceninja_flutter/redux/token/token_selectors.dart';
@ -210,6 +216,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
case EntityType.invoice: case EntityType.invoice:
return invoiceState.map; return invoiceState.map;
// STARTER: states switch map - do not remove comment // STARTER: states switch map - do not remove comment
case EntityType.webhook:
return webhookState.map;
case EntityType.token: case EntityType.token:
return tokenState.map; return tokenState.map;
@ -279,6 +288,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
case EntityType.invoice: case EntityType.invoice:
return invoiceState.list; return invoiceState.list;
// STARTER: states switch list - do not remove comment // STARTER: states switch list - do not remove comment
case EntityType.webhook:
return webhookState.list;
case EntityType.token: case EntityType.token:
return tokenState.list; return tokenState.list;
@ -327,6 +339,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
case EntityType.invoice: case EntityType.invoice:
return invoiceUIState; return invoiceUIState;
// STARTER: states switch - do not remove comment // STARTER: states switch - do not remove comment
case EntityType.webhook:
return webhookUIState;
case EntityType.token: case EntityType.token:
return tokenUIState; return tokenUIState;
@ -387,6 +402,10 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
ListUIState get invoiceListState => uiState.invoiceUIState.listUIState; ListUIState get invoiceListState => uiState.invoiceUIState.listUIState;
// STARTER: state getters - do not remove comment // STARTER: state getters - do not remove comment
WebhookState get webhookState => userCompanyState.webhookState;
ListUIState get webhookListState => uiState.webhookUIState.listUIState;
WebhookUIState get webhookUIState => uiState.webhookUIState;
TokenState get tokenState => userCompanyState.tokenState; TokenState get tokenState => userCompanyState.tokenState;
ListUIState get tokenListState => uiState.tokenUIState.listUIState; ListUIState get tokenListState => uiState.tokenUIState.listUIState;
TokenUIState get tokenUIState => uiState.tokenUIState; TokenUIState get tokenUIState => uiState.tokenUIState;
@ -511,6 +530,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
case CreditEditScreen.route: case CreditEditScreen.route:
return hasCreditChanges(creditUIState.editing, creditState.map); return hasCreditChanges(creditUIState.editing, creditState.map);
// STARTER: has changes - do not remove comment // STARTER: has changes - do not remove comment
case WebhookEditScreen.route:
return hasWebhookChanges(webhookUIState.editing, webhookState.map);
case TokenEditScreen.route: case TokenEditScreen.route:
return hasTokenChanges(tokenUIState.editing, tokenState.map); return hasTokenChanges(tokenUIState.editing, tokenState.map);

View File

@ -18,6 +18,8 @@ import 'package:invoiceninja_flutter/redux/payment/payment_reducer.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_reducer.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_reducer.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_reducer.dart';
import 'package:invoiceninja_flutter/redux/token/token_reducer.dart'; import 'package:invoiceninja_flutter/redux/token/token_reducer.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_reducer.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_reducer.dart';
@ -48,6 +50,7 @@ UserCompanyState companyReducer(UserCompanyState state, dynamic action) {
..vendorState.replace(vendorsReducer(state.vendorState, action)) ..vendorState.replace(vendorsReducer(state.vendorState, action))
..taskState.replace(tasksReducer(state.taskState, action)) ..taskState.replace(tasksReducer(state.taskState, action))
// STARTER: reducer - do not remove comment // STARTER: reducer - do not remove comment
..webhookState.replace(webhooksReducer(state.webhookState, action))
..tokenState.replace(tokensReducer(state.tokenState, action)) ..tokenState.replace(tokensReducer(state.tokenState, action))
..paymentTermState ..paymentTermState
.replace(paymentTermsReducer(state.paymentTermState, action)) .replace(paymentTermsReducer(state.paymentTermState, action))

View File

@ -8,6 +8,8 @@ import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart'; import 'package:built_value/serializer.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
import 'package:invoiceninja_flutter/redux/token/token_state.dart'; import 'package:invoiceninja_flutter/redux/token/token_state.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart';
@ -46,6 +48,8 @@ abstract class UserCompanyState
paymentState: PaymentState(), paymentState: PaymentState(),
quoteState: QuoteState(), quoteState: QuoteState(),
// STARTER: constructor - do not remove comment // STARTER: constructor - do not remove comment
webhookState: WebhookState(),
tokenState: TokenState(), tokenState: TokenState(),
paymentTermState: PaymentTermState(), paymentTermState: PaymentTermState(),
@ -88,6 +92,8 @@ abstract class UserCompanyState
QuoteState get quoteState; QuoteState get quoteState;
// STARTER: fields - do not remove comment // STARTER: fields - do not remove comment
WebhookState get webhookState;
TokenState get tokenState; TokenState get tokenState;
PaymentTermState get paymentTermState; PaymentTermState get paymentTermState;

View File

@ -52,6 +52,9 @@ class _$UserCompanyStateSerializer
'quoteState', 'quoteState',
serializers.serialize(object.quoteState, serializers.serialize(object.quoteState,
specifiedType: const FullType(QuoteState)), specifiedType: const FullType(QuoteState)),
'webhookState',
serializers.serialize(object.webhookState,
specifiedType: const FullType(WebhookState)),
'tokenState', 'tokenState',
serializers.serialize(object.tokenState, serializers.serialize(object.tokenState,
specifiedType: const FullType(TokenState)), specifiedType: const FullType(TokenState)),
@ -143,6 +146,10 @@ class _$UserCompanyStateSerializer
result.quoteState.replace(serializers.deserialize(value, result.quoteState.replace(serializers.deserialize(value,
specifiedType: const FullType(QuoteState)) as QuoteState); specifiedType: const FullType(QuoteState)) as QuoteState);
break; break;
case 'webhookState':
result.webhookState.replace(serializers.deserialize(value,
specifiedType: const FullType(WebhookState)) as WebhookState);
break;
case 'tokenState': case 'tokenState':
result.tokenState.replace(serializers.deserialize(value, result.tokenState.replace(serializers.deserialize(value,
specifiedType: const FullType(TokenState)) as TokenState); specifiedType: const FullType(TokenState)) as TokenState);
@ -343,6 +350,8 @@ class _$UserCompanyState extends UserCompanyState {
@override @override
final QuoteState quoteState; final QuoteState quoteState;
@override @override
final WebhookState webhookState;
@override
final TokenState tokenState; final TokenState tokenState;
@override @override
final PaymentTermState paymentTermState; final PaymentTermState paymentTermState;
@ -375,6 +384,7 @@ class _$UserCompanyState extends UserCompanyState {
this.projectState, this.projectState,
this.paymentState, this.paymentState,
this.quoteState, this.quoteState,
this.webhookState,
this.tokenState, this.tokenState,
this.paymentTermState, this.paymentTermState,
this.designState, this.designState,
@ -414,6 +424,9 @@ class _$UserCompanyState extends UserCompanyState {
if (quoteState == null) { if (quoteState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'quoteState'); throw new BuiltValueNullFieldError('UserCompanyState', 'quoteState');
} }
if (webhookState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'webhookState');
}
if (tokenState == null) { if (tokenState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'tokenState'); throw new BuiltValueNullFieldError('UserCompanyState', 'tokenState');
} }
@ -465,6 +478,7 @@ class _$UserCompanyState extends UserCompanyState {
projectState == other.projectState && projectState == other.projectState &&
paymentState == other.paymentState && paymentState == other.paymentState &&
quoteState == other.quoteState && quoteState == other.quoteState &&
webhookState == other.webhookState &&
tokenState == other.tokenState && tokenState == other.tokenState &&
paymentTermState == other.paymentTermState && paymentTermState == other.paymentTermState &&
designState == other.designState && designState == other.designState &&
@ -497,24 +511,27 @@ class _$UserCompanyState extends UserCompanyState {
$jc( $jc(
$jc( $jc(
$jc( $jc(
0, $jc(
userCompany 0,
userCompany
.hashCode),
documentState
.hashCode), .hashCode),
documentState productState
.hashCode), .hashCode),
productState clientState
.hashCode), .hashCode),
clientState invoiceState
.hashCode), .hashCode),
invoiceState expenseState
.hashCode), .hashCode),
expenseState vendorState
.hashCode), .hashCode),
vendorState.hashCode), taskState.hashCode),
taskState.hashCode), projectState.hashCode),
projectState.hashCode), paymentState.hashCode),
paymentState.hashCode), quoteState.hashCode),
quoteState.hashCode), webhookState.hashCode),
tokenState.hashCode), tokenState.hashCode),
paymentTermState.hashCode), paymentTermState.hashCode),
designState.hashCode), designState.hashCode),
@ -539,6 +556,7 @@ class _$UserCompanyState extends UserCompanyState {
..add('projectState', projectState) ..add('projectState', projectState)
..add('paymentState', paymentState) ..add('paymentState', paymentState)
..add('quoteState', quoteState) ..add('quoteState', quoteState)
..add('webhookState', webhookState)
..add('tokenState', tokenState) ..add('tokenState', tokenState)
..add('paymentTermState', paymentTermState) ..add('paymentTermState', paymentTermState)
..add('designState', designState) ..add('designState', designState)
@ -620,6 +638,12 @@ class UserCompanyStateBuilder
set quoteState(QuoteStateBuilder quoteState) => set quoteState(QuoteStateBuilder quoteState) =>
_$this._quoteState = quoteState; _$this._quoteState = quoteState;
WebhookStateBuilder _webhookState;
WebhookStateBuilder get webhookState =>
_$this._webhookState ??= new WebhookStateBuilder();
set webhookState(WebhookStateBuilder webhookState) =>
_$this._webhookState = webhookState;
TokenStateBuilder _tokenState; TokenStateBuilder _tokenState;
TokenStateBuilder get tokenState => TokenStateBuilder get tokenState =>
_$this._tokenState ??= new TokenStateBuilder(); _$this._tokenState ??= new TokenStateBuilder();
@ -682,6 +706,7 @@ class UserCompanyStateBuilder
_projectState = _$v.projectState?.toBuilder(); _projectState = _$v.projectState?.toBuilder();
_paymentState = _$v.paymentState?.toBuilder(); _paymentState = _$v.paymentState?.toBuilder();
_quoteState = _$v.quoteState?.toBuilder(); _quoteState = _$v.quoteState?.toBuilder();
_webhookState = _$v.webhookState?.toBuilder();
_tokenState = _$v.tokenState?.toBuilder(); _tokenState = _$v.tokenState?.toBuilder();
_paymentTermState = _$v.paymentTermState?.toBuilder(); _paymentTermState = _$v.paymentTermState?.toBuilder();
_designState = _$v.designState?.toBuilder(); _designState = _$v.designState?.toBuilder();
@ -725,6 +750,7 @@ class UserCompanyStateBuilder
projectState: projectState.build(), projectState: projectState.build(),
paymentState: paymentState.build(), paymentState: paymentState.build(),
quoteState: quoteState.build(), quoteState: quoteState.build(),
webhookState: webhookState.build(),
tokenState: tokenState.build(), tokenState: tokenState.build(),
paymentTermState: paymentTermState.build(), paymentTermState: paymentTermState.build(),
designState: designState.build(), designState: designState.build(),
@ -758,6 +784,8 @@ class UserCompanyStateBuilder
paymentState.build(); paymentState.build();
_$failedField = 'quoteState'; _$failedField = 'quoteState';
quoteState.build(); quoteState.build();
_$failedField = 'webhookState';
webhookState.build();
_$failedField = 'tokenState'; _$failedField = 'tokenState';
tokenState.build(); tokenState.build();
_$failedField = 'paymentTermState'; _$failedField = 'paymentTermState';

View File

@ -24,6 +24,8 @@ import 'package:invoiceninja_flutter/redux/user/user_actions.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart'; import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/token/token_actions.dart'; import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart';
@ -412,6 +414,15 @@ Reducer<BuiltList<HistoryRecord>> historyReducer = combineReducers([
_addToHistory(historyList, _addToHistory(historyList,
HistoryRecord(id: action.group.id, entityType: EntityType.group))), HistoryRecord(id: action.group.id, entityType: EntityType.group))),
// STARTER: history - do not remove comment // STARTER: history - do not remove comment
TypedReducer<BuiltList<HistoryRecord>, ViewWebhook>((historyList, action) =>
_addToHistory(historyList,
HistoryRecord(id: action.webhookId, entityType: EntityType.webhook))),
TypedReducer<BuiltList<HistoryRecord>, EditWebhook>((historyList, action) =>
_addToHistory(
historyList,
HistoryRecord(
id: action.webhook.id, entityType: EntityType.webhook))),
TypedReducer<BuiltList<HistoryRecord>, ViewToken>((historyList, action) => TypedReducer<BuiltList<HistoryRecord>, ViewToken>((historyList, action) =>
_addToHistory(historyList, _addToHistory(historyList,
HistoryRecord(id: action.tokenId, entityType: EntityType.token))), HistoryRecord(id: action.tokenId, entityType: EntityType.token))),

View File

@ -22,6 +22,8 @@ import 'package:invoiceninja_flutter/redux/quote/quote_reducer.dart';
import 'package:invoiceninja_flutter/redux/task/task_reducer.dart'; import 'package:invoiceninja_flutter/redux/task/task_reducer.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_reducer.dart'; import 'package:invoiceninja_flutter/redux/vendor/vendor_reducer.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_reducer.dart';
import 'package:invoiceninja_flutter/redux/token/token_reducer.dart'; import 'package:invoiceninja_flutter/redux/token/token_reducer.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_reducer.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_reducer.dart';
@ -65,6 +67,7 @@ UIState uiReducer(UIState state, dynamic action) {
.replace(dashboardUIReducer(state.dashboardUIState, action)) .replace(dashboardUIReducer(state.dashboardUIState, action))
..reportsUIState.replace(reportsUIReducer(state.reportsUIState, action)) ..reportsUIState.replace(reportsUIReducer(state.reportsUIState, action))
// STARTER: reducer - do not remove comment // STARTER: reducer - do not remove comment
..webhookUIState.replace(webhookUIReducer(state.webhookUIState, action))
..tokenUIState.replace(tokenUIReducer(state.tokenUIState, action)) ..tokenUIState.replace(tokenUIReducer(state.tokenUIState, action))
..paymentTermUIState ..paymentTermUIState
.replace(paymentTermUIReducer(state.paymentTermUIState, action)) .replace(paymentTermUIReducer(state.paymentTermUIState, action))

View File

@ -17,6 +17,8 @@ import 'package:invoiceninja_flutter/redux/task/task_state.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart'; import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
import 'package:invoiceninja_flutter/redux/token/token_state.dart'; import 'package:invoiceninja_flutter/redux/token/token_state.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart';
@ -44,6 +46,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
clientUIState: ClientUIState(), clientUIState: ClientUIState(),
invoiceUIState: InvoiceUIState(), invoiceUIState: InvoiceUIState(),
// STARTER: constructor - do not remove comment // STARTER: constructor - do not remove comment
webhookUIState: WebhookUIState(),
tokenUIState: TokenUIState(), tokenUIState: TokenUIState(),
paymentTermUIState: PaymentTermUIState(), paymentTermUIState: PaymentTermUIState(),
@ -98,6 +102,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
InvoiceUIState get invoiceUIState; InvoiceUIState get invoiceUIState;
// STARTER: properties - do not remove comment // STARTER: properties - do not remove comment
WebhookUIState get webhookUIState;
TokenUIState get tokenUIState; TokenUIState get tokenUIState;
PaymentTermUIState get paymentTermUIState; PaymentTermUIState get paymentTermUIState;

View File

@ -42,6 +42,9 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
'invoiceUIState', 'invoiceUIState',
serializers.serialize(object.invoiceUIState, serializers.serialize(object.invoiceUIState,
specifiedType: const FullType(InvoiceUIState)), specifiedType: const FullType(InvoiceUIState)),
'webhookUIState',
serializers.serialize(object.webhookUIState,
specifiedType: const FullType(WebhookUIState)),
'tokenUIState', 'tokenUIState',
serializers.serialize(object.tokenUIState, serializers.serialize(object.tokenUIState,
specifiedType: const FullType(TokenUIState)), specifiedType: const FullType(TokenUIState)),
@ -171,6 +174,10 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
result.invoiceUIState.replace(serializers.deserialize(value, result.invoiceUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(InvoiceUIState)) as InvoiceUIState); specifiedType: const FullType(InvoiceUIState)) as InvoiceUIState);
break; break;
case 'webhookUIState':
result.webhookUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(WebhookUIState)) as WebhookUIState);
break;
case 'tokenUIState': case 'tokenUIState':
result.tokenUIState.replace(serializers.deserialize(value, result.tokenUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(TokenUIState)) as TokenUIState); specifiedType: const FullType(TokenUIState)) as TokenUIState);
@ -274,6 +281,8 @@ class _$UIState extends UIState {
@override @override
final InvoiceUIState invoiceUIState; final InvoiceUIState invoiceUIState;
@override @override
final WebhookUIState webhookUIState;
@override
final TokenUIState tokenUIState; final TokenUIState tokenUIState;
@override @override
final PaymentTermUIState paymentTermUIState; final PaymentTermUIState paymentTermUIState;
@ -323,6 +332,7 @@ class _$UIState extends UIState {
this.productUIState, this.productUIState,
this.clientUIState, this.clientUIState,
this.invoiceUIState, this.invoiceUIState,
this.webhookUIState,
this.tokenUIState, this.tokenUIState,
this.paymentTermUIState, this.paymentTermUIState,
this.designUIState, this.designUIState,
@ -365,6 +375,9 @@ class _$UIState extends UIState {
if (invoiceUIState == null) { if (invoiceUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'invoiceUIState'); throw new BuiltValueNullFieldError('UIState', 'invoiceUIState');
} }
if (webhookUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'webhookUIState');
}
if (tokenUIState == null) { if (tokenUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'tokenUIState'); throw new BuiltValueNullFieldError('UIState', 'tokenUIState');
} }
@ -440,6 +453,7 @@ class _$UIState extends UIState {
productUIState == other.productUIState && productUIState == other.productUIState &&
clientUIState == other.clientUIState && clientUIState == other.clientUIState &&
invoiceUIState == other.invoiceUIState && invoiceUIState == other.invoiceUIState &&
webhookUIState == other.webhookUIState &&
tokenUIState == other.tokenUIState && tokenUIState == other.tokenUIState &&
paymentTermUIState == other.paymentTermUIState && paymentTermUIState == other.paymentTermUIState &&
designUIState == other.designUIState && designUIState == other.designUIState &&
@ -480,9 +494,9 @@ class _$UIState extends UIState {
$jc( $jc(
$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), $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),
clientUIState.hashCode), invoiceUIState.hashCode),
invoiceUIState.hashCode), webhookUIState.hashCode),
tokenUIState.hashCode), tokenUIState.hashCode),
paymentTermUIState.hashCode), paymentTermUIState.hashCode),
designUIState.hashCode), designUIState.hashCode),
@ -516,6 +530,7 @@ class _$UIState extends UIState {
..add('productUIState', productUIState) ..add('productUIState', productUIState)
..add('clientUIState', clientUIState) ..add('clientUIState', clientUIState)
..add('invoiceUIState', invoiceUIState) ..add('invoiceUIState', invoiceUIState)
..add('webhookUIState', webhookUIState)
..add('tokenUIState', tokenUIState) ..add('tokenUIState', tokenUIState)
..add('paymentTermUIState', paymentTermUIState) ..add('paymentTermUIState', paymentTermUIState)
..add('designUIState', designUIState) ..add('designUIState', designUIState)
@ -597,6 +612,12 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
set invoiceUIState(InvoiceUIStateBuilder invoiceUIState) => set invoiceUIState(InvoiceUIStateBuilder invoiceUIState) =>
_$this._invoiceUIState = invoiceUIState; _$this._invoiceUIState = invoiceUIState;
WebhookUIStateBuilder _webhookUIState;
WebhookUIStateBuilder get webhookUIState =>
_$this._webhookUIState ??= new WebhookUIStateBuilder();
set webhookUIState(WebhookUIStateBuilder webhookUIState) =>
_$this._webhookUIState = webhookUIState;
TokenUIStateBuilder _tokenUIState; TokenUIStateBuilder _tokenUIState;
TokenUIStateBuilder get tokenUIState => TokenUIStateBuilder get tokenUIState =>
_$this._tokenUIState ??= new TokenUIStateBuilder(); _$this._tokenUIState ??= new TokenUIStateBuilder();
@ -715,6 +736,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
_productUIState = _$v.productUIState?.toBuilder(); _productUIState = _$v.productUIState?.toBuilder();
_clientUIState = _$v.clientUIState?.toBuilder(); _clientUIState = _$v.clientUIState?.toBuilder();
_invoiceUIState = _$v.invoiceUIState?.toBuilder(); _invoiceUIState = _$v.invoiceUIState?.toBuilder();
_webhookUIState = _$v.webhookUIState?.toBuilder();
_tokenUIState = _$v.tokenUIState?.toBuilder(); _tokenUIState = _$v.tokenUIState?.toBuilder();
_paymentTermUIState = _$v.paymentTermUIState?.toBuilder(); _paymentTermUIState = _$v.paymentTermUIState?.toBuilder();
_designUIState = _$v.designUIState?.toBuilder(); _designUIState = _$v.designUIState?.toBuilder();
@ -767,6 +789,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
productUIState: productUIState.build(), productUIState: productUIState.build(),
clientUIState: clientUIState.build(), clientUIState: clientUIState.build(),
invoiceUIState: invoiceUIState.build(), invoiceUIState: invoiceUIState.build(),
webhookUIState: webhookUIState.build(),
tokenUIState: tokenUIState.build(), tokenUIState: tokenUIState.build(),
paymentTermUIState: paymentTermUIState.build(), paymentTermUIState: paymentTermUIState.build(),
designUIState: designUIState.build(), designUIState: designUIState.build(),
@ -795,6 +818,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
clientUIState.build(); clientUIState.build();
_$failedField = 'invoiceUIState'; _$failedField = 'invoiceUIState';
invoiceUIState.build(); invoiceUIState.build();
_$failedField = 'webhookUIState';
webhookUIState.build();
_$failedField = 'tokenUIState'; _$failedField = 'tokenUIState';
tokenUIState.build(); tokenUIState.build();
_$failedField = 'paymentTermUIState'; _$failedField = 'paymentTermUIState';

View File

@ -0,0 +1,321 @@
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/constants.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/settings/settings_actions.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
class ViewWebhookList extends AbstractNavigatorAction
implements PersistUI, StopLoading {
ViewWebhookList({
@required NavigatorState navigator,
this.force = false,
}) : super(navigator: navigator);
final bool force;
}
class ViewWebhook extends AbstractNavigatorAction
implements PersistUI, PersistPrefs {
ViewWebhook({
@required NavigatorState navigator,
@required this.webhookId,
this.force = false,
}) : super(navigator: navigator);
final String webhookId;
final bool force;
}
class EditWebhook extends AbstractNavigatorAction
implements PersistUI, PersistPrefs {
EditWebhook(
{@required this.webhook,
@required NavigatorState navigator,
this.completer,
this.cancelCompleter,
this.force = false})
: super(navigator: navigator);
final WebhookEntity webhook;
final Completer completer;
final Completer cancelCompleter;
final bool force;
}
class UpdateWebhook implements PersistUI {
UpdateWebhook(this.webhook);
final WebhookEntity webhook;
}
class LoadWebhook {
LoadWebhook({this.completer, this.webhookId});
final Completer completer;
final String webhookId;
}
class LoadWebhookActivity {
LoadWebhookActivity({this.completer, this.webhookId});
final Completer completer;
final String webhookId;
}
class LoadWebhooks {
LoadWebhooks({this.completer, this.force = false});
final Completer completer;
final bool force;
}
class LoadWebhookRequest implements StartLoading {}
class LoadWebhookFailure implements StopLoading {
LoadWebhookFailure(this.error);
final dynamic error;
@override
String toString() {
return 'LoadWebhookFailure{error: $error}';
}
}
class LoadWebhookSuccess implements StopLoading, PersistData {
LoadWebhookSuccess(this.webhook);
final WebhookEntity webhook;
@override
String toString() {
return 'LoadWebhookSuccess{webhook: $webhook}';
}
}
class LoadWebhooksRequest implements StartLoading {}
class LoadWebhooksFailure implements StopLoading {
LoadWebhooksFailure(this.error);
final dynamic error;
@override
String toString() {
return 'LoadWebhooksFailure{error: $error}';
}
}
class LoadWebhooksSuccess implements StopLoading, PersistData {
LoadWebhooksSuccess(this.webhooks);
final BuiltList<WebhookEntity> webhooks;
@override
String toString() {
return 'LoadWebhooksSuccess{webhooks: $webhooks}';
}
}
class SaveWebhookRequest implements StartSaving {
SaveWebhookRequest({this.completer, this.webhook});
final Completer completer;
final WebhookEntity webhook;
}
class SaveWebhookSuccess implements StopSaving, PersistData, PersistUI {
SaveWebhookSuccess(this.webhook);
final WebhookEntity webhook;
}
class AddWebhookSuccess implements StopSaving, PersistData, PersistUI {
AddWebhookSuccess(this.webhook);
final WebhookEntity webhook;
}
class SaveWebhookFailure implements StopSaving {
SaveWebhookFailure(this.error);
final Object error;
}
class ArchiveWebhooksRequest implements StartSaving {
ArchiveWebhooksRequest(this.completer, this.webhookIds);
final Completer completer;
final List<String> webhookIds;
}
class ArchiveWebhooksSuccess implements StopSaving, PersistData {
ArchiveWebhooksSuccess(this.webhooks);
final List<WebhookEntity> webhooks;
}
class ArchiveWebhooksFailure implements StopSaving {
ArchiveWebhooksFailure(this.webhooks);
final List<WebhookEntity> webhooks;
}
class DeleteWebhooksRequest implements StartSaving {
DeleteWebhooksRequest(this.completer, this.webhookIds);
final Completer completer;
final List<String> webhookIds;
}
class DeleteWebhooksSuccess implements StopSaving, PersistData {
DeleteWebhooksSuccess(this.webhooks);
final List<WebhookEntity> webhooks;
}
class DeleteWebhooksFailure implements StopSaving {
DeleteWebhooksFailure(this.webhooks);
final List<WebhookEntity> webhooks;
}
class RestoreWebhooksRequest implements StartSaving {
RestoreWebhooksRequest(this.completer, this.webhookIds);
final Completer completer;
final List<String> webhookIds;
}
class RestoreWebhooksSuccess implements StopSaving, PersistData {
RestoreWebhooksSuccess(this.webhooks);
final List<WebhookEntity> webhooks;
}
class RestoreWebhooksFailure implements StopSaving {
RestoreWebhooksFailure(this.webhooks);
final List<WebhookEntity> webhooks;
}
class FilterWebhooks implements PersistUI {
FilterWebhooks(this.filter);
final String filter;
}
class SortWebhooks implements PersistUI {
SortWebhooks(this.field);
final String field;
}
class FilterWebhooksByState implements PersistUI {
FilterWebhooksByState(this.state);
final EntityState state;
}
class FilterWebhooksByCustom1 implements PersistUI {
FilterWebhooksByCustom1(this.value);
final String value;
}
class FilterWebhooksByCustom2 implements PersistUI {
FilterWebhooksByCustom2(this.value);
final String value;
}
class FilterWebhooksByCustom3 implements PersistUI {
FilterWebhooksByCustom3(this.value);
final String value;
}
class FilterWebhooksByCustom4 implements PersistUI {
FilterWebhooksByCustom4(this.value);
final String value;
}
void handleWebhookAction(
BuildContext context, List<BaseEntity> webhooks, EntityAction action) {
if (webhooks.isEmpty) {
return;
}
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.company;
final localization = AppLocalization.of(context);
final webhook = webhooks.first as WebhookEntity;
final webhookIds = webhooks.map((webhook) => webhook.id).toList();
switch (action) {
case EntityAction.edit:
editEntity(context: context, entity: webhook);
break;
case EntityAction.restore:
store.dispatch(RestoreWebhooksRequest(
snackBarCompleter<Null>(context, localization.restoredWebhook),
webhookIds));
break;
case EntityAction.archive:
store.dispatch(ArchiveWebhooksRequest(
snackBarCompleter<Null>(context, localization.archivedWebhook),
webhookIds));
break;
case EntityAction.delete:
store.dispatch(DeleteWebhooksRequest(
snackBarCompleter<Null>(context, localization.deletedWebhook),
webhookIds));
break;
case EntityAction.toggleMultiselect:
if (!store.state.webhookListState.isInMultiselect()) {
store.dispatch(StartWebhookMultiselect());
}
if (webhooks.isEmpty) {
break;
}
for (final webhook in webhooks) {
if (!store.state.webhookListState.isSelected(webhook.id)) {
store.dispatch(AddToWebhookMultiselect(entity: webhook));
} else {
store.dispatch(RemoveFromWebhookMultiselect(entity: webhook));
}
}
break;
}
}
class StartWebhookMultiselect {
StartWebhookMultiselect();
}
class AddToWebhookMultiselect {
AddToWebhookMultiselect({@required this.entity});
final BaseEntity entity;
}
class RemoveFromWebhookMultiselect {
RemoveFromWebhookMultiselect({@required this.entity});
final BaseEntity entity;
}
class ClearWebhookMultiselect {
ClearWebhookMultiselect();
}

View File

@ -0,0 +1,276 @@
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/redux/app/app_middleware.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.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';
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/data/repositories/webhook_repository.dart';
List<Middleware<AppState>> createStoreWebhooksMiddleware([
WebhookRepository repository = const WebhookRepository(),
]) {
final viewWebhookList = _viewWebhookList();
final viewWebhook = _viewWebhook();
final editWebhook = _editWebhook();
final loadWebhooks = _loadWebhooks(repository);
final loadWebhook = _loadWebhook(repository);
final saveWebhook = _saveWebhook(repository);
final archiveWebhook = _archiveWebhook(repository);
final deleteWebhook = _deleteWebhook(repository);
final restoreWebhook = _restoreWebhook(repository);
return [
TypedMiddleware<AppState, ViewWebhookList>(viewWebhookList),
TypedMiddleware<AppState, ViewWebhook>(viewWebhook),
TypedMiddleware<AppState, EditWebhook>(editWebhook),
TypedMiddleware<AppState, LoadWebhooks>(loadWebhooks),
TypedMiddleware<AppState, LoadWebhook>(loadWebhook),
TypedMiddleware<AppState, SaveWebhookRequest>(saveWebhook),
TypedMiddleware<AppState, ArchiveWebhooksRequest>(archiveWebhook),
TypedMiddleware<AppState, DeleteWebhooksRequest>(deleteWebhook),
TypedMiddleware<AppState, RestoreWebhooksRequest>(restoreWebhook),
];
}
Middleware<AppState> _editWebhook() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as EditWebhook;
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(WebhookEditScreen.route));
if (isMobile(action.context)) {
action.navigator.pushNamed(WebhookEditScreen.route);
}
};
}
Middleware<AppState> _viewWebhook() {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewWebhook;
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(WebhookViewScreen.route));
if (isMobile(action.context)) {
Navigator.of(action.context).pushNamed(WebhookViewScreen.route);
}
};
}
Middleware<AppState> _viewWebhookList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewWebhookList;
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
next(action);
if (store.state.staticState.isStale) {
store.dispatch(RefreshData());
} else if (store.state.webhookState.isStale) {
store.dispatch(LoadWebhooks());
}
store.dispatch(UpdateCurrentRoute(WebhookScreen.route));
if (isMobile(action.context)) {
Navigator.of(action.context).pushNamedAndRemoveUntil(
WebhookScreen.route, (Route<dynamic> route) => false);
}
};
}
Middleware<AppState> _archiveWebhook(WebhookRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ArchiveWebhooksRequest;
final prevWebhooks = action.webhookIds
.map((id) => store.state.webhookState.map[id])
.toList();
repository
.bulkAction(
store.state.credentials, action.webhookIds, EntityAction.archive)
.then((List<WebhookEntity> webhooks) {
store.dispatch(ArchiveWebhooksSuccess(webhooks));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(ArchiveWebhooksFailure(prevWebhooks));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _deleteWebhook(WebhookRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as DeleteWebhooksRequest;
final prevWebhooks = action.webhookIds
.map((id) => store.state.webhookState.map[id])
.toList();
repository
.bulkAction(
store.state.credentials, action.webhookIds, EntityAction.delete)
.then((List<WebhookEntity> webhooks) {
store.dispatch(DeleteWebhooksSuccess(webhooks));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(DeleteWebhooksFailure(prevWebhooks));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _restoreWebhook(WebhookRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as RestoreWebhooksRequest;
final prevWebhooks = action.webhookIds
.map((id) => store.state.webhookState.map[id])
.toList();
repository
.bulkAction(
store.state.credentials, action.webhookIds, EntityAction.restore)
.then((List<WebhookEntity> webhooks) {
store.dispatch(RestoreWebhooksSuccess(webhooks));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(RestoreWebhooksFailure(prevWebhooks));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _saveWebhook(WebhookRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as SaveWebhookRequest;
repository
.saveData(store.state.credentials, action.webhook)
.then((WebhookEntity webhook) {
if (action.webhook.isNew) {
store.dispatch(AddWebhookSuccess(webhook));
} else {
store.dispatch(SaveWebhookSuccess(webhook));
}
action.completer.complete(webhook);
}).catchError((Object error) {
print(error);
store.dispatch(SaveWebhookFailure(error));
action.completer.completeError(error);
});
next(action);
};
}
Middleware<AppState> _loadWebhook(WebhookRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadWebhook;
final AppState state = store.state;
if (state.isLoading) {
next(action);
return;
}
store.dispatch(LoadWebhookRequest());
repository.loadItem(state.credentials, action.webhookId).then((webhook) {
store.dispatch(LoadWebhookSuccess(webhook));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(LoadWebhookFailure(error));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _loadWebhooks(WebhookRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadWebhooks;
final AppState state = store.state;
if (!state.webhookState.isStale && !action.force) {
next(action);
return;
}
if (state.isLoading) {
next(action);
return;
}
final int updatedAt = (state.webhookState.lastUpdated / 1000).round();
store.dispatch(LoadWebhooksRequest());
repository.loadList(state.credentials, updatedAt).then((data) {
store.dispatch(LoadWebhooksSuccess(data));
if (action.completer != null) {
action.completer.complete(null);
}
/*
if (state.productState.isStale) {
store.dispatch(LoadProducts());
}
*/
}).catchError((Object error) {
print(error);
store.dispatch(LoadWebhooksFailure(error));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}

View File

@ -0,0 +1,290 @@
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/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_state.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
EntityUIState webhookUIReducer(WebhookUIState state, dynamic action) {
return state.rebuild((b) => b
..listUIState.replace(webhookListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.editing, action))
..selectedId = selectedIdReducer(state.selectedId, action));
}
Reducer<String> selectedIdReducer = combineReducers([
TypedReducer<String, ViewWebhook>(
(String selectedId, dynamic action) => action.webhookId),
TypedReducer<String, AddWebhookSuccess>(
(String selectedId, dynamic action) => action.webhook.id),
TypedReducer<String, SelectCompany>((selectedId, action) => ''),
TypedReducer<String, DeleteWebhooksSuccess>((selectedId, action) => ''),
TypedReducer<String, ArchiveWebhooksSuccess>((selectedId, action) => ''),
TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''),
TypedReducer<String, FilterByEntity>((selectedId, action) =>
action.entityType == EntityType.webhook ? action.entityId : selectedId),
]);
final editingReducer = combineReducers<WebhookEntity>([
TypedReducer<WebhookEntity, SaveWebhookSuccess>(_updateEditing),
TypedReducer<WebhookEntity, AddWebhookSuccess>(_updateEditing),
TypedReducer<WebhookEntity, RestoreWebhooksSuccess>((webhooks, action) {
return action.webhooks[0];
}),
TypedReducer<WebhookEntity, ArchiveWebhooksSuccess>((webhooks, action) {
return action.webhooks[0];
}),
TypedReducer<WebhookEntity, DeleteWebhooksSuccess>((webhooks, action) {
return action.webhooks[0];
}),
TypedReducer<WebhookEntity, EditWebhook>(_updateEditing),
TypedReducer<WebhookEntity, UpdateWebhook>((webhook, action) {
return action.webhook.rebuild((b) => b..isChanged = true);
}),
TypedReducer<WebhookEntity, SelectCompany>(_clearEditing),
TypedReducer<WebhookEntity, DiscardChanges>(_clearEditing),
]);
WebhookEntity _clearEditing(WebhookEntity webhook, dynamic action) {
return WebhookEntity();
}
WebhookEntity _updateEditing(WebhookEntity webhook, dynamic action) {
return action.webhook;
}
final webhookListReducer = combineReducers<ListUIState>([
TypedReducer<ListUIState, SortWebhooks>(_sortWebhooks),
TypedReducer<ListUIState, FilterWebhooksByState>(_filterWebhooksByState),
TypedReducer<ListUIState, FilterWebhooks>(_filterWebhooks),
TypedReducer<ListUIState, FilterWebhooksByCustom1>(_filterWebhooksByCustom1),
TypedReducer<ListUIState, FilterWebhooksByCustom2>(_filterWebhooksByCustom2),
TypedReducer<ListUIState, StartWebhookMultiselect>(_startListMultiselect),
TypedReducer<ListUIState, AddToWebhookMultiselect>(_addToListMultiselect),
TypedReducer<ListUIState, RemoveFromWebhookMultiselect>(
_removeFromListMultiselect),
TypedReducer<ListUIState, ClearWebhookMultiselect>(_clearListMultiselect),
TypedReducer<ListUIState, ClearEntityFilter>(
(state, action) => state.rebuild((b) => b
..filterEntityId = null
..filterEntityType = null)),
]);
ListUIState _filterWebhooksByCustom1(
ListUIState webhookListState, FilterWebhooksByCustom1 action) {
if (webhookListState.custom1Filters.contains(action.value)) {
return webhookListState
.rebuild((b) => b..custom1Filters.remove(action.value));
} else {
return webhookListState.rebuild((b) => b..custom1Filters.add(action.value));
}
}
ListUIState _filterWebhooksByCustom2(
ListUIState webhookListState, FilterWebhooksByCustom2 action) {
if (webhookListState.custom2Filters.contains(action.value)) {
return webhookListState
.rebuild((b) => b..custom2Filters.remove(action.value));
} else {
return webhookListState.rebuild((b) => b..custom2Filters.add(action.value));
}
}
ListUIState _filterWebhooksByState(
ListUIState webhookListState, FilterWebhooksByState action) {
if (webhookListState.stateFilters.contains(action.state)) {
return webhookListState
.rebuild((b) => b..stateFilters.remove(action.state));
} else {
return webhookListState.rebuild((b) => b..stateFilters.add(action.state));
}
}
ListUIState _filterWebhooks(
ListUIState webhookListState, FilterWebhooks action) {
return webhookListState.rebuild((b) => b
..filter = action.filter
..filterClearedAt = action.filter == null
? DateTime.now().millisecondsSinceEpoch
: webhookListState.filterClearedAt);
}
ListUIState _sortWebhooks(ListUIState webhookListState, SortWebhooks action) {
return webhookListState.rebuild((b) => b
..sortAscending = b.sortField != action.field || !b.sortAscending
..sortField = action.field);
}
ListUIState _startListMultiselect(
ListUIState productListState, StartWebhookMultiselect action) {
return productListState.rebuild((b) => b..selectedIds = ListBuilder());
}
ListUIState _addToListMultiselect(
ListUIState productListState, AddToWebhookMultiselect action) {
return productListState.rebuild((b) => b..selectedIds.add(action.entity.id));
}
ListUIState _removeFromListMultiselect(
ListUIState productListState, RemoveFromWebhookMultiselect action) {
return productListState
.rebuild((b) => b..selectedIds.remove(action.entity.id));
}
ListUIState _clearListMultiselect(
ListUIState productListState, ClearWebhookMultiselect action) {
return productListState.rebuild((b) => b..selectedIds = null);
}
final webhooksReducer = combineReducers<WebhookState>([
TypedReducer<WebhookState, SaveWebhookSuccess>(_updateWebhook),
TypedReducer<WebhookState, AddWebhookSuccess>(_addWebhook),
TypedReducer<WebhookState, LoadWebhooksSuccess>(_setLoadedWebhooks),
TypedReducer<WebhookState, LoadWebhookSuccess>(_setLoadedWebhook),
TypedReducer<WebhookState, LoadCompanySuccess>(_setLoadedCompany),
TypedReducer<WebhookState, ArchiveWebhooksRequest>(_archiveWebhookRequest),
TypedReducer<WebhookState, ArchiveWebhooksSuccess>(_archiveWebhookSuccess),
TypedReducer<WebhookState, ArchiveWebhooksFailure>(_archiveWebhookFailure),
TypedReducer<WebhookState, DeleteWebhooksRequest>(_deleteWebhookRequest),
TypedReducer<WebhookState, DeleteWebhooksSuccess>(_deleteWebhookSuccess),
TypedReducer<WebhookState, DeleteWebhooksFailure>(_deleteWebhookFailure),
TypedReducer<WebhookState, RestoreWebhooksRequest>(_restoreWebhookRequest),
TypedReducer<WebhookState, RestoreWebhooksSuccess>(_restoreWebhookSuccess),
TypedReducer<WebhookState, RestoreWebhooksFailure>(_restoreWebhookFailure),
]);
WebhookState _archiveWebhookRequest(
WebhookState webhookState, ArchiveWebhooksRequest action) {
final webhooks = action.webhookIds.map((id) => webhookState.map[id]).toList();
for (int i = 0; i < webhooks.length; i++) {
webhooks[i] = webhooks[i]
.rebuild((b) => b..archivedAt = DateTime.now().millisecondsSinceEpoch);
}
return webhookState.rebuild((b) {
for (final webhook in webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _archiveWebhookSuccess(
WebhookState webhookState, ArchiveWebhooksSuccess action) {
return webhookState.rebuild((b) {
for (final webhook in action.webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _archiveWebhookFailure(
WebhookState webhookState, ArchiveWebhooksFailure action) {
return webhookState.rebuild((b) {
for (final webhook in action.webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _deleteWebhookRequest(
WebhookState webhookState, DeleteWebhooksRequest action) {
final webhooks = action.webhookIds.map((id) => webhookState.map[id]).toList();
for (int i = 0; i < webhooks.length; i++) {
webhooks[i] = webhooks[i].rebuild((b) => b
..archivedAt = DateTime.now().millisecondsSinceEpoch
..isDeleted = true);
}
return webhookState.rebuild((b) {
for (final webhook in webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _deleteWebhookSuccess(
WebhookState webhookState, DeleteWebhooksSuccess action) {
return webhookState.rebuild((b) {
for (final webhook in action.webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _deleteWebhookFailure(
WebhookState webhookState, DeleteWebhooksFailure action) {
return webhookState.rebuild((b) {
for (final webhook in action.webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _restoreWebhookRequest(
WebhookState webhookState, RestoreWebhooksRequest action) {
final webhooks = action.webhookIds.map((id) => webhookState.map[id]).toList();
for (int i = 0; i < webhooks.length; i++) {
webhooks[i] = webhooks[i].rebuild((b) => b
..archivedAt = 0
..isDeleted = false);
}
return webhookState.rebuild((b) {
for (final webhook in webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _restoreWebhookSuccess(
WebhookState webhookState, RestoreWebhooksSuccess action) {
return webhookState.rebuild((b) {
for (final webhook in action.webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _restoreWebhookFailure(
WebhookState webhookState, RestoreWebhooksFailure action) {
return webhookState.rebuild((b) {
for (final webhook in action.webhooks) {
b.map[webhook.id] = webhook;
}
});
}
WebhookState _addWebhook(WebhookState webhookState, AddWebhookSuccess action) {
return webhookState.rebuild((b) => b
..map[action.webhook.id] = action.webhook
..list.add(action.webhook.id));
}
WebhookState _updateWebhook(
WebhookState webhookState, SaveWebhookSuccess action) {
return webhookState
.rebuild((b) => b..map[action.webhook.id] = action.webhook);
}
WebhookState _setLoadedWebhook(
WebhookState webhookState, LoadWebhookSuccess action) {
return webhookState
.rebuild((b) => b..map[action.webhook.id] = action.webhook);
}
WebhookState _setLoadedWebhooks(
WebhookState webhookState, LoadWebhooksSuccess action) =>
webhookState.loadWebhooks(action.webhooks);
WebhookState _setLoadedCompany(
WebhookState webhookState, LoadCompanySuccess action) {
final company = action.userCompany.company;
return company.hasData
? webhookState.loadWebhooks(company.webhooks)
: webhookState;
}

View File

@ -0,0 +1,69 @@
import 'package:invoiceninja_flutter/data/models/webhook_model.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 memoizedDropdownWebhookList = memo3(
(BuiltMap<String, WebhookEntity> webhookMap, BuiltList<String> webhookList,
String clientId) =>
dropdownWebhooksSelector(webhookMap, webhookList, clientId));
List<String> dropdownWebhooksSelector(
BuiltMap<String, WebhookEntity> webhookMap,
BuiltList<String> webhookList,
String clientId) {
final list = webhookList.where((webhookId) {
final webhook = webhookMap[webhookId];
/*
if (clientId != null && clientId > 0 && webhook.clientId != clientId) {
return false;
}
*/
return webhook.isActive;
}).toList();
list.sort((webhookAId, webhookBId) {
final webhookA = webhookMap[webhookAId];
final webhookB = webhookMap[webhookBId];
return webhookA.compareTo(webhookB, WebhookFields.name, true);
});
return list;
}
var memoizedFilteredWebhookList = memo3(
(BuiltMap<String, WebhookEntity> webhookMap, BuiltList<String> webhookList,
ListUIState webhookListState) =>
filteredWebhooksSelector(webhookMap, webhookList, webhookListState));
List<String> filteredWebhooksSelector(
BuiltMap<String, WebhookEntity> webhookMap,
BuiltList<String> webhookList,
ListUIState webhookListState) {
final list = webhookList.where((webhookId) {
final webhook = webhookMap[webhookId];
if (webhookListState.filterEntityId != null &&
webhook.id != webhookListState.filterEntityId) {
return false;
} else {}
if (!webhook.matchesStates(webhookListState.stateFilters)) {
return false;
}
return webhook.matchesFilter(webhookListState.filter);
}).toList();
list.sort((webhookAId, webhookBId) {
final webhookA = webhookMap[webhookAId];
final webhookB = webhookMap[webhookBId];
return webhookA.compareTo(
webhookB, webhookListState.sortField, webhookListState.sortAscending);
});
return list;
}
bool hasWebhookChanges(
WebhookEntity webhook, BuiltMap<String, WebhookEntity> webhookMap) =>
webhook.isNew ? webhook.isChanged : webhook != webhookMap[webhook.id];

View File

@ -0,0 +1,88 @@
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/constants.dart';
import 'package:invoiceninja_flutter/data/models/webhook_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 'webhook_state.g.dart';
abstract class WebhookState
implements Built<WebhookState, WebhookStateBuilder> {
factory WebhookState() {
return _$WebhookState._(
lastUpdated: 0,
map: BuiltMap<String, WebhookEntity>(),
list: BuiltList<String>(),
);
}
WebhookState._();
@override
@memoized
int get hashCode;
@nullable
int get lastUpdated;
BuiltMap<String, WebhookEntity> get map;
BuiltList<String> get list;
bool get isStale {
if (!isLoaded) {
return true;
}
return DateTime.now().millisecondsSinceEpoch - lastUpdated >
kMillisecondsToRefreshData;
}
bool get isLoaded => lastUpdated != null && lastUpdated > 0;
WebhookState loadWebhooks(BuiltList<WebhookEntity> clients) {
final map = Map<String, WebhookEntity>.fromIterable(
clients,
key: (dynamic item) => item.id,
value: (dynamic item) => item,
);
return rebuild((b) => b
..lastUpdated = DateTime.now().millisecondsSinceEpoch
..map.addAll(map)
..list.replace((map.keys.toList() + list.toList()).toSet().toList()));
}
static Serializer<WebhookState> get serializer => _$webhookStateSerializer;
}
abstract class WebhookUIState extends Object
with EntityUIState
implements Built<WebhookUIState, WebhookUIStateBuilder> {
factory WebhookUIState() {
return _$WebhookUIState._(
listUIState: ListUIState(WebhookFields.name),
editing: WebhookEntity(),
selectedId: '',
);
}
WebhookUIState._();
@override
@memoized
int get hashCode;
@nullable
WebhookEntity get editing;
@override
bool get isCreatingNew => editing.isNew;
@override
String get editingId => editing.id;
static Serializer<WebhookUIState> get serializer =>
_$webhookUIStateSerializer;
}

View File

@ -0,0 +1,412 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'webhook_state.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<WebhookState> _$webhookStateSerializer =
new _$WebhookStateSerializer();
Serializer<WebhookUIState> _$webhookUIStateSerializer =
new _$WebhookUIStateSerializer();
class _$WebhookStateSerializer implements StructuredSerializer<WebhookState> {
@override
final Iterable<Type> types = const [WebhookState, _$WebhookState];
@override
final String wireName = 'WebhookState';
@override
Iterable<Object> serialize(Serializers serializers, WebhookState object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'map',
serializers.serialize(object.map,
specifiedType: const FullType(BuiltMap,
const [const FullType(String), const FullType(WebhookEntity)])),
'list',
serializers.serialize(object.list,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
];
if (object.lastUpdated != null) {
result
..add('lastUpdated')
..add(serializers.serialize(object.lastUpdated,
specifiedType: const FullType(int)));
}
return result;
}
@override
WebhookState deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new WebhookStateBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'lastUpdated':
result.lastUpdated = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'map':
result.map.replace(serializers.deserialize(value,
specifiedType: const FullType(BuiltMap, const [
const FullType(String),
const FullType(WebhookEntity)
])));
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 _$WebhookUIStateSerializer
implements StructuredSerializer<WebhookUIState> {
@override
final Iterable<Type> types = const [WebhookUIState, _$WebhookUIState];
@override
final String wireName = 'WebhookUIState';
@override
Iterable<Object> serialize(Serializers serializers, WebhookUIState 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(WebhookEntity)));
}
if (object.selectedId != null) {
result
..add('selectedId')
..add(serializers.serialize(object.selectedId,
specifiedType: const FullType(String)));
}
return result;
}
@override
WebhookUIState deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new WebhookUIStateBuilder();
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(WebhookEntity)) as WebhookEntity);
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 _$WebhookState extends WebhookState {
@override
final int lastUpdated;
@override
final BuiltMap<String, WebhookEntity> map;
@override
final BuiltList<String> list;
factory _$WebhookState([void Function(WebhookStateBuilder) updates]) =>
(new WebhookStateBuilder()..update(updates)).build();
_$WebhookState._({this.lastUpdated, this.map, this.list}) : super._() {
if (map == null) {
throw new BuiltValueNullFieldError('WebhookState', 'map');
}
if (list == null) {
throw new BuiltValueNullFieldError('WebhookState', 'list');
}
}
@override
WebhookState rebuild(void Function(WebhookStateBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
WebhookStateBuilder toBuilder() => new WebhookStateBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is WebhookState &&
lastUpdated == other.lastUpdated &&
map == other.map &&
list == other.list;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf(
$jc($jc($jc(0, lastUpdated.hashCode), map.hashCode), list.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('WebhookState')
..add('lastUpdated', lastUpdated)
..add('map', map)
..add('list', list))
.toString();
}
}
class WebhookStateBuilder
implements Builder<WebhookState, WebhookStateBuilder> {
_$WebhookState _$v;
int _lastUpdated;
int get lastUpdated => _$this._lastUpdated;
set lastUpdated(int lastUpdated) => _$this._lastUpdated = lastUpdated;
MapBuilder<String, WebhookEntity> _map;
MapBuilder<String, WebhookEntity> get map =>
_$this._map ??= new MapBuilder<String, WebhookEntity>();
set map(MapBuilder<String, WebhookEntity> map) => _$this._map = map;
ListBuilder<String> _list;
ListBuilder<String> get list => _$this._list ??= new ListBuilder<String>();
set list(ListBuilder<String> list) => _$this._list = list;
WebhookStateBuilder();
WebhookStateBuilder get _$this {
if (_$v != null) {
_lastUpdated = _$v.lastUpdated;
_map = _$v.map?.toBuilder();
_list = _$v.list?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(WebhookState other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$WebhookState;
}
@override
void update(void Function(WebhookStateBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$WebhookState build() {
_$WebhookState _$result;
try {
_$result = _$v ??
new _$WebhookState._(
lastUpdated: lastUpdated, map: map.build(), list: list.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'map';
map.build();
_$failedField = 'list';
list.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'WebhookState', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$WebhookUIState extends WebhookUIState {
@override
final WebhookEntity editing;
@override
final ListUIState listUIState;
@override
final String selectedId;
@override
final Completer<SelectableEntity> saveCompleter;
@override
final Completer<Null> cancelCompleter;
factory _$WebhookUIState([void Function(WebhookUIStateBuilder) updates]) =>
(new WebhookUIStateBuilder()..update(updates)).build();
_$WebhookUIState._(
{this.editing,
this.listUIState,
this.selectedId,
this.saveCompleter,
this.cancelCompleter})
: super._() {
if (listUIState == null) {
throw new BuiltValueNullFieldError('WebhookUIState', 'listUIState');
}
}
@override
WebhookUIState rebuild(void Function(WebhookUIStateBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
WebhookUIStateBuilder toBuilder() =>
new WebhookUIStateBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is WebhookUIState &&
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('WebhookUIState')
..add('editing', editing)
..add('listUIState', listUIState)
..add('selectedId', selectedId)
..add('saveCompleter', saveCompleter)
..add('cancelCompleter', cancelCompleter))
.toString();
}
}
class WebhookUIStateBuilder
implements Builder<WebhookUIState, WebhookUIStateBuilder> {
_$WebhookUIState _$v;
WebhookEntityBuilder _editing;
WebhookEntityBuilder get editing =>
_$this._editing ??= new WebhookEntityBuilder();
set editing(WebhookEntityBuilder 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;
WebhookUIStateBuilder();
WebhookUIStateBuilder 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(WebhookUIState other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$WebhookUIState;
}
@override
void update(void Function(WebhookUIStateBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$WebhookUIState build() {
_$WebhookUIState _$result;
try {
_$result = _$v ??
new _$WebhookUIState._(
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(
'WebhookUIState', _$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

View File

@ -29,6 +29,7 @@ import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:invoiceninja_flutter/utils/colors.dart'; import 'package:invoiceninja_flutter/utils/colors.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
class MenuDrawer extends StatelessWidget { class MenuDrawer extends StatelessWidget {
const MenuDrawer({ const MenuDrawer({
@ -309,6 +310,13 @@ class MenuDrawer extends StatelessWidget {
iconTooltip: localization.newExpense, iconTooltip: localization.newExpense,
), ),
// STARTER: menu - do not remove comment // STARTER: menu - do not remove comment
DrawerTile(
company: company,
entityType: EntityType.webhook,
icon: getEntityIcon(EntityType.webhook),
title: localization.webhooks,
),
DrawerTile( DrawerTile(
company: company, company: company,
icon: getEntityIcon(EntityType.reports), icon: getEntityIcon(EntityType.reports),

View File

@ -0,0 +1,106 @@
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/webhook/edit/webhook_edit_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
class WebhookEdit extends StatefulWidget {
const WebhookEdit({
Key key,
@required this.viewModel,
}) : super(key: key);
final WebhookEditVM viewModel;
@override
_WebhookEditState createState() => _WebhookEditState();
}
class _WebhookEditState extends State<WebhookEdit> {
static final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: '_webhookEdit');
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 webhook = widget.viewModel.webhook;
// 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 webhook = widget.viewModel.webhook.rebuild((b) => b
// STARTER: set value - do not remove comment
);
if (webhook != widget.viewModel.webhook) {
widget.viewModel.onChanged(webhook);
}
});
}
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final localization = AppLocalization.of(context);
final webhook = viewModel.webhook;
return EditScaffold(
title: localization.editWebhook,
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
],
),
],
);
})),
);
}
}

View File

@ -0,0 +1,105 @@
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/ui/webhook/webhook_screen.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/webhook/view/webhook_view_vm.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/data/models/webhook_model.dart';
import 'package:invoiceninja_flutter/ui/webhook/edit/webhook_edit.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class WebhookEditScreen extends StatelessWidget {
const WebhookEditScreen({Key key}) : super(key: key);
static const String route = '/webhook/edit';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, WebhookEditVM>(
converter: (Store<AppState> store) {
return WebhookEditVM.fromStore(store);
},
builder: (context, viewModel) {
return WebhookEdit(
viewModel: viewModel,
key: ValueKey(viewModel.webhook.id),
);
},
);
}
}
class WebhookEditVM {
WebhookEditVM({
@required this.state,
@required this.webhook,
@required this.company,
@required this.onChanged,
@required this.isSaving,
@required this.origWebhook,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.isLoading,
});
factory WebhookEditVM.fromStore(Store<AppState> store) {
final state = store.state;
final webhook = state.webhookUIState.editing;
return WebhookEditVM(
state: state,
isLoading: state.isLoading,
isSaving: state.isSaving,
origWebhook: state.webhookState.map[webhook.id],
webhook: webhook,
company: state.company,
onChanged: (WebhookEntity webhook) {
store.dispatch(UpdateWebhook(webhook));
},
onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: WebhookEntity(), force: true);
},
onSavePressed: (BuildContext context) {
final Completer<WebhookEntity> completer =
new Completer<WebhookEntity>();
store.dispatch(
SaveWebhookRequest(completer: completer, webhook: webhook));
return completer.future.then((savedWebhook) {
if (isMobile(context)) {
store.dispatch(UpdateCurrentRoute(WebhookViewScreen.route));
if (webhook.isNew) {
Navigator.of(context)
.pushReplacementNamed(WebhookViewScreen.route);
} else {
Navigator.of(context).pop(savedWebhook);
}
} else {
viewEntity(context: context, entity: savedWebhook, force: true);
}
}).catchError((Object error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
},
);
}
final WebhookEntity webhook;
final CompanyEntity company;
final Function(WebhookEntity) onChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final bool isLoading;
final bool isSaving;
final WebhookEntity origWebhook;
final AppState state;
}

View File

@ -0,0 +1,38 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/edit_icon_button.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/ui/webhook/view/webhook_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_state_title.dart';
class WebhookView extends StatefulWidget {
const WebhookView({
Key key,
@required this.viewModel,
@required this.isFilter,
}) : super(key: key);
final WebhookViewVM viewModel;
final bool isFilter;
@override
_WebhookViewState createState() => new _WebhookViewState();
}
class _WebhookViewState extends State<WebhookView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final userCompany = viewModel.state.userCompany;
final webhook = viewModel.webhook;
return ViewScaffold(
isFilter: widget.isFilter,
entity: webhook,
body: ListView(
children: <Widget>[],
),
);
}
}

View File

@ -0,0 +1,86 @@
import 'dart:async';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/ui/webhook/webhook_screen.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/data/models/webhook_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/webhook/view/webhook_view.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class WebhookViewScreen extends StatelessWidget {
const WebhookViewScreen({
Key key,
this.isFilter = false,
}) : super(key: key);
static const String route = '/webhook/view';
final bool isFilter;
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, WebhookViewVM>(
converter: (Store<AppState> store) {
return WebhookViewVM.fromStore(store);
},
builder: (context, vm) {
return WebhookView(
viewModel: vm,
isFilter: isFilter,
);
},
);
}
}
class WebhookViewVM {
WebhookViewVM({
@required this.state,
@required this.webhook,
@required this.company,
@required this.onEntityAction,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
});
factory WebhookViewVM.fromStore(Store<AppState> store) {
final state = store.state;
final webhook = state.webhookState.map[state.webhookUIState.selectedId] ??
WebhookEntity(id: state.webhookUIState.selectedId);
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(LoadWebhook(completer: completer, webhookId: webhook.id));
return completer.future;
}
return WebhookViewVM(
state: state,
company: state.company,
isSaving: state.isSaving,
isLoading: state.isLoading,
isDirty: webhook.isNew,
webhook: webhook,
onRefreshed: (context) => _handleRefresh(context),
onEntityAction: (BuildContext context, EntityAction action) =>
handleEntitiesActions(context, [webhook], action, autoPop: true),
);
}
final AppState state;
final WebhookEntity webhook;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;
final bool isDirty;
}

View File

@ -0,0 +1,104 @@
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/webhook_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 WebhookListItem extends StatelessWidget {
const WebhookListItem({
@required this.user,
@required this.onEntityAction,
@required this.onTap,
@required this.onLongPress,
@required this.webhook,
@required this.filter,
this.onCheckboxChanged,
this.isChecked = false,
});
final UserEntity user;
final Function(EntityAction) onEntityAction;
final GestureTapCallback onTap;
final GestureTapCallback onLongPress;
final WebhookEntity webhook;
final String filter;
final Function(bool) onCheckboxChanged;
final bool isChecked;
static final webhookItemKey = (int id) => Key('__webhook_item_${id}__');
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final uiState = state.uiState;
final webhookUIState = uiState.webhookUIState;
final listUIState = webhookUIState.listUIState;
final isInMultiselect = listUIState.isInMultiselect();
final showCheckbox = onCheckboxChanged != null || isInMultiselect;
final filterMatch = filter != null && filter.isNotEmpty
? webhook.matchesFilterValue(filter)
: null;
final subtitle = filterMatch;
return DismissibleEntity(
userCompany: state.userCompany,
entity: webhook,
isSelected: webhook.id ==
(uiState.isEditing
? webhookUIState.editing.id
: webhookUIState.selectedId),
onEntityAction: onEntityAction,
child: ListTile(
onTap: isInMultiselect
? () => onEntityAction(EntityAction.toggleMultiselect)
: onTap,
onLongPress: onLongPress,
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(
webhook.name,
style: Theme.of(context).textTheme.headline6,
),
),
Text(formatNumber(webhook.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(webhook),
],
),
),
);
}
}

View File

@ -0,0 +1,170 @@
import 'dart:async';
import 'package:invoiceninja_flutter/data/models/webhook_model.dart';
import 'package:invoiceninja_flutter/ui/app/tables/entity_list.dart';
import 'package:invoiceninja_flutter/ui/webhook/webhook_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/webhook/webhook_selectors.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
class WebhookListBuilder extends StatelessWidget {
const WebhookListBuilder({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, WebhookListVM>(
converter: WebhookListVM.fromStore,
builder: (context, viewModel) {
return EntityList(
isLoaded: viewModel.isLoaded,
entityType: EntityType.webhook,
presenter: WebhookPresenter(),
state: viewModel.state,
entityList: viewModel.webhookList,
onEntityTap: viewModel.onWebhookTap,
tableColumns: viewModel.tableColumns,
onRefreshed: viewModel.onRefreshed,
onClearEntityFilterPressed: viewModel.onClearEntityFilterPressed,
onViewEntityFilterPressed: viewModel.onViewEntityFilterPressed,
onSortColumn: viewModel.onSortColumn,
itemBuilder: (BuildContext context, index) {
final state = viewModel.state;
final webhookId = viewModel.webhookList[index];
final webhook = viewModel.webhookMap[webhookId];
final listState = state.getListState(EntityType.webhook);
final isInMultiselect = listState.isInMultiselect();
return WebhookListItem(
user: viewModel.state.user,
filter: viewModel.filter,
webhook: webhook,
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
showEntityActionsDialog(
entities: [webhook],
context: context,
);
} else {
handleWebhookAction(context, [webhook], action);
}
},
onTap: () => viewModel.onWebhookTap(context, webhook),
onLongPress: () async {
final longPressIsSelection =
state.prefState.longPressSelectionIsDefault ?? true;
if (longPressIsSelection && !isInMultiselect) {
handleWebhookAction(
context, [webhook], EntityAction.toggleMultiselect);
} else {
showEntityActionsDialog(
entities: [webhook],
context: context,
);
}
},
isChecked: isInMultiselect && listState.isSelected(webhook.id),
);
});
},
);
}
}
class WebhookListVM {
WebhookListVM({
@required this.state,
@required this.userCompany,
@required this.webhookList,
@required this.webhookMap,
@required this.filter,
@required this.isLoading,
@required this.isLoaded,
@required this.onWebhookTap,
@required this.listState,
@required this.onRefreshed,
@required this.onEntityAction,
@required this.tableColumns,
@required this.onClearEntityFilterPressed,
@required this.onViewEntityFilterPressed,
@required this.onSortColumn,
});
static WebhookListVM 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(LoadWebhooks(completer: completer, force: true));
return completer.future;
}
final state = store.state;
return WebhookListVM(
state: state,
userCompany: state.userCompany,
listState: state.webhookListState,
webhookList: memoizedFilteredWebhookList(state.webhookState.map,
state.webhookState.list, state.webhookListState),
webhookMap: state.webhookState.map,
isLoading: state.isLoading,
isLoaded: state.webhookState.isLoaded,
filter: state.webhookUIState.listUIState.filter,
onClearEntityFilterPressed: () => store.dispatch(ClearEntityFilter()),
onViewEntityFilterPressed: (BuildContext context) => viewEntityById(
context: context,
entityId: state.webhookListState.filterEntityId,
entityType: state.webhookListState.filterEntityType),
onWebhookTap: (context, webhook) {
if (store.state.webhookListState.isInMultiselect()) {
handleWebhookAction(
context, [webhook], EntityAction.toggleMultiselect);
} else if (isDesktop(context) && state.uiState.isEditing) {
viewEntity(context: context, entity: webhook);
} else if (isDesktop(context) &&
state.webhookUIState.selectedId == webhook.id) {
editEntity(context: context, entity: webhook);
} else {
viewEntity(context: context, entity: webhook);
}
},
onEntityAction: (BuildContext context, List<BaseEntity> webhooks,
EntityAction action) =>
handleWebhookAction(context, webhooks, action),
onRefreshed: (context) => _handleRefresh(context),
tableColumns:
state.userCompany.settings.getTableColumns(EntityType.webhook) ??
WebhookPresenter.getAllTableFields(state.userCompany),
onSortColumn: (field) => store.dispatch(SortWebhooks(field)),
);
}
final AppState state;
final UserCompanyEntity userCompany;
final List<String> webhookList;
final BuiltMap<String, WebhookEntity> webhookMap;
final ListUIState listState;
final String filter;
final bool isLoading;
final bool isLoaded;
final Function(BuildContext, BaseEntity) onWebhookTap;
final Function(BuildContext) onRefreshed;
final Function(BuildContext, List<BaseEntity>, EntityAction) onEntityAction;
final Function onClearEntityFilterPressed;
final Function(BuildContext) onViewEntityFilterPressed;
final List<String> tableColumns;
final Function(String) onSortColumn;
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/data/models/webhook_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
class WebhookPresenter 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 webhook = entity as InvoiceEntity;
switch (field) {
}
return super.getField(field: field, context: context);
}
}

View File

@ -0,0 +1,138 @@
import 'dart:async';
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/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/ui/app/app_bottom_bar.dart';
import 'package:invoiceninja_flutter/ui/app/forms/save_cancel_buttons.dart';
import 'package:invoiceninja_flutter/ui/app/list_scaffold.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/list_filter.dart';
import 'package:invoiceninja_flutter/ui/webhook/webhook_list_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'webhook_screen_vm.dart';
class WebhookScreen extends StatelessWidget {
const WebhookScreen({
Key key,
@required this.viewModel,
}) : super(key: key);
static const String route = '/webhook';
final WebhookScreenVM 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);
final listUIState = state.uiState.webhookUIState.listUIState;
final isInMultiselect = listUIState.isInMultiselect();
return ListScaffold(
entityType: EntityType.webhook,
isChecked: isInMultiselect &&
listUIState.selectedIds.length == viewModel.webhookList.length,
showCheckbox: isInMultiselect,
onHamburgerLongPress: () => store.dispatch(StartWebhookMultiselect()),
onCheckboxChanged: (value) {
final webhooks = viewModel.webhookList
.map<WebhookEntity>((webhookId) => viewModel.webhookMap[webhookId])
.where((webhook) => value != listUIState.isSelected(webhook.id))
.toList();
handleWebhookAction(context, webhooks, EntityAction.toggleMultiselect);
},
appBarTitle: ListFilter(
title: localization.webhooks,
filter: state.webhookListState.filter,
onFilterChanged: (value) {
store.dispatch(FilterWebhooks(value));
},
),
appBarActions: [
if (viewModel.isInMultiselect)
SaveCancelButtons(
saveLabel: localization.done,
onSavePressed: listUIState.selectedIds.isEmpty
? null
: (context) async {
final webhooks = listUIState.selectedIds
.map<WebhookEntity>(
(webhookId) => viewModel.webhookMap[webhookId])
.toList();
await showEntityActionsDialog(
entities: webhooks,
context: context,
multiselect: true,
completer: Completer<Null>()
..future.then<dynamic>(
(_) => store.dispatch(ClearWebhookMultiselect())),
);
},
onCancelPressed: (context) =>
store.dispatch(ClearWebhookMultiselect()),
),
],
body: WebhookListBuilder(),
bottomNavigationBar: AppBottomBar(
entityType: EntityType.webhook,
tableColumns: WebhookPresenter.getAllTableFields(userCompany),
defaultTableColumns:
WebhookPresenter.getDefaultTableFields(userCompany),
onRefreshPressed: () => store.dispatch(LoadWebhooks(force: true)),
onSelectedSortField: (value) {
store.dispatch(SortWebhooks(value));
},
sortFields: [
WebhookFields.name,
WebhookFields.balance,
WebhookFields.updatedAt,
],
onSelectedState: (EntityState state, value) {
store.dispatch(FilterWebhooksByState(state));
},
onCheckboxPressed: () {
if (store.state.webhookListState.isInMultiselect()) {
store.dispatch(ClearWebhookMultiselect());
} else {
store.dispatch(StartWebhookMultiselect());
}
},
onSelectedCustom1: (value) =>
store.dispatch(FilterWebhooksByCustom1(value)),
onSelectedCustom2: (value) =>
store.dispatch(FilterWebhooksByCustom2(value)),
onSelectedCustom3: (value) =>
store.dispatch(FilterWebhooksByCustom3(value)),
onSelectedCustom4: (value) =>
store.dispatch(FilterWebhooksByCustom4(value)),
),
floatingActionButton: state.prefState.isMenuFloated &&
userCompany.canCreate(EntityType.webhook)
? FloatingActionButton(
heroTag: 'webhook_fab',
backgroundColor: Theme.of(context).primaryColorDark,
onPressed: () {
createEntityByType(
context: context, entityType: EntityType.webhook);
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newWebhook,
)
: null,
);
}
}

View File

@ -0,0 +1,59 @@
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/webhook/webhook_actions.dart';
import 'package:invoiceninja_flutter/redux/webhook/webhook_selectors.dart';
import 'package:redux/redux.dart';
import 'webhook_screen.dart';
class WebhookScreenBuilder extends StatelessWidget {
const WebhookScreenBuilder({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, WebhookScreenVM>(
converter: WebhookScreenVM.fromStore,
builder: (context, vm) {
return WebhookScreen(
viewModel: vm,
);
},
);
}
}
class WebhookScreenVM {
WebhookScreenVM({
@required this.isInMultiselect,
@required this.webhookList,
@required this.userCompany,
@required this.onEntityAction,
@required this.webhookMap,
});
final bool isInMultiselect;
final UserCompanyEntity userCompany;
final List<String> webhookList;
final Function(BuildContext, List<BaseEntity>, EntityAction) onEntityAction;
final BuiltMap<String, WebhookEntity> webhookMap;
static WebhookScreenVM fromStore(Store<AppState> store) {
final state = store.state;
return WebhookScreenVM(
webhookMap: state.webhookState.map,
webhookList: memoizedFilteredWebhookList(state.webhookState.map,
state.webhookState.list, state.webhookListState),
userCompany: state.userCompany,
isInMultiselect: state.webhookListState.isInMultiselect(),
onEntityAction: (BuildContext context, List<BaseEntity> webhooks,
EntityAction action) =>
handleWebhookAction(context, webhooks, action),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -339,7 +339,7 @@ else
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/data/models/serializers.dart sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/data/models/serializers.dart
comment="STARTER: serializers - do not remove comment" comment="STARTER: serializers - do not remove comment"
code="${Module}Entity,${Module}ListResponse,${Module}ItemResponse,${lineBreak}" code="${Module}Entity,${lineBreak}${Module}ListResponse,${lineBreak}${Module}ItemResponse,${lineBreak}"
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/data/models/serializers.dart sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/data/models/serializers.dart
comment="STARTER: import - do not remove comment" comment="STARTER: import - do not remove comment"

View File

@ -66,7 +66,6 @@ final stubListReducer = combineReducers<ListUIState>([
TypedReducer<ListUIState, FilterStubs>(_filterStubs), TypedReducer<ListUIState, FilterStubs>(_filterStubs),
TypedReducer<ListUIState, FilterStubsByCustom1>(_filterStubsByCustom1), TypedReducer<ListUIState, FilterStubsByCustom1>(_filterStubsByCustom1),
TypedReducer<ListUIState, FilterStubsByCustom2>(_filterStubsByCustom2), TypedReducer<ListUIState, FilterStubsByCustom2>(_filterStubsByCustom2),
TypedReducer<ListUIState, FilterStubsByEntity>(_filterStubsByClient),
TypedReducer<ListUIState, StartStubMultiselect>(_startListMultiselect), TypedReducer<ListUIState, StartStubMultiselect>(_startListMultiselect),
TypedReducer<ListUIState, AddToStubMultiselect>(_addToListMultiselect), TypedReducer<ListUIState, AddToStubMultiselect>(_addToListMultiselect),
TypedReducer<ListUIState, RemoveFromStubMultiselect>( TypedReducer<ListUIState, RemoveFromStubMultiselect>(