This commit is contained in:
Hillel Coren 2019-10-06 16:07:59 +03:00
parent b900779749
commit 635377cf5a
39 changed files with 3139 additions and 391 deletions

View File

@ -744,22 +744,3 @@ abstract class CompanyItemResponse
static Serializer<CompanyItemResponse> get serializer =>
_$companyItemResponseSerializer;
}
abstract class GroupEntity extends Object
with BaseEntity, SelectableEntity
implements Built<GroupEntity, GroupEntityBuilder> {
factory GroupEntity() {
return _$GroupEntity._(
name: '',
settings: SettingsEntity(),
);
}
GroupEntity._();
String get name;
SettingsEntity get settings;
static Serializer<GroupEntity> get serializer => _$groupEntitySerializer;
}

View File

@ -22,7 +22,6 @@ Serializer<UserItemResponse> _$userItemResponseSerializer =
new _$UserItemResponseSerializer();
Serializer<CompanyItemResponse> _$companyItemResponseSerializer =
new _$CompanyItemResponseSerializer();
Serializer<GroupEntity> _$groupEntitySerializer = new _$GroupEntitySerializer();
class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
@override
@ -1373,121 +1372,6 @@ class _$CompanyItemResponseSerializer
}
}
class _$GroupEntitySerializer implements StructuredSerializer<GroupEntity> {
@override
final Iterable<Type> types = const [GroupEntity, _$GroupEntity];
@override
final String wireName = 'GroupEntity';
@override
Iterable<Object> serialize(Serializers serializers, GroupEntity object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'name',
serializers.serialize(object.name, specifiedType: const FullType(String)),
'settings',
serializers.serialize(object.settings,
specifiedType: const FullType(SettingsEntity)),
];
if (object.isChanged != null) {
result
..add('isChanged')
..add(serializers.serialize(object.isChanged,
specifiedType: const FullType(bool)));
}
if (object.createdAt != null) {
result
..add('created_at')
..add(serializers.serialize(object.createdAt,
specifiedType: const FullType(int)));
}
if (object.updatedAt != null) {
result
..add('updated_at')
..add(serializers.serialize(object.updatedAt,
specifiedType: const FullType(int)));
}
if (object.archivedAt != null) {
result
..add('archived_at')
..add(serializers.serialize(object.archivedAt,
specifiedType: const FullType(int)));
}
if (object.isDeleted != null) {
result
..add('is_deleted')
..add(serializers.serialize(object.isDeleted,
specifiedType: const FullType(bool)));
}
if (object.isOwner != null) {
result
..add('is_owner')
..add(serializers.serialize(object.isOwner,
specifiedType: const FullType(bool)));
}
if (object.id != null) {
result
..add('id')
..add(serializers.serialize(object.id,
specifiedType: const FullType(String)));
}
return result;
}
@override
GroupEntity deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new GroupEntityBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'name':
result.name = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'settings':
result.settings.replace(serializers.deserialize(value,
specifiedType: const FullType(SettingsEntity)) as SettingsEntity);
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 'is_owner':
result.isOwner = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
case 'id':
result.id = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$CompanyEntity extends CompanyEntity {
@override
final String sizeId;
@ -3566,204 +3450,4 @@ class CompanyItemResponseBuilder
}
}
class _$GroupEntity extends GroupEntity {
@override
final String name;
@override
final SettingsEntity settings;
@override
final bool isChanged;
@override
final int createdAt;
@override
final int updatedAt;
@override
final int archivedAt;
@override
final bool isDeleted;
@override
final bool isOwner;
@override
final String id;
factory _$GroupEntity([void Function(GroupEntityBuilder) updates]) =>
(new GroupEntityBuilder()..update(updates)).build();
_$GroupEntity._(
{this.name,
this.settings,
this.isChanged,
this.createdAt,
this.updatedAt,
this.archivedAt,
this.isDeleted,
this.isOwner,
this.id})
: super._() {
if (name == null) {
throw new BuiltValueNullFieldError('GroupEntity', 'name');
}
if (settings == null) {
throw new BuiltValueNullFieldError('GroupEntity', 'settings');
}
}
@override
GroupEntity rebuild(void Function(GroupEntityBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
GroupEntityBuilder toBuilder() => new GroupEntityBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is GroupEntity &&
name == other.name &&
settings == other.settings &&
isChanged == other.isChanged &&
createdAt == other.createdAt &&
updatedAt == other.updatedAt &&
archivedAt == other.archivedAt &&
isDeleted == other.isDeleted &&
isOwner == other.isOwner &&
id == other.id;
}
@override
int get hashCode {
return $jf($jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc($jc($jc(0, name.hashCode), settings.hashCode),
isChanged.hashCode),
createdAt.hashCode),
updatedAt.hashCode),
archivedAt.hashCode),
isDeleted.hashCode),
isOwner.hashCode),
id.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('GroupEntity')
..add('name', name)
..add('settings', settings)
..add('isChanged', isChanged)
..add('createdAt', createdAt)
..add('updatedAt', updatedAt)
..add('archivedAt', archivedAt)
..add('isDeleted', isDeleted)
..add('isOwner', isOwner)
..add('id', id))
.toString();
}
}
class GroupEntityBuilder implements Builder<GroupEntity, GroupEntityBuilder> {
_$GroupEntity _$v;
String _name;
String get name => _$this._name;
set name(String name) => _$this._name = name;
SettingsEntityBuilder _settings;
SettingsEntityBuilder get settings =>
_$this._settings ??= new SettingsEntityBuilder();
set settings(SettingsEntityBuilder settings) => _$this._settings = settings;
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;
bool _isOwner;
bool get isOwner => _$this._isOwner;
set isOwner(bool isOwner) => _$this._isOwner = isOwner;
String _id;
String get id => _$this._id;
set id(String id) => _$this._id = id;
GroupEntityBuilder();
GroupEntityBuilder get _$this {
if (_$v != null) {
_name = _$v.name;
_settings = _$v.settings?.toBuilder();
_isChanged = _$v.isChanged;
_createdAt = _$v.createdAt;
_updatedAt = _$v.updatedAt;
_archivedAt = _$v.archivedAt;
_isDeleted = _$v.isDeleted;
_isOwner = _$v.isOwner;
_id = _$v.id;
_$v = null;
}
return this;
}
@override
void replace(GroupEntity other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$GroupEntity;
}
@override
void update(void Function(GroupEntityBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$GroupEntity build() {
_$GroupEntity _$result;
try {
_$result = _$v ??
new _$GroupEntity._(
name: name,
settings: settings.build(),
isChanged: isChanged,
createdAt: createdAt,
updatedAt: updatedAt,
archivedAt: archivedAt,
isDeleted: isDeleted,
isOwner: isOwner,
id: id);
} catch (_) {
String _$failedField;
try {
_$failedField = 'settings';
settings.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'GroupEntity', _$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

@ -0,0 +1,143 @@
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/utils/formatting.dart';
part 'group_model.g.dart';
abstract class GroupListResponse
implements Built<GroupListResponse, GroupListResponseBuilder> {
factory GroupListResponse([void updates(GroupListResponseBuilder b)]) =
_$GroupListResponse;
GroupListResponse._();
BuiltList<GroupEntity> get data;
static Serializer<GroupListResponse> get serializer =>
_$groupListResponseSerializer;
}
abstract class GroupItemResponse
implements Built<GroupItemResponse, GroupItemResponseBuilder> {
factory GroupItemResponse([void updates(GroupItemResponseBuilder b)]) =
_$GroupItemResponse;
GroupItemResponse._();
GroupEntity get data;
static Serializer<GroupItemResponse> get serializer =>
_$groupItemResponseSerializer;
}
class GroupFields {
static const String name = 'name';
}
abstract class GroupEntity extends Object
with BaseEntity, SelectableEntity
implements Built<GroupEntity, GroupEntityBuilder> {
factory GroupEntity() {
return _$GroupEntity._(
name: '',
settings: SettingsEntity(),
);
}
GroupEntity._();
String get name;
// TODO remove this
@nullable
@BuiltValueField(wireName: 'custom_value1')
String get customValue1;
// TODO remove this
@BuiltValueField(wireName: 'custom_value2')
String get customValue2;
SettingsEntity get settings;
int compareTo(GroupEntity group, String sortField, bool sortAscending) {
int response = 0;
final GroupEntity groupA = sortAscending ? this : group;
final GroupEntity groupB = sortAscending ? group : this;
switch (sortField) {
/*
case GroupFields.balance:
response = groupA.balance.compareTo(groupB.balance);
break;
case GroupFields.updatedAt:
response = groupA.updatedAt.compareTo(groupB.updatedAt);
break;
*/
}
if (response == 0) {
return groupA.name.toLowerCase().compareTo(groupB.name.toLowerCase());
} else {
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}) {
final actions = <EntityAction>[];
if (!isDeleted) {
if (includeEdit && userCompany.canEditEntity(this)) {
actions.add(EntityAction.edit);
}
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<GroupEntity> get serializer => _$groupEntitySerializer;
}

View File

@ -0,0 +1,650 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'group_model.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<GroupListResponse> _$groupListResponseSerializer =
new _$GroupListResponseSerializer();
Serializer<GroupItemResponse> _$groupItemResponseSerializer =
new _$GroupItemResponseSerializer();
Serializer<GroupEntity> _$groupEntitySerializer = new _$GroupEntitySerializer();
class _$GroupListResponseSerializer
implements StructuredSerializer<GroupListResponse> {
@override
final Iterable<Type> types = const [GroupListResponse, _$GroupListResponse];
@override
final String wireName = 'GroupListResponse';
@override
Iterable<Object> serialize(Serializers serializers, GroupListResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType:
const FullType(BuiltList, const [const FullType(GroupEntity)])),
];
return result;
}
@override
GroupListResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new GroupListResponseBuilder();
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(GroupEntity)]))
as BuiltList<dynamic>);
break;
}
}
return result.build();
}
}
class _$GroupItemResponseSerializer
implements StructuredSerializer<GroupItemResponse> {
@override
final Iterable<Type> types = const [GroupItemResponse, _$GroupItemResponse];
@override
final String wireName = 'GroupItemResponse';
@override
Iterable<Object> serialize(Serializers serializers, GroupItemResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType: const FullType(GroupEntity)),
];
return result;
}
@override
GroupItemResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new GroupItemResponseBuilder();
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(GroupEntity)) as GroupEntity);
break;
}
}
return result.build();
}
}
class _$GroupEntitySerializer implements StructuredSerializer<GroupEntity> {
@override
final Iterable<Type> types = const [GroupEntity, _$GroupEntity];
@override
final String wireName = 'GroupEntity';
@override
Iterable<Object> serialize(Serializers serializers, GroupEntity object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'name',
serializers.serialize(object.name, specifiedType: const FullType(String)),
'custom_value2',
serializers.serialize(object.customValue2,
specifiedType: const FullType(String)),
'settings',
serializers.serialize(object.settings,
specifiedType: const FullType(SettingsEntity)),
];
if (object.customValue1 != null) {
result
..add('custom_value1')
..add(serializers.serialize(object.customValue1,
specifiedType: const FullType(String)));
}
if (object.isChanged != null) {
result
..add('isChanged')
..add(serializers.serialize(object.isChanged,
specifiedType: const FullType(bool)));
}
if (object.createdAt != null) {
result
..add('created_at')
..add(serializers.serialize(object.createdAt,
specifiedType: const FullType(int)));
}
if (object.updatedAt != null) {
result
..add('updated_at')
..add(serializers.serialize(object.updatedAt,
specifiedType: const FullType(int)));
}
if (object.archivedAt != null) {
result
..add('archived_at')
..add(serializers.serialize(object.archivedAt,
specifiedType: const FullType(int)));
}
if (object.isDeleted != null) {
result
..add('is_deleted')
..add(serializers.serialize(object.isDeleted,
specifiedType: const FullType(bool)));
}
if (object.isOwner != null) {
result
..add('is_owner')
..add(serializers.serialize(object.isOwner,
specifiedType: const FullType(bool)));
}
if (object.id != null) {
result
..add('id')
..add(serializers.serialize(object.id,
specifiedType: const FullType(String)));
}
return result;
}
@override
GroupEntity deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new GroupEntityBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'name':
result.name = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'custom_value1':
result.customValue1 = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'custom_value2':
result.customValue2 = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'settings':
result.settings.replace(serializers.deserialize(value,
specifiedType: const FullType(SettingsEntity)) as SettingsEntity);
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 'is_owner':
result.isOwner = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
case 'id':
result.id = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$GroupListResponse extends GroupListResponse {
@override
final BuiltList<GroupEntity> data;
factory _$GroupListResponse(
[void Function(GroupListResponseBuilder) updates]) =>
(new GroupListResponseBuilder()..update(updates)).build();
_$GroupListResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('GroupListResponse', 'data');
}
}
@override
GroupListResponse rebuild(void Function(GroupListResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
GroupListResponseBuilder toBuilder() =>
new GroupListResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is GroupListResponse && data == other.data;
}
@override
int get hashCode {
return $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('GroupListResponse')..add('data', data))
.toString();
}
}
class GroupListResponseBuilder
implements Builder<GroupListResponse, GroupListResponseBuilder> {
_$GroupListResponse _$v;
ListBuilder<GroupEntity> _data;
ListBuilder<GroupEntity> get data =>
_$this._data ??= new ListBuilder<GroupEntity>();
set data(ListBuilder<GroupEntity> data) => _$this._data = data;
GroupListResponseBuilder();
GroupListResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(GroupListResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$GroupListResponse;
}
@override
void update(void Function(GroupListResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$GroupListResponse build() {
_$GroupListResponse _$result;
try {
_$result = _$v ?? new _$GroupListResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'GroupListResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$GroupItemResponse extends GroupItemResponse {
@override
final GroupEntity data;
factory _$GroupItemResponse(
[void Function(GroupItemResponseBuilder) updates]) =>
(new GroupItemResponseBuilder()..update(updates)).build();
_$GroupItemResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('GroupItemResponse', 'data');
}
}
@override
GroupItemResponse rebuild(void Function(GroupItemResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
GroupItemResponseBuilder toBuilder() =>
new GroupItemResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is GroupItemResponse && data == other.data;
}
@override
int get hashCode {
return $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('GroupItemResponse')..add('data', data))
.toString();
}
}
class GroupItemResponseBuilder
implements Builder<GroupItemResponse, GroupItemResponseBuilder> {
_$GroupItemResponse _$v;
GroupEntityBuilder _data;
GroupEntityBuilder get data => _$this._data ??= new GroupEntityBuilder();
set data(GroupEntityBuilder data) => _$this._data = data;
GroupItemResponseBuilder();
GroupItemResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(GroupItemResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$GroupItemResponse;
}
@override
void update(void Function(GroupItemResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$GroupItemResponse build() {
_$GroupItemResponse _$result;
try {
_$result = _$v ?? new _$GroupItemResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'GroupItemResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$GroupEntity extends GroupEntity {
@override
final String name;
@override
final String customValue1;
@override
final String customValue2;
@override
final SettingsEntity settings;
@override
final bool isChanged;
@override
final int createdAt;
@override
final int updatedAt;
@override
final int archivedAt;
@override
final bool isDeleted;
@override
final bool isOwner;
@override
final String id;
factory _$GroupEntity([void Function(GroupEntityBuilder) updates]) =>
(new GroupEntityBuilder()..update(updates)).build();
_$GroupEntity._(
{this.name,
this.customValue1,
this.customValue2,
this.settings,
this.isChanged,
this.createdAt,
this.updatedAt,
this.archivedAt,
this.isDeleted,
this.isOwner,
this.id})
: super._() {
if (name == null) {
throw new BuiltValueNullFieldError('GroupEntity', 'name');
}
if (customValue2 == null) {
throw new BuiltValueNullFieldError('GroupEntity', 'customValue2');
}
if (settings == null) {
throw new BuiltValueNullFieldError('GroupEntity', 'settings');
}
}
@override
GroupEntity rebuild(void Function(GroupEntityBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
GroupEntityBuilder toBuilder() => new GroupEntityBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is GroupEntity &&
name == other.name &&
customValue1 == other.customValue1 &&
customValue2 == other.customValue2 &&
settings == other.settings &&
isChanged == other.isChanged &&
createdAt == other.createdAt &&
updatedAt == other.updatedAt &&
archivedAt == other.archivedAt &&
isDeleted == other.isDeleted &&
isOwner == other.isOwner &&
id == other.id;
}
@override
int get hashCode {
return $jf($jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc($jc(0, name.hashCode),
customValue1.hashCode),
customValue2.hashCode),
settings.hashCode),
isChanged.hashCode),
createdAt.hashCode),
updatedAt.hashCode),
archivedAt.hashCode),
isDeleted.hashCode),
isOwner.hashCode),
id.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('GroupEntity')
..add('name', name)
..add('customValue1', customValue1)
..add('customValue2', customValue2)
..add('settings', settings)
..add('isChanged', isChanged)
..add('createdAt', createdAt)
..add('updatedAt', updatedAt)
..add('archivedAt', archivedAt)
..add('isDeleted', isDeleted)
..add('isOwner', isOwner)
..add('id', id))
.toString();
}
}
class GroupEntityBuilder implements Builder<GroupEntity, GroupEntityBuilder> {
_$GroupEntity _$v;
String _name;
String get name => _$this._name;
set name(String name) => _$this._name = name;
String _customValue1;
String get customValue1 => _$this._customValue1;
set customValue1(String customValue1) => _$this._customValue1 = customValue1;
String _customValue2;
String get customValue2 => _$this._customValue2;
set customValue2(String customValue2) => _$this._customValue2 = customValue2;
SettingsEntityBuilder _settings;
SettingsEntityBuilder get settings =>
_$this._settings ??= new SettingsEntityBuilder();
set settings(SettingsEntityBuilder settings) => _$this._settings = settings;
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;
bool _isOwner;
bool get isOwner => _$this._isOwner;
set isOwner(bool isOwner) => _$this._isOwner = isOwner;
String _id;
String get id => _$this._id;
set id(String id) => _$this._id = id;
GroupEntityBuilder();
GroupEntityBuilder get _$this {
if (_$v != null) {
_name = _$v.name;
_customValue1 = _$v.customValue1;
_customValue2 = _$v.customValue2;
_settings = _$v.settings?.toBuilder();
_isChanged = _$v.isChanged;
_createdAt = _$v.createdAt;
_updatedAt = _$v.updatedAt;
_archivedAt = _$v.archivedAt;
_isDeleted = _$v.isDeleted;
_isOwner = _$v.isOwner;
_id = _$v.id;
_$v = null;
}
return this;
}
@override
void replace(GroupEntity other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$GroupEntity;
}
@override
void update(void Function(GroupEntityBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$GroupEntity build() {
_$GroupEntity _$result;
try {
_$result = _$v ??
new _$GroupEntity._(
name: name,
customValue1: customValue1,
customValue2: customValue2,
settings: settings.build(),
isChanged: isChanged,
createdAt: createdAt,
updatedAt: updatedAt,
archivedAt: archivedAt,
isDeleted: isDeleted,
isOwner: isOwner,
id: id);
} catch (_) {
String _$failedField;
try {
_$failedField = 'settings';
settings.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'GroupEntity', _$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

@ -46,6 +46,7 @@ class EntityAction extends EnumClass {
static const EntityAction download = _$download;
static const EntityAction sendEmail = _$sendEmail;
static const EntityAction markSent = _$markSent;
static const EntityAction newClient = _$newClient;
static const EntityAction newInvoice = _$newInvoice;
static const EntityAction newExpense = _$newExpense;
static const EntityAction newTask = _$newTask;

View File

@ -17,6 +17,7 @@ const EntityAction _$convert = const EntityAction._('convert');
const EntityAction _$download = const EntityAction._('download');
const EntityAction _$sendEmail = const EntityAction._('sendEmail');
const EntityAction _$markSent = const EntityAction._('markSent');
const EntityAction _$newClient = const EntityAction._('newClient');
const EntityAction _$newInvoice = const EntityAction._('newInvoice');
const EntityAction _$newExpense = const EntityAction._('newExpense');
const EntityAction _$newTask = const EntityAction._('newTask');
@ -53,6 +54,8 @@ EntityAction _$valueOf(String name) {
return _$sendEmail;
case 'markSent':
return _$markSent;
case 'newClient':
return _$newClient;
case 'newInvoice':
return _$newInvoice;
case 'newExpense':
@ -93,6 +96,7 @@ final BuiltSet<EntityAction> _$values =
_$download,
_$sendEmail,
_$markSent,
_$newClient,
_$newInvoice,
_$newExpense,
_$newTask,

View File

@ -5,6 +5,7 @@ import 'package:invoiceninja_flutter/data/models/credit_model.dart';
import 'package:invoiceninja_flutter/data/models/document_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/expense_model.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
@ -30,6 +31,8 @@ import 'package:invoiceninja_flutter/redux/project/project_state.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_state.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_state.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_state.dart';
import 'package:invoiceninja_flutter/redux/document/document_state.dart';
part 'serializers.g.dart';
@ -91,6 +94,8 @@ part 'serializers.g.dart';
TaskStatusEntity,
ExpenseStatusEntity,
// STARTER: serializers - do not remove comment
GroupEntity,
DocumentEntity,
])
final Serializers serializers =

View File

@ -58,6 +58,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
..add(FrequencyItemResponse.serializer)
..add(FrequencyListResponse.serializer)
..add(GroupEntity.serializer)
..add(GroupState.serializer)
..add(GroupUIState.serializer)
..add(IndustryEntity.serializer)
..add(IndustryItemResponse.serializer)
..add(IndustryListResponse.serializer)
@ -330,6 +332,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(ExpenseEntity)]), () => new MapBuilder<String, ExpenseEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(GroupEntity)]), () => new MapBuilder<String, GroupEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(InvoiceEntity)]), () => new MapBuilder<String, InvoiceEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(String)]), () => new ListBuilder<String>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(InvoiceEntity)]), () => new MapBuilder<String, InvoiceEntity>())

View File

@ -0,0 +1,68 @@
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/group_model.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 GroupRepository {
const GroupRepository({
this.webClient = const WebClient(),
});
final WebClient webClient;
Future<GroupEntity> loadItem(Credentials credentials, String entityId) async {
final dynamic response = await webClient.get(
'${credentials.url}/groups/$entityId', credentials.token);
final GroupItemResponse groupResponse =
serializers.deserializeWith(GroupItemResponse.serializer, response);
return groupResponse.data;
}
Future<BuiltList<GroupEntity>> loadList(
Credentials credentials, int updatedAt) async {
String url = credentials.url + '/groups?';
if (updatedAt > 0) {
url += '&updated_at=${updatedAt - kUpdatedAtBufferSeconds}';
}
final dynamic response = await webClient.get(url, credentials.token);
final GroupListResponse groupResponse =
serializers.deserializeWith(GroupListResponse.serializer, response);
return groupResponse.data;
}
Future<GroupEntity> saveData(Credentials credentials, GroupEntity group,
[EntityAction action]) async {
final data = serializers.serializeWith(GroupEntity.serializer, group);
dynamic response;
if (group.isNew) {
response = await webClient.post(
credentials.url + '/groups', credentials.token,
data: json.encode(data));
} else {
var url = credentials.url + '/groups/' + group.id.toString();
if (action != null) {
url += '?action=' + action.toString();
}
response =
await webClient.put(url, credentials.token, data: json.encode(data));
}
final GroupItemResponse groupResponse =
serializers.deserializeWith(GroupItemResponse.serializer, response);
return groupResponse.data;
}
}

View File

@ -52,7 +52,13 @@ import 'package:invoiceninja_flutter/redux/task/task_middleware.dart';
import 'package:invoiceninja_flutter/redux/project/project_middleware.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_middleware.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_middleware.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/ui/group/group_screen.dart';
import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/group/view/group_view_vm.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_middleware.dart';
void main({bool isTesting = false}) async {
final SentryClient _sentry = Config.SENTRY_DNS.isEmpty
@ -92,6 +98,7 @@ void main({bool isTesting = false}) async {
..addAll(createStoreQuotesMiddleware())
..addAll(createStoreSettingsMiddleware())
// STARTER: middleware - do not remove comment
..addAll(createStoreGroupsMiddleware())
..addAll(isTesting
? []
: [
@ -306,6 +313,9 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
QuoteEditScreen.route: (context) => QuoteEditScreen(),
QuoteEmailScreen.route: (context) => QuoteEmailScreen(),
// STARTER: routes - do not remove comment
GroupScreen.route: (context) => GroupScreen(),
GroupViewScreen.route: (context) => GroupViewScreen(),
GroupEditScreen.route: (context) => GroupEditScreen(),
SettingsScreen.route: (context) => SettingsScreen(),
CompanyDetailsScreen.route: (context) => CompanyDetailsScreen(),
UserDetailsScreen.route: (context) => UserDetailsScreen(),
@ -317,7 +327,6 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
NotificationsSettingsScreen(),
ImportExportScreen.route: (context) => ImportExportScreen(),
DeviceSettingsScreen.route: (context) => DeviceSettingsScreen(),
GroupSettingsScreen.route: (context) GroupSettingsScreen(),
InvoiceSettingsScreen.route: (context) => InvoiceSettingsScreen(),
InvoiceDesignScreen.route: (context) => InvoiceDesignScreen(),
ClientPortalScreen.route: (context) => ClientPortalScreen(),

View File

@ -21,6 +21,8 @@ import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_state.dart';
import 'package:invoiceninja_flutter/redux/document/document_state.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_state.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_selectors.dart';
@ -139,6 +141,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
case EntityType.invoice:
return invoiceUIState;
// STARTER: states switch - do not remove comment
case EntityType.group:
return groupUIState;
case EntityType.document:
return documentUIState;
case EntityType.expense:
@ -181,6 +186,11 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
ListUIState get invoiceListState => uiState.invoiceUIState.listUIState;
// STARTER: state getters - do not remove comment
GroupState get groupState => selectedCompanyState.groupState;
ListUIState get groupListState => uiState.groupUIState.listUIState;
GroupUIState get groupUIState => uiState.groupUIState;
DocumentState get documentState => selectedCompanyState.documentState;
ListUIState get documentListState => uiState.documentUIState.listUIState;

View File

@ -17,6 +17,7 @@ import 'package:invoiceninja_flutter/redux/project/project_reducer.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_reducer.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_reducer.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_reducer.dart';
UserCompanyState companyReducer(UserCompanyState state, dynamic action) {
if (action is RefreshData && action.loadCompanies) {
@ -33,11 +34,11 @@ UserCompanyState companyReducer(UserCompanyState state, dynamic action) {
..expenseState.replace(expensesReducer(state.expenseState, action))
..vendorState.replace(vendorsReducer(state.vendorState, action))
..taskState.replace(tasksReducer(state.taskState, action))
// STARTER: reducer - do not remove comment
..projectState.replace(projectsReducer(state.projectState, action))
..paymentState.replace(paymentsReducer(state.paymentState, action))
..quoteState.replace(quotesReducer(state.quoteState, action)));
// STARTER: reducer - do not remove comment
..quoteState.replace(quotesReducer(state.quoteState, action))
..groupState.replace(groupsReducer(state.groupState, action)));
}
Reducer<UserCompanyEntity> userCompanyEntityReducer = combineReducers([

View File

@ -1,4 +1,5 @@
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_state.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_state.dart';
import 'package:invoiceninja_flutter/redux/product/product_state.dart';
@ -8,6 +9,8 @@ import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_state.dart';
import 'package:invoiceninja_flutter/redux/document/document_state.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_state.dart';
@ -41,6 +44,7 @@ abstract class UserCompanyState
paymentState: PaymentState(),
quoteState: QuoteState(),
// STARTER: constructor - do not remove comment
groupState: GroupState(),
);
}
@ -72,6 +76,7 @@ abstract class UserCompanyState
QuoteState get quoteState;
// STARTER: fields - do not remove comment
GroupState get groupState;
CompanyEntity get company => userCompany.company;

View File

@ -55,6 +55,9 @@ class _$UserCompanyStateSerializer
'quoteState',
serializers.serialize(object.quoteState,
specifiedType: const FullType(QuoteState)),
'groupState',
serializers.serialize(object.groupState,
specifiedType: const FullType(GroupState)),
];
if (object.userCompany != null) {
result
@ -126,6 +129,10 @@ class _$UserCompanyStateSerializer
result.quoteState.replace(serializers.deserialize(value,
specifiedType: const FullType(QuoteState)) as QuoteState);
break;
case 'groupState':
result.groupState.replace(serializers.deserialize(value,
specifiedType: const FullType(GroupState)) as GroupState);
break;
}
}
@ -243,6 +250,8 @@ class _$UserCompanyState extends UserCompanyState {
final PaymentState paymentState;
@override
final QuoteState quoteState;
@override
final GroupState groupState;
factory _$UserCompanyState(
[void Function(UserCompanyStateBuilder) updates]) =>
@ -260,7 +269,8 @@ class _$UserCompanyState extends UserCompanyState {
this.taskState,
this.projectState,
this.paymentState,
this.quoteState})
this.quoteState,
this.groupState})
: super._() {
if (documentState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'documentState');
@ -295,6 +305,9 @@ class _$UserCompanyState extends UserCompanyState {
if (quoteState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'quoteState');
}
if (groupState == null) {
throw new BuiltValueNullFieldError('UserCompanyState', 'groupState');
}
}
@override
@ -320,7 +333,8 @@ class _$UserCompanyState extends UserCompanyState {
taskState == other.taskState &&
projectState == other.projectState &&
paymentState == other.paymentState &&
quoteState == other.quoteState;
quoteState == other.quoteState &&
groupState == other.groupState;
}
@override
@ -335,18 +349,22 @@ class _$UserCompanyState extends UserCompanyState {
$jc(
$jc(
$jc(
$jc($jc(0, userCompany.hashCode),
documentState.hashCode),
dashboardState.hashCode),
productState.hashCode),
clientState.hashCode),
invoiceState.hashCode),
expenseState.hashCode),
vendorState.hashCode),
taskState.hashCode),
projectState.hashCode),
paymentState.hashCode),
quoteState.hashCode));
$jc(
$jc(
$jc(0,
userCompany.hashCode),
documentState.hashCode),
dashboardState.hashCode),
productState.hashCode),
clientState.hashCode),
invoiceState.hashCode),
expenseState.hashCode),
vendorState.hashCode),
taskState.hashCode),
projectState.hashCode),
paymentState.hashCode),
quoteState.hashCode),
groupState.hashCode));
}
@override
@ -363,7 +381,8 @@ class _$UserCompanyState extends UserCompanyState {
..add('taskState', taskState)
..add('projectState', projectState)
..add('paymentState', paymentState)
..add('quoteState', quoteState))
..add('quoteState', quoteState)
..add('groupState', groupState))
.toString();
}
}
@ -443,6 +462,12 @@ class UserCompanyStateBuilder
set quoteState(QuoteStateBuilder quoteState) =>
_$this._quoteState = quoteState;
GroupStateBuilder _groupState;
GroupStateBuilder get groupState =>
_$this._groupState ??= new GroupStateBuilder();
set groupState(GroupStateBuilder groupState) =>
_$this._groupState = groupState;
UserCompanyStateBuilder();
UserCompanyStateBuilder get _$this {
@ -459,6 +484,7 @@ class UserCompanyStateBuilder
_projectState = _$v.projectState?.toBuilder();
_paymentState = _$v.paymentState?.toBuilder();
_quoteState = _$v.quoteState?.toBuilder();
_groupState = _$v.groupState?.toBuilder();
_$v = null;
}
return this;
@ -494,7 +520,8 @@ class UserCompanyStateBuilder
taskState: taskState.build(),
projectState: projectState.build(),
paymentState: paymentState.build(),
quoteState: quoteState.build());
quoteState: quoteState.build(),
groupState: groupState.build());
} catch (_) {
String _$failedField;
try {
@ -522,6 +549,8 @@ class UserCompanyStateBuilder
paymentState.build();
_$failedField = 'quoteState';
quoteState.build();
_$failedField = 'groupState';
groupState.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'UserCompanyState', _$failedField, e.toString());

View File

@ -0,0 +1,263 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
class ViewGroupList implements PersistUI {
ViewGroupList({@required this.context, this.force = false});
final BuildContext context;
final bool force;
}
class ViewGroup implements PersistUI {
ViewGroup({
@required this.groupId,
@required this.context,
this.force = false,
});
final int groupId;
final BuildContext context;
final bool force;
}
class EditGroup implements PersistUI {
EditGroup(
{@required this.group,
@required this.context,
this.completer,
this.force = false});
final GroupEntity group;
final BuildContext context;
final Completer completer;
final bool force;
}
class UpdateGroup implements PersistUI {
UpdateGroup(this.group);
final GroupEntity group;
}
class LoadGroup {
LoadGroup({this.completer, this.groupId, this.loadActivities = false});
final Completer completer;
final String groupId;
final bool loadActivities;
}
class LoadGroupActivity {
LoadGroupActivity({this.completer, this.groupId});
final Completer completer;
final String groupId;
}
class LoadGroups {
LoadGroups({this.completer, this.force = false});
final Completer completer;
final bool force;
}
class LoadGroupRequest implements StartLoading {}
class LoadGroupFailure implements StopLoading {
LoadGroupFailure(this.error);
final dynamic error;
@override
String toString() {
return 'LoadGroupFailure{error: $error}';
}
}
class LoadGroupSuccess implements StopLoading, PersistData {
LoadGroupSuccess(this.group);
final GroupEntity group;
@override
String toString() {
return 'LoadGroupSuccess{group: $group}';
}
}
class LoadGroupsRequest implements StartLoading {}
class LoadGroupsFailure implements StopLoading {
LoadGroupsFailure(this.error);
final dynamic error;
@override
String toString() {
return 'LoadGroupsFailure{error: $error}';
}
}
class LoadGroupsSuccess implements StopLoading, PersistData {
LoadGroupsSuccess(this.groups);
final BuiltList<GroupEntity> groups;
@override
String toString() {
return 'LoadGroupsSuccess{groups: $groups}';
}
}
class SaveGroupRequest implements StartSaving {
SaveGroupRequest({this.completer, this.group});
final Completer completer;
final GroupEntity group;
}
class SaveGroupSuccess implements StopSaving, PersistData, PersistUI {
SaveGroupSuccess(this.group);
final GroupEntity group;
}
class AddGroupSuccess implements StopSaving, PersistData, PersistUI {
AddGroupSuccess(this.group);
final GroupEntity group;
}
class SaveGroupFailure implements StopSaving {
SaveGroupFailure(this.error);
final Object error;
}
class ArchiveGroupRequest implements StartSaving {
ArchiveGroupRequest(this.completer, this.groupId);
final Completer completer;
final String groupId;
}
class ArchiveGroupSuccess implements StopSaving, PersistData {
ArchiveGroupSuccess(this.group);
final GroupEntity group;
}
class ArchiveGroupFailure implements StopSaving {
ArchiveGroupFailure(this.group);
final GroupEntity group;
}
class DeleteGroupRequest implements StartSaving {
DeleteGroupRequest(this.completer, this.groupId);
final Completer completer;
final String groupId;
}
class DeleteGroupSuccess implements StopSaving, PersistData {
DeleteGroupSuccess(this.group);
final GroupEntity group;
}
class DeleteGroupFailure implements StopSaving {
DeleteGroupFailure(this.group);
final GroupEntity group;
}
class RestoreGroupRequest implements StartSaving {
RestoreGroupRequest(this.completer, this.groupId);
final Completer completer;
final String groupId;
}
class RestoreGroupSuccess implements StopSaving, PersistData {
RestoreGroupSuccess(this.group);
final GroupEntity group;
}
class RestoreGroupFailure implements StopSaving {
RestoreGroupFailure(this.group);
final GroupEntity group;
}
class FilterGroups {
FilterGroups(this.filter);
final String filter;
}
class SortGroups implements PersistUI {
SortGroups(this.field);
final String field;
}
class FilterGroupsByState implements PersistUI {
FilterGroupsByState(this.state);
final EntityState state;
}
class FilterGroupsByCustom1 implements PersistUI {
FilterGroupsByCustom1(this.value);
final String value;
}
class FilterGroupsByCustom2 implements PersistUI {
FilterGroupsByCustom2(this.value);
final String value;
}
class FilterGroupsByEntity implements PersistUI {
FilterGroupsByEntity({this.entityId, this.entityType});
final String entityId;
final EntityType entityType;
}
void handleGroupAction(
BuildContext context, GroupEntity group, EntityAction action) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final CompanyEntity company = state.selectedCompany;
final localization = AppLocalization.of(context);
switch (action) {
case EntityAction.edit:
store.dispatch(EditGroup(context: context, group: group));
break;
case EntityAction.restore:
store.dispatch(RestoreGroupRequest(
snackBarCompleter(context, localization.restoredGroup), group.id));
break;
case EntityAction.archive:
store.dispatch(ArchiveGroupRequest(
snackBarCompleter(context, localization.archivedGroup), group.id));
break;
case EntityAction.delete:
store.dispatch(DeleteGroupRequest(
snackBarCompleter(context, localization.deletedGroup), group.id));
break;
}
}

View File

@ -0,0 +1,267 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:redux/redux.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/group/group_screen.dart';
import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/group/view/group_view_vm.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/data/repositories/group_repository.dart';
List<Middleware<AppState>> createStoreGroupsMiddleware([
GroupRepository repository = const GroupRepository(),
]) {
final viewGroupList = _viewGroupList();
final viewGroup = _viewGroup();
final editGroup = _editGroup();
final loadGroups = _loadGroups(repository);
final loadGroup = _loadGroup(repository);
final saveGroup = _saveGroup(repository);
final archiveGroup = _archiveGroup(repository);
final deleteGroup = _deleteGroup(repository);
final restoreGroup = _restoreGroup(repository);
return [
TypedMiddleware<AppState, ViewGroupList>(viewGroupList),
TypedMiddleware<AppState, ViewGroup>(viewGroup),
TypedMiddleware<AppState, EditGroup>(editGroup),
TypedMiddleware<AppState, LoadGroups>(loadGroups),
TypedMiddleware<AppState, LoadGroup>(loadGroup),
TypedMiddleware<AppState, SaveGroupRequest>(saveGroup),
TypedMiddleware<AppState, ArchiveGroupRequest>(archiveGroup),
TypedMiddleware<AppState, DeleteGroupRequest>(deleteGroup),
TypedMiddleware<AppState, RestoreGroupRequest>(restoreGroup),
];
}
Middleware<AppState> _editGroup() {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as EditGroup;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(GroupEditScreen.route));
if (isMobile(action.context)) {
final group =
await Navigator.of(action.context).pushNamed(GroupEditScreen.route);
if (action.completer != null && group != null) {
action.completer.complete(group);
}
}
};
}
Middleware<AppState> _viewGroup() {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewGroup;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(GroupViewScreen.route));
Navigator.of(action.context).pushNamed(GroupViewScreen.route);
};
}
Middleware<AppState> _viewGroupList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewGroupList;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
return;
}
next(action);
if (store.state.groupState.isStale) {
store.dispatch(LoadGroups());
}
store.dispatch(UpdateCurrentRoute(GroupScreen.route));
if (isMobile(action.context)) {
Navigator.of(action.context).pushNamedAndRemoveUntil(
GroupScreen.route, (Route<dynamic> route) => false);
}
};
}
Middleware<AppState> _archiveGroup(GroupRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ArchiveGroupRequest;
final origGroup = store.state.groupState.map[action.groupId];
repository
.saveData(store.state.credentials, origGroup, EntityAction.archive)
.then((GroupEntity group) {
store.dispatch(ArchiveGroupSuccess(group));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(ArchiveGroupFailure(origGroup));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _deleteGroup(GroupRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as DeleteGroupRequest;
final origGroup = store.state.groupState.map[action.groupId];
repository
.saveData(store.state.credentials, origGroup, EntityAction.delete)
.then((GroupEntity group) {
store.dispatch(DeleteGroupSuccess(group));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(DeleteGroupFailure(origGroup));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _restoreGroup(GroupRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as RestoreGroupRequest;
final origGroup = store.state.groupState.map[action.groupId];
repository
.saveData(store.state.credentials, origGroup, EntityAction.restore)
.then((GroupEntity group) {
store.dispatch(RestoreGroupSuccess(group));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(RestoreGroupFailure(origGroup));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _saveGroup(GroupRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as SaveGroupRequest;
repository
.saveData(store.state.credentials, action.group)
.then((GroupEntity group) {
if (action.group.isNew) {
store.dispatch(AddGroupSuccess(group));
} else {
store.dispatch(SaveGroupSuccess(group));
}
action.completer.complete(group);
}).catchError((Object error) {
print(error);
store.dispatch(SaveGroupFailure(error));
action.completer.completeError(error);
});
next(action);
};
}
Middleware<AppState> _loadGroup(GroupRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadGroup;
final AppState state = store.state;
if (state.isLoading) {
next(action);
return;
}
store.dispatch(LoadGroupRequest());
repository.loadItem(state.credentials, action.groupId).then((group) {
store.dispatch(LoadGroupSuccess(group));
if (action.completer != null) {
action.completer.complete(null);
}
}).catchError((Object error) {
print(error);
store.dispatch(LoadGroupFailure(error));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}
Middleware<AppState> _loadGroups(GroupRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadGroups;
final AppState state = store.state;
if (!state.groupState.isStale && !action.force) {
next(action);
return;
}
if (state.isLoading) {
next(action);
return;
}
final int updatedAt = (state.groupState.lastUpdated / 1000).round();
store.dispatch(LoadGroupsRequest());
repository.loadList(state.credentials, updatedAt).then((data) {
store.dispatch(LoadGroupsSuccess(data));
if (action.completer != null) {
action.completer.complete(null);
}
/*
if (state.productState.isStale) {
store.dispatch(LoadProducts());
}
*/
}).catchError((Object error) {
print(error);
store.dispatch(LoadGroupsFailure(error));
if (action.completer != null) {
action.completer.completeError(error);
}
});
next(action);
};
}

View File

@ -0,0 +1,201 @@
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:redux/redux.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/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_state.dart';
EntityUIState groupUIReducer(GroupUIState state, dynamic action) {
return state.rebuild((b) => b
..listUIState.replace(groupListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.editing, action))
..selectedId = selectedIdReducer(state.selectedId, action));
}
Reducer<String> selectedIdReducer = combineReducers([
TypedReducer<String, ViewGroup>(
(String selectedId, dynamic action) => action.groupId),
TypedReducer<String, AddGroupSuccess>(
(String selectedId, dynamic action) => action.group.id),
TypedReducer<String, FilterGroupsByEntity>(
(selectedId, action) => action.entityId == null ? selectedId : 0)
]);
final editingReducer = combineReducers<GroupEntity>([
TypedReducer<GroupEntity, SaveGroupSuccess>(_updateEditing),
TypedReducer<GroupEntity, AddGroupSuccess>(_updateEditing),
TypedReducer<GroupEntity, RestoreGroupSuccess>(_updateEditing),
TypedReducer<GroupEntity, ArchiveGroupSuccess>(_updateEditing),
TypedReducer<GroupEntity, DeleteGroupSuccess>(_updateEditing),
TypedReducer<GroupEntity, EditGroup>(_updateEditing),
TypedReducer<GroupEntity, UpdateGroup>((group, action) {
return action.group.rebuild((b) => b..isChanged = true);
}),
TypedReducer<GroupEntity, SelectCompany>(_clearEditing),
]);
GroupEntity _clearEditing(GroupEntity group, dynamic action) {
return GroupEntity();
}
GroupEntity _updateEditing(GroupEntity group, dynamic action) {
return action.group;
}
final groupListReducer = combineReducers<ListUIState>([
TypedReducer<ListUIState, SortGroups>(_sortGroups),
TypedReducer<ListUIState, FilterGroupsByState>(_filterGroupsByState),
TypedReducer<ListUIState, FilterGroups>(_filterGroups),
TypedReducer<ListUIState, FilterGroupsByCustom1>(_filterGroupsByCustom1),
TypedReducer<ListUIState, FilterGroupsByCustom2>(_filterGroupsByCustom2),
TypedReducer<ListUIState, FilterGroupsByEntity>(_filterGroupsByClient),
]);
ListUIState _filterGroupsByClient(
ListUIState groupListState, FilterGroupsByEntity action) {
return groupListState.rebuild((b) => b
..filterEntityId = action.entityId
..filterEntityType = action.entityType);
}
ListUIState _filterGroupsByCustom1(
ListUIState groupListState, FilterGroupsByCustom1 action) {
if (groupListState.custom1Filters.contains(action.value)) {
return groupListState
.rebuild((b) => b..custom1Filters.remove(action.value));
} else {
return groupListState.rebuild((b) => b..custom1Filters.add(action.value));
}
}
ListUIState _filterGroupsByCustom2(
ListUIState groupListState, FilterGroupsByCustom2 action) {
if (groupListState.custom2Filters.contains(action.value)) {
return groupListState
.rebuild((b) => b..custom2Filters.remove(action.value));
} else {
return groupListState.rebuild((b) => b..custom2Filters.add(action.value));
}
}
ListUIState _filterGroupsByState(
ListUIState groupListState, FilterGroupsByState action) {
if (groupListState.stateFilters.contains(action.state)) {
return groupListState.rebuild((b) => b..stateFilters.remove(action.state));
} else {
return groupListState.rebuild((b) => b..stateFilters.add(action.state));
}
}
ListUIState _filterGroups(ListUIState groupListState, FilterGroups action) {
return groupListState.rebuild((b) => b
..filter = action.filter
..filterClearedAt = action.filter == null
? DateTime.now().millisecondsSinceEpoch
: groupListState.filterClearedAt);
}
ListUIState _sortGroups(ListUIState groupListState, SortGroups action) {
return groupListState.rebuild((b) => b
..sortAscending = b.sortField != action.field || !b.sortAscending
..sortField = action.field);
}
final groupsReducer = combineReducers<GroupState>([
TypedReducer<GroupState, SaveGroupSuccess>(_updateGroup),
TypedReducer<GroupState, AddGroupSuccess>(_addGroup),
TypedReducer<GroupState, LoadGroupsSuccess>(_setLoadedGroups),
TypedReducer<GroupState, LoadGroupSuccess>(_setLoadedGroup),
TypedReducer<GroupState, ArchiveGroupRequest>(_archiveGroupRequest),
TypedReducer<GroupState, ArchiveGroupSuccess>(_archiveGroupSuccess),
TypedReducer<GroupState, ArchiveGroupFailure>(_archiveGroupFailure),
TypedReducer<GroupState, DeleteGroupRequest>(_deleteGroupRequest),
TypedReducer<GroupState, DeleteGroupSuccess>(_deleteGroupSuccess),
TypedReducer<GroupState, DeleteGroupFailure>(_deleteGroupFailure),
TypedReducer<GroupState, RestoreGroupRequest>(_restoreGroupRequest),
TypedReducer<GroupState, RestoreGroupSuccess>(_restoreGroupSuccess),
TypedReducer<GroupState, RestoreGroupFailure>(_restoreGroupFailure),
]);
GroupState _archiveGroupRequest(
GroupState groupState, ArchiveGroupRequest action) {
final group = groupState.map[action.groupId]
.rebuild((b) => b..archivedAt = DateTime.now().millisecondsSinceEpoch);
return groupState.rebuild((b) => b..map[action.groupId] = group);
}
GroupState _archiveGroupSuccess(
GroupState groupState, ArchiveGroupSuccess action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _archiveGroupFailure(
GroupState groupState, ArchiveGroupFailure action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _deleteGroupRequest(
GroupState groupState, DeleteGroupRequest action) {
final group = groupState.map[action.groupId].rebuild((b) => b
..archivedAt = DateTime.now().millisecondsSinceEpoch
..isDeleted = true);
return groupState.rebuild((b) => b..map[action.groupId] = group);
}
GroupState _deleteGroupSuccess(
GroupState groupState, DeleteGroupSuccess action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _deleteGroupFailure(
GroupState groupState, DeleteGroupFailure action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _restoreGroupRequest(
GroupState groupState, RestoreGroupRequest action) {
final group = groupState.map[action.groupId].rebuild((b) => b
..archivedAt = null
..isDeleted = false);
return groupState.rebuild((b) => b..map[action.groupId] = group);
}
GroupState _restoreGroupSuccess(
GroupState groupState, RestoreGroupSuccess action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _restoreGroupFailure(
GroupState groupState, RestoreGroupFailure action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _addGroup(GroupState groupState, AddGroupSuccess action) {
return groupState.rebuild((b) => b
..map[action.group.id] = action.group
..list.add(action.group.id));
}
GroupState _updateGroup(GroupState groupState, SaveGroupSuccess action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _setLoadedGroup(GroupState groupState, LoadGroupSuccess action) {
return groupState.rebuild((b) => b..map[action.group.id] = action.group);
}
GroupState _setLoadedGroups(GroupState groupState, LoadGroupsSuccess action) {
final state = groupState.rebuild((b) => b
..lastUpdated = DateTime.now().millisecondsSinceEpoch
..map.addAll(Map.fromIterable(
action.groups,
key: (dynamic item) => item.id,
value: (dynamic item) => item,
)));
return state.rebuild((b) => b..list.replace(state.map.keys));
}

View File

@ -0,0 +1,63 @@
import 'package:invoiceninja_flutter/data/models/group_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 memoizedDropdownGroupList = memo3((BuiltMap<String, GroupEntity> groupMap,
BuiltList<String> groupList, String clientId) =>
dropdownGroupsSelector(groupMap, groupList, clientId));
List<String> dropdownGroupsSelector(BuiltMap<String, GroupEntity> groupMap,
BuiltList<String> groupList, String clientId) {
final list = groupList.where((groupId) {
final group = groupMap[groupId];
/*
if (clientId != null && clientId > 0 && group.clientId != clientId) {
return false;
}
*/
return group.isActive;
}).toList();
list.sort((groupAId, groupBId) {
final groupA = groupMap[groupAId];
final groupB = groupMap[groupBId];
return groupA.compareTo(groupB, GroupFields.name, true);
});
return list;
}
var memoizedFilteredGroupList = memo3((BuiltMap<String, GroupEntity> groupMap,
BuiltList<String> groupList, ListUIState groupListState) =>
filteredGroupsSelector(groupMap, groupList, groupListState));
List<String> filteredGroupsSelector(BuiltMap<String, GroupEntity> groupMap,
BuiltList<String> groupList, ListUIState groupListState) {
final list = groupList.where((groupId) {
final group = groupMap[groupId];
if (!group.matchesStates(groupListState.stateFilters)) {
return false;
}
if (groupListState.custom1Filters.isNotEmpty &&
!groupListState.custom1Filters.contains(group.customValue1)) {
return false;
}
if (groupListState.custom2Filters.isNotEmpty &&
!groupListState.custom2Filters.contains(group.customValue2)) {
return false;
}
return group.matchesFilter(groupListState.filter);
}).toList();
list.sort((groupAId, groupBId) {
final groupA = groupMap[groupAId];
final groupB = groupMap[groupBId];
return groupA.compareTo(
groupB, groupListState.sortField, groupListState.sortAscending);
});
return list;
}

View File

@ -0,0 +1,60 @@
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/group_model.dart';
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
part 'group_state.g.dart';
abstract class GroupState implements Built<GroupState, GroupStateBuilder> {
factory GroupState() {
return _$GroupState._(
lastUpdated: 0,
map: BuiltMap<String, GroupEntity>(),
list: BuiltList<String>(),
);
}
GroupState._();
@nullable
int get lastUpdated;
BuiltMap<String, GroupEntity> 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;
static Serializer<GroupState> get serializer => _$groupStateSerializer;
}
abstract class GroupUIState extends Object
with EntityUIState
implements Built<GroupUIState, GroupUIStateBuilder> {
factory GroupUIState() {
return _$GroupUIState._(
listUIState: ListUIState(GroupFields.name),
editing: GroupEntity(),
selectedId: '',
);
}
GroupUIState._();
@nullable
GroupEntity get editing;
@override
bool get isCreatingNew => editing.isNew;
static Serializer<GroupUIState> get serializer => _$groupUIStateSerializer;
}

View File

@ -0,0 +1,405 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'group_state.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<GroupState> _$groupStateSerializer = new _$GroupStateSerializer();
Serializer<GroupUIState> _$groupUIStateSerializer =
new _$GroupUIStateSerializer();
class _$GroupStateSerializer implements StructuredSerializer<GroupState> {
@override
final Iterable<Type> types = const [GroupState, _$GroupState];
@override
final String wireName = 'GroupState';
@override
Iterable<Object> serialize(Serializers serializers, GroupState object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'map',
serializers.serialize(object.map,
specifiedType: const FullType(BuiltMap,
const [const FullType(String), const FullType(GroupEntity)])),
'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
GroupState deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new GroupStateBuilder();
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(GroupEntity)
])) as BuiltMap<dynamic, dynamic>);
break;
case 'list':
result.list.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList<dynamic>);
break;
}
}
return result.build();
}
}
class _$GroupUIStateSerializer implements StructuredSerializer<GroupUIState> {
@override
final Iterable<Type> types = const [GroupUIState, _$GroupUIState];
@override
final String wireName = 'GroupUIState';
@override
Iterable<Object> serialize(Serializers serializers, GroupUIState 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(GroupEntity)));
}
if (object.selectedId != null) {
result
..add('selectedId')
..add(serializers.serialize(object.selectedId,
specifiedType: const FullType(String)));
}
return result;
}
@override
GroupUIState deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new GroupUIStateBuilder();
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(GroupEntity)) as GroupEntity);
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 _$GroupState extends GroupState {
@override
final int lastUpdated;
@override
final BuiltMap<String, GroupEntity> map;
@override
final BuiltList<String> list;
factory _$GroupState([void Function(GroupStateBuilder) updates]) =>
(new GroupStateBuilder()..update(updates)).build();
_$GroupState._({this.lastUpdated, this.map, this.list}) : super._() {
if (map == null) {
throw new BuiltValueNullFieldError('GroupState', 'map');
}
if (list == null) {
throw new BuiltValueNullFieldError('GroupState', 'list');
}
}
@override
GroupState rebuild(void Function(GroupStateBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
GroupStateBuilder toBuilder() => new GroupStateBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is GroupState &&
lastUpdated == other.lastUpdated &&
map == other.map &&
list == other.list;
}
@override
int get hashCode {
return $jf(
$jc($jc($jc(0, lastUpdated.hashCode), map.hashCode), list.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('GroupState')
..add('lastUpdated', lastUpdated)
..add('map', map)
..add('list', list))
.toString();
}
}
class GroupStateBuilder implements Builder<GroupState, GroupStateBuilder> {
_$GroupState _$v;
int _lastUpdated;
int get lastUpdated => _$this._lastUpdated;
set lastUpdated(int lastUpdated) => _$this._lastUpdated = lastUpdated;
MapBuilder<String, GroupEntity> _map;
MapBuilder<String, GroupEntity> get map =>
_$this._map ??= new MapBuilder<String, GroupEntity>();
set map(MapBuilder<String, GroupEntity> map) => _$this._map = map;
ListBuilder<String> _list;
ListBuilder<String> get list => _$this._list ??= new ListBuilder<String>();
set list(ListBuilder<String> list) => _$this._list = list;
GroupStateBuilder();
GroupStateBuilder get _$this {
if (_$v != null) {
_lastUpdated = _$v.lastUpdated;
_map = _$v.map?.toBuilder();
_list = _$v.list?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(GroupState other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$GroupState;
}
@override
void update(void Function(GroupStateBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$GroupState build() {
_$GroupState _$result;
try {
_$result = _$v ??
new _$GroupState._(
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(
'GroupState', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$GroupUIState extends GroupUIState {
@override
final GroupEntity editing;
@override
final ListUIState listUIState;
@override
final String selectedId;
@override
final Completer<SelectableEntity> saveCompleter;
@override
final Completer<Null> cancelCompleter;
factory _$GroupUIState([void Function(GroupUIStateBuilder) updates]) =>
(new GroupUIStateBuilder()..update(updates)).build();
_$GroupUIState._(
{this.editing,
this.listUIState,
this.selectedId,
this.saveCompleter,
this.cancelCompleter})
: super._() {
if (listUIState == null) {
throw new BuiltValueNullFieldError('GroupUIState', 'listUIState');
}
}
@override
GroupUIState rebuild(void Function(GroupUIStateBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
GroupUIStateBuilder toBuilder() => new GroupUIStateBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is GroupUIState &&
editing == other.editing &&
listUIState == other.listUIState &&
selectedId == other.selectedId &&
saveCompleter == other.saveCompleter &&
cancelCompleter == other.cancelCompleter;
}
@override
int get hashCode {
return $jf($jc(
$jc(
$jc($jc($jc(0, editing.hashCode), listUIState.hashCode),
selectedId.hashCode),
saveCompleter.hashCode),
cancelCompleter.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('GroupUIState')
..add('editing', editing)
..add('listUIState', listUIState)
..add('selectedId', selectedId)
..add('saveCompleter', saveCompleter)
..add('cancelCompleter', cancelCompleter))
.toString();
}
}
class GroupUIStateBuilder
implements Builder<GroupUIState, GroupUIStateBuilder> {
_$GroupUIState _$v;
GroupEntityBuilder _editing;
GroupEntityBuilder get editing =>
_$this._editing ??= new GroupEntityBuilder();
set editing(GroupEntityBuilder 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;
GroupUIStateBuilder();
GroupUIStateBuilder 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(GroupUIState other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$GroupUIState;
}
@override
void update(void Function(GroupUIStateBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$GroupUIState build() {
_$GroupUIState _$result;
try {
_$result = _$v ??
new _$GroupUIState._(
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(
'GroupUIState', _$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

@ -12,6 +12,8 @@ import 'package:invoiceninja_flutter/redux/invoice/invoice_reducer.dart';
import 'package:redux/redux.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_reducer.dart';
import 'package:invoiceninja_flutter/redux/document/document_reducer.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_reducer.dart';
@ -54,6 +56,8 @@ UIState uiReducer(UIState state, dynamic action) {
..dashboardUIState
.replace(dashboardUIReducer(state.dashboardUIState, action))
// STARTER: reducer - do not remove comment
..groupUIState.replace(groupUIReducer(state.groupUIState, action))
..documentUIState.replace(documentUIReducer(state.documentUIState, action))
..expenseUIState.replace(expenseUIReducer(state.expenseUIState, action))
..vendorUIState.replace(vendorUIReducer(state.vendorUIState, action))

View File

@ -10,6 +10,8 @@ import 'package:invoiceninja_flutter/redux/product/product_state.dart';
import 'package:invoiceninja_flutter/ui/auth/login_vm.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_state.dart';
import 'package:invoiceninja_flutter/redux/document/document_state.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_state.dart';
@ -53,6 +55,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
clientUIState: ClientUIState(),
invoiceUIState: InvoiceUIState(),
// STARTER: constructor - do not remove comment
groupUIState: GroupUIState(),
documentUIState: DocumentUIState(),
expenseUIState: ExpenseUIState(),
vendorUIState: VendorUIState(),
@ -102,6 +106,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
InvoiceUIState get invoiceUIState;
// STARTER: properties - do not remove comment
GroupUIState get groupUIState;
DocumentUIState get documentUIState;
ExpenseUIState get expenseUIState;

View File

@ -111,6 +111,9 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
'invoiceUIState',
serializers.serialize(object.invoiceUIState,
specifiedType: const FullType(InvoiceUIState)),
'groupUIState',
serializers.serialize(object.groupUIState,
specifiedType: const FullType(GroupUIState)),
'documentUIState',
serializers.serialize(object.documentUIState,
specifiedType: const FullType(DocumentUIState)),
@ -225,6 +228,10 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
result.invoiceUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(InvoiceUIState)) as InvoiceUIState);
break;
case 'groupUIState':
result.groupUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(GroupUIState)) as GroupUIState);
break;
case 'documentUIState':
result.documentUIState.replace(serializers.deserialize(value,
specifiedType: const FullType(DocumentUIState))
@ -336,6 +343,8 @@ class _$UIState extends UIState {
@override
final InvoiceUIState invoiceUIState;
@override
final GroupUIState groupUIState;
@override
final DocumentUIState documentUIState;
@override
final ExpenseUIState expenseUIState;
@ -373,6 +382,7 @@ class _$UIState extends UIState {
this.productUIState,
this.clientUIState,
this.invoiceUIState,
this.groupUIState,
this.documentUIState,
this.expenseUIState,
this.vendorUIState,
@ -430,6 +440,9 @@ class _$UIState extends UIState {
if (invoiceUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'invoiceUIState');
}
if (groupUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'groupUIState');
}
if (documentUIState == null) {
throw new BuiltValueNullFieldError('UIState', 'documentUIState');
}
@ -484,6 +497,7 @@ class _$UIState extends UIState {
productUIState == other.productUIState &&
clientUIState == other.clientUIState &&
invoiceUIState == other.invoiceUIState &&
groupUIState == other.groupUIState &&
documentUIState == other.documentUIState &&
expenseUIState == other.expenseUIState &&
vendorUIState == other.vendorUIState &&
@ -514,18 +528,18 @@ class _$UIState extends UIState {
$jc(
$jc(
$jc(
$jc($jc($jc($jc($jc($jc($jc(0, layout.hashCode), isTesting.hashCode), isMenuVisible.hashCode), isHistoryVisible.hashCode), selectedCompanyIndex.hashCode), currentRoute.hashCode),
previousRoute.hashCode),
enableDarkMode.hashCode),
requireAuthentication.hashCode),
emailPayment.hashCode),
autoStartTasks.hashCode),
addDocumentsToInvoice.hashCode),
filter.hashCode),
dashboardUIState.hashCode),
productUIState.hashCode),
clientUIState.hashCode),
invoiceUIState.hashCode),
$jc($jc($jc($jc($jc($jc($jc($jc(0, layout.hashCode), isTesting.hashCode), isMenuVisible.hashCode), isHistoryVisible.hashCode), selectedCompanyIndex.hashCode), currentRoute.hashCode), previousRoute.hashCode),
enableDarkMode.hashCode),
requireAuthentication.hashCode),
emailPayment.hashCode),
autoStartTasks.hashCode),
addDocumentsToInvoice.hashCode),
filter.hashCode),
dashboardUIState.hashCode),
productUIState.hashCode),
clientUIState.hashCode),
invoiceUIState.hashCode),
groupUIState.hashCode),
documentUIState.hashCode),
expenseUIState.hashCode),
vendorUIState.hashCode),
@ -556,6 +570,7 @@ class _$UIState extends UIState {
..add('productUIState', productUIState)
..add('clientUIState', clientUIState)
..add('invoiceUIState', invoiceUIState)
..add('groupUIState', groupUIState)
..add('documentUIState', documentUIState)
..add('expenseUIState', expenseUIState)
..add('vendorUIState', vendorUIState)
@ -655,6 +670,12 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
set invoiceUIState(InvoiceUIStateBuilder invoiceUIState) =>
_$this._invoiceUIState = invoiceUIState;
GroupUIStateBuilder _groupUIState;
GroupUIStateBuilder get groupUIState =>
_$this._groupUIState ??= new GroupUIStateBuilder();
set groupUIState(GroupUIStateBuilder groupUIState) =>
_$this._groupUIState = groupUIState;
DocumentUIStateBuilder _documentUIState;
DocumentUIStateBuilder get documentUIState =>
_$this._documentUIState ??= new DocumentUIStateBuilder();
@ -724,6 +745,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
_productUIState = _$v.productUIState?.toBuilder();
_clientUIState = _$v.clientUIState?.toBuilder();
_invoiceUIState = _$v.invoiceUIState?.toBuilder();
_groupUIState = _$v.groupUIState?.toBuilder();
_documentUIState = _$v.documentUIState?.toBuilder();
_expenseUIState = _$v.expenseUIState?.toBuilder();
_vendorUIState = _$v.vendorUIState?.toBuilder();
@ -773,6 +795,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
productUIState: productUIState.build(),
clientUIState: clientUIState.build(),
invoiceUIState: invoiceUIState.build(),
groupUIState: groupUIState.build(),
documentUIState: documentUIState.build(),
expenseUIState: expenseUIState.build(),
vendorUIState: vendorUIState.build(),
@ -792,6 +815,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
clientUIState.build();
_$failedField = 'invoiceUIState';
invoiceUIState.build();
_$failedField = 'groupUIState';
groupUIState.build();
_$failedField = 'documentUIState';
documentUIState.build();
_$failedField = 'expenseUIState';

View File

@ -25,6 +25,8 @@ import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:url_launcher/url_launcher.dart';
// STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
class AppDrawer extends StatelessWidget {
const AppDrawer({
@ -317,6 +319,19 @@ class AppDrawer extends StatelessWidget {
),
*/
// STARTER: menu - do not remove comment
DrawerTile(
company: company,
entityType: EntityType.group,
icon: getEntityIcon(EntityType.group),
title: localization.groups,
onTap: () => store.dispatch(ViewGroupList(context)),
onCreateTap: () {
navigator.pop();
store.dispatch(EditGroup(
group: GroupEntity(), context: context));
},
),
DrawerTile(
company: company,
icon: FontAwesomeIcons.cog,

View File

@ -0,0 +1,121 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/group/edit/group_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/action_icon_button.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class GroupEdit extends StatefulWidget {
const GroupEdit({
Key key,
@required this.viewModel,
}) : super(key: key);
final GroupEditVM viewModel;
@override
_GroupEditState createState() => _GroupEditState();
}
class _GroupEditState extends State<GroupEdit> {
static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
// 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 group = widget.viewModel.group;
// 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() {
final group = widget.viewModel.group.rebuild((b) => b
// STARTER: set value - do not remove comment
);
if (group != widget.viewModel.group) {
widget.viewModel.onChanged(group);
}
}
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final localization = AppLocalization.of(context);
final group = viewModel.group;
return WillPopScope(
onWillPop: () async {
viewModel.onBackPressed();
return true;
},
child: Scaffold(
automaticallyImplyLeading: isMobile(context),
appBar: AppBar(
title: Text(viewModel.group.isNew
? localization.newGroup
: localization.editGroup),
actions: <Widget>[
if (!isMobile(context))
FlatButton(
child: Text(
localization.cancel,
style: TextStyle(color: Colors.white),
),
onPressed: () => viewModel.onCancelPressed(context),
),
ActionIconButton(
icon: Icons.cloud_upload,
tooltip: localization.save,
isVisible: !group.isDeleted,
isDirty: group.isNew || group != viewModel.origGroup,
isSaving: viewModel.isSaving,
onPressed: () {
if (! _formKey.currentState.validate()) {
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,106 @@
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/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/group/group_screen.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/group/view/group_view_vm.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/ui/group/edit/group_edit.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class GroupEditScreen extends StatelessWidget {
const GroupEditScreen({Key key}) : super(key: key);
static const String route = '/group/edit';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, GroupEditVM>(
converter: (Store<AppState> store) {
return GroupEditVM.fromStore(store);
},
builder: (context, viewModel) {
return GroupEdit(
viewModel: viewModel,
);
},
);
}
}
class GroupEditVM {
GroupEditVM({
@required this.state,
@required this.group,
@required this.company,
@required this.onChanged,
@required this.isSaving,
@required this.origGroup,
@required this.onSavePressed,
@required this.onCancelPressed,
@required this.onBackPressed,
@required this.isLoading,
});
factory GroupEditVM.fromStore(Store<AppState> store) {
final group = store.state.groupUIState.editing;
final state = store.state;
return GroupEditVM(
state: state,
isLoading: state.isLoading,
isSaving: state.isSaving,
origGroup: state.groupState.map[group.id],
group: group,
company: state.selectedCompany,
onChanged: (GroupEntity group) {
store.dispatch(UpdateGroup(group));
},
onBackPressed: () {
if (state.uiState.currentRoute.contains(GroupScreen.route)) {
store.dispatch(UpdateCurrentRoute(group.isNew ? GroupScreen.route : GroupViewScreen.route));
}
},
onCancelPressed: (BuildContext context) {
store.dispatch(EditGroup(
group: GroupEntity(), context: context, force: true));
store.dispatch(UpdateCurrentRoute(state.uiState.previousRoute));
},
onSavePressed: (BuildContext context) {
final Completer<GroupEntity> completer = new Completer<GroupEntity>();
store.dispatch(SaveGroupRequest(completer: completer, group: group));
return completer.future.then((savedGroup) {
store.dispatch(UpdateCurrentRoute(GroupViewScreen.route));
if (isMobile(context)) {
if (group.isNew) {
Navigator.of(context).pushReplacementNamed(GroupViewScreen.route);
} else {
Navigator.of(context).pop(savedGroup);
}
}
}).catchError((Object error) {
showDialog<ErrorDialog>(
context: context,
builder: (BuildContext context) {
return ErrorDialog(error);
});
});
},
);
}
final GroupEntity group;
final CompanyEntity company;
final Function(GroupEntity) onChanged;
final Function(BuildContext) onSavePressed;
final Function(BuildContext) onCancelPressed;
final Function onBackPressed;
final bool isLoading;
final bool isSaving;
final GroupEntity origGroup;
final AppState state;
}

View File

@ -0,0 +1,166 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:invoiceninja_flutter/ui/group/group_list_item.dart';
import 'package:invoiceninja_flutter/ui/group/group_list_vm.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class GroupList extends StatelessWidget {
const GroupList({
Key key,
@required this.viewModel,
}) : super(key: key);
final GroupListVM viewModel;
@override
Widget build(BuildContext context) {
/*
final localization = AppLocalization.of(context);
final listState = viewModel.listState;
final filteredClientId = listState.filterEntityId;
final filteredClient =
filteredClientId != null ? viewModel.clientMap[filteredClientId] : null;
*/
return Column(
children: <Widget>[
Expanded(
child: !viewModel.isLoaded
? (viewModel.isLoading ? LoadingIndicator() : SizedBox())
: RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: viewModel.groupList.isEmpty
? HelpText(AppLocalization.of(context).noRecordsFound)
: ListView.separated(
shrinkWrap: true,
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.groupList.length,
itemBuilder: (BuildContext context, index) {
final groupId = viewModel.groupList[index];
final group = viewModel.groupMap[groupId];
final user = viewModel.user;
void showDialog() => showEntityActionsDialog(
entity: group,
context: context,
user: user,
onEntityAction: viewModel.onEntityAction);
return GroupListItem(
user: viewModel.user,
filter: viewModel.filter,
group: group,
onTap: () =>
viewModel.onGroupTap(context, group),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
showDialog();
} else {
viewModel.onEntityAction(
context, group, action);
}
},
onLongPress: () =>
showDialog(),
);
},
),
),
),
/*
filteredClient != null
? Material(
color: Colors.orangeAccent,
elevation: 6.0,
child: InkWell(
onTap: () => viewModel.onViewEntityFilterPressed(context),
child: Row(
children: <Widget>[
SizedBox(width: 18.0),
Expanded(
child: Text(
'${localization.filteredBy} ${filteredClient.listDisplayName}',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
),
),
),
IconButton(
icon: Icon(
Icons.close,
color: Colors.white,
),
onPressed: () => viewModel.onClearEntityFilterPressed(),
)
],
),
),
)
: Container(),
Expanded(
child: !viewModel.isLoaded
? LoadingIndicator()
: RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: viewModel.groupList.isEmpty
? HelpText(AppLocalization.of(context).noRecordsFound)
: ListView.separated(
shrinkWrap: true,
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.groupList.length,
itemBuilder: (BuildContext context, index) {
final user = viewModel.user;
final groupId = viewModel.groupList[index];
final group = viewModel.groupMap[groupId];
final client =
viewModel.clientMap[group.clientId] ??
ClientEntity();
void showDialog() => showEntityActionsDialog(
entity: group,
context: context,
user: user,
onEntityAction: viewModel.onEntityAction);
return GroupListItem(
user: viewModel.user,
filter: viewModel.filter,
group: group,
client:
viewModel.clientMap[group.clientId] ??
ClientEntity(),
onTap: () =>
viewModel.onGroupTap(context, group),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
showDialog();
} else {
viewModel.onEntityAction(
context, group, action);
}
},
onLongPress: () =>
showDialog(),
);
},
),
),
),*/
],
);
}
}

View File

@ -0,0 +1,85 @@
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 GroupListItem extends StatelessWidget {
const GroupListItem({
@required this.user,
@required this.onEntityAction,
@required this.onTap,
@required this.onLongPress,
//@required this.onCheckboxChanged,
@required this.group,
@required this.filter,
});
final UserEntity user;
final Function(EntityAction) onEntityAction;
final GestureTapCallback onTap;
final GestureTapCallback onLongPress;
//final ValueChanged<bool> onCheckboxChanged;
final GroupEntity group;
final String filter;
static final groupItemKey = (int id) => Key('__group_item_${id}__');
@override
Widget build(BuildContext context) {
final filterMatch = filter != null && filter.isNotEmpty
? group.matchesFilterValue(filter)
: null;
final subtitle = filterMatch;
return DismissibleEntity(
user: user,
entity: group,
onEntityAction: onEntityAction,
child: ListTile(
onTap: onTap,
onLongPress: onLongPress,
/*
leading: Checkbox(
//key: NinjaKeys.groupItemCheckbox(group.id),
value: true,
//onChanged: onCheckboxChanged,
onChanged: (value) {
return true;
},
),
*/
title: Container(
width: MediaQuery.of(context).size.width,
child: Row(
children: <Widget>[
Expanded(
child: Text(
group.name,
//key: NinjaKeys.clientItemClientKey(client.id),
style: Theme.of(context).textTheme.title,
),
),
Text(formatNumber(group.listDisplayAmount, context),
style: Theme.of(context).textTheme.title),
],
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
subtitle != null && subtitle.isNotEmpty ?
Text(
subtitle,
maxLines: 3,
overflow: TextOverflow.ellipsis,
) : Container(),
EntityStateLabel(group),
],
),
),
);
}
}

View File

@ -0,0 +1,101 @@
import 'dart:async';
import 'package:redux/redux.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/client/client_actions.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/group/group_selectors.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/group/group_list.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
class GroupListBuilder extends StatelessWidget {
const GroupListBuilder({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, GroupListVM>(
converter: GroupListVM.fromStore,
builder: (context, viewModel) {
return GroupList(
viewModel: viewModel,
);
},
);
}
}
class GroupListVM {
GroupListVM({
@required this.user,
@required this.groupList,
@required this.groupMap,
@required this.filter,
@required this.isLoading,
@required this.isLoaded,
@required this.onGroupTap,
@required this.listState,
@required this.onRefreshed,
@required this.onEntityAction,
@required this.onClearEntityFilterPressed,
@required this.onViewEntityFilterPressed,
});
static GroupListVM fromStore(Store<AppState> store) {
Future<Null> _handleRefresh(BuildContext context) {
if (store.state.isLoading) {
return Future<Null>(null);
}
final completer = snackBarCompleter(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(LoadGroups(completer: completer, force: true));
return completer.future;
}
final state = store.state;
return GroupListVM(
user: state.user,
listState: state.groupListState,
groupList: memoizedFilteredGroupList(state.groupState.map,
state.groupState.list, state.groupListState),
groupMap: state.groupState.map,
isLoading: state.isLoading,
isLoaded: state.groupState.isLoaded,
filter: state.groupUIState.listUIState.filter,
onClearEntityFilterPressed: () =>
store.dispatch(FilterGroupsByEntity()),
onViewEntityFilterPressed: (BuildContext context) => store.dispatch(
ViewClient(
clientId: state.groupListState.filterEntityId,
context: context)),
onGroupTap: (context, group) {
store.dispatch(ViewGroup(groupId: group.id, context: context));
},
onEntityAction:
(BuildContext context, BaseEntity group, EntityAction action) =>
handleGroupAction(context, group, action),
onRefreshed: (context) => _handleRefresh(context),
);
}
final UserEntity user;
final List<int> groupList;
final BuiltMap<String, GroupEntity> groupMap;
final ListUIState listState;
final String filter;
final bool isLoading;
final bool isLoaded;
final Function(BuildContext, GroupEntity) onGroupTap;
final Function(BuildContext) onRefreshed;
final Function(BuildContext, GroupEntity, EntityAction) onEntityAction;
final Function onClearEntityFilterPressed;
final Function(BuildContext) onViewEntityFilterPressed;
}

View File

@ -0,0 +1,78 @@
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/ui/app/app_scaffold.dart';
import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart';
import 'package:invoiceninja_flutter/ui/app/list_filter.dart';
import 'package:invoiceninja_flutter/ui/app/list_filter_button.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/group/group_list_vm.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/ui/app/app_drawer_vm.dart';
import 'package:invoiceninja_flutter/ui/app/app_bottom_bar.dart';
class GroupScreen extends StatelessWidget {
static const String route = '/group';
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final company = state.selectedCompany;
final user = company.user;
final localization = AppLocalization.of(context);
return AppScaffold(
appBarTitle: ListFilter(
key: ValueKey(state.groupListState.filterClearedAt),
entityType: EntityType.group,
onFilterChanged: (value) {
store.dispatch(FilterGroups(value));
},
),
appBarActions: [
ListFilterButton(
entityType: EntityType.group,
onFilterPressed: (String value) {
store.dispatch(FilterGroups(value));
},
),
],
body: GroupListBuilder(),
bottomNavigationBar: AppBottomBar(
entityType: EntityType.group,
onSelectedSortField: (value) => store.dispatch(SortGroups(value)),
customValues1: company.getCustomFieldValues(CustomFieldType.group1,
excludeBlank: true),
customValues2: company.getCustomFieldValues(CustomFieldType.group2,
excludeBlank: true),
onSelectedCustom1: (value) =>
store.dispatch(FilterGroupsByCustom1(value)),
onSelectedCustom2: (value) =>
store.dispatch(FilterGroupsByCustom2(value)),
sortFields: [
GroupFields.updatedAt,
],
onSelectedState: (EntityState state, value) {
store.dispatch(FilterGroupsByState(state));
},
),
floatingActionButton: user.canCreate(EntityType.group)
? FloatingActionButton(
heroTag: 'group_fab',
backgroundColor: Theme.of(context).primaryColorDark,
onPressed: () {
store.dispatch(
EditGroup(group: GroupEntity(), context: context));
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newGroup,
)
: null,
);
}
}

View File

@ -0,0 +1,54 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/ui/group/view/group_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_state_title.dart';
class GroupView extends StatefulWidget {
const GroupView({
Key key,
@required this.viewModel,
}) : super(key: key);
final GroupViewVM viewModel;
@override
_GroupViewState createState() => new _GroupViewState();
}
class _GroupViewState extends State<GroupView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final group = viewModel.group;
return Scaffold(
appBar: AppBar(
title: EntityStateTitle(entity: group),
actions: group.isNew
? []
: [
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
viewModel.onEditPressed(context);
},
),
ActionMenuButton(
user: viewModel.company.user,
isSaving: viewModel.isSaving,
entity: group,
onSelected: viewModel.onEntityAction,
),
],
),
body: FormCard(
children: [
// STARTER: widgets - do not remove comment
]
),
);
}
}

View File

@ -0,0 +1,102 @@
import 'dart:async';
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/ui/group/group_screen.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/ui/group/view/group_view.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class GroupViewScreen extends StatelessWidget {
const GroupViewScreen({Key key}) : super(key: key);
static const String route = '/group/view';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, GroupViewVM>(
converter: (Store<AppState> store) {
return GroupViewVM.fromStore(store);
},
builder: (context, vm) {
return GroupView(
viewModel: vm,
);
},
);
}
}
class GroupViewVM {
GroupViewVM({
@required this.state,
@required this.group,
@required this.company,
@required this.onEntityAction,
@required this.onEditPressed,
@required this.onBackPressed,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
});
factory GroupViewVM.fromStore(Store<AppState> store) {
final state = store.state;
final group = state.groupState.map[state.groupUIState.selectedId] ??
GroupEntity(id: state.groupUIState.selectedId);
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(LoadGroup(completer: completer, groupId: group.id));
return completer.future;
}
return GroupViewVM(
state: state,
company: state.selectedCompany,
isSaving: state.isSaving,
isLoading: state.isLoading,
isDirty: group.isNew,
group: group,
onEditPressed: (BuildContext context) {
final Completer<GroupEntity> completer = Completer<GroupEntity>();
store.dispatch(EditGroup(
group: group, context: context, completer: completer));
completer.future.then((group) {
Scaffold.of(context).showSnackBar(SnackBar(
content: SnackBarRow(
message: AppLocalization.of(context).updatedGroup,
)));
});
},
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
if (state.uiState.currentRoute.contains(GroupScreen.route)) {
store.dispatch(UpdateCurrentRoute(GroupScreen.route));
}
},
onEntityAction: (BuildContext context, EntityAction action) =>
handleGroupAction(context, group, action),
);
}
final AppState state;
final GroupEntity group;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onEditPressed;
final Function onBackPressed;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;
final bool isDirty;
}

View File

@ -14,6 +14,12 @@ abstract class LocaleCodeAware {
mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
'new_group': 'New Group',
'created_group': 'Successfully created group',
'updated_group': 'Successfully updated group',
'archived_group': 'Successfully archived group',
'deleted_group': 'Successfully deleted group',
'restored_group': 'Successfully restored group',
'upload_logo': 'Upload Logo',
'uploaded_logo': 'Successfully uploaded logo',
'logo': 'Logo',
@ -14688,6 +14694,18 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get uploadedLogo => _localizedValues[localeCode]['uploaded_logo'];
String get newGroup => _localizedValues[localeCode]['new_group'];
String get createdGroup => _localizedValues[localeCode]['created_group'];
String get updatedGroup => _localizedValues[localeCode]['updated_group'];
String get archivedGroup => _localizedValues[localeCode]['archived_group'];
String get deletedGroup => _localizedValues[localeCode]['deleted_group'];
String get restoredGroup => _localizedValues[localeCode]['restored_group'];
String lookup(String key) {
final lookupKey = toSnakeCase(key);
return _localizedValues[localeCode][lookupKey] ??

View File

@ -297,10 +297,7 @@ else
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/main.dart
comment="STARTER: routes - do not remove comment"
code="${Module}Screen.route: (context) {${lineBreak}"
code="${code}widget.store.dispatch(Load${Module}s());${lineBreak}"
code="${code}return ${Module}Screen();${lineBreak}"
code="${code}},${lineBreak}"
code="${Module}Screen.route: (context) => ${Module}Screen(),${lineBreak}"
code="${code}${Module}ViewScreen.route: (context) => ${Module}ViewScreen(),${lineBreak}"
code="${code}${Module}EditScreen.route: (context) => ${Module}EditScreen(),${lineBreak}"
sed -i -e "s/$comment/$comment${lineBreak}$code/g" ./lib/main.dart

View File

@ -4,7 +4,7 @@ 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/auth/auth_state.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';
@ -53,7 +53,7 @@ class StubRepository {
response = await webClient.post(
credentials.url + '/stubs',
credentials.token,
json.encode(data));
data: json.encode(data));
} else {
var url = credentials.url + '/stubs/' + stub.id.toString();
if (action != null) {

View File

@ -22,7 +22,7 @@ class ViewStub implements PersistUI {
this.force = false,
});
final int stubId;
final String stubId;
final BuildContext context;
final bool force;
}
@ -32,7 +32,7 @@ class EditStub implements PersistUI {
{@required this.stub,
@required this.context,
this.completer,
this.force = false);
this.force = false});
final StubEntity stub;
final BuildContext context;
@ -50,7 +50,7 @@ class LoadStub {
LoadStub({this.completer, this.stubId, this.loadActivities = false});
final Completer completer;
final int stubId;
final String stubId;
final bool loadActivities;
}
@ -58,7 +58,7 @@ class LoadStubActivity {
LoadStubActivity({this.completer, this.stubId});
final Completer completer;
final int stubId;
final String stubId;
}
class LoadStubs {
@ -146,7 +146,7 @@ class ArchiveStubRequest implements StartSaving {
ArchiveStubRequest(this.completer, this.stubId);
final Completer completer;
final int stubId;
final String stubId;
}
class ArchiveStubSuccess implements StopSaving, PersistData {
@ -165,7 +165,7 @@ class DeleteStubRequest implements StartSaving {
DeleteStubRequest(this.completer, this.stubId);
final Completer completer;
final int stubId;
final String stubId;
}
class DeleteStubSuccess implements StopSaving, PersistData {
@ -184,7 +184,7 @@ class RestoreStubRequest implements StartSaving {
RestoreStubRequest(this.completer, this.stubId);
final Completer completer;
final int stubId;
final String stubId;
}
class RestoreStubSuccess implements StopSaving, PersistData {

View File

@ -40,13 +40,15 @@ List<Middleware<AppState>> createStoreStubsMiddleware([
Middleware<AppState> _editStub() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
next(action);
final action = dynamicAction as EditStub;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(StubEditScreen.route));
@ -63,6 +65,15 @@ Middleware<AppState> _editStub() {
Middleware<AppState> _viewStub() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) async {
final action = dynamicAction as ViewStub;
if (hasChanges(
store: store, context: action.context, force: action.force)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(StubViewScreen.route));
@ -96,6 +107,7 @@ Middleware<AppState> _viewStubList() {
Middleware<AppState> _archiveStub(StubRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ArchiveStubRequest;
final origStub = store.state.stubState.map[action.stubId];
repository
.saveData(store.state.credentials,
@ -119,6 +131,7 @@ Middleware<AppState> _archiveStub(StubRepository repository) {
Middleware<AppState> _deleteStub(StubRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as DeleteStubRequest;
final origStub = store.state.stubState.map[action.stubId];
repository
.saveData(store.state.credentials,
@ -142,6 +155,7 @@ Middleware<AppState> _deleteStub(StubRepository repository) {
Middleware<AppState> _restoreStub(StubRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as RestoreStubRequest;
final origStub = store.state.stubState.map[action.stubId];
repository
.saveData(store.state.credentials,
@ -165,6 +179,7 @@ Middleware<AppState> _restoreStub(StubRepository repository) {
Middleware<AppState> _saveStub(StubRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as SaveStubRequest;
repository
.saveData(
store.state.credentials, action.stub)
@ -187,6 +202,7 @@ Middleware<AppState> _saveStub(StubRepository repository) {
Middleware<AppState> _loadStub(StubRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadStub;
final AppState state = store.state;
if (state.isLoading) {
@ -217,6 +233,7 @@ Middleware<AppState> _loadStub(StubRepository repository) {
Middleware<AppState> _loadStubs(StubRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadStubs;
final AppState state = store.state;
if (!state.stubState.isStale && !action.force) {

View File

@ -6,19 +6,19 @@ import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/redux/stub/stub_actions.dart';
import 'package:invoiceninja_flutter/redux/stub/stub_state.dart';
EntityUIState stubUIReducer(StubUIState state, dynamic dynamicAction) {
EntityUIState stubUIReducer(StubUIState state, dynamic action) {
return state.rebuild((b) => b
..listUIState.replace(stubListReducer(state.listUIState, action))
..editing.replace(editingReducer(state.editing, action))
..selectedId = selectedIdReducer(state.selectedId, action));
}
Reducer<int> selectedIdReducer = combineReducers([
TypedReducer<int, ViewStub>(
(int selectedId, dynamic dynamicAction) => action.stubId),
TypedReducer<int, AddStubSuccess>(
(int selectedId, dynamic dynamicAction) => action.stub.id),
TypedReducer<int, FilterStubsByEntity>((selectedId, action) => action.entityId == null ? selectedId : 0)
Reducer<String> selectedIdReducer = combineReducers([
TypedReducer<String, ViewStub>(
(String selectedId, dynamic action) => action.stubId),
TypedReducer<String, AddStubSuccess>(
(String selectedId, dynamic action) => action.stub.id),
TypedReducer<String, FilterStubsByEntity>((selectedId, action) => action.entityId == null ? selectedId : 0)
]);
final editingReducer = combineReducers<StubEntity>([
@ -34,11 +34,11 @@ final editingReducer = combineReducers<StubEntity>([
TypedReducer<StubEntity, SelectCompany>(_clearEditing),
]);
StubEntity _clearEditing(StubEntity stub, dynamic dynamicAction) {
StubEntity _clearEditing(StubEntity stub, dynamic action) {
return StubEntity();
}
StubEntity _updateEditing(StubEntity stub, dynamic dynamicAction) {
StubEntity _updateEditing(StubEntity stub, dynamic action) {
return action.stub;
}

View File

@ -44,7 +44,7 @@ abstract class StubUIState extends Object with EntityUIState implements Built<St
return _$StubUIState._(
listUIState: ListUIState(StubFields.name),
editing: StubEntity(),
selectedId: 0,
selectedId: '',
);
}
StubUIState._();