diff --git a/lib/data/models/company_model.dart b/lib/data/models/company_model.dart index a58137b9d..21bd4099b 100644 --- a/lib/data/models/company_model.dart +++ b/lib/data/models/company_model.dart @@ -254,18 +254,22 @@ abstract class CompanyEntity } } - List getCustomFieldValues(String field) { + List 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 get serializer => _$companyEntitySerializer; } diff --git a/lib/data/models/serializers.g.dart b/lib/data/models/serializers.g.dart index 1218fd67f..fe8979fdd 100644 --- a/lib/data/models/serializers.g.dart +++ b/lib/data/models/serializers.g.dart @@ -222,6 +222,12 @@ Serializers _$serializers = (new Serializers().toBuilder() ..addBuilderFactory( const FullType(BuiltList, const [const FullType(EntityStatus)]), () => new ListBuilder()) + ..addBuilderFactory( + const FullType(BuiltList, const [const FullType(String)]), + () => new ListBuilder()) + ..addBuilderFactory( + const FullType(BuiltList, const [const FullType(String)]), + () => new ListBuilder()) ..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()) - ..addBuilderFactory( - const FullType(BuiltMap, const [const FullType(int), const FullType(DatetimeFormatEntity)]), - () => new MapBuilder()) + ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(DatetimeFormatEntity)]), () => new MapBuilder()) ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(LanguageEntity)]), () => new MapBuilder()) ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(PaymentTypeEntity)]), () => new MapBuilder()) ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(CountryEntity)]), () => new MapBuilder()) diff --git a/lib/redux/ui/list_ui_state.dart b/lib/redux/ui/list_ui_state.dart index 5acdcbb26..3ae9fdcb2 100644 --- a/lib/redux/ui/list_ui_state.dart +++ b/lib/redux/ui/list_ui_state.dart @@ -15,6 +15,8 @@ abstract class ListUIState implements Built { EntityState.active, ]), statusFilters: BuiltList(), + custom1Filters: BuiltList(), + custom2Filters: BuiltList(), ); } ListUIState._(); @@ -29,6 +31,8 @@ abstract class ListUIState implements Built { bool get sortAscending; BuiltList get stateFilters; BuiltList get statusFilters; + BuiltList get custom1Filters; + BuiltList get custom2Filters; bool get hasCustomStateFilters => stateFilters.length != 1 || stateFilters.first != EntityState.active; bool get hasCustomStatusFilters => statusFilters.isNotEmpty; diff --git a/lib/redux/ui/list_ui_state.g.dart b/lib/redux/ui/list_ui_state.g.dart index 95ef73a12..5acf43654 100644 --- a/lib/redux/ui/list_ui_state.g.dart +++ b/lib/redux/ui/list_ui_state.g.dart @@ -42,6 +42,14 @@ class _$ListUIStateSerializer implements StructuredSerializer { 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 { 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 stateFilters; @override final BuiltList statusFilters; + @override + final BuiltList custom1Filters; + @override + final BuiltList 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 { set statusFilters(ListBuilder statusFilters) => _$this._statusFilters = statusFilters; + ListBuilder _custom1Filters; + ListBuilder get custom1Filters => + _$this._custom1Filters ??= new ListBuilder(); + set custom1Filters(ListBuilder custom1Filters) => + _$this._custom1Filters = custom1Filters; + + ListBuilder _custom2Filters; + ListBuilder get custom2Filters => + _$this._custom2Filters ??= new ListBuilder(); + set custom2Filters(ListBuilder custom2Filters) => + _$this._custom2Filters = custom2Filters; + ListUIStateBuilder(); ListUIStateBuilder get _$this { @@ -227,6 +279,8 @@ class ListUIStateBuilder implements Builder { _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 { 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 { stateFilters.build(); _$failedField = 'statusFilters'; statusFilters.build(); + _$failedField = 'custom1Filters'; + custom1Filters.build(); + _$failedField = 'custom2Filters'; + custom2Filters.build(); } catch (e) { throw new BuiltValueNestedFieldError( 'ListUIState', _$failedField, e.toString()); diff --git a/lib/ui/app/app_bottom_bar.dart b/lib/ui/app/app_bottom_bar.dart index 5da55d976..213aff9de 100644 --- a/lib/ui/app/app_bottom_bar.dart +++ b/lib/ui/app/app_bottom_bar.dart @@ -14,14 +14,18 @@ class AppBottomBar extends StatefulWidget { final Function(String) onSelectedSortField; final Function(EntityState, bool) onSelectedState; final Function(EntityStatus, bool) onSelectedStatus; + final List customValues1; + final List 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 { 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 { _filterStateController = Scaffold.of(context).showBottomSheet((context) { return StoreConnector>( - //distinct: true, converter: (Store store) => store.state.getListState(widget.entityType).stateFilters, builder: (BuildContext context, stateFilters) { @@ -165,6 +171,47 @@ class _AppBottomBarState extends State { }); }; + final _showFilterCustom1Sheet = () { + if (_filterCustom1Controller != null) { + _filterCustom1Controller.close(); + return; + } + + _filterCustom1Controller = + Scaffold.of(context).showBottomSheet((context) { + return StoreConnector>( + converter: (Store store) => + store.state.getListState(widget.entityType).custom1Filters, + builder: (BuildContext context, customFilters) { + return Container( + color: Theme.of(context).backgroundColor, + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Column( + children: widget.customValues1.map((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 store) { return BottomAppBar( shape: CircularNotchedRectangle(), @@ -185,19 +232,28 @@ class _AppBottomBarState extends State { ? 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) ], ), ); diff --git a/lib/ui/product/product_screen.dart b/lib/ui/product/product_screen.dart index d7b3c0ae9..07be84727 100644 --- a/lib/ui/product/product_screen.dart +++ b/lib/ui/product/product_screen.dart @@ -17,7 +17,8 @@ class ProductScreen extends StatelessWidget { @override Widget build(BuildContext context) { final store = StoreProvider.of(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)); },