Custom filters

This commit is contained in:
Hillel Coren 2018-08-17 15:58:21 -07:00
parent 37dda74dfa
commit 5eddfadee2
6 changed files with 166 additions and 33 deletions

View File

@ -254,18 +254,22 @@ abstract class CompanyEntity
}
}
List<String> getCustomFieldValues(String field) {
List<String> getCustomFieldValues(String field, {bool excludeBlank = false}) {
final values = customFields[field];
if (values == null || !values.contains('|')) {
return [];
} else {
return values.split('|').last.split(',');
final data = values.split('|').last.split(',');
if (excludeBlank) {
return data.where((data) => data.isNotEmpty).toList();
} else {
return data;
}
}
}
//UserEntity get user => userMap[userId];
static Serializer<CompanyEntity> get serializer => _$companyEntitySerializer;
}

View File

@ -222,6 +222,12 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(EntityStatus)]),
() => new ListBuilder<EntityStatus>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(String)]),
() => new ListBuilder<String>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(String)]),
() => new ListBuilder<String>())
..addBuilderFactory(
const FullType(
BuiltList, const [const FullType(ExpenseCategoryEntity)]),
@ -320,9 +326,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
const FullType(BuiltMap,
const [const FullType(int), const FullType(DateFormatEntity)]),
() => new MapBuilder<int, DateFormatEntity>())
..addBuilderFactory(
const FullType(BuiltMap, const [const FullType(int), const FullType(DatetimeFormatEntity)]),
() => new MapBuilder<int, DatetimeFormatEntity>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(DatetimeFormatEntity)]), () => new MapBuilder<int, DatetimeFormatEntity>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(LanguageEntity)]), () => new MapBuilder<int, LanguageEntity>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(PaymentTypeEntity)]), () => new MapBuilder<int, PaymentTypeEntity>())
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(CountryEntity)]), () => new MapBuilder<int, CountryEntity>())

View File

@ -15,6 +15,8 @@ abstract class ListUIState implements Built<ListUIState, ListUIStateBuilder> {
EntityState.active,
]),
statusFilters: BuiltList<EntityStatus>(),
custom1Filters: BuiltList<String>(),
custom2Filters: BuiltList<String>(),
);
}
ListUIState._();
@ -29,6 +31,8 @@ abstract class ListUIState implements Built<ListUIState, ListUIStateBuilder> {
bool get sortAscending;
BuiltList<EntityState> get stateFilters;
BuiltList<EntityStatus> get statusFilters;
BuiltList<String> get custom1Filters;
BuiltList<String> get custom2Filters;
bool get hasCustomStateFilters => stateFilters.length != 1 || stateFilters.first != EntityState.active;
bool get hasCustomStatusFilters => statusFilters.isNotEmpty;

View File

@ -42,6 +42,14 @@ class _$ListUIStateSerializer implements StructuredSerializer<ListUIState> {
serializers.serialize(object.statusFilters,
specifiedType:
const FullType(BuiltList, const [const FullType(EntityStatus)])),
'custom1Filters',
serializers.serialize(object.custom1Filters,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
'custom2Filters',
serializers.serialize(object.custom2Filters,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
];
if (object.filter != null) {
result
@ -98,6 +106,18 @@ class _$ListUIStateSerializer implements StructuredSerializer<ListUIState> {
BuiltList, const [const FullType(EntityStatus)]))
as BuiltList);
break;
case 'custom1Filters':
result.custom1Filters.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList);
break;
case 'custom2Filters':
result.custom2Filters.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList);
break;
}
}
@ -118,6 +138,10 @@ class _$ListUIState extends ListUIState {
final BuiltList<EntityState> stateFilters;
@override
final BuiltList<EntityStatus> statusFilters;
@override
final BuiltList<String> custom1Filters;
@override
final BuiltList<String> custom2Filters;
factory _$ListUIState([void updates(ListUIStateBuilder b)]) =>
(new ListUIStateBuilder()..update(updates)).build();
@ -128,7 +152,9 @@ class _$ListUIState extends ListUIState {
this.sortField,
this.sortAscending,
this.stateFilters,
this.statusFilters})
this.statusFilters,
this.custom1Filters,
this.custom2Filters})
: super._() {
if (sortField == null)
throw new BuiltValueNullFieldError('ListUIState', 'sortField');
@ -138,6 +164,10 @@ class _$ListUIState extends ListUIState {
throw new BuiltValueNullFieldError('ListUIState', 'stateFilters');
if (statusFilters == null)
throw new BuiltValueNullFieldError('ListUIState', 'statusFilters');
if (custom1Filters == null)
throw new BuiltValueNullFieldError('ListUIState', 'custom1Filters');
if (custom2Filters == null)
throw new BuiltValueNullFieldError('ListUIState', 'custom2Filters');
}
@override
@ -156,7 +186,9 @@ class _$ListUIState extends ListUIState {
sortField == other.sortField &&
sortAscending == other.sortAscending &&
stateFilters == other.stateFilters &&
statusFilters == other.statusFilters;
statusFilters == other.statusFilters &&
custom1Filters == other.custom1Filters &&
custom2Filters == other.custom2Filters;
}
@override
@ -164,11 +196,17 @@ class _$ListUIState extends ListUIState {
return $jf($jc(
$jc(
$jc(
$jc($jc($jc(0, filter.hashCode), filterClientId.hashCode),
sortField.hashCode),
sortAscending.hashCode),
stateFilters.hashCode),
statusFilters.hashCode));
$jc(
$jc(
$jc(
$jc($jc(0, filter.hashCode),
filterClientId.hashCode),
sortField.hashCode),
sortAscending.hashCode),
stateFilters.hashCode),
statusFilters.hashCode),
custom1Filters.hashCode),
custom2Filters.hashCode));
}
@override
@ -179,7 +217,9 @@ class _$ListUIState extends ListUIState {
..add('sortField', sortField)
..add('sortAscending', sortAscending)
..add('stateFilters', stateFilters)
..add('statusFilters', statusFilters))
..add('statusFilters', statusFilters)
..add('custom1Filters', custom1Filters)
..add('custom2Filters', custom2Filters))
.toString();
}
}
@ -217,6 +257,18 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
set statusFilters(ListBuilder<EntityStatus> statusFilters) =>
_$this._statusFilters = statusFilters;
ListBuilder<String> _custom1Filters;
ListBuilder<String> get custom1Filters =>
_$this._custom1Filters ??= new ListBuilder<String>();
set custom1Filters(ListBuilder<String> custom1Filters) =>
_$this._custom1Filters = custom1Filters;
ListBuilder<String> _custom2Filters;
ListBuilder<String> get custom2Filters =>
_$this._custom2Filters ??= new ListBuilder<String>();
set custom2Filters(ListBuilder<String> custom2Filters) =>
_$this._custom2Filters = custom2Filters;
ListUIStateBuilder();
ListUIStateBuilder get _$this {
@ -227,6 +279,8 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
_sortAscending = _$v.sortAscending;
_stateFilters = _$v.stateFilters?.toBuilder();
_statusFilters = _$v.statusFilters?.toBuilder();
_custom1Filters = _$v.custom1Filters?.toBuilder();
_custom2Filters = _$v.custom2Filters?.toBuilder();
_$v = null;
}
return this;
@ -254,7 +308,9 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
sortField: sortField,
sortAscending: sortAscending,
stateFilters: stateFilters.build(),
statusFilters: statusFilters.build());
statusFilters: statusFilters.build(),
custom1Filters: custom1Filters.build(),
custom2Filters: custom2Filters.build());
} catch (_) {
String _$failedField;
try {
@ -262,6 +318,10 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
stateFilters.build();
_$failedField = 'statusFilters';
statusFilters.build();
_$failedField = 'custom1Filters';
custom1Filters.build();
_$failedField = 'custom2Filters';
custom2Filters.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'ListUIState', _$failedField, e.toString());

View File

@ -14,14 +14,18 @@ class AppBottomBar extends StatefulWidget {
final Function(String) onSelectedSortField;
final Function(EntityState, bool) onSelectedState;
final Function(EntityStatus, bool) onSelectedStatus;
final List<String> customValues1;
final List<String> customValues2;
const AppBottomBar({
this.sortFields,
this.onSelectedSortField,
this.entityType,
this.onSelectedState,
this.statuses,
this.onSelectedStatus,
this.statuses = const [],
this.customValues1 = const [],
this.customValues2 = const [],
});
@override
@ -32,9 +36,12 @@ class _AppBottomBarState extends State<AppBottomBar> {
PersistentBottomSheetController _sortController;
PersistentBottomSheetController _filterStateController;
PersistentBottomSheetController _filterStatusController;
PersistentBottomSheetController _filterCustom1Controller;
PersistentBottomSheetController _filterCustom2Controller;
@override
Widget build(BuildContext context) {
final _showFilterStateSheet = () {
if (_filterStateController != null) {
_filterStateController.close();
@ -44,7 +51,6 @@ class _AppBottomBarState extends State<AppBottomBar> {
_filterStateController =
Scaffold.of(context).showBottomSheet<StoreConnector>((context) {
return StoreConnector<AppState, BuiltList<EntityState>>(
//distinct: true,
converter: (Store<AppState> store) =>
store.state.getListState(widget.entityType).stateFilters,
builder: (BuildContext context, stateFilters) {
@ -165,6 +171,47 @@ class _AppBottomBarState extends State<AppBottomBar> {
});
};
final _showFilterCustom1Sheet = () {
if (_filterCustom1Controller != null) {
_filterCustom1Controller.close();
return;
}
_filterCustom1Controller =
Scaffold.of(context).showBottomSheet<StoreConnector>((context) {
return StoreConnector<AppState, BuiltList<String>>(
converter: (Store<AppState> store) =>
store.state.getListState(widget.entityType).custom1Filters,
builder: (BuildContext context, customFilters) {
return Container(
color: Theme.of(context).backgroundColor,
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Column(
children: widget.customValues1.map<Widget>((customField) {
return CheckboxListTile(
key: Key(customField.toString()),
title: Text(customField),
controlAffinity: ListTileControlAffinity.leading,
value: customFilters.contains(customField),
activeColor: Theme.of(context).accentColor,
dense: true,
onChanged: (value) {
//widget.onSelectedState(customField, value);
},
);
}).toList(),
),
]),
);
},
);
});
_filterCustom1Controller.closed.whenComplete(() {
_filterCustom1Controller = null;
});
};
return StoreBuilder(builder: (BuildContext context, Store<AppState> store) {
return BottomAppBar(
shape: CircularNotchedRectangle(),
@ -185,19 +232,28 @@ class _AppBottomBarState extends State<AppBottomBar> {
? Theme.of(context).accentColor
: null,
),
Opacity(
opacity: widget.statuses == null ? 0.0 : 1.0,
child: IconButton(
tooltip: AppLocalization.of(context).filter,
icon: Icon(Icons.filter),
onPressed: _showFilterStatusSheet,
color: store.state
.getListState(widget.entityType)
.hasCustomStatusFilters
? Theme.of(context).accentColor
: null,
),
),
widget.statuses.isNotEmpty ? IconButton(
tooltip: AppLocalization.of(context).filter,
icon: Icon(Icons.filter),
onPressed: _showFilterStatusSheet,
color: store.state
.getListState(widget.entityType)
.hasCustomStatusFilters
? Theme.of(context).accentColor
: null,
) : SizedBox(width: 0.0),
widget.customValues1.isNotEmpty ? IconButton(
tooltip: AppLocalization.of(context).filter,
icon: Icon(Icons.looks_one),
onPressed: _showFilterCustom1Sheet,
/*
color: store.state
.getListState(widget.entityType)
.hasCustomStatusFilters
? Theme.of(context).accentColor
: null,
*/
) : SizedBox(width: 0.0)
],
),
);

View File

@ -17,7 +17,8 @@ class ProductScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final user = store.state.user;
final company = store.state.selectedCompany;
final user = company.user;
final localization = AppLocalization.of(context);
return Scaffold(
@ -41,6 +42,10 @@ class ProductScreen extends StatelessWidget {
body: ProductListBuilder(),
bottomNavigationBar: AppBottomBar(
entityType: EntityType.product,
customValues1: company.getCustomFieldValues(CustomFieldType.product1,
excludeBlank: true),
customValues2: company.getCustomFieldValues(CustomFieldType.product2,
excludeBlank: true),
onSelectedSortField: (value) {
store.dispatch(SortProducts(value));
},