Tokens UI

This commit is contained in:
Hillel Coren 2020-07-05 14:50:53 +03:00
parent ad2e8cb1e0
commit bb1bdc1257
52 changed files with 4533 additions and 1321 deletions

View File

@ -324,12 +324,8 @@ abstract class ClientEntity extends Object
bool get hasEmailAddress => bool get hasEmailAddress =>
contacts.where((contact) => contact.email?.isNotEmpty).isNotEmpty; contacts.where((contact) => contact.email?.isNotEmpty).isNotEmpty;
int compareTo( int compareTo(ClientEntity client, String sortField, bool sortAscending,
ClientEntity client, BuiltMap<String, UserEntity> userMap, StaticState staticState) {
String sortField,
bool sortAscending,
BuiltMap<String, UserEntity> userMap,
StaticState staticState) {
int response = 0; int response = 0;
final ClientEntity clientA = sortAscending ? this : client; final ClientEntity clientA = sortAscending ? this : client;
final ClientEntity clientB = sortAscending ? client : this; final ClientEntity clientB = sortAscending ? client : this;
@ -378,9 +374,8 @@ abstract class ClientEntity extends Object
.compareTo(clientB.address2.toLowerCase()); .compareTo(clientB.address2.toLowerCase());
break; break;
case ClientFields.phone: case ClientFields.phone:
response = clientA.phone response =
.toLowerCase() clientA.phone.toLowerCase().compareTo(clientB.phone.toLowerCase());
.compareTo(clientB.phone.toLowerCase());
break; break;
case ClientFields.publicNotes: case ClientFields.publicNotes:
response = clientA.publicNotes response = clientA.publicNotes
@ -414,28 +409,38 @@ abstract class ClientEntity extends Object
.compareTo(userB.listDisplayName.toLowerCase()); .compareTo(userB.listDisplayName.toLowerCase());
break; break;
case ClientFields.country: case ClientFields.country:
final countryA = staticState.countryMap[clientA.countryId] ?? CountryEntity(); final countryA =
final countryB = staticState.countryMap[clientB.countryId] ?? CountryEntity(); staticState.countryMap[clientA.countryId] ?? CountryEntity();
response = countryA.name.toLowerCase() final countryB =
.compareTo(countryB.name.toLowerCase()); staticState.countryMap[clientB.countryId] ?? CountryEntity();
response =
countryA.name.toLowerCase().compareTo(countryB.name.toLowerCase());
break; break;
case ClientFields.currency: case ClientFields.currency:
final currencyA = staticState.currencyMap[clientA.currencyId] ?? CurrencyEntity(); final currencyA =
final currencyB = staticState.currencyMap[clientB.currencyId] ?? CurrencyEntity(); staticState.currencyMap[clientA.currencyId] ?? CurrencyEntity();
response = currencyA.name.toLowerCase() final currencyB =
staticState.currencyMap[clientB.currencyId] ?? CurrencyEntity();
response = currencyA.name
.toLowerCase()
.compareTo(currencyB.name.toLowerCase()); .compareTo(currencyB.name.toLowerCase());
break; break;
case EntityFields.state: case EntityFields.state:
case ClientFields.state: case ClientFields.state:
final stateA = EntityState.valueOf(clientA.entityState) ?? EntityState.active; final stateA =
final stateB = EntityState.valueOf(clientB.entityState) ?? EntityState.active; EntityState.valueOf(clientA.entityState) ?? EntityState.active;
response = stateA.name.toLowerCase() final stateB =
.compareTo(stateB.name.toLowerCase()); EntityState.valueOf(clientB.entityState) ?? EntityState.active;
response =
stateA.name.toLowerCase().compareTo(stateB.name.toLowerCase());
break; break;
case ClientFields.language: case ClientFields.language:
final languageA = staticState.languageMap[clientA.languageId] ?? LanguageEntity(); final languageA =
final languageB = staticState.languageMap[clientB.languageId] ?? LanguageEntity(); staticState.languageMap[clientA.languageId] ?? LanguageEntity();
response = languageA.name.toLowerCase() final languageB =
staticState.languageMap[clientB.languageId] ?? LanguageEntity();
response = languageA.name
.toLowerCase()
.compareTo(languageB.name.toLowerCase()); .compareTo(languageB.name.toLowerCase());
break; break;
case ClientFields.createdAt: case ClientFields.createdAt:

View File

@ -98,6 +98,7 @@ abstract class CompanyEntity extends Object
vendors: BuiltList<VendorEntity>(), vendors: BuiltList<VendorEntity>(),
designs: BuiltList<DesignEntity>(), designs: BuiltList<DesignEntity>(),
paymentTerms: BuiltList<PaymentTermEntity>(), paymentTerms: BuiltList<PaymentTermEntity>(),
tokens: BuiltList<TokenEntity>(),
); );
} }
@ -221,6 +222,8 @@ abstract class CompanyEntity extends Object
BuiltList<DesignEntity> get designs; BuiltList<DesignEntity> get designs;
BuiltList<TokenEntity> get tokens;
@BuiltValueField(wireName: 'payment_terms') @BuiltValueField(wireName: 'payment_terms')
BuiltList<PaymentTermEntity> get paymentTerms; BuiltList<PaymentTermEntity> get paymentTerms;
@ -666,37 +669,6 @@ abstract class ReportSettingsEntity
_$reportSettingsEntitySerializer; _$reportSettingsEntitySerializer;
} }
abstract class TokenEntity implements Built<TokenEntity, TokenEntityBuilder> {
factory TokenEntity() {
return _$TokenEntity._(
token: '',
name: '',
);
}
TokenEntity._();
@override
@memoized
int get hashCode;
String get token;
String get name;
String get obscuredToken => base64Encode(utf8.encode(token));
static String unobscureToken(String value) {
if (value == null || value.isEmpty) {
return null;
}
return utf8.decode(base64Decode(value));
}
static Serializer<TokenEntity> get serializer => _$tokenEntitySerializer;
}
abstract class SettingsEntity abstract class SettingsEntity
implements Built<SettingsEntity, SettingsEntityBuilder> { implements Built<SettingsEntity, SettingsEntityBuilder> {
factory SettingsEntity({ factory SettingsEntity({

View File

@ -16,7 +16,6 @@ Serializer<UserSettingsEntity> _$userSettingsEntitySerializer =
new _$UserSettingsEntitySerializer(); new _$UserSettingsEntitySerializer();
Serializer<ReportSettingsEntity> _$reportSettingsEntitySerializer = Serializer<ReportSettingsEntity> _$reportSettingsEntitySerializer =
new _$ReportSettingsEntitySerializer(); new _$ReportSettingsEntitySerializer();
Serializer<TokenEntity> _$tokenEntitySerializer = new _$TokenEntitySerializer();
Serializer<SettingsEntity> _$settingsEntitySerializer = Serializer<SettingsEntity> _$settingsEntitySerializer =
new _$SettingsEntitySerializer(); new _$SettingsEntitySerializer();
Serializer<CompanyItemResponse> _$companyItemResponseSerializer = Serializer<CompanyItemResponse> _$companyItemResponseSerializer =
@ -182,6 +181,10 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
serializers.serialize(object.designs, serializers.serialize(object.designs,
specifiedType: specifiedType:
const FullType(BuiltList, const [const FullType(DesignEntity)])), const FullType(BuiltList, const [const FullType(DesignEntity)])),
'tokens',
serializers.serialize(object.tokens,
specifiedType:
const FullType(BuiltList, const [const FullType(TokenEntity)])),
'payment_terms', 'payment_terms',
serializers.serialize(object.paymentTerms, serializers.serialize(object.paymentTerms,
specifiedType: const FullType( specifiedType: const FullType(
@ -486,6 +489,12 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
BuiltList, const [const FullType(DesignEntity)])) BuiltList, const [const FullType(DesignEntity)]))
as BuiltList<Object>); as BuiltList<Object>);
break; break;
case 'tokens':
result.tokens.replace(serializers.deserialize(value,
specifiedType: const FullType(
BuiltList, const [const FullType(TokenEntity)]))
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(
@ -914,52 +923,6 @@ class _$ReportSettingsEntitySerializer
} }
} }
class _$TokenEntitySerializer implements StructuredSerializer<TokenEntity> {
@override
final Iterable<Type> types = const [TokenEntity, _$TokenEntity];
@override
final String wireName = 'TokenEntity';
@override
Iterable<Object> serialize(Serializers serializers, TokenEntity object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'token',
serializers.serialize(object.token,
specifiedType: const FullType(String)),
'name',
serializers.serialize(object.name, specifiedType: const FullType(String)),
];
return result;
}
@override
TokenEntity deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TokenEntityBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'token':
result.token = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'name':
result.name = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$SettingsEntitySerializer class _$SettingsEntitySerializer
implements StructuredSerializer<SettingsEntity> { implements StructuredSerializer<SettingsEntity> {
@override @override
@ -2738,6 +2701,8 @@ class _$CompanyEntity extends CompanyEntity {
@override @override
final BuiltList<DesignEntity> designs; final BuiltList<DesignEntity> designs;
@override @override
final BuiltList<TokenEntity> tokens;
@override
final BuiltList<PaymentTermEntity> paymentTerms; final BuiltList<PaymentTermEntity> paymentTerms;
@override @override
final BuiltMap<String, UserEntity> userMap; final BuiltMap<String, UserEntity> userMap;
@ -2817,6 +2782,7 @@ class _$CompanyEntity extends CompanyEntity {
this.expenses, this.expenses,
this.vendors, this.vendors,
this.designs, this.designs,
this.tokens,
this.paymentTerms, this.paymentTerms,
this.userMap, this.userMap,
this.customFields, this.customFields,
@ -2968,6 +2934,9 @@ class _$CompanyEntity extends CompanyEntity {
if (designs == null) { if (designs == null) {
throw new BuiltValueNullFieldError('CompanyEntity', 'designs'); throw new BuiltValueNullFieldError('CompanyEntity', 'designs');
} }
if (tokens == null) {
throw new BuiltValueNullFieldError('CompanyEntity', 'tokens');
}
if (paymentTerms == null) { if (paymentTerms == null) {
throw new BuiltValueNullFieldError('CompanyEntity', 'paymentTerms'); throw new BuiltValueNullFieldError('CompanyEntity', 'paymentTerms');
} }
@ -3054,6 +3023,7 @@ class _$CompanyEntity extends CompanyEntity {
expenses == other.expenses && expenses == other.expenses &&
vendors == other.vendors && vendors == other.vendors &&
designs == other.designs && designs == other.designs &&
tokens == other.tokens &&
paymentTerms == other.paymentTerms && paymentTerms == other.paymentTerms &&
userMap == other.userMap && userMap == other.userMap &&
customFields == other.customFields && customFields == other.customFields &&
@ -3093,10 +3063,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(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), $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),
expenses.hashCode), vendors.hashCode),
vendors.hashCode), designs.hashCode),
designs.hashCode), tokens.hashCode),
paymentTerms.hashCode), paymentTerms.hashCode),
userMap.hashCode), userMap.hashCode),
customFields.hashCode), customFields.hashCode),
@ -3161,6 +3131,7 @@ class _$CompanyEntity extends CompanyEntity {
..add('expenses', expenses) ..add('expenses', expenses)
..add('vendors', vendors) ..add('vendors', vendors)
..add('designs', designs) ..add('designs', designs)
..add('tokens', tokens)
..add('paymentTerms', paymentTerms) ..add('paymentTerms', paymentTerms)
..add('userMap', userMap) ..add('userMap', userMap)
..add('customFields', customFields) ..add('customFields', customFields)
@ -3406,6 +3377,11 @@ class CompanyEntityBuilder
_$this._designs ??= new ListBuilder<DesignEntity>(); _$this._designs ??= new ListBuilder<DesignEntity>();
set designs(ListBuilder<DesignEntity> designs) => _$this._designs = designs; set designs(ListBuilder<DesignEntity> designs) => _$this._designs = designs;
ListBuilder<TokenEntity> _tokens;
ListBuilder<TokenEntity> get tokens =>
_$this._tokens ??= new ListBuilder<TokenEntity>();
set tokens(ListBuilder<TokenEntity> tokens) => _$this._tokens = tokens;
ListBuilder<PaymentTermEntity> _paymentTerms; ListBuilder<PaymentTermEntity> _paymentTerms;
ListBuilder<PaymentTermEntity> get paymentTerms => ListBuilder<PaymentTermEntity> get paymentTerms =>
_$this._paymentTerms ??= new ListBuilder<PaymentTermEntity>(); _$this._paymentTerms ??= new ListBuilder<PaymentTermEntity>();
@ -3529,6 +3505,7 @@ class CompanyEntityBuilder
_expenses = _$v.expenses?.toBuilder(); _expenses = _$v.expenses?.toBuilder();
_vendors = _$v.vendors?.toBuilder(); _vendors = _$v.vendors?.toBuilder();
_designs = _$v.designs?.toBuilder(); _designs = _$v.designs?.toBuilder();
_tokens = _$v.tokens?.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();
@ -3612,6 +3589,7 @@ class CompanyEntityBuilder
expenses: expenses.build(), expenses: expenses.build(),
vendors: vendors.build(), vendors: vendors.build(),
designs: designs.build(), designs: designs.build(),
tokens: tokens.build(),
paymentTerms: paymentTerms.build(), paymentTerms: paymentTerms.build(),
userMap: userMap.build(), userMap: userMap.build(),
customFields: customFields.build(), customFields: customFields.build(),
@ -3671,6 +3649,8 @@ class CompanyEntityBuilder
vendors.build(); vendors.build();
_$failedField = 'designs'; _$failedField = 'designs';
designs.build(); designs.build();
_$failedField = 'tokens';
tokens.build();
_$failedField = 'paymentTerms'; _$failedField = 'paymentTerms';
paymentTerms.build(); paymentTerms.build();
_$failedField = 'userMap'; _$failedField = 'userMap';
@ -4336,95 +4316,6 @@ class ReportSettingsEntityBuilder
} }
} }
class _$TokenEntity extends TokenEntity {
@override
final String token;
@override
final String name;
factory _$TokenEntity([void Function(TokenEntityBuilder) updates]) =>
(new TokenEntityBuilder()..update(updates)).build();
_$TokenEntity._({this.token, this.name}) : super._() {
if (token == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'token');
}
if (name == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'name');
}
}
@override
TokenEntity rebuild(void Function(TokenEntityBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TokenEntityBuilder toBuilder() => new TokenEntityBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is TokenEntity && token == other.token && name == other.name;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf($jc($jc(0, token.hashCode), name.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('TokenEntity')
..add('token', token)
..add('name', name))
.toString();
}
}
class TokenEntityBuilder implements Builder<TokenEntity, TokenEntityBuilder> {
_$TokenEntity _$v;
String _token;
String get token => _$this._token;
set token(String token) => _$this._token = token;
String _name;
String get name => _$this._name;
set name(String name) => _$this._name = name;
TokenEntityBuilder();
TokenEntityBuilder get _$this {
if (_$v != null) {
_token = _$v.token;
_name = _$v.name;
_$v = null;
}
return this;
}
@override
void replace(TokenEntity other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$TokenEntity;
}
@override
void update(void Function(TokenEntityBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$TokenEntity build() {
final _$result = _$v ?? new _$TokenEntity._(token: token, name: name);
replace(_$result);
return _$result;
}
}
class _$SettingsEntity extends SettingsEntity { class _$SettingsEntity extends SettingsEntity {
@override @override
final String timezoneId; final String timezoneId;

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 token = _$token;
static const EntityType paymentTerm = _$paymentTerm; static const EntityType paymentTerm = _$paymentTerm;
static const EntityType quoteItem = _$quoteItem; static const EntityType quoteItem = _$quoteItem;
static const EntityType contact = _$contact; static const EntityType contact = _$contact;

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 _$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');
const EntityType _$contact = const EntityType._('contact'); const EntityType _$contact = const EntityType._('contact');
@ -96,6 +97,8 @@ EntityType _$typeValueOf(String name) {
return _$invoiceItem; return _$invoiceItem;
case 'design': case 'design':
return _$design; return _$design;
case 'token':
return _$token;
case 'paymentTerm': case 'paymentTerm':
return _$paymentTerm; return _$paymentTerm;
case 'quoteItem': case 'quoteItem':
@ -157,6 +160,7 @@ final BuiltSet<EntityType> _$typeValues =
_$gatewayToken, _$gatewayToken,
_$invoiceItem, _$invoiceItem,
_$design, _$design,
_$token,
_$paymentTerm, _$paymentTerm,
_$quoteItem, _$quoteItem,
_$contact, _$contact,

View File

@ -418,7 +418,8 @@ abstract class InvoiceEntity extends Object
response = invoiceA.discount.compareTo(invoiceB.discount); response = invoiceA.discount.compareTo(invoiceB.discount);
break; break;
case InvoiceFields.documents: case InvoiceFields.documents:
response = invoiceA.documents.length.compareTo(invoiceB.documents.length); response =
invoiceA.documents.length.compareTo(invoiceB.documents.length);
break; break;
case InvoiceFields.poNumber: case InvoiceFields.poNumber:
response = invoiceA.poNumber.compareTo(invoiceB.poNumber); response = invoiceA.poNumber.compareTo(invoiceB.poNumber);
@ -433,10 +434,12 @@ abstract class InvoiceEntity extends Object
staticState.invoiceStatusMap[invoiceB.statusId]?.name ?? ''); staticState.invoiceStatusMap[invoiceB.statusId]?.name ?? '');
break; break;
case EntityFields.state: case EntityFields.state:
final stateA = EntityState.valueOf(invoiceA.entityState) ?? EntityState.active; final stateA =
final stateB = EntityState.valueOf(invoiceB.entityState) ?? EntityState.active; EntityState.valueOf(invoiceA.entityState) ?? EntityState.active;
response = stateA.name.toLowerCase() final stateB =
.compareTo(stateB.name.toLowerCase()); EntityState.valueOf(invoiceB.entityState) ?? EntityState.active;
response =
stateA.name.toLowerCase().compareTo(stateB.name.toLowerCase());
break; break;
case InvoiceFields.dueDate: case InvoiceFields.dueDate:
case QuoteFields.validUntil: case QuoteFields.validUntil:

View File

@ -9,6 +9,7 @@ export 'package:invoiceninja_flutter/data/models/tax_rate_model.dart';
export 'package:invoiceninja_flutter/data/models/document_model.dart'; 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/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

@ -283,10 +283,12 @@ abstract class PaymentEntity extends Object
.compareTo(userB.listDisplayName.toLowerCase()); .compareTo(userB.listDisplayName.toLowerCase());
break; break;
case EntityFields.state: case EntityFields.state:
final stateA = EntityState.valueOf(paymentA.entityState) ?? EntityState.active; final stateA =
final stateB = EntityState.valueOf(paymentB.entityState) ?? EntityState.active; EntityState.valueOf(paymentA.entityState) ?? EntityState.active;
response = stateA.name.toLowerCase() final stateB =
.compareTo(stateB.name.toLowerCase()); EntityState.valueOf(paymentB.entityState) ?? EntityState.active;
response =
stateA.name.toLowerCase().compareTo(stateB.name.toLowerCase());
break; break;
default: default:
print('## ERROR: sort by payment.$sortField is not implemented'); print('## ERROR: sort by payment.$sortField is not implemented');

View File

@ -222,10 +222,12 @@ abstract class ProductEntity extends Object
.compareTo(userB.listDisplayName.toLowerCase()); .compareTo(userB.listDisplayName.toLowerCase());
break; break;
case EntityFields.state: case EntityFields.state:
final stateA = EntityState.valueOf(productA.entityState) ?? EntityState.active; final stateA =
final stateB = EntityState.valueOf(productB.entityState) ?? EntityState.active; EntityState.valueOf(productA.entityState) ?? EntityState.active;
response = stateA.name.toLowerCase() final stateB =
.compareTo(stateB.name.toLowerCase()); EntityState.valueOf(productB.entityState) ?? EntityState.active;
response =
stateA.name.toLowerCase().compareTo(stateB.name.toLowerCase());
break; break;
case ProductFields.customValue1: case ProductFields.customValue1:
response = productA.customValue1 response = productA.customValue1

View File

@ -38,6 +38,9 @@ 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/token_model.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';
@ -113,6 +116,8 @@ part 'serializers.g.dart';
TaxRateItemResponse, TaxRateItemResponse,
TaxRateListResponse, TaxRateListResponse,
// STARTER: serializers - do not remove comment // STARTER: serializers - do not remove comment
TokenEntity, TokenListResponse, TokenItemResponse,
PaymentTermEntity, PaymentTermEntity,
PaymentTermListResponse, PaymentTermListResponse,
PaymentTermItemResponse, PaymentTermItemResponse,

View File

@ -149,6 +149,10 @@ Serializers _$serializers = (new Serializers().toBuilder()
..add(TimezoneItemResponse.serializer) ..add(TimezoneItemResponse.serializer)
..add(TimezoneListResponse.serializer) ..add(TimezoneListResponse.serializer)
..add(TokenEntity.serializer) ..add(TokenEntity.serializer)
..add(TokenItemResponse.serializer)
..add(TokenListResponse.serializer)
..add(TokenState.serializer)
..add(TokenUIState.serializer)
..add(UIState.serializer) ..add(UIState.serializer)
..add(UserCompanyEntity.serializer) ..add(UserCompanyEntity.serializer)
..add(UserCompanyItemResponse.serializer) ..add(UserCompanyItemResponse.serializer)
@ -338,6 +342,9 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(DesignEntity)]), const FullType(BuiltList, const [const FullType(DesignEntity)]),
() => new ListBuilder<DesignEntity>()) () => new ListBuilder<DesignEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(TokenEntity)]),
() => new ListBuilder<TokenEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(PaymentTermEntity)]), const FullType(BuiltList, const [const FullType(PaymentTermEntity)]),
() => new ListBuilder<PaymentTermEntity>()) () => new ListBuilder<PaymentTermEntity>())
@ -362,10 +369,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(InvoiceItemEntity)]), const FullType(BuiltList, const [const FullType(InvoiceItemEntity)]), () => new ListBuilder<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>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentEntity)]), () => new ListBuilder<PaymentEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentEntity)]), () => new ListBuilder<PaymentEntity>())
@ -381,6 +386,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TaskEntity)]), () => new ListBuilder<TaskEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(TaskEntity)]), () => new ListBuilder<TaskEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TaxRateEntity)]), () => new ListBuilder<TaxRateEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(TaxRateEntity)]), () => new ListBuilder<TaxRateEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TimezoneEntity)]), () => new ListBuilder<TimezoneEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(TimezoneEntity)]), () => new ListBuilder<TimezoneEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TokenEntity)]), () => new ListBuilder<TokenEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserCompanyEntity)]), () => new ListBuilder<UserCompanyEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserCompanyEntity)]), () => new ListBuilder<UserCompanyEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserCompanyState)]), () => new ListBuilder<UserCompanyState>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserCompanyState)]), () => new ListBuilder<UserCompanyState>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserEntity)]), () => new ListBuilder<UserEntity>()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserEntity)]), () => new ListBuilder<UserEntity>())
@ -450,6 +456,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
..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(TaxRateEntity)]), () => new MapBuilder<String, TaxRateEntity>()) ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(TaxRateEntity)]), () => new MapBuilder<String, TaxRateEntity>())
..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(TokenEntity)]), () => new MapBuilder<String, TokenEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..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>())

View File

@ -0,0 +1,186 @@
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 'token_model.g.dart';
abstract class TokenListResponse
implements Built<TokenListResponse, TokenListResponseBuilder> {
factory TokenListResponse([void updates(TokenListResponseBuilder b)]) =
_$TokenListResponse;
TokenListResponse._();
@override
@memoized
int get hashCode;
BuiltList<TokenEntity> get data;
static Serializer<TokenListResponse> get serializer =>
_$tokenListResponseSerializer;
}
abstract class TokenItemResponse
implements Built<TokenItemResponse, TokenItemResponseBuilder> {
factory TokenItemResponse([void updates(TokenItemResponseBuilder b)]) =
_$TokenItemResponse;
TokenItemResponse._();
@override
@memoized
int get hashCode;
TokenEntity get data;
static Serializer<TokenItemResponse> get serializer =>
_$tokenItemResponseSerializer;
}
class TokenFields {
static const String name = 'name';
static const String custom1 = 'custom1';
static const String custom2 = 'custom2';
}
abstract class TokenEntity extends Object
with BaseEntity, SelectableEntity
implements Built<TokenEntity, TokenEntityBuilder> {
factory TokenEntity({String id, AppState state}) {
return _$TokenEntity._(
id: id ?? BaseEntity.nextId,
isChanged: false,
name: '',
token: '',
updatedAt: 0,
archivedAt: 0,
isDeleted: false,
createdAt: 0,
assignedUserId: '',
createdUserId: '',
);
}
TokenEntity._();
@override
@memoized
int get hashCode;
@override
EntityType get entityType {
return EntityType.token;
}
// TODO remove this
@override
@nullable
String get id;
String get token;
String get name;
String get obscuredToken => base64Encode(utf8.encode(token));
static String unobscureToken(String value) {
if (value == null || value.isEmpty) {
return null;
}
return utf8.decode(base64Decode(value));
}
@override
String get listDisplayName {
return name;
}
int compareTo(TokenEntity token, String sortField, bool sortAscending) {
int response = 0;
final TokenEntity tokenA = sortAscending ? this : token;
final TokenEntity tokenB = sortAscending ? token : this;
switch (sortField) {
case TokenFields.name:
response =
tokenA.name.toLowerCase().compareTo(tokenB.name.toLowerCase());
break;
default:
print('## ERROR: sort by token.$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<TokenEntity> get serializer => _$tokenEntitySerializer;
}

View File

@ -0,0 +1,616 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'token_model.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<TokenListResponse> _$tokenListResponseSerializer =
new _$TokenListResponseSerializer();
Serializer<TokenItemResponse> _$tokenItemResponseSerializer =
new _$TokenItemResponseSerializer();
Serializer<TokenEntity> _$tokenEntitySerializer = new _$TokenEntitySerializer();
class _$TokenListResponseSerializer
implements StructuredSerializer<TokenListResponse> {
@override
final Iterable<Type> types = const [TokenListResponse, _$TokenListResponse];
@override
final String wireName = 'TokenListResponse';
@override
Iterable<Object> serialize(Serializers serializers, TokenListResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType:
const FullType(BuiltList, const [const FullType(TokenEntity)])),
];
return result;
}
@override
TokenListResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TokenListResponseBuilder();
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(TokenEntity)]))
as BuiltList<Object>);
break;
}
}
return result.build();
}
}
class _$TokenItemResponseSerializer
implements StructuredSerializer<TokenItemResponse> {
@override
final Iterable<Type> types = const [TokenItemResponse, _$TokenItemResponse];
@override
final String wireName = 'TokenItemResponse';
@override
Iterable<Object> serialize(Serializers serializers, TokenItemResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType: const FullType(TokenEntity)),
];
return result;
}
@override
TokenItemResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TokenItemResponseBuilder();
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(TokenEntity)) as TokenEntity);
break;
}
}
return result.build();
}
}
class _$TokenEntitySerializer implements StructuredSerializer<TokenEntity> {
@override
final Iterable<Type> types = const [TokenEntity, _$TokenEntity];
@override
final String wireName = 'TokenEntity';
@override
Iterable<Object> serialize(Serializers serializers, TokenEntity object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'token',
serializers.serialize(object.token,
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
TokenEntity deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TokenEntityBuilder();
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 'token':
result.token = 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 _$TokenListResponse extends TokenListResponse {
@override
final BuiltList<TokenEntity> data;
factory _$TokenListResponse(
[void Function(TokenListResponseBuilder) updates]) =>
(new TokenListResponseBuilder()..update(updates)).build();
_$TokenListResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('TokenListResponse', 'data');
}
}
@override
TokenListResponse rebuild(void Function(TokenListResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TokenListResponseBuilder toBuilder() =>
new TokenListResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is TokenListResponse && data == other.data;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('TokenListResponse')..add('data', data))
.toString();
}
}
class TokenListResponseBuilder
implements Builder<TokenListResponse, TokenListResponseBuilder> {
_$TokenListResponse _$v;
ListBuilder<TokenEntity> _data;
ListBuilder<TokenEntity> get data =>
_$this._data ??= new ListBuilder<TokenEntity>();
set data(ListBuilder<TokenEntity> data) => _$this._data = data;
TokenListResponseBuilder();
TokenListResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(TokenListResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$TokenListResponse;
}
@override
void update(void Function(TokenListResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$TokenListResponse build() {
_$TokenListResponse _$result;
try {
_$result = _$v ?? new _$TokenListResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'TokenListResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$TokenItemResponse extends TokenItemResponse {
@override
final TokenEntity data;
factory _$TokenItemResponse(
[void Function(TokenItemResponseBuilder) updates]) =>
(new TokenItemResponseBuilder()..update(updates)).build();
_$TokenItemResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('TokenItemResponse', 'data');
}
}
@override
TokenItemResponse rebuild(void Function(TokenItemResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TokenItemResponseBuilder toBuilder() =>
new TokenItemResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is TokenItemResponse && data == other.data;
}
int __hashCode;
@override
int get hashCode {
return __hashCode ??= $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('TokenItemResponse')..add('data', data))
.toString();
}
}
class TokenItemResponseBuilder
implements Builder<TokenItemResponse, TokenItemResponseBuilder> {
_$TokenItemResponse _$v;
TokenEntityBuilder _data;
TokenEntityBuilder get data => _$this._data ??= new TokenEntityBuilder();
set data(TokenEntityBuilder data) => _$this._data = data;
TokenItemResponseBuilder();
TokenItemResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(TokenItemResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$TokenItemResponse;
}
@override
void update(void Function(TokenItemResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$TokenItemResponse build() {
_$TokenItemResponse _$result;
try {
_$result = _$v ?? new _$TokenItemResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'TokenItemResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$TokenEntity extends TokenEntity {
@override
final String id;
@override
final String token;
@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 _$TokenEntity([void Function(TokenEntityBuilder) updates]) =>
(new TokenEntityBuilder()..update(updates)).build();
_$TokenEntity._(
{this.id,
this.token,
this.name,
this.isChanged,
this.createdAt,
this.updatedAt,
this.archivedAt,
this.isDeleted,
this.createdUserId,
this.assignedUserId})
: super._() {
if (token == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'token');
}
if (name == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'name');
}
if (createdAt == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'createdAt');
}
if (updatedAt == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'updatedAt');
}
if (archivedAt == null) {
throw new BuiltValueNullFieldError('TokenEntity', 'archivedAt');
}
}
@override
TokenEntity rebuild(void Function(TokenEntityBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TokenEntityBuilder toBuilder() => new TokenEntityBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is TokenEntity &&
id == other.id &&
token == other.token &&
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), token.hashCode),
name.hashCode),
isChanged.hashCode),
createdAt.hashCode),
updatedAt.hashCode),
archivedAt.hashCode),
isDeleted.hashCode),
createdUserId.hashCode),
assignedUserId.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('TokenEntity')
..add('id', id)
..add('token', token)
..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 TokenEntityBuilder implements Builder<TokenEntity, TokenEntityBuilder> {
_$TokenEntity _$v;
String _id;
String get id => _$this._id;
set id(String id) => _$this._id = id;
String _token;
String get token => _$this._token;
set token(String token) => _$this._token = token;
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;
TokenEntityBuilder();
TokenEntityBuilder get _$this {
if (_$v != null) {
_id = _$v.id;
_token = _$v.token;
_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(TokenEntity other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$TokenEntity;
}
@override
void update(void Function(TokenEntityBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$TokenEntity build() {
final _$result = _$v ??
new _$TokenEntity._(
id: id,
token: token,
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,76 @@
import 'dart:async';
import 'dart:convert';
import 'dart:core';
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 TokenRepository {
const TokenRepository({
this.webClient = const WebClient(),
});
final WebClient webClient;
Future<TokenEntity> loadItem(Credentials credentials, String entityId) async {
final dynamic response = await webClient.get(
'${credentials.url}/tokens/$entityId', credentials.token);
final TokenItemResponse tokenResponse =
serializers.deserializeWith(TokenItemResponse.serializer, response);
return tokenResponse.data;
}
Future<BuiltList<TokenEntity>> loadList(
Credentials credentials, int updatedAt) async {
String url = credentials.url + '/tokens?';
if (updatedAt > 0) {
url += '&updated_at=${updatedAt - kUpdatedAtBufferSeconds}';
}
final dynamic response = await webClient.get(url, credentials.token);
final TokenListResponse tokenResponse =
serializers.deserializeWith(TokenListResponse.serializer, response);
return tokenResponse.data;
}
Future<List<TokenEntity>> bulkAction(
Credentials credentials, List<String> ids, EntityAction action) async {
final url = credentials.url + '/tokens/bulk';
final dynamic response = await webClient.post(url, credentials.token,
data: json.encode({'ids': ids, 'action': '$action'}));
final TokenListResponse tokenResponse =
serializers.deserializeWith(TokenListResponse.serializer, response);
return tokenResponse.data.toList();
}
Future<TokenEntity> saveData(
Credentials credentials, TokenEntity token) async {
final data = serializers.serializeWith(TokenEntity.serializer, token);
dynamic response;
if (token.isNew) {
response = await webClient.post(
credentials.url + '/tokens', credentials.token,
data: json.encode(data));
} else {
final url = '${credentials.url}/tokens/${token.id}';
response =
await webClient.put(url, credentials.token, data: json.encode(data));
}
final TokenItemResponse tokenResponse =
serializers.deserializeWith(TokenItemResponse.serializer, response);
return tokenResponse.data;
}
}

View File

@ -38,8 +38,8 @@ import 'package:sentry/sentry.dart';
import 'package:shared_preferences/shared_preferences.dart'; 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/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';
void main({bool isTesting = false}) async { void main({bool isTesting = false}) async {
@ -70,6 +70,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(createStoreTokensMiddleware())
..addAll(createStorePaymentTermsMiddleware()) ..addAll(createStorePaymentTermsMiddleware())
..addAll(createStoreDesignsMiddleware()) ..addAll(createStoreDesignsMiddleware())
..addAll(createStoreCreditsMiddleware()) ..addAll(createStoreCreditsMiddleware())

View File

@ -50,6 +50,10 @@ import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:local_auth/local_auth.dart'; 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/token/token_screen.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/token_screen_vm.dart';
class InvoiceNinjaApp extends StatefulWidget { class InvoiceNinjaApp extends StatefulWidget {
const InvoiceNinjaApp({Key key, this.store}) : super(key: key); const InvoiceNinjaApp({Key key, this.store}) : super(key: key);
@ -250,6 +254,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
TokenScreen.route: (context) => TokenScreenBuilder(),
TokenViewScreen.route: (context) => TokenViewScreen(),
TokenEditScreen.route: (context) => TokenEditScreen(),
PaymentTermScreen.route: (context) => PaymentTermScreen.route: (context) =>
PaymentTermScreenBuilder(), PaymentTermScreenBuilder(),
PaymentTermEditScreen.route: (context) => PaymentTermEditScreen.route: (context) =>

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/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';
import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart';
@ -254,6 +256,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.token:
store.dispatch(ViewTokenList(navigator: navigator));
break;
case EntityType.paymentTerm: case EntityType.paymentTerm:
store.dispatch(ViewPaymentTermList(navigator: navigator)); store.dispatch(ViewPaymentTermList(navigator: navigator));
break; break;
@ -394,6 +400,14 @@ void viewEntityById({
)); ));
break; break;
// STARTER: view - do not remove comment // STARTER: view - do not remove comment
case EntityType.token:
store.dispatch(ViewToken(
tokenId: entityId,
navigator: navigator,
force: force,
));
break;
case EntityType.paymentTerm: case EntityType.paymentTerm:
store.dispatch(ViewPaymentTerm( store.dispatch(ViewPaymentTerm(
paymentTermId: entityId, paymentTermId: entityId,
@ -532,6 +546,14 @@ void createEntityByType(
)); ));
break; break;
// STARTER: create type - do not remove comment // STARTER: create type - do not remove comment
case EntityType.token:
store.dispatch(EditToken(
navigator: navigator,
force: force,
token: TokenEntity(state: state),
));
break;
case EntityType.paymentTerm: case EntityType.paymentTerm:
store.dispatch(EditPaymentTerm( store.dispatch(EditPaymentTerm(
navigator: navigator, navigator: navigator,
@ -700,6 +722,15 @@ void createEntity({
)); ));
break; break;
// STARTER: create - do not remove comment // STARTER: create - do not remove comment
case EntityType.token:
store.dispatch(EditToken(
navigator: navigator,
token: entity,
force: force,
completer: completer,
));
break;
case EntityType.paymentTerm: case EntityType.paymentTerm:
store.dispatch(EditPaymentTerm( store.dispatch(EditPaymentTerm(
navigator: navigator, navigator: navigator,
@ -912,6 +943,19 @@ void editEntityById(
)); ));
break; break;
// STARTER: edit - do not remove comment // STARTER: edit - do not remove comment
case EntityType.token:
store.dispatch(EditToken(
token: map[entityId],
navigator: navigator,
completer: completer ??
snackBarCompleter<TokenEntity>(
context,
entity.isNew
? localization.createdToken
: localization.updatedToken),
));
break;
case EntityType.paymentTerm: case EntityType.paymentTerm:
store.dispatch(EditPaymentTerm( store.dispatch(EditPaymentTerm(
paymentTerm: map[entityId], paymentTerm: map[entityId],
@ -1028,6 +1072,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.token:
handleTokenAction(context, entities, action);
break;
case EntityType.paymentTerm: case EntityType.paymentTerm:
handlePaymentTermAction(context, entities, action); handlePaymentTermAction(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/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';
import 'package:invoiceninja_flutter/redux/design/design_actions.dart'; import 'package:invoiceninja_flutter/redux/design/design_actions.dart';
import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart'; import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart';
@ -91,6 +93,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, LoadTokensFailure>((state, action) {
return '${action.error}';
}),
TypedReducer<String, LoadPaymentTermsFailure>((state, action) { TypedReducer<String, LoadPaymentTermsFailure>((state, action) {
return '${action.error}'; return '${action.error}';
}), }),

View File

@ -45,8 +45,10 @@ import 'package:invoiceninja_flutter/ui/credit/edit/credit_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/design/edit/design_edit_vm.dart'; 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/token/token_state.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/payment_term/payment_term_state.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_state.dart';
import 'package:invoiceninja_flutter/ui/payment_term/edit/payment_term_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/payment_term/edit/payment_term_edit_vm.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_selectors.dart'; import 'package:invoiceninja_flutter/redux/payment_term/payment_term_selectors.dart';
@ -208,6 +210,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.token:
return tokenState.map;
case EntityType.paymentTerm: case EntityType.paymentTerm:
return paymentTermState.map; return paymentTermState.map;
@ -274,6 +279,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.token:
return tokenState.list;
case EntityType.paymentTerm: case EntityType.paymentTerm:
return paymentTermState.list; return paymentTermState.list;
@ -319,6 +327,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.token:
return tokenUIState;
case EntityType.paymentTerm: case EntityType.paymentTerm:
return paymentTermUIState; return paymentTermUIState;
@ -376,6 +387,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
TokenState get tokenState => userCompanyState.tokenState;
ListUIState get tokenListState => uiState.tokenUIState.listUIState;
TokenUIState get tokenUIState => uiState.tokenUIState;
PaymentTermState get paymentTermState => userCompanyState.paymentTermState; PaymentTermState get paymentTermState => userCompanyState.paymentTermState;
ListUIState get paymentTermListState => ListUIState get paymentTermListState =>
@ -496,6 +511,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 TokenEditScreen.route:
return hasTokenChanges(tokenUIState.editing, tokenState.map);
case PaymentTermEditScreen.route: case PaymentTermEditScreen.route:
return hasPaymentTermChanges( return hasPaymentTermChanges(
paymentTermUIState.editing, paymentTermState.map); paymentTermUIState.editing, paymentTermState.map);

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/company_model.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_actions.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
@ -196,9 +196,11 @@ Middleware<AppState> _createRefreshRequest(AuthRepository repository) {
final action = dynamicAction as RefreshData; final action = dynamicAction as RefreshData;
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
final url = final url = formatApiUrl(
formatApiUrl(prefs.getString(kSharedPrefUrl) ?? store.state.authState.url); prefs.getString(kSharedPrefUrl) ?? store.state.authState.url);
final token = TokenEntity.unobscureToken(prefs.getString(kSharedPrefToken)) ?? 'TOKEN'; final token =
TokenEntity.unobscureToken(prefs.getString(kSharedPrefToken)) ??
'TOKEN';
store.dispatch(UserLoadUrl(url: url)); store.dispatch(UserLoadUrl(url: url));

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/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';
import 'package:invoiceninja_flutter/redux/design/design_reducer.dart'; import 'package:invoiceninja_flutter/redux/design/design_reducer.dart';
@ -46,6 +48,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
..tokenState.replace(tokensReducer(state.tokenState, action))
..paymentTermState ..paymentTermState
.replace(paymentTermsReducer(state.paymentTermState, action)) .replace(paymentTermsReducer(state.paymentTermState, action))
..designState.replace(designsReducer(state.designState, action)) ..designState.replace(designsReducer(state.designState, 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/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/redux/design/design_state.dart'; import 'package:invoiceninja_flutter/redux/design/design_state.dart';
@ -44,6 +46,8 @@ abstract class UserCompanyState
paymentState: PaymentState(), paymentState: PaymentState(),
quoteState: QuoteState(), quoteState: QuoteState(),
// STARTER: constructor - do not remove comment // STARTER: constructor - do not remove comment
tokenState: TokenState(),
paymentTermState: PaymentTermState(), paymentTermState: PaymentTermState(),
designState: DesignState(), designState: DesignState(),
creditState: CreditState(), creditState: CreditState(),
@ -84,6 +88,8 @@ abstract class UserCompanyState
QuoteState get quoteState; QuoteState get quoteState;
// STARTER: fields - do not remove comment // STARTER: fields - do not remove comment
TokenState get tokenState;
PaymentTermState get paymentTermState; PaymentTermState get paymentTermState;
DesignState get designState; DesignState get designState;

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)),
'tokenState',
serializers.serialize(object.tokenState,
specifiedType: const FullType(TokenState)),
'paymentTermState', 'paymentTermState',
serializers.serialize(object.paymentTermState, serializers.serialize(object.paymentTermState,
specifiedType: const FullType(PaymentTermState)), specifiedType: const FullType(PaymentTermState)),
@ -140,6 +143,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 'tokenState':
result.tokenState.replace(serializers.deserialize(value,
specifiedType: const FullType(TokenState)) as TokenState);
break;
case 'paymentTermState': case 'paymentTermState':
result.paymentTermState.replace(serializers.deserialize(value, result.paymentTermState.replace(serializers.deserialize(value,
specifiedType: const FullType(PaymentTermState)) specifiedType: const FullType(PaymentTermState))
@ -336,6 +343,8 @@ class _$UserCompanyState extends UserCompanyState {
@override @override
final QuoteState quoteState; final QuoteState quoteState;
@override @override
final TokenState tokenState;
@override
final PaymentTermState paymentTermState; final PaymentTermState paymentTermState;
@override @override
final DesignState designState; final DesignState designState;
@ -366,6 +375,7 @@ class _$UserCompanyState extends UserCompanyState {
this.projectState, this.projectState,
this.paymentState, this.paymentState,
this.quoteState, this.quoteState,
this.tokenState,
this.paymentTermState, this.paymentTermState,
this.designState, this.designState,
this.creditState, this.creditState,
@ -404,6 +414,9 @@ class _$UserCompanyState extends UserCompanyState {
if (quoteState == null) { if (quoteState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'quoteState'); throw new BuiltValueNullFieldError('UserCompanyState', 'quoteState');
} }
if (tokenState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'tokenState');
}
if (paymentTermState == null) { if (paymentTermState == null) {
throw new BuiltValueNullFieldError( throw new BuiltValueNullFieldError(
'UserCompanyState', 'paymentTermState'); 'UserCompanyState', 'paymentTermState');
@ -452,6 +465,7 @@ class _$UserCompanyState extends UserCompanyState {
projectState == other.projectState && projectState == other.projectState &&
paymentState == other.paymentState && paymentState == other.paymentState &&
quoteState == other.quoteState && quoteState == other.quoteState &&
tokenState == other.tokenState &&
paymentTermState == other.paymentTermState && paymentTermState == other.paymentTermState &&
designState == other.designState && designState == other.designState &&
creditState == other.creditState && creditState == other.creditState &&
@ -482,23 +496,26 @@ 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.hashCode), vendorState.hashCode),
vendorState.hashCode), taskState.hashCode),
taskState.hashCode), projectState.hashCode),
projectState.hashCode), paymentState.hashCode),
paymentState.hashCode), quoteState.hashCode),
quoteState.hashCode), tokenState.hashCode),
paymentTermState.hashCode), paymentTermState.hashCode),
designState.hashCode), designState.hashCode),
creditState.hashCode), creditState.hashCode),
@ -522,6 +539,7 @@ class _$UserCompanyState extends UserCompanyState {
..add('projectState', projectState) ..add('projectState', projectState)
..add('paymentState', paymentState) ..add('paymentState', paymentState)
..add('quoteState', quoteState) ..add('quoteState', quoteState)
..add('tokenState', tokenState)
..add('paymentTermState', paymentTermState) ..add('paymentTermState', paymentTermState)
..add('designState', designState) ..add('designState', designState)
..add('creditState', creditState) ..add('creditState', creditState)
@ -602,6 +620,12 @@ class UserCompanyStateBuilder
set quoteState(QuoteStateBuilder quoteState) => set quoteState(QuoteStateBuilder quoteState) =>
_$this._quoteState = quoteState; _$this._quoteState = quoteState;
TokenStateBuilder _tokenState;
TokenStateBuilder get tokenState =>
_$this._tokenState ??= new TokenStateBuilder();
set tokenState(TokenStateBuilder tokenState) =>
_$this._tokenState = tokenState;
PaymentTermStateBuilder _paymentTermState; PaymentTermStateBuilder _paymentTermState;
PaymentTermStateBuilder get paymentTermState => PaymentTermStateBuilder get paymentTermState =>
_$this._paymentTermState ??= new PaymentTermStateBuilder(); _$this._paymentTermState ??= new PaymentTermStateBuilder();
@ -658,6 +682,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();
_tokenState = _$v.tokenState?.toBuilder();
_paymentTermState = _$v.paymentTermState?.toBuilder(); _paymentTermState = _$v.paymentTermState?.toBuilder();
_designState = _$v.designState?.toBuilder(); _designState = _$v.designState?.toBuilder();
_creditState = _$v.creditState?.toBuilder(); _creditState = _$v.creditState?.toBuilder();
@ -700,6 +725,7 @@ class UserCompanyStateBuilder
projectState: projectState.build(), projectState: projectState.build(),
paymentState: paymentState.build(), paymentState: paymentState.build(),
quoteState: quoteState.build(), quoteState: quoteState.build(),
tokenState: tokenState.build(),
paymentTermState: paymentTermState.build(), paymentTermState: paymentTermState.build(),
designState: designState.build(), designState: designState.build(),
creditState: creditState.build(), creditState: creditState.build(),
@ -732,6 +758,8 @@ class UserCompanyStateBuilder
paymentState.build(); paymentState.build();
_$failedField = 'quoteState'; _$failedField = 'quoteState';
quoteState.build(); quoteState.build();
_$failedField = 'tokenState';
tokenState.build();
_$failedField = 'paymentTermState'; _$failedField = 'paymentTermState';
paymentTermState.build(); paymentTermState.build();
_$failedField = 'designState'; _$failedField = 'designState';

View File

@ -23,7 +23,8 @@ Reducer<String> selectedIdReducer = combineReducers([
(String selectedId, action) => action.companyGateway.id), (String selectedId, action) => action.companyGateway.id),
TypedReducer<String, SelectCompany>((selectedId, action) => ''), TypedReducer<String, SelectCompany>((selectedId, action) => ''),
TypedReducer<String, DeleteCompanyGatewaySuccess>((selectedId, action) => ''), TypedReducer<String, DeleteCompanyGatewaySuccess>((selectedId, action) => ''),
TypedReducer<String, ArchiveCompanyGatewaySuccess>((selectedId, action) => ''), TypedReducer<String, ArchiveCompanyGatewaySuccess>(
(selectedId, action) => ''),
TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''), TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''),
]); ]);

View File

@ -511,7 +511,8 @@ void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
case EntityAction.emailInvoice: case EntityAction.emailInvoice:
final client = state.clientState.get(invoice.clientId); final client = state.clientState.get(invoice.clientId);
if (!client.hasEmailAddress) { if (!client.hasEmailAddress) {
showMessageDialog(context: context, message: localization.clientEmailNotSet); showMessageDialog(
context: context, message: localization.clientEmailNotSet);
return; return;
} }
store.dispatch(ShowEmailInvoice( store.dispatch(ShowEmailInvoice(

View File

@ -0,0 +1,316 @@
import 'dart:async';
import 'package:built_collection/built_collection.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class ViewTokenList extends AbstractNavigatorAction
implements PersistUI, StopLoading {
ViewTokenList({
@required NavigatorState navigator,
this.force = false,
}) : super(navigator: navigator);
final bool force;
}
class ViewToken extends AbstractNavigatorAction
implements PersistUI, PersistPrefs {
ViewToken({
@required NavigatorState navigator,
@required this.tokenId,
this.force = false,
}) : super(navigator: navigator);
final String tokenId;
final bool force;
}
class EditToken extends AbstractNavigatorAction
implements PersistUI, PersistPrefs {
EditToken(
{@required this.token,
@required NavigatorState navigator,
this.completer,
this.cancelCompleter,
this.force = false})
: super(navigator: navigator);
final TokenEntity token;
final Completer completer;
final Completer cancelCompleter;
final bool force;
}
class UpdateToken implements PersistUI {
UpdateToken(this.token);
final TokenEntity token;
}
class LoadToken {
LoadToken({this.completer, this.tokenId});
final Completer completer;
final String tokenId;
}
class LoadTokenActivity {
LoadTokenActivity({this.completer, this.tokenId});
final Completer completer;
final String tokenId;
}
class LoadTokens {
LoadTokens({this.completer, this.force = false});
final Completer completer;
final bool force;
}
class LoadTokenRequest implements StartLoading {}
class LoadTokenFailure implements StopLoading {
LoadTokenFailure(this.error);
final dynamic error;
@override
String toString() {
return 'LoadTokenFailure{error: $error}';
}
}
class LoadTokenSuccess implements StopLoading, PersistData {
LoadTokenSuccess(this.token);
final TokenEntity token;
@override
String toString() {
return 'LoadTokenSuccess{token: $token}';
}
}
class LoadTokensRequest implements StartLoading {}
class LoadTokensFailure implements StopLoading {
LoadTokensFailure(this.error);
final dynamic error;
@override
String toString() {
return 'LoadTokensFailure{error: $error}';
}
}
class LoadTokensSuccess implements StopLoading, PersistData {
LoadTokensSuccess(this.tokens);
final BuiltList<TokenEntity> tokens;
@override
String toString() {
return 'LoadTokensSuccess{tokens: $tokens}';
}
}
class SaveTokenRequest implements StartSaving {
SaveTokenRequest({this.completer, this.token});
final Completer completer;
final TokenEntity token;
}
class SaveTokenSuccess implements StopSaving, PersistData, PersistUI {
SaveTokenSuccess(this.token);
final TokenEntity token;
}
class AddTokenSuccess implements StopSaving, PersistData, PersistUI {
AddTokenSuccess(this.token);
final TokenEntity token;
}
class SaveTokenFailure implements StopSaving {
SaveTokenFailure(this.error);
final Object error;
}
class ArchiveTokensRequest implements StartSaving {
ArchiveTokensRequest(this.completer, this.tokenIds);
final Completer completer;
final List<String> tokenIds;
}
class ArchiveTokensSuccess implements StopSaving, PersistData {
ArchiveTokensSuccess(this.tokens);
final List<TokenEntity> tokens;
}
class ArchiveTokensFailure implements StopSaving {
ArchiveTokensFailure(this.tokens);
final List<TokenEntity> tokens;
}
class DeleteTokensRequest implements StartSaving {
DeleteTokensRequest(this.completer, this.tokenIds);
final Completer completer;
final List<String> tokenIds;
}
class DeleteTokensSuccess implements StopSaving, PersistData {
DeleteTokensSuccess(this.tokens);
final List<TokenEntity> tokens;
}
class DeleteTokensFailure implements StopSaving {
DeleteTokensFailure(this.tokens);
final List<TokenEntity> tokens;
}
class RestoreTokensRequest implements StartSaving {
RestoreTokensRequest(this.completer, this.tokenIds);
final Completer completer;
final List<String> tokenIds;
}
class RestoreTokensSuccess implements StopSaving, PersistData {
RestoreTokensSuccess(this.tokens);
final List<TokenEntity> tokens;
}
class RestoreTokensFailure implements StopSaving {
RestoreTokensFailure(this.tokens);
final List<TokenEntity> tokens;
}
class FilterTokens implements PersistUI {
FilterTokens(this.filter);
final String filter;
}
class SortTokens implements PersistUI {
SortTokens(this.field);
final String field;
}
class FilterTokensByState implements PersistUI {
FilterTokensByState(this.state);
final EntityState state;
}
class FilterTokensByCustom1 implements PersistUI {
FilterTokensByCustom1(this.value);
final String value;
}
class FilterTokensByCustom2 implements PersistUI {
FilterTokensByCustom2(this.value);
final String value;
}
class FilterTokensByCustom3 implements PersistUI {
FilterTokensByCustom3(this.value);
final String value;
}
class FilterTokensByCustom4 implements PersistUI {
FilterTokensByCustom4(this.value);
final String value;
}
void handleTokenAction(
BuildContext context, List<BaseEntity> tokens, EntityAction action) {
if (tokens.isEmpty) {
return;
}
final store = StoreProvider.of<AppState>(context);
final localization = AppLocalization.of(context);
final token = tokens.first as TokenEntity;
final tokenIds = tokens.map((token) => token.id).toList();
switch (action) {
case EntityAction.edit:
editEntity(context: context, entity: token);
break;
case EntityAction.restore:
store.dispatch(RestoreTokensRequest(
snackBarCompleter<Null>(context, localization.restoredToken),
tokenIds));
break;
case EntityAction.archive:
store.dispatch(ArchiveTokensRequest(
snackBarCompleter<Null>(context, localization.archivedToken),
tokenIds));
break;
case EntityAction.delete:
store.dispatch(DeleteTokensRequest(
snackBarCompleter<Null>(context, localization.deletedToken),
tokenIds));
break;
case EntityAction.toggleMultiselect:
if (!store.state.tokenListState.isInMultiselect()) {
store.dispatch(StartTokenMultiselect());
}
if (tokens.isEmpty) {
break;
}
for (final token in tokens) {
if (!store.state.tokenListState.isSelected(token.id)) {
store.dispatch(AddToTokenMultiselect(entity: token));
} else {
store.dispatch(RemoveFromTokenMultiselect(entity: token));
}
}
break;
}
}
class StartTokenMultiselect {
StartTokenMultiselect();
}
class AddToTokenMultiselect {
AddToTokenMultiselect({@required this.entity});
final BaseEntity entity;
}
class RemoveFromTokenMultiselect {
RemoveFromTokenMultiselect({@required this.entity});
final BaseEntity entity;
}
class ClearTokenMultiselect {
ClearTokenMultiselect();
}

View File

@ -0,0 +1,273 @@
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/token/token_screen.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/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/data/repositories/token_repository.dart';
List<Middleware<AppState>> createStoreTokensMiddleware([
TokenRepository repository = const TokenRepository(),
]) {
final viewTokenList = _viewTokenList();
final viewToken = _viewToken();
final editToken = _editToken();
final loadTokens = _loadTokens(repository);
final loadToken = _loadToken(repository);
final saveToken = _saveToken(repository);
final archiveToken = _archiveToken(repository);
final deleteToken = _deleteToken(repository);
final restoreToken = _restoreToken(repository);
return [
TypedMiddleware<AppState, ViewTokenList>(viewTokenList),
TypedMiddleware<AppState, ViewToken>(viewToken),
TypedMiddleware<AppState, EditToken>(editToken),
TypedMiddleware<AppState, LoadTokens>(loadTokens),
TypedMiddleware<AppState, LoadToken>(loadToken),
TypedMiddleware<AppState, SaveTokenRequest>(saveToken),
TypedMiddleware<AppState, ArchiveTokensRequest>(archiveToken),
TypedMiddleware<AppState, DeleteTokensRequest>(deleteToken),
TypedMiddleware<AppState, RestoreTokensRequest>(restoreToken),
];
}
Middleware<AppState> _editToken() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as EditToken;
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(TokenEditScreen.route));
if (isMobile(action.context)) {
action.navigator.pushNamed(TokenEditScreen.route);
}
};
}
Middleware<AppState> _viewToken() {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewToken;
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(TokenViewScreen.route));
if (isMobile(action.context)) {
Navigator.of(action.context).pushNamed(TokenViewScreen.route);
}
};
}
Middleware<AppState> _viewTokenList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewTokenList;
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.tokenState.isStale) {
store.dispatch(LoadTokens());
}
store.dispatch(UpdateCurrentRoute(TokenScreen.route));
if (isMobile(action.context)) {
Navigator.of(action.context).pushNamedAndRemoveUntil(
TokenScreen.route, (Route<dynamic> route) => false);
}
};
}
Middleware<AppState> _archiveToken(TokenRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ArchiveTokensRequest;
final prevTokens =
action.tokenIds.map((id) => store.state.tokenState.map[id]).toList();
repository
.bulkAction(
store.state.credentials, action.tokenIds, EntityAction.archive)
.then((List<TokenEntity> tokens) {
store.dispatch(ArchiveTokensSuccess(tokens));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(ArchiveTokensFailure(prevTokens));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _deleteToken(TokenRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as DeleteTokensRequest;
final prevTokens =
action.tokenIds.map((id) => store.state.tokenState.map[id]).toList();
repository
.bulkAction(
store.state.credentials, action.tokenIds, EntityAction.delete)
.then((List<TokenEntity> tokens) {
store.dispatch(DeleteTokensSuccess(tokens));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(DeleteTokensFailure(prevTokens));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _restoreToken(TokenRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as RestoreTokensRequest;
final prevTokens =
action.tokenIds.map((id) => store.state.tokenState.map[id]).toList();
repository
.bulkAction(
store.state.credentials, action.tokenIds, EntityAction.restore)
.then((List<TokenEntity> tokens) {
store.dispatch(RestoreTokensSuccess(tokens));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(RestoreTokensFailure(prevTokens));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _saveToken(TokenRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as SaveTokenRequest;
repository
.saveData(store.state.credentials, action.token)
.then((TokenEntity token) {
if (action.token.isNew) {
store.dispatch(AddTokenSuccess(token));
} else {
store.dispatch(SaveTokenSuccess(token));
}
action.completer.complete(token);
}).catchError((Object error) {
print(error);
store.dispatch(SaveTokenFailure(error));
action.completer.completeError(error);
});
next(action);
};
}
Middleware<AppState> _loadToken(TokenRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadToken;
final AppState state = store.state;
if (state.isLoading) {
next(action);
return;
}
store.dispatch(LoadTokenRequest());
repository.loadItem(state.credentials, action.tokenId).then((token) {
store.dispatch(LoadTokenSuccess(token));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(LoadTokenFailure(error));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _loadTokens(TokenRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadTokens;
final AppState state = store.state;
if (!state.tokenState.isStale && !action.force) {
next(action);
return;
}
if (state.isLoading) {
next(action);
return;
}
final int updatedAt = (state.tokenState.lastUpdated / 1000).round();
store.dispatch(LoadTokensRequest());
repository.loadList(state.credentials, updatedAt).then((data) {
store.dispatch(LoadTokensSuccess(data));
if (action.completer != null) {
action.completer.complete(null);
}
/*
if (state.productState.isStale) {
store.dispatch(LoadProducts());
}
*/
}).catchError((Object error) {
print(error);
store.dispatch(LoadTokensFailure(error));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}

View File

@ -0,0 +1,279 @@
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/token/token_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/redux/token/token_state.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
EntityUIState tokenUIReducer(TokenUIState state, dynamic action) {
return state.rebuild((b) => b
..listUIState.replace(tokenListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.editing, action))
..selectedId = selectedIdReducer(state.selectedId, action));
}
Reducer<String> selectedIdReducer = combineReducers([
TypedReducer<String, ViewToken>(
(String selectedId, dynamic action) => action.tokenId),
TypedReducer<String, AddTokenSuccess>(
(String selectedId, dynamic action) => action.token.id),
TypedReducer<String, SelectCompany>((selectedId, action) => ''),
TypedReducer<String, DeleteTokensSuccess>((selectedId, action) => ''),
TypedReducer<String, ArchiveTokensSuccess>((selectedId, action) => ''),
TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''),
TypedReducer<String, FilterByEntity>((selectedId, action) =>
action.entityType == EntityType.token ? action.entityId : selectedId),
]);
final editingReducer = combineReducers<TokenEntity>([
TypedReducer<TokenEntity, SaveTokenSuccess>(_updateEditing),
TypedReducer<TokenEntity, AddTokenSuccess>(_updateEditing),
TypedReducer<TokenEntity, RestoreTokensSuccess>((tokens, action) {
return action.tokens[0];
}),
TypedReducer<TokenEntity, ArchiveTokensSuccess>((tokens, action) {
return action.tokens[0];
}),
TypedReducer<TokenEntity, DeleteTokensSuccess>((tokens, action) {
return action.tokens[0];
}),
TypedReducer<TokenEntity, EditToken>(_updateEditing),
TypedReducer<TokenEntity, UpdateToken>((token, action) {
return action.token.rebuild((b) => b..isChanged = true);
}),
TypedReducer<TokenEntity, SelectCompany>(_clearEditing),
TypedReducer<TokenEntity, DiscardChanges>(_clearEditing),
]);
TokenEntity _clearEditing(TokenEntity token, dynamic action) {
return TokenEntity();
}
TokenEntity _updateEditing(TokenEntity token, dynamic action) {
return action.token;
}
final tokenListReducer = combineReducers<ListUIState>([
TypedReducer<ListUIState, SortTokens>(_sortTokens),
TypedReducer<ListUIState, FilterTokensByState>(_filterTokensByState),
TypedReducer<ListUIState, FilterTokens>(_filterTokens),
TypedReducer<ListUIState, FilterTokensByCustom1>(_filterTokensByCustom1),
TypedReducer<ListUIState, FilterTokensByCustom2>(_filterTokensByCustom2),
TypedReducer<ListUIState, StartTokenMultiselect>(_startListMultiselect),
TypedReducer<ListUIState, AddToTokenMultiselect>(_addToListMultiselect),
TypedReducer<ListUIState, RemoveFromTokenMultiselect>(
_removeFromListMultiselect),
TypedReducer<ListUIState, ClearTokenMultiselect>(_clearListMultiselect),
TypedReducer<ListUIState, ClearEntityFilter>(
(state, action) => state.rebuild((b) => b
..filterEntityId = null
..filterEntityType = null)),
]);
ListUIState _filterTokensByCustom1(
ListUIState tokenListState, FilterTokensByCustom1 action) {
if (tokenListState.custom1Filters.contains(action.value)) {
return tokenListState
.rebuild((b) => b..custom1Filters.remove(action.value));
} else {
return tokenListState.rebuild((b) => b..custom1Filters.add(action.value));
}
}
ListUIState _filterTokensByCustom2(
ListUIState tokenListState, FilterTokensByCustom2 action) {
if (tokenListState.custom2Filters.contains(action.value)) {
return tokenListState
.rebuild((b) => b..custom2Filters.remove(action.value));
} else {
return tokenListState.rebuild((b) => b..custom2Filters.add(action.value));
}
}
ListUIState _filterTokensByState(
ListUIState tokenListState, FilterTokensByState action) {
if (tokenListState.stateFilters.contains(action.state)) {
return tokenListState.rebuild((b) => b..stateFilters.remove(action.state));
} else {
return tokenListState.rebuild((b) => b..stateFilters.add(action.state));
}
}
ListUIState _filterTokens(ListUIState tokenListState, FilterTokens action) {
return tokenListState.rebuild((b) => b
..filter = action.filter
..filterClearedAt = action.filter == null
? DateTime.now().millisecondsSinceEpoch
: tokenListState.filterClearedAt);
}
ListUIState _sortTokens(ListUIState tokenListState, SortTokens action) {
return tokenListState.rebuild((b) => b
..sortAscending = b.sortField != action.field || !b.sortAscending
..sortField = action.field);
}
ListUIState _startListMultiselect(
ListUIState productListState, StartTokenMultiselect action) {
return productListState.rebuild((b) => b..selectedIds = ListBuilder());
}
ListUIState _addToListMultiselect(
ListUIState productListState, AddToTokenMultiselect action) {
return productListState.rebuild((b) => b..selectedIds.add(action.entity.id));
}
ListUIState _removeFromListMultiselect(
ListUIState productListState, RemoveFromTokenMultiselect action) {
return productListState
.rebuild((b) => b..selectedIds.remove(action.entity.id));
}
ListUIState _clearListMultiselect(
ListUIState productListState, ClearTokenMultiselect action) {
return productListState.rebuild((b) => b..selectedIds = null);
}
final tokensReducer = combineReducers<TokenState>([
TypedReducer<TokenState, SaveTokenSuccess>(_updateToken),
TypedReducer<TokenState, AddTokenSuccess>(_addToken),
TypedReducer<TokenState, LoadTokensSuccess>(_setLoadedTokens),
TypedReducer<TokenState, LoadTokenSuccess>(_setLoadedToken),
TypedReducer<TokenState, LoadCompanySuccess>(_setLoadedCompany),
TypedReducer<TokenState, ArchiveTokensRequest>(_archiveTokenRequest),
TypedReducer<TokenState, ArchiveTokensSuccess>(_archiveTokenSuccess),
TypedReducer<TokenState, ArchiveTokensFailure>(_archiveTokenFailure),
TypedReducer<TokenState, DeleteTokensRequest>(_deleteTokenRequest),
TypedReducer<TokenState, DeleteTokensSuccess>(_deleteTokenSuccess),
TypedReducer<TokenState, DeleteTokensFailure>(_deleteTokenFailure),
TypedReducer<TokenState, RestoreTokensRequest>(_restoreTokenRequest),
TypedReducer<TokenState, RestoreTokensSuccess>(_restoreTokenSuccess),
TypedReducer<TokenState, RestoreTokensFailure>(_restoreTokenFailure),
]);
TokenState _archiveTokenRequest(
TokenState tokenState, ArchiveTokensRequest action) {
final tokens = action.tokenIds.map((id) => tokenState.map[id]).toList();
for (int i = 0; i < tokens.length; i++) {
tokens[i] = tokens[i]
.rebuild((b) => b..archivedAt = DateTime.now().millisecondsSinceEpoch);
}
return tokenState.rebuild((b) {
for (final token in tokens) {
b.map[token.id] = token;
}
});
}
TokenState _archiveTokenSuccess(
TokenState tokenState, ArchiveTokensSuccess action) {
return tokenState.rebuild((b) {
for (final token in action.tokens) {
b.map[token.id] = token;
}
});
}
TokenState _archiveTokenFailure(
TokenState tokenState, ArchiveTokensFailure action) {
return tokenState.rebuild((b) {
for (final token in action.tokens) {
b.map[token.id] = token;
}
});
}
TokenState _deleteTokenRequest(
TokenState tokenState, DeleteTokensRequest action) {
final tokens = action.tokenIds.map((id) => tokenState.map[id]).toList();
for (int i = 0; i < tokens.length; i++) {
tokens[i] = tokens[i].rebuild((b) => b
..archivedAt = DateTime.now().millisecondsSinceEpoch
..isDeleted = true);
}
return tokenState.rebuild((b) {
for (final token in tokens) {
b.map[token.id] = token;
}
});
}
TokenState _deleteTokenSuccess(
TokenState tokenState, DeleteTokensSuccess action) {
return tokenState.rebuild((b) {
for (final token in action.tokens) {
b.map[token.id] = token;
}
});
}
TokenState _deleteTokenFailure(
TokenState tokenState, DeleteTokensFailure action) {
return tokenState.rebuild((b) {
for (final token in action.tokens) {
b.map[token.id] = token;
}
});
}
TokenState _restoreTokenRequest(
TokenState tokenState, RestoreTokensRequest action) {
final tokens = action.tokenIds.map((id) => tokenState.map[id]).toList();
for (int i = 0; i < tokens.length; i++) {
tokens[i] = tokens[i].rebuild((b) => b
..archivedAt = 0
..isDeleted = false);
}
return tokenState.rebuild((b) {
for (final token in tokens) {
b.map[token.id] = token;
}
});
}
TokenState _restoreTokenSuccess(
TokenState tokenState, RestoreTokensSuccess action) {
return tokenState.rebuild((b) {
for (final token in action.tokens) {
b.map[token.id] = token;
}
});
}
TokenState _restoreTokenFailure(
TokenState tokenState, RestoreTokensFailure action) {
return tokenState.rebuild((b) {
for (final token in action.tokens) {
b.map[token.id] = token;
}
});
}
TokenState _addToken(TokenState tokenState, AddTokenSuccess action) {
return tokenState.rebuild((b) => b
..map[action.token.id] = action.token
..list.add(action.token.id));
}
TokenState _updateToken(TokenState tokenState, SaveTokenSuccess action) {
return tokenState.rebuild((b) => b..map[action.token.id] = action.token);
}
TokenState _setLoadedToken(TokenState tokenState, LoadTokenSuccess action) {
return tokenState.rebuild((b) => b..map[action.token.id] = action.token);
}
TokenState _setLoadedTokens(TokenState tokenState, LoadTokensSuccess action) =>
tokenState.loadTokens(action.tokens);
TokenState _setLoadedCompany(TokenState tokenState, LoadCompanySuccess action) {
final company = action.userCompany.company;
return company.hasData ? tokenState.loadTokens(company.tokens) : tokenState;
}

View File

@ -0,0 +1,63 @@
import 'package:invoiceninja_flutter/data/models/token_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 memoizedDropdownTokenList = memo3((BuiltMap<String, TokenEntity> tokenMap,
BuiltList<String> tokenList, String clientId) =>
dropdownTokensSelector(tokenMap, tokenList, clientId));
List<String> dropdownTokensSelector(BuiltMap<String, TokenEntity> tokenMap,
BuiltList<String> tokenList, String clientId) {
final list = tokenList.where((tokenId) {
final token = tokenMap[tokenId];
/*
if (clientId != null && clientId > 0 && token.clientId != clientId) {
return false;
}
*/
return token.isActive;
}).toList();
list.sort((tokenAId, tokenBId) {
final tokenA = tokenMap[tokenAId];
final tokenB = tokenMap[tokenBId];
return tokenA.compareTo(tokenB, TokenFields.name, true);
});
return list;
}
var memoizedFilteredTokenList = memo3((BuiltMap<String, TokenEntity> tokenMap,
BuiltList<String> tokenList, ListUIState tokenListState) =>
filteredTokensSelector(tokenMap, tokenList, tokenListState));
List<String> filteredTokensSelector(BuiltMap<String, TokenEntity> tokenMap,
BuiltList<String> tokenList, ListUIState tokenListState) {
final list = tokenList.where((tokenId) {
final token = tokenMap[tokenId];
if (tokenListState.filterEntityId != null &&
token.id != tokenListState.filterEntityId) {
return false;
} else {}
if (!token.matchesStates(tokenListState.stateFilters)) {
return false;
}
return token.matchesFilter(tokenListState.filter);
}).toList();
list.sort((tokenAId, tokenBId) {
final tokenA = tokenMap[tokenAId];
final tokenB = tokenMap[tokenBId];
return tokenA.compareTo(
tokenB, tokenListState.sortField, tokenListState.sortAscending);
});
return list;
}
bool hasTokenChanges(
TokenEntity token, BuiltMap<String, TokenEntity> tokenMap) =>
token.isNew ? token.isChanged : token != tokenMap[token.id];

View File

@ -0,0 +1,86 @@
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/token_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 'token_state.g.dart';
abstract class TokenState implements Built<TokenState, TokenStateBuilder> {
factory TokenState() {
return _$TokenState._(
lastUpdated: 0,
map: BuiltMap<String, TokenEntity>(),
list: BuiltList<String>(),
);
}
TokenState._();
@override
@memoized
int get hashCode;
@nullable
int get lastUpdated;
BuiltMap<String, TokenEntity> 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;
TokenState loadTokens(BuiltList<TokenEntity> clients) {
final map = Map<String, TokenEntity>.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<TokenState> get serializer => _$tokenStateSerializer;
}
abstract class TokenUIState extends Object
with EntityUIState
implements Built<TokenUIState, TokenUIStateBuilder> {
factory TokenUIState() {
return _$TokenUIState._(
listUIState: ListUIState(TokenFields.name),
editing: TokenEntity(),
selectedId: '',
);
}
TokenUIState._();
@override
@memoized
int get hashCode;
@nullable
TokenEntity get editing;
@override
bool get isCreatingNew => editing.isNew;
@override
String get editingId => editing.id;
static Serializer<TokenUIState> get serializer => _$tokenUIStateSerializer;
}

View File

@ -0,0 +1,407 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'token_state.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<TokenState> _$tokenStateSerializer = new _$TokenStateSerializer();
Serializer<TokenUIState> _$tokenUIStateSerializer =
new _$TokenUIStateSerializer();
class _$TokenStateSerializer implements StructuredSerializer<TokenState> {
@override
final Iterable<Type> types = const [TokenState, _$TokenState];
@override
final String wireName = 'TokenState';
@override
Iterable<Object> serialize(Serializers serializers, TokenState object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'map',
serializers.serialize(object.map,
specifiedType: const FullType(BuiltMap,
const [const FullType(String), const FullType(TokenEntity)])),
'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
TokenState deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TokenStateBuilder();
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(TokenEntity)
])));
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 _$TokenUIStateSerializer implements StructuredSerializer<TokenUIState> {
@override
final Iterable<Type> types = const [TokenUIState, _$TokenUIState];
@override
final String wireName = 'TokenUIState';
@override
Iterable<Object> serialize(Serializers serializers, TokenUIState 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(TokenEntity)));
}
if (object.selectedId != null) {
result
..add('selectedId')
..add(serializers.serialize(object.selectedId,
specifiedType: const FullType(String)));
}
return result;
}
@override
TokenUIState deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TokenUIStateBuilder();
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(TokenEntity)) as TokenEntity);
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 _$TokenState extends TokenState {
@override
final int lastUpdated;
@override
final BuiltMap<String, TokenEntity> map;
@override
final BuiltList<String> list;
factory _$TokenState([void Function(TokenStateBuilder) updates]) =>
(new TokenStateBuilder()..update(updates)).build();
_$TokenState._({this.lastUpdated, this.map, this.list}) : super._() {
if (map == null) {
throw new BuiltValueNullFieldError('TokenState', 'map');
}
if (list == null) {
throw new BuiltValueNullFieldError('TokenState', 'list');
}
}
@override
TokenState rebuild(void Function(TokenStateBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TokenStateBuilder toBuilder() => new TokenStateBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is TokenState &&
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('TokenState')
..add('lastUpdated', lastUpdated)
..add('map', map)
..add('list', list))
.toString();
}
}
class TokenStateBuilder implements Builder<TokenState, TokenStateBuilder> {
_$TokenState _$v;
int _lastUpdated;
int get lastUpdated => _$this._lastUpdated;
set lastUpdated(int lastUpdated) => _$this._lastUpdated = lastUpdated;
MapBuilder<String, TokenEntity> _map;
MapBuilder<String, TokenEntity> get map =>
_$this._map ??= new MapBuilder<String, TokenEntity>();
set map(MapBuilder<String, TokenEntity> map) => _$this._map = map;
ListBuilder<String> _list;
ListBuilder<String> get list => _$this._list ??= new ListBuilder<String>();
set list(ListBuilder<String> list) => _$this._list = list;
TokenStateBuilder();
TokenStateBuilder get _$this {
if (_$v != null) {
_lastUpdated = _$v.lastUpdated;
_map = _$v.map?.toBuilder();
_list = _$v.list?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(TokenState other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$TokenState;
}
@override
void update(void Function(TokenStateBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$TokenState build() {
_$TokenState _$result;
try {
_$result = _$v ??
new _$TokenState._(
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(
'TokenState', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$TokenUIState extends TokenUIState {
@override
final TokenEntity editing;
@override
final ListUIState listUIState;
@override
final String selectedId;
@override
final Completer<SelectableEntity> saveCompleter;
@override
final Completer<Null> cancelCompleter;
factory _$TokenUIState([void Function(TokenUIStateBuilder) updates]) =>
(new TokenUIStateBuilder()..update(updates)).build();
_$TokenUIState._(
{this.editing,
this.listUIState,
this.selectedId,
this.saveCompleter,
this.cancelCompleter})
: super._() {
if (listUIState == null) {
throw new BuiltValueNullFieldError('TokenUIState', 'listUIState');
}
}
@override
TokenUIState rebuild(void Function(TokenUIStateBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TokenUIStateBuilder toBuilder() => new TokenUIStateBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is TokenUIState &&
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('TokenUIState')
..add('editing', editing)
..add('listUIState', listUIState)
..add('selectedId', selectedId)
..add('saveCompleter', saveCompleter)
..add('cancelCompleter', cancelCompleter))
.toString();
}
}
class TokenUIStateBuilder
implements Builder<TokenUIState, TokenUIStateBuilder> {
_$TokenUIState _$v;
TokenEntityBuilder _editing;
TokenEntityBuilder get editing =>
_$this._editing ??= new TokenEntityBuilder();
set editing(TokenEntityBuilder 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;
TokenUIStateBuilder();
TokenUIStateBuilder 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(TokenUIState other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$TokenUIState;
}
@override
void update(void Function(TokenUIStateBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$TokenUIState build() {
_$TokenUIState _$result;
try {
_$result = _$v ??
new _$TokenUIState._(
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(
'TokenUIState', _$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

@ -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/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';
import 'package:invoiceninja_flutter/redux/design/design_actions.dart'; import 'package:invoiceninja_flutter/redux/design/design_actions.dart';
@ -410,6 +412,13 @@ 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>, ViewToken>((historyList, action) =>
_addToHistory(historyList,
HistoryRecord(id: action.tokenId, entityType: EntityType.token))),
TypedReducer<BuiltList<HistoryRecord>, EditToken>((historyList, action) =>
_addToHistory(historyList,
HistoryRecord(id: action.token.id, entityType: EntityType.token))),
TypedReducer<BuiltList<HistoryRecord>, ViewPaymentTerm>( TypedReducer<BuiltList<HistoryRecord>, ViewPaymentTerm>(
(historyList, action) => _addToHistory( (historyList, action) => _addToHistory(
historyList, historyList,

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/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';
import 'package:invoiceninja_flutter/redux/design/design_reducer.dart'; import 'package:invoiceninja_flutter/redux/design/design_reducer.dart';
import 'package:invoiceninja_flutter/redux/credit/credit_reducer.dart'; import 'package:invoiceninja_flutter/redux/credit/credit_reducer.dart';
@ -63,6 +65,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
..tokenUIState.replace(tokenUIReducer(state.tokenUIState, action))
..paymentTermUIState ..paymentTermUIState
.replace(paymentTermUIReducer(state.paymentTermUIState, action)) .replace(paymentTermUIReducer(state.paymentTermUIState, action))
..designUIState.replace(designUIReducer(state.designUIState, action)) ..designUIState.replace(designUIReducer(state.designUIState, 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/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/redux/design/design_state.dart'; import 'package:invoiceninja_flutter/redux/design/design_state.dart';
@ -42,6 +44,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
tokenUIState: TokenUIState(),
paymentTermUIState: PaymentTermUIState(), paymentTermUIState: PaymentTermUIState(),
designUIState: DesignUIState(), designUIState: DesignUIState(),
@ -94,6 +98,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
TokenUIState get tokenUIState;
PaymentTermUIState get paymentTermUIState; PaymentTermUIState get paymentTermUIState;
DesignUIState get designUIState; DesignUIState get designUIState;

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)),
'tokenUIState',
serializers.serialize(object.tokenUIState,
specifiedType: const FullType(TokenUIState)),
'paymentTermUIState', 'paymentTermUIState',
serializers.serialize(object.paymentTermUIState, serializers.serialize(object.paymentTermUIState,
specifiedType: const FullType(PaymentTermUIState)), specifiedType: const FullType(PaymentTermUIState)),
@ -168,6 +171,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 'tokenUIState':
result.tokenUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(TokenUIState)) as TokenUIState);
break;
case 'paymentTermUIState': case 'paymentTermUIState':
result.paymentTermUIState.replace(serializers.deserialize(value, result.paymentTermUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(PaymentTermUIState)) specifiedType: const FullType(PaymentTermUIState))
@ -267,6 +274,8 @@ class _$UIState extends UIState {
@override @override
final InvoiceUIState invoiceUIState; final InvoiceUIState invoiceUIState;
@override @override
final TokenUIState tokenUIState;
@override
final PaymentTermUIState paymentTermUIState; final PaymentTermUIState paymentTermUIState;
@override @override
final DesignUIState designUIState; final DesignUIState designUIState;
@ -314,6 +323,7 @@ class _$UIState extends UIState {
this.productUIState, this.productUIState,
this.clientUIState, this.clientUIState,
this.invoiceUIState, this.invoiceUIState,
this.tokenUIState,
this.paymentTermUIState, this.paymentTermUIState,
this.designUIState, this.designUIState,
this.creditUIState, this.creditUIState,
@ -355,6 +365,9 @@ class _$UIState extends UIState {
if (invoiceUIState == null) { if (invoiceUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'invoiceUIState'); throw new BuiltValueNullFieldError('UIState', 'invoiceUIState');
} }
if (tokenUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'tokenUIState');
}
if (paymentTermUIState == null) { if (paymentTermUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'paymentTermUIState'); throw new BuiltValueNullFieldError('UIState', 'paymentTermUIState');
} }
@ -427,6 +440,7 @@ class _$UIState extends UIState {
productUIState == other.productUIState && productUIState == other.productUIState &&
clientUIState == other.clientUIState && clientUIState == other.clientUIState &&
invoiceUIState == other.invoiceUIState && invoiceUIState == other.invoiceUIState &&
tokenUIState == other.tokenUIState &&
paymentTermUIState == other.paymentTermUIState && paymentTermUIState == other.paymentTermUIState &&
designUIState == other.designUIState && designUIState == other.designUIState &&
creditUIState == other.creditUIState && creditUIState == other.creditUIState &&
@ -466,10 +480,10 @@ class _$UIState extends UIState {
$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), $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),
productUIState.hashCode), clientUIState.hashCode),
clientUIState.hashCode), invoiceUIState.hashCode),
invoiceUIState.hashCode), tokenUIState.hashCode),
paymentTermUIState.hashCode), paymentTermUIState.hashCode),
designUIState.hashCode), designUIState.hashCode),
creditUIState.hashCode), creditUIState.hashCode),
@ -502,6 +516,7 @@ class _$UIState extends UIState {
..add('productUIState', productUIState) ..add('productUIState', productUIState)
..add('clientUIState', clientUIState) ..add('clientUIState', clientUIState)
..add('invoiceUIState', invoiceUIState) ..add('invoiceUIState', invoiceUIState)
..add('tokenUIState', tokenUIState)
..add('paymentTermUIState', paymentTermUIState) ..add('paymentTermUIState', paymentTermUIState)
..add('designUIState', designUIState) ..add('designUIState', designUIState)
..add('creditUIState', creditUIState) ..add('creditUIState', creditUIState)
@ -582,6 +597,12 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
set invoiceUIState(InvoiceUIStateBuilder invoiceUIState) => set invoiceUIState(InvoiceUIStateBuilder invoiceUIState) =>
_$this._invoiceUIState = invoiceUIState; _$this._invoiceUIState = invoiceUIState;
TokenUIStateBuilder _tokenUIState;
TokenUIStateBuilder get tokenUIState =>
_$this._tokenUIState ??= new TokenUIStateBuilder();
set tokenUIState(TokenUIStateBuilder tokenUIState) =>
_$this._tokenUIState = tokenUIState;
PaymentTermUIStateBuilder _paymentTermUIState; PaymentTermUIStateBuilder _paymentTermUIState;
PaymentTermUIStateBuilder get paymentTermUIState => PaymentTermUIStateBuilder get paymentTermUIState =>
_$this._paymentTermUIState ??= new PaymentTermUIStateBuilder(); _$this._paymentTermUIState ??= new PaymentTermUIStateBuilder();
@ -694,6 +715,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();
_tokenUIState = _$v.tokenUIState?.toBuilder();
_paymentTermUIState = _$v.paymentTermUIState?.toBuilder(); _paymentTermUIState = _$v.paymentTermUIState?.toBuilder();
_designUIState = _$v.designUIState?.toBuilder(); _designUIState = _$v.designUIState?.toBuilder();
_creditUIState = _$v.creditUIState?.toBuilder(); _creditUIState = _$v.creditUIState?.toBuilder();
@ -745,6 +767,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(),
tokenUIState: tokenUIState.build(),
paymentTermUIState: paymentTermUIState.build(), paymentTermUIState: paymentTermUIState.build(),
designUIState: designUIState.build(), designUIState: designUIState.build(),
creditUIState: creditUIState.build(), creditUIState: creditUIState.build(),
@ -772,6 +795,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
clientUIState.build(); clientUIState.build();
_$failedField = 'invoiceUIState'; _$failedField = 'invoiceUIState';
invoiceUIState.build(); invoiceUIState.build();
_$failedField = 'tokenUIState';
tokenUIState.build();
_$failedField = 'paymentTermUIState'; _$failedField = 'paymentTermUIState';
paymentTermUIState.build(); paymentTermUIState.build();
_$failedField = 'designUIState'; _$failedField = 'designUIState';

View File

@ -31,7 +31,6 @@ class ViewScaffold extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localization = AppLocalization.of(context); final localization = AppLocalization.of(context);
final store = StoreProvider.of<AppState>(context); final store = StoreProvider.of<AppState>(context);
final state = store.state; final state = store.state;

View File

@ -79,7 +79,8 @@ class CompanyGatewayViewVM {
store.dispatch(UpdateCurrentRoute(CompanyGatewayScreen.route)); store.dispatch(UpdateCurrentRoute(CompanyGatewayScreen.route));
}, },
onEntityAction: (BuildContext context, EntityAction action) => onEntityAction: (BuildContext context, EntityAction action) =>
handleEntitiesActions(context, [companyGateway], action, autoPop: true), handleEntitiesActions(context, [companyGateway], action,
autoPop: true),
); );
} }

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/token/edit/token_edit_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
class TokenEdit extends StatefulWidget {
const TokenEdit({
Key key,
@required this.viewModel,
}) : super(key: key);
final TokenEditVM viewModel;
@override
_TokenEditState createState() => _TokenEditState();
}
class _TokenEditState extends State<TokenEdit> {
static final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: '_tokenEdit');
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 token = widget.viewModel.token;
// 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 token = widget.viewModel.token.rebuild((b) => b
// STARTER: set value - do not remove comment
);
if (token != widget.viewModel.token) {
widget.viewModel.onChanged(token);
}
});
}
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final localization = AppLocalization.of(context);
//final token = viewModel.token;
return EditScaffold(
title: localization.editToken,
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,101 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/token/view/token_view_vm.dart';
import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/data/models/token_model.dart';
import 'package:invoiceninja_flutter/ui/token/edit/token_edit.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class TokenEditScreen extends StatelessWidget {
const TokenEditScreen({Key key}) : super(key: key);
static const String route = '/token/edit';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, TokenEditVM>(
converter: (Store<AppState> store) {
return TokenEditVM.fromStore(store);
},
builder: (context, viewModel) {
return TokenEdit(
viewModel: viewModel,
key: ValueKey(viewModel.token.id),
);
},
);
}
}
class TokenEditVM {
TokenEditVM({
@required this.state,
@required this.token,
@required this.company,
@required this.onChanged,
@required this.isSaving,
@required this.origToken,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.isLoading,
});
factory TokenEditVM.fromStore(Store<AppState> store) {
final state = store.state;
final token = state.tokenUIState.editing;
return TokenEditVM(
state: state,
isLoading: state.isLoading,
isSaving: state.isSaving,
origToken: state.tokenState.map[token.id],
token: token,
company: state.company,
onChanged: (TokenEntity token) {
store.dispatch(UpdateToken(token));
},
onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: TokenEntity(), force: true);
},
onSavePressed: (BuildContext context) {
final Completer<TokenEntity> completer = new Completer<TokenEntity>();
store.dispatch(SaveTokenRequest(completer: completer, token: token));
return completer.future.then((savedToken) {
if (isMobile(context)) {
store.dispatch(UpdateCurrentRoute(TokenViewScreen.route));
if (token.isNew) {
Navigator.of(context).pushReplacementNamed(TokenViewScreen.route);
} else {
Navigator.of(context).pop(savedToken);
}
} else {
viewEntity(context: context, entity: savedToken, force: true);
}
}).catchError((Object error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
},
);
}
final TokenEntity token;
final CompanyEntity company;
final Function(TokenEntity) onChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final bool isLoading;
final bool isSaving;
final TokenEntity origToken;
final AppState state;
}

View File

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

View File

@ -0,0 +1,171 @@
import 'dart:async';
import 'package:invoiceninja_flutter/data/models/token_model.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/tables/entity_list.dart';
import 'package:invoiceninja_flutter/ui/token/token_list_item.dart';
import 'package:invoiceninja_flutter/ui/token/token_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/token/token_selectors.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
class TokenListBuilder extends StatelessWidget {
const TokenListBuilder({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, TokenListVM>(
converter: TokenListVM.fromStore,
builder: (context, viewModel) {
return EntityList(
isLoaded: viewModel.isLoaded,
entityType: EntityType.token,
presenter: TokenPresenter(),
state: viewModel.state,
entityList: viewModel.tokenList,
onEntityTap: viewModel.onTokenTap,
tableColumns: viewModel.tableColumns,
onRefreshed: viewModel.onRefreshed,
onClearEntityFilterPressed: viewModel.onClearEntityFilterPressed,
onViewEntityFilterPressed: viewModel.onViewEntityFilterPressed,
onSortColumn: viewModel.onSortColumn,
itemBuilder: (BuildContext context, index) {
final state = viewModel.state;
final tokenId = viewModel.tokenList[index];
final token = viewModel.tokenMap[tokenId];
final listState = state.getListState(EntityType.token);
final isInMultiselect = listState.isInMultiselect();
return TokenListItem(
user: viewModel.state.user,
filter: viewModel.filter,
token: token,
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
showEntityActionsDialog(
entities: [token],
context: context,
);
} else {
handleTokenAction(context, [token], action);
}
},
onTap: () => viewModel.onTokenTap(context, token),
onLongPress: () async {
final longPressIsSelection =
state.prefState.longPressSelectionIsDefault ?? true;
if (longPressIsSelection && !isInMultiselect) {
handleTokenAction(
context, [token], EntityAction.toggleMultiselect);
} else {
showEntityActionsDialog(
entities: [token],
context: context,
);
}
},
isChecked: isInMultiselect && listState.isSelected(token.id),
);
});
},
);
}
}
class TokenListVM {
TokenListVM({
@required this.state,
@required this.userCompany,
@required this.tokenList,
@required this.tokenMap,
@required this.filter,
@required this.isLoading,
@required this.isLoaded,
@required this.onTokenTap,
@required this.listState,
@required this.onRefreshed,
@required this.onEntityAction,
@required this.tableColumns,
@required this.onClearEntityFilterPressed,
@required this.onViewEntityFilterPressed,
@required this.onSortColumn,
});
static TokenListVM 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(LoadTokens(completer: completer, force: true));
return completer.future;
}
final state = store.state;
return TokenListVM(
state: state,
userCompany: state.userCompany,
listState: state.tokenListState,
tokenList: memoizedFilteredTokenList(
state.tokenState.map, state.tokenState.list, state.tokenListState),
tokenMap: state.tokenState.map,
isLoading: state.isLoading,
isLoaded: state.tokenState.isLoaded,
filter: state.tokenUIState.listUIState.filter,
onClearEntityFilterPressed: () => store.dispatch(ClearEntityFilter()),
onViewEntityFilterPressed: (BuildContext context) => viewEntityById(
context: context,
entityId: state.tokenListState.filterEntityId,
entityType: state.tokenListState.filterEntityType),
onTokenTap: (context, token) {
if (store.state.tokenListState.isInMultiselect()) {
handleTokenAction(context, [token], EntityAction.toggleMultiselect);
} else if (isDesktop(context) && state.uiState.isEditing) {
viewEntity(context: context, entity: token);
} else if (isDesktop(context) &&
state.tokenUIState.selectedId == token.id) {
editEntity(context: context, entity: token);
} else {
viewEntity(context: context, entity: token);
}
},
onEntityAction: (BuildContext context, List<BaseEntity> tokens,
EntityAction action) =>
handleTokenAction(context, tokens, action),
onRefreshed: (context) => _handleRefresh(context),
tableColumns:
state.userCompany.settings.getTableColumns(EntityType.token) ??
TokenPresenter.getAllTableFields(state.userCompany),
onSortColumn: (field) => store.dispatch(SortTokens(field)),
);
}
final AppState state;
final UserCompanyEntity userCompany;
final List<String> tokenList;
final BuiltMap<String, TokenEntity> tokenMap;
final ListUIState listState;
final String filter;
final bool isLoading;
final bool isLoaded;
final Function(BuildContext, BaseEntity) onTokenTap;
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,27 @@
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
class TokenPresenter 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 token = entity as InvoiceEntity;
switch (field) {
}
return super.getField(field: field, context: context);
}
}

View File

@ -0,0 +1,135 @@
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/token/token_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/token/token_list_vm.dart';
import 'package:invoiceninja_flutter/ui/token/token_presenter.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'token_screen_vm.dart';
class TokenScreen extends StatelessWidget {
const TokenScreen({
Key key,
@required this.viewModel,
}) : super(key: key);
static const String route = '/token';
final TokenScreenVM 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.tokenUIState.listUIState;
final isInMultiselect = listUIState.isInMultiselect();
return ListScaffold(
entityType: EntityType.token,
isChecked: isInMultiselect &&
listUIState.selectedIds.length == viewModel.tokenList.length,
showCheckbox: isInMultiselect,
onHamburgerLongPress: () => store.dispatch(StartTokenMultiselect()),
onCheckboxChanged: (value) {
final tokens = viewModel.tokenList
.map<TokenEntity>((tokenId) => viewModel.tokenMap[tokenId])
.where((token) => value != listUIState.isSelected(token.id))
.toList();
handleTokenAction(context, tokens, EntityAction.toggleMultiselect);
},
appBarTitle: ListFilter(
placeholder: localization.searchTokens,
filter: state.tokenListState.filter,
onFilterChanged: (value) {
store.dispatch(FilterTokens(value));
},
),
appBarActions: [
if (viewModel.isInMultiselect)
SaveCancelButtons(
saveLabel: localization.done,
onSavePressed: listUIState.selectedIds.isEmpty
? null
: (context) async {
final tokens = listUIState.selectedIds
.map<TokenEntity>(
(tokenId) => viewModel.tokenMap[tokenId])
.toList();
await showEntityActionsDialog(
entities: tokens,
context: context,
multiselect: true,
completer: Completer<Null>()
..future.then<dynamic>(
(_) => store.dispatch(ClearTokenMultiselect())),
);
},
onCancelPressed: (context) =>
store.dispatch(ClearTokenMultiselect()),
),
],
body: TokenListBuilder(),
bottomNavigationBar: AppBottomBar(
entityType: EntityType.token,
tableColumns: TokenPresenter.getAllTableFields(userCompany),
defaultTableColumns: TokenPresenter.getDefaultTableFields(userCompany),
onRefreshPressed: () => store.dispatch(LoadTokens(force: true)),
onSelectedSortField: (value) {
store.dispatch(SortTokens(value));
},
sortFields: [
TokenFields.name,
],
onSelectedState: (EntityState state, value) {
store.dispatch(FilterTokensByState(state));
},
onCheckboxPressed: () {
if (store.state.tokenListState.isInMultiselect()) {
store.dispatch(ClearTokenMultiselect());
} else {
store.dispatch(StartTokenMultiselect());
}
},
onSelectedCustom1: (value) =>
store.dispatch(FilterTokensByCustom1(value)),
onSelectedCustom2: (value) =>
store.dispatch(FilterTokensByCustom2(value)),
onSelectedCustom3: (value) =>
store.dispatch(FilterTokensByCustom3(value)),
onSelectedCustom4: (value) =>
store.dispatch(FilterTokensByCustom4(value)),
),
floatingActionButton: state.prefState.isMenuFloated &&
userCompany.canCreate(EntityType.token)
? FloatingActionButton(
heroTag: 'token_fab',
backgroundColor: Theme.of(context).primaryColorDark,
onPressed: () {
createEntityByType(
context: context, entityType: EntityType.token);
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newToken,
)
: 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/token/token_actions.dart';
import 'package:invoiceninja_flutter/redux/token/token_selectors.dart';
import 'package:redux/redux.dart';
import 'token_screen.dart';
class TokenScreenBuilder extends StatelessWidget {
const TokenScreenBuilder({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, TokenScreenVM>(
converter: TokenScreenVM.fromStore,
builder: (context, vm) {
return TokenScreen(
viewModel: vm,
);
},
);
}
}
class TokenScreenVM {
TokenScreenVM({
@required this.isInMultiselect,
@required this.tokenList,
@required this.userCompany,
@required this.onEntityAction,
@required this.tokenMap,
});
final bool isInMultiselect;
final UserCompanyEntity userCompany;
final List<String> tokenList;
final Function(BuildContext, List<BaseEntity>, EntityAction) onEntityAction;
final BuiltMap<String, TokenEntity> tokenMap;
static TokenScreenVM fromStore(Store<AppState> store) {
final state = store.state;
return TokenScreenVM(
tokenMap: state.tokenState.map,
tokenList: memoizedFilteredTokenList(
state.tokenState.map, state.tokenState.list, state.tokenListState),
userCompany: state.userCompany,
isInMultiselect: state.tokenListState.isInMultiselect(),
onEntityAction: (BuildContext context, List<BaseEntity> tokens,
EntityAction action) =>
handleTokenAction(context, tokens, action),
);
}
}

View File

@ -0,0 +1,35 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
import 'package:invoiceninja_flutter/ui/token/view/token_view_vm.dart';
class TokenView extends StatefulWidget {
const TokenView({
Key key,
@required this.viewModel,
@required this.isFilter,
}) : super(key: key);
final TokenViewVM viewModel;
final bool isFilter;
@override
_TokenViewState createState() => new _TokenViewState();
}
class _TokenViewState extends State<TokenView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
//final userCompany = viewModel.state.userCompany;
final token = viewModel.token;
return ViewScaffold(
isFilter: widget.isFilter,
entity: token,
body: ListView(
children: <Widget>[],
),
);
}
}

View File

@ -0,0 +1,84 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/token/token_actions.dart';
import 'package:invoiceninja_flutter/data/models/token_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/token/view/token_view.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class TokenViewScreen extends StatelessWidget {
const TokenViewScreen({
Key key,
this.isFilter = false,
}) : super(key: key);
static const String route = '/token/view';
final bool isFilter;
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, TokenViewVM>(
converter: (Store<AppState> store) {
return TokenViewVM.fromStore(store);
},
builder: (context, vm) {
return TokenView(
viewModel: vm,
isFilter: isFilter,
);
},
);
}
}
class TokenViewVM {
TokenViewVM({
@required this.state,
@required this.token,
@required this.company,
@required this.onEntityAction,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
});
factory TokenViewVM.fromStore(Store<AppState> store) {
final state = store.state;
final token = state.tokenState.map[state.tokenUIState.selectedId] ??
TokenEntity(id: state.tokenUIState.selectedId);
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(LoadToken(completer: completer, tokenId: token.id));
return completer.future;
}
return TokenViewVM(
state: state,
company: state.company,
isSaving: state.isSaving,
isLoading: state.isLoading,
isDirty: token.isNew,
token: token,
onRefreshed: (context) => _handleRefresh(context),
onEntityAction: (BuildContext context, EntityAction action) =>
handleEntitiesActions(context, [token], action, autoPop: true),
);
}
final AppState state;
final TokenEntity token;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;
final bool isDirty;
}

File diff suppressed because it is too large Load Diff

View File

@ -107,7 +107,6 @@ if [ ${action} = "init" ]; then
'./stubs/ui/stub/view/stub_view_vm' './stubs/ui/stub/view/stub_view_vm'
'./stubs/ui/stub/stub_list_item' './stubs/ui/stub/stub_list_item'
'./stubs/ui/stub/stub_list_vm' './stubs/ui/stub/stub_list_vm'
'./stubs/ui/stub/stub_list'
'./stubs/ui/stub/stub_screen') './stubs/ui/stub/stub_screen')
for i in "${files[@]}" for i in "${files[@]}"
@ -167,7 +166,6 @@ else
'./stubs/ui/stub/view/stub_view_vm' './stubs/ui/stub/view/stub_view_vm'
'./stubs/ui/stub/stub_list_item' './stubs/ui/stub/stub_list_item'
'./stubs/ui/stub/stub_list_vm' './stubs/ui/stub/stub_list_vm'
'./stubs/ui/stub/stub_list'
'./stubs/ui/stub/stub_presenter' './stubs/ui/stub/stub_presenter'
'./stubs/ui/stub/stub_screen' './stubs/ui/stub/stub_screen'
'./stubs/ui/stub/stub_screen_vm') './stubs/ui/stub/stub_screen_vm')

View File

@ -26,6 +26,9 @@ Reducer<String> selectedIdReducer = combineReducers([
TypedReducer<String, DeleteStubsSuccess>((selectedId, action) => ''), TypedReducer<String, DeleteStubsSuccess>((selectedId, action) => ''),
TypedReducer<String, ArchiveStubsSuccess>((selectedId, action) => ''), TypedReducer<String, ArchiveStubsSuccess>((selectedId, action) => ''),
TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''), TypedReducer<String, ClearEntityFilter>((selectedId, action) => ''),
TypedReducer<String, FilterByEntity>((selectedId, action) =>
action.entityType == EntityType.stub ? action.entityId : selectedId),
]); ]);
final editingReducer = combineReducers<StubEntity>([ final editingReducer = combineReducers<StubEntity>([
@ -76,13 +79,6 @@ final stubListReducer = combineReducers<ListUIState>([
]); ]);
ListUIState _filterStubsByClient(
ListUIState stubListState, FilterStubsByEntity action) {
return stubListState.rebuild((b) => b
..filterEntityId = action.entityId
..filterEntityType = action.entityType);
}
ListUIState _filterStubsByCustom1( ListUIState _filterStubsByCustom1(
ListUIState stubListState, FilterStubsByCustom1 action) { ListUIState stubListState, FilterStubsByCustom1 action) {
if (stubListState.custom1Filters.contains(action.value)) { if (stubListState.custom1Filters.contains(action.value)) {

View File

@ -39,7 +39,7 @@ List<String> filteredStubsSelector(BuiltMap<String, StubEntity> stubMap,
final list = stubList.where((stubId) { final list = stubList.where((stubId) {
final stub = stubMap[stubId]; final stub = stubMap[stubId];
if (stubListState.filterEntityId != null && if (stubListState.filterEntityId != null &&
stub.entityId != stubListState.filterEntityId) { stub.id != stubListState.filterEntityId) {
return false; return false;
} else { } else {

View File

@ -1,7 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'package:invoiceninja_flutter/data/models/stub_model.dart'; import 'package:invoiceninja_flutter/data/models/stub_model.dart';
import 'package:invoiceninja_flutter/ui/app/tables/entity_list.dart';
import 'package:invoiceninja_flutter/ui/stub/stub_presenter.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/ui/design/design_presenter.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -122,8 +123,7 @@ class StubListVM {
isLoading: state.isLoading, isLoading: state.isLoading,
isLoaded: state.stubState.isLoaded, isLoaded: state.stubState.isLoaded,
filter: state.stubUIState.listUIState.filter, filter: state.stubUIState.listUIState.filter,
onClearEntityFilterPressed: () => onClearEntityFilterPressed: () => store.dispatch(ClearEntityFilter()),
store.dispatch(FilterStubsByEntity()),
onViewEntityFilterPressed: (BuildContext context) => viewEntityById( onViewEntityFilterPressed: (BuildContext context) => viewEntityById(
context: context, context: context,
entityId: state.stubListState.filterEntityId, entityId: state.stubListState.filterEntityId,

View File

@ -15,8 +15,9 @@ import 'package:invoiceninja_flutter/ui/stub/view/stub_view.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class StubViewScreen extends StatelessWidget { class StubViewScreen extends StatelessWidget {
const StubViewScreen({Key key}) : super(key: key); const StubViewScreen({Key key, this.isFilter = false,}) : super(key: key);
static const String route = '/stub/view'; static const String route = '/stub/view';
final bool isFilter;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -27,6 +28,7 @@ class StubViewScreen extends StatelessWidget {
builder: (context, vm) { builder: (context, vm) {
return StubView( return StubView(
viewModel: vm, viewModel: vm,
isFilter: isFilter,
); );
}, },
); );