This commit is contained in:
Hillel Coren 2019-12-15 21:11:24 +02:00
parent 517f5d9c0b
commit 51e2995850
7 changed files with 273 additions and 42 deletions

View File

@ -242,6 +242,12 @@ Serializers _$serializers = (new Serializers().toBuilder()
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(String)]),
() => new ListBuilder<String>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(String)]),
() => new ListBuilder<String>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(String)]),
() => new ListBuilder<String>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(ExpenseEntity)]),
() => new ListBuilder<ExpenseEntity>())
@ -276,10 +282,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
BuiltList, const [const FullType(ExpenseCategoryEntity)]),
() => new ListBuilder<ExpenseCategoryEntity>())
..addBuilderFactory(
const FullType(BuiltMap, const [
const FullType(String),
const FullType(ExpenseCategoryEntity)
]),
const FullType(BuiltMap,
const [const FullType(String), const FullType(ExpenseCategoryEntity)]),
() => new MapBuilder<String, ExpenseCategoryEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(UserEntity)]),
@ -327,8 +331,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
const FullType(BuiltList, const [const FullType(ProjectEntity)]),
() => new ListBuilder<ProjectEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(SizeEntity)]),
() => new ListBuilder<SizeEntity>())
const FullType(BuiltList, const [const FullType(SizeEntity)]), () => new ListBuilder<SizeEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TaskEntity)]), () => new ListBuilder<TaskEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TaxRateEntity)]), () => new ListBuilder<TaxRateEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(TimezoneEntity)]), () => new ListBuilder<TimezoneEntity>())

View File

@ -268,6 +268,18 @@ class FilterClientsByCustom2 implements PersistUI {
final String value;
}
class FilterClientsByCustom3 implements PersistUI {
FilterClientsByCustom3(this.value);
final String value;
}
class FilterClientsByCustom4 implements PersistUI {
FilterClientsByCustom4(this.value);
final String value;
}
void handleClientAction(
BuildContext context, List<BaseEntity> clients, EntityAction action) {
assert(

View File

@ -106,6 +106,8 @@ final clientListReducer = combineReducers<ListUIState>([
TypedReducer<ListUIState, FilterClientsByEntity>(_filterClientsByEntity),
TypedReducer<ListUIState, FilterClientsByCustom1>(_filterClientsByCustom1),
TypedReducer<ListUIState, FilterClientsByCustom2>(_filterClientsByCustom2),
TypedReducer<ListUIState, FilterClientsByCustom3>(_filterClientsByCustom3),
TypedReducer<ListUIState, FilterClientsByCustom4>(_filterClientsByCustom4),
TypedReducer<ListUIState, StartClientMultiselect>(_startListMultiselect),
TypedReducer<ListUIState, AddToClientMultiselect>(_addToListMultiselect),
TypedReducer<ListUIState, RemoveFromClientMultiselect>(
@ -133,6 +135,26 @@ ListUIState _filterClientsByCustom2(
}
}
ListUIState _filterClientsByCustom3(
ListUIState clientListState, FilterClientsByCustom3 action) {
if (clientListState.custom3Filters.contains(action.value)) {
return clientListState
.rebuild((b) => b..custom3Filters.remove(action.value));
} else {
return clientListState.rebuild((b) => b..custom3Filters.add(action.value));
}
}
ListUIState _filterClientsByCustom4(
ListUIState clientListState, FilterClientsByCustom4 action) {
if (clientListState.custom4Filters.contains(action.value)) {
return clientListState
.rebuild((b) => b..custom4Filters.remove(action.value));
} else {
return clientListState.rebuild((b) => b..custom4Filters.add(action.value));
}
}
ListUIState _filterClientsByState(
ListUIState clientListState, FilterClientsByState action) {
if (clientListState.stateFilters.contains(action.state)) {

View File

@ -17,6 +17,8 @@ abstract class ListUIState implements Built<ListUIState, ListUIStateBuilder> {
statusFilters: BuiltList<EntityStatus>(),
custom1Filters: BuiltList<String>(),
custom2Filters: BuiltList<String>(),
custom3Filters: BuiltList<String>(),
custom4Filters: BuiltList<String>(),
filter: null);
}
@ -49,6 +51,10 @@ abstract class ListUIState implements Built<ListUIState, ListUIStateBuilder> {
BuiltList<String> get custom2Filters;
BuiltList<String> get custom3Filters;
BuiltList<String> get custom4Filters;
bool get hasStateFilters =>
stateFilters.length != 1 || stateFilters.first != EntityState.active;
@ -58,6 +64,10 @@ abstract class ListUIState implements Built<ListUIState, ListUIStateBuilder> {
bool get hasCustom2Filters => custom2Filters.isNotEmpty;
bool get hasCustom3Filters => custom3Filters.isNotEmpty;
bool get hasCustom4Filters => custom4Filters.isNotEmpty;
@nullable
BuiltList<String> get selectedIds;

View File

@ -43,6 +43,14 @@ class _$ListUIStateSerializer implements StructuredSerializer<ListUIState> {
serializers.serialize(object.custom2Filters,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
'custom3Filters',
serializers.serialize(object.custom3Filters,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
'custom4Filters',
serializers.serialize(object.custom4Filters,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
];
if (object.filter != null) {
result
@ -131,6 +139,18 @@ class _$ListUIStateSerializer implements StructuredSerializer<ListUIState> {
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList<dynamic>);
break;
case 'custom3Filters':
result.custom3Filters.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList<dynamic>);
break;
case 'custom4Filters':
result.custom4Filters.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList<dynamic>);
break;
case 'selectedIds':
result.selectedIds.replace(serializers.deserialize(value,
specifiedType:
@ -166,6 +186,10 @@ class _$ListUIState extends ListUIState {
@override
final BuiltList<String> custom2Filters;
@override
final BuiltList<String> custom3Filters;
@override
final BuiltList<String> custom4Filters;
@override
final BuiltList<String> selectedIds;
factory _$ListUIState([void Function(ListUIStateBuilder) updates]) =>
@ -182,6 +206,8 @@ class _$ListUIState extends ListUIState {
this.statusFilters,
this.custom1Filters,
this.custom2Filters,
this.custom3Filters,
this.custom4Filters,
this.selectedIds})
: super._() {
if (filterClearedAt == null) {
@ -205,6 +231,12 @@ class _$ListUIState extends ListUIState {
if (custom2Filters == null) {
throw new BuiltValueNullFieldError('ListUIState', 'custom2Filters');
}
if (custom3Filters == null) {
throw new BuiltValueNullFieldError('ListUIState', 'custom3Filters');
}
if (custom4Filters == null) {
throw new BuiltValueNullFieldError('ListUIState', 'custom4Filters');
}
}
@override
@ -228,6 +260,8 @@ class _$ListUIState extends ListUIState {
statusFilters == other.statusFilters &&
custom1Filters == other.custom1Filters &&
custom2Filters == other.custom2Filters &&
custom3Filters == other.custom3Filters &&
custom4Filters == other.custom4Filters &&
selectedIds == other.selectedIds;
}
@ -242,16 +276,20 @@ class _$ListUIState extends ListUIState {
$jc(
$jc(
$jc(
$jc($jc(0, filter.hashCode),
filterClearedAt.hashCode),
filterEntityId.hashCode),
filterEntityType.hashCode),
sortField.hashCode),
sortAscending.hashCode),
stateFilters.hashCode),
statusFilters.hashCode),
custom1Filters.hashCode),
custom2Filters.hashCode),
$jc(
$jc(
$jc($jc(0, filter.hashCode),
filterClearedAt.hashCode),
filterEntityId.hashCode),
filterEntityType.hashCode),
sortField.hashCode),
sortAscending.hashCode),
stateFilters.hashCode),
statusFilters.hashCode),
custom1Filters.hashCode),
custom2Filters.hashCode),
custom3Filters.hashCode),
custom4Filters.hashCode),
selectedIds.hashCode));
}
@ -268,6 +306,8 @@ class _$ListUIState extends ListUIState {
..add('statusFilters', statusFilters)
..add('custom1Filters', custom1Filters)
..add('custom2Filters', custom2Filters)
..add('custom3Filters', custom3Filters)
..add('custom4Filters', custom4Filters)
..add('selectedIds', selectedIds))
.toString();
}
@ -328,6 +368,18 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
set custom2Filters(ListBuilder<String> custom2Filters) =>
_$this._custom2Filters = custom2Filters;
ListBuilder<String> _custom3Filters;
ListBuilder<String> get custom3Filters =>
_$this._custom3Filters ??= new ListBuilder<String>();
set custom3Filters(ListBuilder<String> custom3Filters) =>
_$this._custom3Filters = custom3Filters;
ListBuilder<String> _custom4Filters;
ListBuilder<String> get custom4Filters =>
_$this._custom4Filters ??= new ListBuilder<String>();
set custom4Filters(ListBuilder<String> custom4Filters) =>
_$this._custom4Filters = custom4Filters;
ListBuilder<String> _selectedIds;
ListBuilder<String> get selectedIds =>
_$this._selectedIds ??= new ListBuilder<String>();
@ -348,6 +400,8 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
_statusFilters = _$v.statusFilters?.toBuilder();
_custom1Filters = _$v.custom1Filters?.toBuilder();
_custom2Filters = _$v.custom2Filters?.toBuilder();
_custom3Filters = _$v.custom3Filters?.toBuilder();
_custom4Filters = _$v.custom4Filters?.toBuilder();
_selectedIds = _$v.selectedIds?.toBuilder();
_$v = null;
}
@ -383,6 +437,8 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
statusFilters: statusFilters.build(),
custom1Filters: custom1Filters.build(),
custom2Filters: custom2Filters.build(),
custom3Filters: custom3Filters.build(),
custom4Filters: custom4Filters.build(),
selectedIds: _selectedIds?.build());
} catch (_) {
String _$failedField;
@ -395,6 +451,10 @@ class ListUIStateBuilder implements Builder<ListUIState, ListUIStateBuilder> {
custom1Filters.build();
_$failedField = 'custom2Filters';
custom2Filters.build();
_$failedField = 'custom3Filters';
custom3Filters.build();
_$failedField = 'custom4Filters';
custom4Filters.build();
_$failedField = 'selectedIds';
_selectedIds?.build();
} catch (e) {

View File

@ -16,11 +16,15 @@ class AppBottomBar extends StatefulWidget {
this.entityType,
this.onSelectedState,
this.onSelectedStatus,
this.onSelectedCustom1,
this.onSelectedCustom2,
@required this.onSelectedCustom1,
@required this.onSelectedCustom2,
@required this.onSelectedCustom3,
@required this.onSelectedCustom4,
this.statuses = const [],
this.customValues1 = const [],
this.customValues2 = const [],
@required this.customValues1 = const [],
@required this.customValues2 = const [],
@required this.customValues3 = const [],
@required this.customValues4 = const [],
});
final EntityType entityType;
@ -31,8 +35,12 @@ class AppBottomBar extends StatefulWidget {
final Function(EntityStatus, bool) onSelectedStatus;
final Function(String) onSelectedCustom1;
final Function(String) onSelectedCustom2;
final Function(String) onSelectedCustom3;
final Function(String) onSelectedCustom4;
final List<String> customValues1;
final List<String> customValues2;
final List<String> customValues3;
final List<String> customValues4;
@override
_AppBottomBarState createState() => _AppBottomBarState();
@ -44,6 +52,8 @@ class _AppBottomBarState extends State<AppBottomBar> {
PersistentBottomSheetController _filterStatusController;
PersistentBottomSheetController _filterCustom1Controller;
PersistentBottomSheetController _filterCustom2Controller;
PersistentBottomSheetController _filterCustom3Controller;
PersistentBottomSheetController _filterCustom4Controller;
@override
Widget build(BuildContext context) {
@ -260,6 +270,88 @@ class _AppBottomBarState extends State<AppBottomBar> {
});
};
final _showFilterCustom3Sheet = () {
if (_filterCustom3Controller != null) {
_filterCustom3Controller.close();
return;
}
_filterCustom3Controller =
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.customValues3.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.onSelectedCustom3(customField);
},
);
}).toList(),
),
]),
);
},
);
});
_filterCustom3Controller.closed.whenComplete(() {
_filterCustom3Controller = null;
});
};
final _showFilterCustom4Sheet = () {
if (_filterCustom4Controller != null) {
_filterCustom4Controller.close();
return;
}
_filterCustom4Controller =
Scaffold.of(context).showBottomSheet<StoreConnector>((context) {
return StoreConnector<AppState, BuiltList<String>>(
converter: (Store<AppState> store) =>
store.state.getListState(widget.entityType).custom4Filters,
builder: (BuildContext context, customFilters) {
return Container(
color: Theme.of(context).backgroundColor,
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Column(
children: widget.customValues4.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.onSelectedCustom4(customField);
},
);
}).toList(),
),
]),
);
},
);
});
_filterCustom4Controller.closed.whenComplete(() {
_filterCustom4Controller = null;
});
};
return StoreBuilder(builder: (BuildContext context, Store<AppState> store) {
final localization = AppLocalization.of(context);
final prefState = store.state.prefState;
@ -318,8 +410,30 @@ class _AppBottomBarState extends State<AppBottomBar> {
icon: Icon(Icons.looks_two),
onPressed: _showFilterCustom2Sheet,
color: store.state
.getListState(widget.entityType)
.hasCustom2Filters
.getListState(widget.entityType)
.hasCustom2Filters
? Theme.of(context).accentColor
: null,
),
if (widget.customValues3.isNotEmpty)
IconButton(
tooltip: AppLocalization.of(context).filter,
icon: Icon(Icons.looks_two),
onPressed: _showFilterCustom3Sheet,
color: store.state
.getListState(widget.entityType)
.hasCustom3Filters
? Theme.of(context).accentColor
: null,
),
if (widget.customValues4.isNotEmpty)
IconButton(
tooltip: AppLocalization.of(context).filter,
icon: Icon(Icons.looks_two),
onPressed: _showFilterCustom4Sheet,
color: store.state
.getListState(widget.entityType)
.hasCustom4Filters
? Theme.of(context).accentColor
: null,
),

View File

@ -70,16 +70,16 @@ class ClientScreen extends StatelessWidget {
onSavePressed: state.clientListState.selectedIds.isEmpty
? null
: (context) async {
final clients = viewModel.clientList
.map<ClientEntity>(
(clientId) => viewModel.clientMap[clientId])
.toList();
final clients = viewModel.clientList
.map<ClientEntity>(
(clientId) => viewModel.clientMap[clientId])
.toList();
await showEntityActionsDialog(
entities: clients, context: context, multiselect: true);
await showEntityActionsDialog(
entities: clients, context: context, multiselect: true);
store.dispatch(ClearClientMultiselect());
},
store.dispatch(ClearClientMultiselect());
},
onCancelPressed: (context) =>
store.dispatch(ClearClientMultiselect()),
),
@ -102,25 +102,35 @@ class ClientScreen extends StatelessWidget {
excludeBlank: true),
customValues2: company.getCustomFieldValues(CustomFieldType.client2,
excludeBlank: true),
customValues3: company.getCustomFieldValues(CustomFieldType.client3,
excludeBlank: true),
customValues4: company.getCustomFieldValues(CustomFieldType.client4,
excludeBlank: true),
onSelectedCustom1: (value) =>
store.dispatch(FilterClientsByCustom1(value)),
onSelectedCustom2: (value) =>
store.dispatch(FilterClientsByCustom2(value)),
onSelectedCustom3: (value) =>
store.dispatch(FilterClientsByCustom3(value)),
onSelectedCustom4: (value) =>
store.dispatch(FilterClientsByCustom4(value)),
),
floatingActionButton: userCompany.canCreate(EntityType.client)
? FloatingActionButton(
heroTag: 'client_fab',
backgroundColor: Theme.of(context).primaryColorDark,
onPressed: () {
createEntityByType(
context: context, entityType: EntityType.client);
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newClient,
)
heroTag: 'client_fab',
backgroundColor: Theme
.of(context)
.primaryColorDark,
onPressed: () {
createEntityByType(
context: context, entityType: EntityType.client);
},
child: Icon(
Icons.add,
color: Colors.white,
),
tooltip: localization.newClient,
)
: null,
);
}