mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
test: filter integration (#2821)
* test: add checklist filter test * fix: widget reference to invalid databaseController * fix: SelectOptionFilterList doesn't expand to fill the CustomScrollView * test: add single select and multi-select filter test * ci: set protoc version
This commit is contained in:
parent
63eee8b415
commit
14dee6b797
@ -1,3 +1,5 @@
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/text.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
@ -45,14 +47,14 @@ void main() {
|
||||
await tester.assertNumberOfRowsInGridPage(1);
|
||||
|
||||
// open the menu to delete the filter
|
||||
await tester.tapTextFilterDisclosureButtonInGrid();
|
||||
await tester.tapDeleteTextFilterButtonInGrid();
|
||||
await tester.tapDisclosureButtonInFinder(find.byType(TextFilterEditor));
|
||||
await tester.tapDeleteFilterButtonInGrid();
|
||||
await tester.assertNumberOfRowsInGridPage(10);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('add checklist filter', (tester) async {
|
||||
testWidgets('add checkbox filter', (tester) async {
|
||||
await tester.openV020database();
|
||||
|
||||
// create a filter
|
||||
@ -66,6 +68,90 @@ void main() {
|
||||
await tester.tapUnCheckedButtonOnCheckboxFilter();
|
||||
await tester.assertNumberOfRowsInGridPage(5);
|
||||
|
||||
await tester
|
||||
.tapDisclosureButtonInFinder(find.byType(CheckboxFilterEditor));
|
||||
await tester.tapDeleteFilterButtonInGrid();
|
||||
await tester.assertNumberOfRowsInGridPage(10);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('add checklist filter', (tester) async {
|
||||
await tester.openV020database();
|
||||
|
||||
// create a filter
|
||||
await tester.tapDatabaseFilterButton();
|
||||
await tester.tapCreateFilterByFieldType(FieldType.Checklist, 'checklist');
|
||||
|
||||
// By default, the condition of checklist filter is 'uncompleted'
|
||||
await tester.assertNumberOfRowsInGridPage(9);
|
||||
|
||||
await tester.tapFilterButtonInGrid('checklist');
|
||||
await tester.tapChecklistFilterButtonInGrid();
|
||||
|
||||
await tester.tapCompletedButtonOnChecklistFilter();
|
||||
await tester.assertNumberOfRowsInGridPage(1);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('add single select filter', (tester) async {
|
||||
await tester.openV020database();
|
||||
|
||||
// create a filter
|
||||
await tester.tapDatabaseFilterButton();
|
||||
await tester.tapCreateFilterByFieldType(FieldType.SingleSelect, 'Type');
|
||||
|
||||
await tester.tapFilterButtonInGrid('Type');
|
||||
|
||||
// select the option 's6'
|
||||
await tester.tapOptionFilterWithName('s6');
|
||||
await tester.assertNumberOfRowsInGridPage(0);
|
||||
|
||||
// unselect the option 's6'
|
||||
await tester.tapOptionFilterWithName('s6');
|
||||
await tester.assertNumberOfRowsInGridPage(10);
|
||||
|
||||
// select the option 's5'
|
||||
await tester.tapOptionFilterWithName('s5');
|
||||
await tester.assertNumberOfRowsInGridPage(1);
|
||||
|
||||
// select the option 's4'
|
||||
await tester.tapOptionFilterWithName('s4');
|
||||
|
||||
// The row with 's4' or 's5' should be shown.
|
||||
await tester.assertNumberOfRowsInGridPage(2);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('add multi select filter', (tester) async {
|
||||
await tester.openV020database();
|
||||
|
||||
// create a filter
|
||||
await tester.tapDatabaseFilterButton();
|
||||
await tester.tapCreateFilterByFieldType(
|
||||
FieldType.MultiSelect,
|
||||
'multi-select',
|
||||
);
|
||||
|
||||
await tester.tapFilterButtonInGrid('multi-select');
|
||||
await tester.scrollOptionFilterListByOffset(const Offset(0, -200));
|
||||
|
||||
// select the option 'm1'. Any option with 'm1' should be shown.
|
||||
await tester.tapOptionFilterWithName('m1');
|
||||
await tester.assertNumberOfRowsInGridPage(5);
|
||||
await tester.tapOptionFilterWithName('m1');
|
||||
|
||||
// select the option 'm2'. Any option with 'm2' should be shown.
|
||||
await tester.tapOptionFilterWithName('m2');
|
||||
await tester.assertNumberOfRowsInGridPage(4);
|
||||
await tester.tapOptionFilterWithName('m2');
|
||||
|
||||
// select the option 'm4'. Any option with 'm4' should be shown.
|
||||
await tester.tapOptionFilterWithName('m4');
|
||||
await tester.assertNumberOfRowsInGridPage(1);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
});
|
||||
|
@ -85,7 +85,10 @@ extension AppFlowyTestBase on WidgetTester {
|
||||
bool warnIfMissed = true,
|
||||
int milliseconds = 500,
|
||||
}) async {
|
||||
await tap(finder);
|
||||
await tap(
|
||||
finder,
|
||||
warnIfMissed: warnIfMissed,
|
||||
);
|
||||
await pumpAndSettle(Duration(milliseconds: milliseconds));
|
||||
return;
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import 'package:appflowy/plugins/database_view/application/setting/setting_bloc.
|
||||
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/option_list.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/text.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/create_filter_list.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/disclosure_button.dart';
|
||||
@ -555,6 +558,11 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
Future<void> scrollOptionFilterListByOffset(Offset offset) async {
|
||||
await drag(find.byType(SelectOptionFilterEditor), offset);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> enterTextInTextFilter(String text) async {
|
||||
final findEditor = find.byType(TextFilterEditor);
|
||||
final findTextField = find.descendant(
|
||||
@ -566,18 +574,17 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await pumpAndSettle(const Duration(milliseconds: 300));
|
||||
}
|
||||
|
||||
Future<void> tapTextFilterDisclosureButtonInGrid() async {
|
||||
final findEditor = find.byType(TextFilterEditor);
|
||||
Future<void> tapDisclosureButtonInFinder(Finder finder) async {
|
||||
final findDisclosure = find.descendant(
|
||||
of: findEditor,
|
||||
of: finder,
|
||||
matching: find.byType(DisclosureButton),
|
||||
);
|
||||
|
||||
await tapButton(findDisclosure);
|
||||
}
|
||||
|
||||
/// must call [tapTextFilterDisclosureButtonInGrid] first.
|
||||
Future<void> tapDeleteTextFilterButtonInGrid() async {
|
||||
/// must call [tapDisclosureButtonInFinder] first.
|
||||
Future<void> tapDeleteFilterButtonInGrid() async {
|
||||
await tapButton(find.text(LocaleKeys.grid_settings_deleteFilter.tr()));
|
||||
}
|
||||
|
||||
@ -585,6 +592,25 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapButton(find.byType(CheckboxFilterConditionList));
|
||||
}
|
||||
|
||||
Future<void> tapChecklistFilterButtonInGrid() async {
|
||||
await tapButton(find.byType(ChecklistFilterConditionList));
|
||||
}
|
||||
|
||||
/// The [SelectOptionFilterList] must show up first.
|
||||
Future<void> tapOptionFilterWithName(String name) async {
|
||||
final findCell = find.descendant(
|
||||
of: find.byType(SelectOptionFilterList),
|
||||
matching: find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is SelectOptionFilterCell && widget.option.name == name,
|
||||
skipOffstage: false,
|
||||
),
|
||||
skipOffstage: false,
|
||||
);
|
||||
expect(findCell, findsOneWidget);
|
||||
await tapButton(findCell, warnIfMissed: false);
|
||||
}
|
||||
|
||||
Future<void> tapCheckedButtonOnCheckboxFilter() async {
|
||||
final button = find.descendant(
|
||||
of: find.byType(HoverButton),
|
||||
@ -603,6 +629,24 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
Future<void> tapCompletedButtonOnChecklistFilter() async {
|
||||
final button = find.descendant(
|
||||
of: find.byType(HoverButton),
|
||||
matching: find.text(LocaleKeys.grid_checklistFilter_isComplete.tr()),
|
||||
);
|
||||
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
Future<void> tapUnCompletedButtonOnChecklistFilter() async {
|
||||
final button = find.descendant(
|
||||
of: find.byType(HoverButton),
|
||||
matching: find.text(LocaleKeys.grid_checklistFilter_isIncomplted.tr()),
|
||||
);
|
||||
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
/// Should call [tapDatabaseSettingButton] first.
|
||||
Future<void> tapDatabaseLayoutButton() async {
|
||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
||||
|
@ -3,6 +3,7 @@ import 'package:appflowy/plugins/database_view/application/layout/calendar_setti
|
||||
import 'package:appflowy/plugins/database_view/application/view/view_cache.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/group_changeset.pb.dart';
|
||||
@ -129,29 +130,33 @@ class DatabaseController {
|
||||
Future<Either<Unit, FlowyError>> open() async {
|
||||
return _databaseViewBackendSvc.openGrid().then((result) {
|
||||
return result.fold(
|
||||
(database) async {
|
||||
(DatabasePB database) async {
|
||||
databaseLayout = database.layoutType;
|
||||
|
||||
// Listen on layout changed if database layout is calendar
|
||||
if (databaseLayout == DatabaseLayoutPB.Calendar) {
|
||||
_listenOnCalendarLayoutChanged();
|
||||
}
|
||||
|
||||
// Load the actual database field data.
|
||||
final fieldsOrFail = await fieldController.loadFields(
|
||||
fieldIds: database.fields,
|
||||
);
|
||||
return fieldsOrFail.fold(
|
||||
(fields) {
|
||||
// Notify the database is changed after the fields are loaded.
|
||||
// The database won't can't be used until the fields are loaded.
|
||||
_databaseCallbacks?.onDatabaseChanged?.call(database);
|
||||
_viewCache.rowCache.setInitialRows(database.rows);
|
||||
return await fieldController
|
||||
.loadFields(
|
||||
fieldIds: database.fields,
|
||||
)
|
||||
.then(
|
||||
(result) {
|
||||
return result.fold(
|
||||
(l) => Future(() async {
|
||||
return Future(() async {
|
||||
await _loadGroups();
|
||||
await _loadLayoutSetting();
|
||||
return left(l);
|
||||
}),
|
||||
(err) => right(err),
|
||||
);
|
||||
return left(fields);
|
||||
});
|
||||
},
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return right(err);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
@ -33,7 +33,8 @@ class _GridFieldNotifier extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<FieldInfo> get fieldInfos => _fieldInfos;
|
||||
UnmodifiableListView<FieldInfo> get fieldInfos =>
|
||||
UnmodifiableListView(_fieldInfos);
|
||||
}
|
||||
|
||||
class _GridFilterNotifier extends ChangeNotifier {
|
||||
@ -85,9 +86,11 @@ class FieldController {
|
||||
final FilterBackendService _filterBackendSvc;
|
||||
final SortBackendService _sortBackendSvc;
|
||||
|
||||
bool _isDisposed = false;
|
||||
|
||||
// Field callbacks
|
||||
final Map<OnReceiveFields, VoidCallback> _fieldCallbacks = {};
|
||||
_GridFieldNotifier? _fieldNotifier = _GridFieldNotifier();
|
||||
final _GridFieldNotifier _fieldNotifier = _GridFieldNotifier();
|
||||
|
||||
// Field updated callbacks
|
||||
final Map<OnReceiveUpdateFields, void Function(List<FieldInfo>)>
|
||||
@ -107,15 +110,15 @@ class FieldController {
|
||||
final Map<String, SortPB> _sortPBByFieldId = {};
|
||||
|
||||
// Getters
|
||||
List<FieldInfo> get fieldInfos => [..._fieldNotifier?.fieldInfos ?? []];
|
||||
List<FieldInfo> get fieldInfos => [..._fieldNotifier.fieldInfos];
|
||||
List<FilterInfo> get filterInfos => [..._filterNotifier?.filters ?? []];
|
||||
List<SortInfo> get sortInfos => [..._sortNotifier?.sorts ?? []];
|
||||
|
||||
FieldInfo? getField(String fieldId) {
|
||||
final fields = _fieldNotifier?.fieldInfos
|
||||
final fields = _fieldNotifier.fieldInfos
|
||||
.where((element) => element.id == fieldId)
|
||||
.toList() ??
|
||||
[];
|
||||
.toList();
|
||||
|
||||
if (fields.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
@ -169,6 +172,10 @@ class FieldController {
|
||||
_listenOnSortChanged();
|
||||
|
||||
_settingBackendSvc.getSetting().then((result) {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.fold(
|
||||
(setting) => _updateSetting(setting),
|
||||
(err) => Log.error(err),
|
||||
@ -257,6 +264,10 @@ class FieldController {
|
||||
|
||||
_filtersListener.start(
|
||||
onFilterChanged: (result) {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.fold(
|
||||
(FilterChangesetNotificationPB changeset) {
|
||||
final List<FilterInfo> filters = filterInfos;
|
||||
@ -351,6 +362,9 @@ class FieldController {
|
||||
|
||||
_sortsListener.start(
|
||||
onSortChanged: (result) {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(SortChangesetNotificationPB changeset) {
|
||||
final List<SortInfo> newSortInfos = sortInfos;
|
||||
@ -371,6 +385,10 @@ class FieldController {
|
||||
//Listen on setting changes
|
||||
_settingListener.start(
|
||||
onSettingUpdated: (result) {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.fold(
|
||||
(setting) => _updateSetting(setting),
|
||||
(r) => Log.error(r),
|
||||
@ -385,6 +403,9 @@ class FieldController {
|
||||
onFieldsChanged: (result) {
|
||||
result.fold(
|
||||
(changeset) {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
_deleteFields(changeset.deletedFields);
|
||||
_insertFields(changeset.insertedFields);
|
||||
|
||||
@ -417,27 +438,29 @@ class FieldController {
|
||||
}
|
||||
|
||||
void _updateFieldInfos() {
|
||||
if (_fieldNotifier != null) {
|
||||
for (final field in _fieldNotifier!.fieldInfos) {
|
||||
for (final field in _fieldNotifier.fieldInfos) {
|
||||
field._isGroupField = _groupConfigurationByFieldId[field.id] != null;
|
||||
field._hasFilter = _filterPBByFieldId[field.id] != null;
|
||||
field._hasSort = _sortPBByFieldId[field.id] != null;
|
||||
}
|
||||
_fieldNotifier?.notify();
|
||||
}
|
||||
_fieldNotifier.notify();
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
if (_isDisposed) {
|
||||
Log.warn('FieldController is already disposed');
|
||||
return;
|
||||
}
|
||||
_isDisposed = true;
|
||||
await _fieldListener.stop();
|
||||
await _filtersListener.stop();
|
||||
await _settingListener.stop();
|
||||
await _sortsListener.stop();
|
||||
|
||||
for (final callback in _fieldCallbacks.values) {
|
||||
_fieldNotifier?.removeListener(callback);
|
||||
_fieldNotifier.removeListener(callback);
|
||||
}
|
||||
_fieldNotifier?.dispose();
|
||||
_fieldNotifier = null;
|
||||
_fieldNotifier.dispose();
|
||||
|
||||
for (final callback in _filterCallbacks.values) {
|
||||
_filterNotifier?.removeListener(callback);
|
||||
@ -460,7 +483,11 @@ class FieldController {
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(newFields) {
|
||||
_fieldNotifier?.fieldInfos =
|
||||
if (_isDisposed) {
|
||||
return left(unit);
|
||||
}
|
||||
|
||||
_fieldNotifier.fieldInfos =
|
||||
newFields.map((field) => FieldInfo(field: field)).toList();
|
||||
_loadFilters();
|
||||
_loadSorts();
|
||||
@ -551,7 +578,7 @@ class FieldController {
|
||||
}
|
||||
|
||||
_fieldCallbacks[onReceiveFields] = callback;
|
||||
_fieldNotifier?.addListener(callback);
|
||||
_fieldNotifier.addListener(callback);
|
||||
}
|
||||
|
||||
if (onFilters != null) {
|
||||
@ -588,7 +615,7 @@ class FieldController {
|
||||
if (onFieldsListener != null) {
|
||||
final callback = _fieldCallbacks.remove(onFieldsListener);
|
||||
if (callback != null) {
|
||||
_fieldNotifier?.removeListener(callback);
|
||||
_fieldNotifier.removeListener(callback);
|
||||
}
|
||||
}
|
||||
if (onFiltersListener != null) {
|
||||
@ -616,7 +643,7 @@ class FieldController {
|
||||
};
|
||||
|
||||
newFields.retainWhere((field) => (deletedFieldMap[field.id] == null));
|
||||
_fieldNotifier?.fieldInfos = newFields;
|
||||
_fieldNotifier.fieldInfos = newFields;
|
||||
}
|
||||
|
||||
void _insertFields(List<IndexFieldPB> insertedFields) {
|
||||
@ -632,7 +659,7 @@ class FieldController {
|
||||
newFieldInfos.add(fieldInfo);
|
||||
}
|
||||
}
|
||||
_fieldNotifier?.fieldInfos = newFieldInfos;
|
||||
_fieldNotifier.fieldInfos = newFieldInfos;
|
||||
}
|
||||
|
||||
List<FieldInfo> _updateFields(List<FieldPB> updatedFieldPBs) {
|
||||
@ -654,7 +681,7 @@ class FieldController {
|
||||
}
|
||||
|
||||
if (updatedFields.isNotEmpty) {
|
||||
_fieldNotifier?.fieldInfos = newFields;
|
||||
_fieldNotifier.fieldInfos = newFields;
|
||||
}
|
||||
return updatedFields;
|
||||
}
|
||||
|
@ -29,9 +29,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
||||
String get viewId => databaseController.viewId;
|
||||
|
||||
BoardBloc({required ViewPB view})
|
||||
: databaseController = DatabaseController(
|
||||
view: view,
|
||||
),
|
||||
: databaseController = DatabaseController(view: view),
|
||||
super(BoardState.initial(view.id)) {
|
||||
boardController = AppFlowyBoardController(
|
||||
onMoveGroup: (
|
||||
|
@ -32,15 +32,13 @@ import 'widgets/shortcuts.dart';
|
||||
import 'widgets/toolbar/grid_toolbar.dart';
|
||||
|
||||
class GridPage extends StatefulWidget {
|
||||
GridPage({
|
||||
const GridPage({
|
||||
required this.view,
|
||||
this.onDeleted,
|
||||
Key? key,
|
||||
}) : databaseController = DatabaseController(view: view),
|
||||
super(key: key);
|
||||
}) : super(key: key);
|
||||
|
||||
final ViewPB view;
|
||||
final DatabaseController databaseController;
|
||||
final VoidCallback? onDeleted;
|
||||
|
||||
@override
|
||||
@ -48,6 +46,14 @@ class GridPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _GridPageState extends State<GridPage> {
|
||||
late DatabaseController databaseController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
databaseController = DatabaseController(view: widget.view);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
@ -55,19 +61,19 @@ class _GridPageState extends State<GridPage> {
|
||||
BlocProvider<GridBloc>(
|
||||
create: (context) => GridBloc(
|
||||
view: widget.view,
|
||||
databaseController: widget.databaseController,
|
||||
databaseController: databaseController,
|
||||
)..add(const GridEvent.initial()),
|
||||
),
|
||||
BlocProvider<GridFilterMenuBloc>(
|
||||
create: (context) => GridFilterMenuBloc(
|
||||
viewId: widget.view.id,
|
||||
fieldController: widget.databaseController.fieldController,
|
||||
fieldController: databaseController.fieldController,
|
||||
)..add(const GridFilterMenuEvent.initial()),
|
||||
),
|
||||
BlocProvider<SortMenuBloc>(
|
||||
create: (context) => SortMenuBloc(
|
||||
viewId: widget.view.id,
|
||||
fieldController: widget.databaseController.fieldController,
|
||||
fieldController: databaseController.fieldController,
|
||||
)..add(const SortMenuEvent.initial()),
|
||||
),
|
||||
BlocProvider<DatabaseSettingBloc>(
|
||||
|
@ -93,7 +93,7 @@ class ChecklistState extends State<ChecklistFilterEditor> {
|
||||
children: [
|
||||
FlowyText(state.filterInfo.fieldInfo.name),
|
||||
const HSpace(4),
|
||||
ChecklistFilterConditionPBList(
|
||||
ChecklistFilterConditionList(
|
||||
filterInfo: state.filterInfo,
|
||||
),
|
||||
const Spacer(),
|
||||
@ -118,9 +118,9 @@ class ChecklistState extends State<ChecklistFilterEditor> {
|
||||
}
|
||||
}
|
||||
|
||||
class ChecklistFilterConditionPBList extends StatelessWidget {
|
||||
class ChecklistFilterConditionList extends StatelessWidget {
|
||||
final FilterInfo filterInfo;
|
||||
const ChecklistFilterConditionPBList({
|
||||
const ChecklistFilterConditionList({
|
||||
required this.filterInfo,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
@ -2,7 +2,6 @@ import 'package:appflowy/plugins/database_view/grid/application/filter/select_op
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -58,16 +57,16 @@ class SelectOptionFilterList extends StatelessWidget {
|
||||
SelectOptionFilterListState>(
|
||||
builder: (context, state) {
|
||||
return ListView.separated(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
controller: ScrollController(),
|
||||
itemCount: state.visibleOptions.length,
|
||||
separatorBuilder: (context, index) {
|
||||
return VSpace(GridSize.typeOptionSeparatorHeight);
|
||||
},
|
||||
physics: StyledScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final option = state.visibleOptions[index];
|
||||
return _SelectOptionFilterCell(
|
||||
return SelectOptionFilterCell(
|
||||
option: option.optionPB,
|
||||
isSelected: option.isSelected,
|
||||
);
|
||||
@ -80,21 +79,20 @@ class SelectOptionFilterList extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _SelectOptionFilterCell extends StatefulWidget {
|
||||
class SelectOptionFilterCell extends StatefulWidget {
|
||||
final SelectOptionPB option;
|
||||
final bool isSelected;
|
||||
const _SelectOptionFilterCell({
|
||||
const SelectOptionFilterCell({
|
||||
required this.option,
|
||||
required this.isSelected,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<_SelectOptionFilterCell> createState() =>
|
||||
_SelectOptionFilterCellState();
|
||||
State<SelectOptionFilterCell> createState() => _SelectOptionFilterCellState();
|
||||
}
|
||||
|
||||
class _SelectOptionFilterCellState extends State<_SelectOptionFilterCell> {
|
||||
class _SelectOptionFilterCellState extends State<SelectOptionFilterCell> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
|
@ -45,7 +45,7 @@ if is_empty ${ret}
|
||||
end
|
||||
ret = which protoc-gen-dart
|
||||
if is_empty ${ret}
|
||||
exec cmd.exe /c dart pub global activate protoc_plugin
|
||||
exec cmd.exe /c dart pub global activate protoc_plugin 20.0.1
|
||||
end
|
||||
ret = which protoc-gen-dart
|
||||
if is_empty ${ret}
|
||||
@ -60,14 +60,14 @@ script_runner = "@duckscript"
|
||||
[tasks.install_flutter_protobuf_compiler]
|
||||
script = """
|
||||
echo "Install protoc_plugin (Dart)"
|
||||
dart pub global activate protoc_plugin
|
||||
dart pub global activate protoc_plugin 20.0.1
|
||||
"""
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.install_flutter_protobuf_compiler.linux]
|
||||
script = """
|
||||
echo "Install protoc_plugin (Dart)"
|
||||
dart pub global activate protoc_plugin
|
||||
dart pub global activate protoc_plugin 20.0.1
|
||||
"""
|
||||
script_runner = "@shell"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user