mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: clean up db sort blocs (#4725)
This commit is contained in:
@ -1116,7 +1116,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
|
|
||||||
/// Must call [tapSortMenuInSettingBar] first.
|
/// Must call [tapSortMenuInSettingBar] first.
|
||||||
Future<void> tapAllSortButton() async {
|
Future<void> tapAllSortButton() async {
|
||||||
await tapButton(find.byType(DatabaseDeleteSortButton));
|
await tapButton(find.byType(DeleteAllSortsButton));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> scrollOptionFilterListByOffset(Offset offset) async {
|
Future<void> scrollOptionFilterListByOffset(Offset offset) async {
|
||||||
|
@ -121,8 +121,8 @@ class _Header extends StatelessWidget {
|
|||||||
if (state.newSortFieldId != null && state.newSortCondition != null) {
|
if (state.newSortFieldId != null && state.newSortCondition != null) {
|
||||||
context.read<SortEditorBloc>().add(
|
context.read<SortEditorBloc>().add(
|
||||||
SortEditorEvent.createSort(
|
SortEditorEvent.createSort(
|
||||||
state.newSortFieldId!,
|
fieldId: state.newSortFieldId!,
|
||||||
state.newSortCondition!,
|
condition: state.newSortCondition!,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -531,9 +531,8 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
context.read<SortEditorBloc>().add(
|
context.read<SortEditorBloc>().add(
|
||||||
SortEditorEvent.editSort(
|
SortEditorEvent.editSort(
|
||||||
sortInfo!.sortId,
|
sortId: sortInfo!.sortId,
|
||||||
null,
|
condition: newCondition,
|
||||||
newCondition,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -545,9 +544,8 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
context.read<SortEditorBloc>().add(
|
context.read<SortEditorBloc>().add(
|
||||||
SortEditorEvent.editSort(
|
SortEditorEvent.editSort(
|
||||||
sortInfo!.sortId,
|
sortId: sortInfo!.sortId,
|
||||||
newFieldId,
|
fieldId: newFieldId,
|
||||||
null,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbserver.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
|
|
||||||
import 'package:appflowy_result/appflowy_result.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
|
|
||||||
import '../../../application/field/field_controller.dart';
|
|
||||||
import '../../../application/sort/sort_service.dart';
|
|
||||||
import 'util.dart';
|
|
||||||
|
|
||||||
part 'sort_create_bloc.freezed.dart';
|
|
||||||
|
|
||||||
class CreateSortBloc extends Bloc<CreateSortEvent, CreateSortState> {
|
|
||||||
CreateSortBloc({required this.viewId, required this.fieldController})
|
|
||||||
: _sortBackendSvc = SortBackendService(viewId: viewId),
|
|
||||||
super(CreateSortState.initial(fieldController.fieldInfos)) {
|
|
||||||
_dispatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String viewId;
|
|
||||||
final SortBackendService _sortBackendSvc;
|
|
||||||
final FieldController fieldController;
|
|
||||||
void Function(List<FieldInfo>)? _onFieldFn;
|
|
||||||
|
|
||||||
void _dispatch() {
|
|
||||||
on<CreateSortEvent>(
|
|
||||||
(event, emit) async {
|
|
||||||
event.when(
|
|
||||||
initial: () {
|
|
||||||
_startListening();
|
|
||||||
},
|
|
||||||
didReceiveFields: (List<FieldInfo> fields) {
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
allFields: fields,
|
|
||||||
creatableFields: _filterFields(fields, state.filterText),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
didReceiveFilterText: (String text) {
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
filterText: text,
|
|
||||||
creatableFields: _filterFields(state.allFields, text),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
createDefaultSort: (FieldInfo field) {
|
|
||||||
emit(state.copyWith(didCreateSort: true));
|
|
||||||
_createDefaultSort(field);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<FieldInfo> _filterFields(
|
|
||||||
List<FieldInfo> fields,
|
|
||||||
String filterText,
|
|
||||||
) {
|
|
||||||
final List<FieldInfo> allFields = List.from(fields);
|
|
||||||
final keyword = filterText.toLowerCase();
|
|
||||||
allFields.retainWhere((field) {
|
|
||||||
if (!field.canCreateSort) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filterText.isNotEmpty) {
|
|
||||||
return field.name.toLowerCase().contains(keyword);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return allFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
|
||||||
_onFieldFn = (fields) {
|
|
||||||
fields.retainWhere((field) => field.canCreateSort);
|
|
||||||
add(CreateSortEvent.didReceiveFields(fields));
|
|
||||||
};
|
|
||||||
fieldController.addListener(onReceiveFields: _onFieldFn);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<FlowyResult<void, FlowyError>> _createDefaultSort(
|
|
||||||
FieldInfo field,
|
|
||||||
) async {
|
|
||||||
final result = await _sortBackendSvc.insertSort(
|
|
||||||
fieldId: field.id,
|
|
||||||
condition: SortConditionPB.Ascending,
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onFieldFn != null) {
|
|
||||||
fieldController.removeListener(onFieldsListener: _onFieldFn);
|
|
||||||
_onFieldFn = null;
|
|
||||||
}
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class CreateSortEvent with _$CreateSortEvent {
|
|
||||||
const factory CreateSortEvent.initial() = _Initial;
|
|
||||||
const factory CreateSortEvent.didReceiveFields(List<FieldInfo> fields) =
|
|
||||||
_DidReceiveFields;
|
|
||||||
|
|
||||||
const factory CreateSortEvent.createDefaultSort(FieldInfo field) =
|
|
||||||
_CreateDefaultSort;
|
|
||||||
|
|
||||||
const factory CreateSortEvent.didReceiveFilterText(String text) =
|
|
||||||
_DidReceiveFilterText;
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class CreateSortState with _$CreateSortState {
|
|
||||||
const factory CreateSortState({
|
|
||||||
required String filterText,
|
|
||||||
required List<FieldInfo> creatableFields,
|
|
||||||
required List<FieldInfo> allFields,
|
|
||||||
required bool didCreateSort,
|
|
||||||
}) = _CreateSortState;
|
|
||||||
|
|
||||||
factory CreateSortState.initial(List<FieldInfo> fields) {
|
|
||||||
return CreateSortState(
|
|
||||||
filterText: "",
|
|
||||||
creatableFields: getCreatableSorts(fields),
|
|
||||||
allFields: fields,
|
|
||||||
didCreateSort: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,29 +5,26 @@ import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
|||||||
import 'package:appflowy/plugins/database/application/sort/sort_service.dart';
|
import 'package:appflowy/plugins/database/application/sort/sort_service.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/sort_info.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/sort_info.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbserver.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
import 'util.dart';
|
|
||||||
|
|
||||||
part 'sort_editor_bloc.freezed.dart';
|
part 'sort_editor_bloc.freezed.dart';
|
||||||
|
|
||||||
class SortEditorBloc extends Bloc<SortEditorEvent, SortEditorState> {
|
class SortEditorBloc extends Bloc<SortEditorEvent, SortEditorState> {
|
||||||
SortEditorBloc({
|
SortEditorBloc({
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
required this.fieldController,
|
required this.fieldController,
|
||||||
required List<SortInfo> sortInfos,
|
|
||||||
}) : _sortBackendSvc = SortBackendService(viewId: viewId),
|
}) : _sortBackendSvc = SortBackendService(viewId: viewId),
|
||||||
super(
|
super(
|
||||||
SortEditorState.initial(
|
SortEditorState.initial(
|
||||||
sortInfos,
|
fieldController.sortInfos,
|
||||||
fieldController.fieldInfos,
|
fieldController.fieldInfos,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
_dispatch();
|
_dispatch();
|
||||||
|
_startListening();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String viewId;
|
final String viewId;
|
||||||
@ -41,9 +38,6 @@ class SortEditorBloc extends Bloc<SortEditorEvent, SortEditorState> {
|
|||||||
on<SortEditorEvent>(
|
on<SortEditorEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.when(
|
await event.when(
|
||||||
initial: () {
|
|
||||||
_startListening();
|
|
||||||
},
|
|
||||||
didReceiveFields: (List<FieldInfo> fields) {
|
didReceiveFields: (List<FieldInfo> fields) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
@ -52,10 +46,16 @@ class SortEditorBloc extends Bloc<SortEditorEvent, SortEditorState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
createSort: (String fieldId, SortConditionPB condition) async {
|
updateCreateSortFilter: (text) {
|
||||||
|
emit(state.copyWith(filter: text));
|
||||||
|
},
|
||||||
|
createSort: (
|
||||||
|
String fieldId,
|
||||||
|
SortConditionPB? condition,
|
||||||
|
) async {
|
||||||
final result = await _sortBackendSvc.insertSort(
|
final result = await _sortBackendSvc.insertSort(
|
||||||
fieldId: fieldId,
|
fieldId: fieldId,
|
||||||
condition: condition,
|
condition: condition ?? SortConditionPB.Ascending,
|
||||||
);
|
);
|
||||||
result.fold((l) => {}, (err) => Log.error(err));
|
result.fold((l) => {}, (err) => Log.error(err));
|
||||||
},
|
},
|
||||||
@ -142,24 +142,25 @@ class SortEditorBloc extends Bloc<SortEditorEvent, SortEditorState> {
|
|||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SortEditorEvent with _$SortEditorEvent {
|
class SortEditorEvent with _$SortEditorEvent {
|
||||||
const factory SortEditorEvent.initial() = _Initial;
|
|
||||||
const factory SortEditorEvent.didReceiveFields(List<FieldInfo> fieldInfos) =
|
const factory SortEditorEvent.didReceiveFields(List<FieldInfo> fieldInfos) =
|
||||||
_DidReceiveFields;
|
_DidReceiveFields;
|
||||||
const factory SortEditorEvent.didReceiveSorts(List<SortInfo> sortInfos) =
|
const factory SortEditorEvent.didReceiveSorts(List<SortInfo> sortInfos) =
|
||||||
_DidReceiveSorts;
|
_DidReceiveSorts;
|
||||||
const factory SortEditorEvent.createSort(
|
const factory SortEditorEvent.updateCreateSortFilter(String text) =
|
||||||
String fieldId,
|
_UpdateCreateSortFilter;
|
||||||
SortConditionPB condition,
|
const factory SortEditorEvent.createSort({
|
||||||
) = _CreateSort;
|
required String fieldId,
|
||||||
const factory SortEditorEvent.editSort(
|
SortConditionPB? condition,
|
||||||
String sortId,
|
}) = _CreateSort;
|
||||||
|
const factory SortEditorEvent.editSort({
|
||||||
|
required String sortId,
|
||||||
String? fieldId,
|
String? fieldId,
|
||||||
SortConditionPB? condition,
|
SortConditionPB? condition,
|
||||||
) = _EditSort;
|
}) = _EditSort;
|
||||||
const factory SortEditorEvent.deleteSort(SortInfo sortInfo) = _DeleteSort;
|
|
||||||
const factory SortEditorEvent.deleteAllSorts() = _DeleteAllSorts;
|
|
||||||
const factory SortEditorEvent.reorderSort(int oldIndex, int newIndex) =
|
const factory SortEditorEvent.reorderSort(int oldIndex, int newIndex) =
|
||||||
_ReorderSort;
|
_ReorderSort;
|
||||||
|
const factory SortEditorEvent.deleteSort(SortInfo sortInfo) = _DeleteSort;
|
||||||
|
const factory SortEditorEvent.deleteAllSorts() = _DeleteAllSorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
@ -168,6 +169,7 @@ class SortEditorState with _$SortEditorState {
|
|||||||
required List<SortInfo> sortInfos,
|
required List<SortInfo> sortInfos,
|
||||||
required List<FieldInfo> creatableFields,
|
required List<FieldInfo> creatableFields,
|
||||||
required List<FieldInfo> allFields,
|
required List<FieldInfo> allFields,
|
||||||
|
required String filter,
|
||||||
}) = _SortEditorState;
|
}) = _SortEditorState;
|
||||||
|
|
||||||
factory SortEditorState.initial(
|
factory SortEditorState.initial(
|
||||||
@ -178,6 +180,13 @@ class SortEditorState with _$SortEditorState {
|
|||||||
creatableFields: getCreatableSorts(fields),
|
creatableFields: getCreatableSorts(fields),
|
||||||
allFields: fields,
|
allFields: fields,
|
||||||
sortInfos: sortInfos,
|
sortInfos: sortInfos,
|
||||||
|
filter: "",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<FieldInfo> getCreatableSorts(List<FieldInfo> fieldInfos) {
|
||||||
|
final List<FieldInfo> creatableFields = List.from(fieldInfos);
|
||||||
|
creatableFields.retainWhere((element) => element.canCreateSort);
|
||||||
|
return creatableFields;
|
||||||
|
}
|
||||||
|
@ -1,123 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
|
|
||||||
import '../../../application/field/field_controller.dart';
|
|
||||||
import '../../presentation/widgets/sort/sort_info.dart';
|
|
||||||
|
|
||||||
import 'util.dart';
|
|
||||||
|
|
||||||
part 'sort_menu_bloc.freezed.dart';
|
|
||||||
|
|
||||||
class SortMenuBloc extends Bloc<SortMenuEvent, SortMenuState> {
|
|
||||||
SortMenuBloc({required this.viewId, required this.fieldController})
|
|
||||||
: super(
|
|
||||||
SortMenuState.initial(
|
|
||||||
viewId,
|
|
||||||
fieldController.sortInfos,
|
|
||||||
fieldController.fieldInfos,
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
_dispatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String viewId;
|
|
||||||
final FieldController fieldController;
|
|
||||||
void Function(List<SortInfo>)? _onSortChangeFn;
|
|
||||||
void Function(List<FieldInfo>)? _onFieldFn;
|
|
||||||
|
|
||||||
void _dispatch() {
|
|
||||||
on<SortMenuEvent>(
|
|
||||||
(event, emit) async {
|
|
||||||
event.when(
|
|
||||||
initial: () {
|
|
||||||
_startListening();
|
|
||||||
},
|
|
||||||
didReceiveSortInfos: (sortInfos) {
|
|
||||||
emit(state.copyWith(sortInfos: sortInfos));
|
|
||||||
},
|
|
||||||
toggleMenu: () {
|
|
||||||
final isVisible = !state.isVisible;
|
|
||||||
emit(state.copyWith(isVisible: isVisible));
|
|
||||||
},
|
|
||||||
didReceiveFields: (List<FieldInfo> fields) {
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
fields: fields,
|
|
||||||
creatableFields: getCreatableSorts(fields),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
|
||||||
_onSortChangeFn = (sortInfos) {
|
|
||||||
add(SortMenuEvent.didReceiveSortInfos(sortInfos));
|
|
||||||
};
|
|
||||||
|
|
||||||
_onFieldFn = (fields) {
|
|
||||||
add(SortMenuEvent.didReceiveFields(fields));
|
|
||||||
};
|
|
||||||
|
|
||||||
fieldController.addListener(
|
|
||||||
onSorts: (sortInfos) {
|
|
||||||
_onSortChangeFn?.call(sortInfos);
|
|
||||||
},
|
|
||||||
onReceiveFields: (fields) {
|
|
||||||
_onFieldFn?.call(fields);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
if (_onSortChangeFn != null) {
|
|
||||||
fieldController.removeListener(onSortsListener: _onSortChangeFn!);
|
|
||||||
_onSortChangeFn = null;
|
|
||||||
}
|
|
||||||
if (_onFieldFn != null) {
|
|
||||||
fieldController.removeListener(onFieldsListener: _onFieldFn!);
|
|
||||||
_onFieldFn = null;
|
|
||||||
}
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class SortMenuEvent with _$SortMenuEvent {
|
|
||||||
const factory SortMenuEvent.initial() = _Initial;
|
|
||||||
const factory SortMenuEvent.didReceiveSortInfos(List<SortInfo> sortInfos) =
|
|
||||||
_DidReceiveSortInfos;
|
|
||||||
const factory SortMenuEvent.didReceiveFields(List<FieldInfo> fields) =
|
|
||||||
_DidReceiveFields;
|
|
||||||
const factory SortMenuEvent.toggleMenu() = _SetMenuVisibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class SortMenuState with _$SortMenuState {
|
|
||||||
const factory SortMenuState({
|
|
||||||
required String viewId,
|
|
||||||
required List<SortInfo> sortInfos,
|
|
||||||
required List<FieldInfo> fields,
|
|
||||||
required List<FieldInfo> creatableFields,
|
|
||||||
required bool isVisible,
|
|
||||||
}) = _SortMenuState;
|
|
||||||
|
|
||||||
factory SortMenuState.initial(
|
|
||||||
String viewId,
|
|
||||||
List<SortInfo> sortInfos,
|
|
||||||
List<FieldInfo> fields,
|
|
||||||
) =>
|
|
||||||
SortMenuState(
|
|
||||||
viewId: viewId,
|
|
||||||
sortInfos: sortInfos,
|
|
||||||
fields: fields,
|
|
||||||
creatableFields: getCreatableSorts(fields),
|
|
||||||
isVisible: false,
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
|
||||||
|
|
||||||
List<FieldInfo> getCreatableSorts(List<FieldInfo> fieldInfos) {
|
|
||||||
final List<FieldInfo> creatableFields = List.from(fieldInfos);
|
|
||||||
creatableFields.retainWhere((element) => element.canCreateSort);
|
|
||||||
return creatableFields;
|
|
||||||
}
|
|
@ -1,8 +1,7 @@
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
|
||||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_create_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||||
import 'package:appflowy/util/field_type_extension.dart';
|
import 'package:appflowy/util/field_type_extension.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -15,97 +14,56 @@ import 'package:flowy_infra_ui/widget/spacing.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class GridCreateSortList extends StatefulWidget {
|
class CreateDatabaseViewSortList extends StatelessWidget {
|
||||||
const GridCreateSortList({
|
const CreateDatabaseViewSortList({
|
||||||
super.key,
|
super.key,
|
||||||
required this.viewId,
|
required this.onTap,
|
||||||
required this.fieldController,
|
|
||||||
required this.onClosed,
|
|
||||||
this.onCreateSort,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String viewId;
|
final VoidCallback onTap;
|
||||||
final FieldController fieldController;
|
|
||||||
final VoidCallback onClosed;
|
|
||||||
final VoidCallback? onCreateSort;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => _GridCreateSortListState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GridCreateSortListState extends State<GridCreateSortList> {
|
|
||||||
late CreateSortBloc editBloc;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
editBloc = CreateSortBloc(
|
|
||||||
viewId: widget.viewId,
|
|
||||||
fieldController: widget.fieldController,
|
|
||||||
)..add(const CreateSortEvent.initial());
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider.value(
|
return BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||||
value: editBloc,
|
builder: (context, state) {
|
||||||
child: BlocListener<CreateSortBloc, CreateSortState>(
|
final filter = state.filter.toLowerCase();
|
||||||
listener: (context, state) {
|
final cells = state.creatableFields
|
||||||
if (state.didCreateSort) {
|
.where((field) => field.field.name.toLowerCase().contains(filter))
|
||||||
widget.onClosed();
|
.map((fieldInfo) {
|
||||||
}
|
return GridSortPropertyCell(
|
||||||
},
|
fieldInfo: fieldInfo,
|
||||||
child: BlocBuilder<CreateSortBloc, CreateSortState>(
|
onTap: () {
|
||||||
builder: (context, state) {
|
context
|
||||||
final cells = state.creatableFields.map((fieldInfo) {
|
.read<SortEditorBloc>()
|
||||||
return SizedBox(
|
.add(SortEditorEvent.createSort(fieldId: fieldInfo.id));
|
||||||
height: GridSize.popoverItemHeight,
|
onTap.call();
|
||||||
child: GridSortPropertyCell(
|
},
|
||||||
fieldInfo: fieldInfo,
|
);
|
||||||
onTap: (fieldInfo) => createSort(fieldInfo),
|
}).toList();
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
final List<Widget> slivers = [
|
final List<Widget> slivers = [
|
||||||
SliverPersistentHeader(
|
SliverPersistentHeader(
|
||||||
pinned: true,
|
pinned: true,
|
||||||
delegate: _SortTextFieldDelegate(),
|
delegate: _SortTextFieldDelegate(),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: cells.length,
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
return cells[index];
|
|
||||||
},
|
|
||||||
separatorBuilder: (BuildContext context, int index) {
|
|
||||||
return VSpace(GridSize.typeOptionSeparatorHeight);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
return CustomScrollView(
|
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
slivers: slivers,
|
itemCount: cells.length,
|
||||||
physics: StyledScrollPhysics(),
|
itemBuilder: (_, index) => cells[index],
|
||||||
);
|
separatorBuilder: (_, __) =>
|
||||||
},
|
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
];
|
||||||
|
return CustomScrollView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
slivers: slivers,
|
||||||
|
physics: StyledScrollPhysics(),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
editBloc.close();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void createSort(FieldInfo field) {
|
|
||||||
editBloc.add(CreateSortEvent.createDefaultSort(field));
|
|
||||||
widget.onCreateSort?.call();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SortTextFieldDelegate extends SliverPersistentHeaderDelegate {
|
class _SortTextFieldDelegate extends SliverPersistentHeaderDelegate {
|
||||||
@ -127,8 +85,8 @@ class _SortTextFieldDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
hintText: LocaleKeys.grid_settings_sortBy.tr(),
|
hintText: LocaleKeys.grid_settings_sortBy.tr(),
|
||||||
onChanged: (text) {
|
onChanged: (text) {
|
||||||
context
|
context
|
||||||
.read<CreateSortBloc>()
|
.read<SortEditorBloc>()
|
||||||
.add(CreateSortEvent.didReceiveFilterText(text));
|
.add(SortEditorEvent.updateCreateSortFilter(text));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -141,9 +99,7 @@ class _SortTextFieldDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
double get minExtent => fixHeight;
|
double get minExtent => fixHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
bool shouldRebuild(covariant oldDelegate) => false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class GridSortPropertyCell extends StatelessWidget {
|
class GridSortPropertyCell extends StatelessWidget {
|
||||||
@ -154,20 +110,23 @@ class GridSortPropertyCell extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final FieldInfo fieldInfo;
|
final FieldInfo fieldInfo;
|
||||||
final Function(FieldInfo) onTap;
|
final VoidCallback onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlowyButton(
|
return SizedBox(
|
||||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
height: GridSize.popoverItemHeight,
|
||||||
text: FlowyText.medium(
|
child: FlowyButton(
|
||||||
fieldInfo.name,
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
color: AFThemeExtension.of(context).textColor,
|
text: FlowyText.medium(
|
||||||
),
|
fieldInfo.name,
|
||||||
onTap: () => onTap(fieldInfo),
|
color: AFThemeExtension.of(context).textColor,
|
||||||
leftIcon: FlowySvg(
|
),
|
||||||
fieldInfo.fieldType.svgData,
|
onTap: onTap,
|
||||||
color: Theme.of(context).iconTheme.color,
|
leftIcon: FlowySvg(
|
||||||
|
fieldInfo.fieldType.svgData,
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,16 +27,15 @@ class SortChoiceButton extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
border: Border.fromBorderSide(
|
border: Border.fromBorderSide(
|
||||||
BorderSide(
|
BorderSide(color: Theme.of(context).dividerColor),
|
||||||
color: AFThemeExtension.of(context).toggleOffFill,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(14)),
|
borderRadius: BorderRadius.all(radius),
|
||||||
),
|
),
|
||||||
useIntrinsicWidth: true,
|
useIntrinsicWidth: true,
|
||||||
text: FlowyText(
|
text: FlowyText(
|
||||||
text,
|
text,
|
||||||
color: AFThemeExtension.of(context).textColor,
|
color: AFThemeExtension.of(context).textColor,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||||
radius: BorderRadius.all(radius),
|
radius: BorderRadius.all(radius),
|
||||||
|
@ -2,9 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/util.dart';
|
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
@ -14,7 +12,6 @@ import 'package:flowy_infra/theme_extension.dart';
|
|||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'dart:math' as math;
|
|
||||||
|
|
||||||
import 'create_sort_list.dart';
|
import 'create_sort_list.dart';
|
||||||
import 'order_panel.dart';
|
import 'order_panel.dart';
|
||||||
@ -22,16 +19,7 @@ import 'sort_choice_button.dart';
|
|||||||
import 'sort_info.dart';
|
import 'sort_info.dart';
|
||||||
|
|
||||||
class SortEditor extends StatefulWidget {
|
class SortEditor extends StatefulWidget {
|
||||||
const SortEditor({
|
const SortEditor({super.key});
|
||||||
super.key,
|
|
||||||
required this.viewId,
|
|
||||||
required this.fieldController,
|
|
||||||
required this.sortInfos,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String viewId;
|
|
||||||
final FieldController fieldController;
|
|
||||||
final List<SortInfo> sortInfos;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SortEditor> createState() => _SortEditorState();
|
State<SortEditor> createState() => _SortEditorState();
|
||||||
@ -42,69 +30,57 @@ class _SortEditorState extends State<SortEditor> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||||
create: (context) => SortEditorBloc(
|
builder: (context, state) {
|
||||||
viewId: widget.viewId,
|
final sortInfos = state.sortInfos;
|
||||||
fieldController: widget.fieldController,
|
return ReorderableListView.builder(
|
||||||
sortInfos: widget.sortInfos,
|
onReorder: (oldIndex, newIndex) => context
|
||||||
)..add(const SortEditorEvent.initial()),
|
.read<SortEditorBloc>()
|
||||||
child: BlocBuilder<SortEditorBloc, SortEditorState>(
|
.add(SortEditorEvent.reorderSort(oldIndex, newIndex)),
|
||||||
builder: (context, state) {
|
itemCount: state.sortInfos.length,
|
||||||
final sortInfos = state.sortInfos;
|
itemBuilder: (context, index) => DatabaseSortItem(
|
||||||
|
key: ValueKey(sortInfos[index].sortId),
|
||||||
return ReorderableListView.builder(
|
index: index,
|
||||||
onReorder: (oldIndex, newIndex) => context
|
sortInfo: sortInfos[index],
|
||||||
.read<SortEditorBloc>()
|
popoverMutex: popoverMutex,
|
||||||
.add(SortEditorEvent.reorderSort(oldIndex, newIndex)),
|
),
|
||||||
itemCount: state.sortInfos.length,
|
proxyDecorator: (child, index, animation) => Material(
|
||||||
itemBuilder: (context, index) => Padding(
|
color: Colors.transparent,
|
||||||
key: ValueKey(sortInfos[index].sortId),
|
child: Stack(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
|
||||||
child: DatabaseSortItem(
|
|
||||||
index: index,
|
|
||||||
sortInfo: sortInfos[index],
|
|
||||||
popoverMutex: popoverMutex,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
proxyDecorator: (child, index, animation) => Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
BlocProvider.value(
|
|
||||||
value: context.read<SortEditorBloc>(),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
MouseRegion(
|
|
||||||
cursor: Platform.isWindows
|
|
||||||
? SystemMouseCursors.click
|
|
||||||
: SystemMouseCursors.grabbing,
|
|
||||||
child: const SizedBox.expand(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
shrinkWrap: true,
|
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
footer: Row(
|
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
BlocProvider.value(
|
||||||
child: DatabaseAddSortButton(
|
value: context.read<SortEditorBloc>(),
|
||||||
viewId: widget.viewId,
|
child: child,
|
||||||
fieldController: widget.fieldController,
|
|
||||||
popoverMutex: popoverMutex,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const HSpace(6),
|
MouseRegion(
|
||||||
Flexible(
|
cursor: Platform.isWindows
|
||||||
child: DatabaseDeleteSortButton(
|
? SystemMouseCursors.click
|
||||||
popoverMutex: popoverMutex,
|
: SystemMouseCursors.grabbing,
|
||||||
),
|
child: const SizedBox.expand(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
shrinkWrap: true,
|
||||||
),
|
buildDefaultDragHandles: false,
|
||||||
|
footer: Row(
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: DatabaseAddSortButton(
|
||||||
|
disable: state.creatableFields.isEmpty,
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(6),
|
||||||
|
Flexible(
|
||||||
|
child: DeleteAllSortsButton(
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,80 +99,89 @@ class DatabaseSortItem extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final deleteButton = FlowyIconButton(
|
return Container(
|
||||||
width: 26,
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
onPressed: () => context
|
color: Theme.of(context).cardColor,
|
||||||
.read<SortEditorBloc>()
|
child: Row(
|
||||||
.add(SortEditorEvent.deleteSort(sortInfo)),
|
children: [
|
||||||
iconPadding: const EdgeInsets.all(5),
|
ReorderableDragStartListener(
|
||||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
index: index,
|
||||||
icon:
|
child: MouseRegion(
|
||||||
FlowySvg(FlowySvgs.close_s, color: Theme.of(context).iconTheme.color),
|
cursor: Platform.isWindows
|
||||||
);
|
? SystemMouseCursors.click
|
||||||
|
: SystemMouseCursors.grab,
|
||||||
return Row(
|
child: SizedBox(
|
||||||
children: [
|
width: 14 + 12,
|
||||||
ReorderableDragStartListener(
|
height: 14,
|
||||||
index: index,
|
child: FlowySvg(
|
||||||
child: MouseRegion(
|
FlowySvgs.drag_element_s,
|
||||||
cursor: Platform.isWindows
|
size: const Size.square(14),
|
||||||
? SystemMouseCursors.click
|
color: Theme.of(context).iconTheme.color,
|
||||||
: SystemMouseCursors.grab,
|
),
|
||||||
child: SizedBox(
|
|
||||||
width: 14,
|
|
||||||
height: 14,
|
|
||||||
child: FlowySvg(
|
|
||||||
FlowySvgs.drag_element_s,
|
|
||||||
color: Theme.of(context).iconTheme.color,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Flexible(
|
||||||
const HSpace(6),
|
fit: FlexFit.tight,
|
||||||
SizedBox(
|
child: SizedBox(
|
||||||
height: 26,
|
height: 26,
|
||||||
child: SortChoiceButton(
|
child: SortChoiceButton(
|
||||||
text: sortInfo.fieldInfo.name,
|
text: sortInfo.fieldInfo.name,
|
||||||
editable: false,
|
editable: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const HSpace(6),
|
||||||
const HSpace(6),
|
Flexible(
|
||||||
SizedBox(
|
fit: FlexFit.tight,
|
||||||
height: 26,
|
child: SizedBox(
|
||||||
child: DatabaseSortItemOrderButton(
|
height: 26,
|
||||||
sortInfo: sortInfo,
|
child: SortConditionButton(
|
||||||
popoverMutex: popoverMutex,
|
sortInfo: sortInfo,
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const HSpace(6),
|
||||||
const Spacer(),
|
FlowyIconButton(
|
||||||
const HSpace(6),
|
width: 26,
|
||||||
deleteButton,
|
onPressed: () {
|
||||||
],
|
context
|
||||||
|
.read<SortEditorBloc>()
|
||||||
|
.add(SortEditorEvent.deleteSort(sortInfo));
|
||||||
|
PopoverContainer.of(context).close();
|
||||||
|
},
|
||||||
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
|
icon: FlowySvg(
|
||||||
|
FlowySvgs.trash_m,
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
size: const Size.square(16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SortConditionExtension on SortConditionPB {
|
extension SortConditionExtension on SortConditionPB {
|
||||||
String get title {
|
String get title {
|
||||||
switch (this) {
|
return switch (this) {
|
||||||
case SortConditionPB.Descending:
|
SortConditionPB.Ascending => LocaleKeys.grid_sort_ascending.tr(),
|
||||||
return LocaleKeys.grid_sort_descending.tr();
|
SortConditionPB.Descending => LocaleKeys.grid_sort_descending.tr(),
|
||||||
default:
|
_ => throw UnimplementedError(),
|
||||||
return LocaleKeys.grid_sort_ascending.tr();
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DatabaseAddSortButton extends StatefulWidget {
|
class DatabaseAddSortButton extends StatefulWidget {
|
||||||
const DatabaseAddSortButton({
|
const DatabaseAddSortButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.viewId,
|
required this.disable,
|
||||||
required this.fieldController,
|
|
||||||
required this.popoverMutex,
|
required this.popoverMutex,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String viewId;
|
final bool disable;
|
||||||
final FieldController fieldController;
|
|
||||||
final PopoverMutex popoverMutex;
|
final PopoverMutex popoverMutex;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -213,32 +198,36 @@ class _DatabaseAddSortButtonState extends State<DatabaseAddSortButton> {
|
|||||||
mutex: widget.popoverMutex,
|
mutex: widget.popoverMutex,
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
direction: PopoverDirection.bottomWithLeftAligned,
|
||||||
constraints: BoxConstraints.loose(const Size(200, 300)),
|
constraints: BoxConstraints.loose(const Size(200, 300)),
|
||||||
offset: const Offset(0, 8),
|
offset: const Offset(-6, 8),
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
asBarrier: true,
|
asBarrier: true,
|
||||||
|
popupBuilder: (popoverContext) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: context.read<SortEditorBloc>(),
|
||||||
|
child: CreateDatabaseViewSortList(
|
||||||
|
onTap: () => _popoverController.close(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onClose: () => context
|
||||||
|
.read<SortEditorBloc>()
|
||||||
|
.add(const SortEditorEvent.updateCreateSortFilter("")),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: GridSize.popoverItemHeight,
|
height: GridSize.popoverItemHeight,
|
||||||
child: FlowyButton(
|
child: FlowyButton(
|
||||||
hoverColor: AFThemeExtension.of(context).greyHover,
|
hoverColor: AFThemeExtension.of(context).greyHover,
|
||||||
disable: getCreatableSorts(widget.fieldController.fieldInfos).isEmpty,
|
disable: widget.disable,
|
||||||
text: FlowyText.medium(LocaleKeys.grid_sort_addSort.tr()),
|
text: FlowyText.medium(LocaleKeys.grid_sort_addSort.tr()),
|
||||||
onTap: () => _popoverController.show(),
|
onTap: () => _popoverController.show(),
|
||||||
leftIcon: const FlowySvg(FlowySvgs.add_s),
|
leftIcon: const FlowySvg(FlowySvgs.add_s),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
popupBuilder: (BuildContext context) {
|
|
||||||
return GridCreateSortList(
|
|
||||||
viewId: widget.viewId,
|
|
||||||
fieldController: widget.fieldController,
|
|
||||||
onClosed: () => _popoverController.close(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DatabaseDeleteSortButton extends StatelessWidget {
|
class DeleteAllSortsButton extends StatelessWidget {
|
||||||
const DatabaseDeleteSortButton({super.key, required this.popoverMutex});
|
const DeleteAllSortsButton({super.key, required this.popoverMutex});
|
||||||
|
|
||||||
final PopoverMutex popoverMutex;
|
final PopoverMutex popoverMutex;
|
||||||
|
|
||||||
@ -264,8 +253,8 @@ class DatabaseDeleteSortButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DatabaseSortItemOrderButton extends StatefulWidget {
|
class SortConditionButton extends StatefulWidget {
|
||||||
const DatabaseSortItemOrderButton({
|
const SortConditionButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.popoverMutex,
|
required this.popoverMutex,
|
||||||
required this.sortInfo,
|
required this.sortInfo,
|
||||||
@ -275,21 +264,14 @@ class DatabaseSortItemOrderButton extends StatefulWidget {
|
|||||||
final SortInfo sortInfo;
|
final SortInfo sortInfo;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DatabaseSortItemOrderButton> createState() =>
|
State<SortConditionButton> createState() => _SortConditionButtonState();
|
||||||
_DatabaseSortItemOrderButtonState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DatabaseSortItemOrderButtonState
|
class _SortConditionButtonState extends State<SortConditionButton> {
|
||||||
extends State<DatabaseSortItemOrderButton> {
|
|
||||||
final PopoverController popoverController = PopoverController();
|
final PopoverController popoverController = PopoverController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final arrow = Transform.rotate(
|
|
||||||
angle: -math.pi / 2,
|
|
||||||
child: const FlowySvg(FlowySvgs.arrow_left_s),
|
|
||||||
);
|
|
||||||
|
|
||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
controller: popoverController,
|
controller: popoverController,
|
||||||
mutex: widget.popoverMutex,
|
mutex: widget.popoverMutex,
|
||||||
@ -301,9 +283,8 @@ class _DatabaseSortItemOrderButtonState
|
|||||||
onCondition: (condition) {
|
onCondition: (condition) {
|
||||||
context.read<SortEditorBloc>().add(
|
context.read<SortEditorBloc>().add(
|
||||||
SortEditorEvent.editSort(
|
SortEditorEvent.editSort(
|
||||||
widget.sortInfo.sortId,
|
sortId: widget.sortInfo.sortId,
|
||||||
null,
|
condition: condition,
|
||||||
condition,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
popoverController.close();
|
popoverController.close();
|
||||||
@ -312,7 +293,10 @@ class _DatabaseSortItemOrderButtonState
|
|||||||
},
|
},
|
||||||
child: SortChoiceButton(
|
child: SortChoiceButton(
|
||||||
text: widget.sortInfo.sortPB.condition.title,
|
text: widget.sortInfo.sortPB.condition.title,
|
||||||
rightIcon: arrow,
|
rightIcon: FlowySvg(
|
||||||
|
FlowySvgs.arrow_down_s,
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
onTap: () => popoverController.show(),
|
onTap: () => popoverController.show(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -8,8 +10,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
import 'dart:math' as math;
|
|
||||||
|
|
||||||
import 'sort_choice_button.dart';
|
import 'sort_choice_button.dart';
|
||||||
import 'sort_editor.dart';
|
import 'sort_editor.dart';
|
||||||
import 'sort_info.dart';
|
import 'sort_info.dart';
|
||||||
@ -24,12 +24,12 @@ class SortMenu extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider<SortMenuBloc>(
|
return BlocProvider(
|
||||||
create: (context) => SortMenuBloc(
|
create: (context) => SortEditorBloc(
|
||||||
viewId: fieldController.viewId,
|
viewId: fieldController.viewId,
|
||||||
fieldController: fieldController,
|
fieldController: fieldController,
|
||||||
)..add(const SortMenuEvent.initial()),
|
),
|
||||||
child: BlocBuilder<SortMenuBloc, SortMenuState>(
|
child: BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.sortInfos.isEmpty) {
|
if (state.sortInfos.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
@ -42,10 +42,9 @@ class SortMenu extends StatelessWidget {
|
|||||||
offset: const Offset(0, 5),
|
offset: const Offset(0, 5),
|
||||||
margin: const EdgeInsets.fromLTRB(6.0, 0.0, 6.0, 6.0),
|
margin: const EdgeInsets.fromLTRB(6.0, 0.0, 6.0, 6.0),
|
||||||
popupBuilder: (BuildContext popoverContext) {
|
popupBuilder: (BuildContext popoverContext) {
|
||||||
return SortEditor(
|
return BlocProvider.value(
|
||||||
viewId: state.viewId,
|
value: context.read<SortEditorBloc>(),
|
||||||
fieldController: context.read<SortMenuBloc>().fieldController,
|
child: const SortEditor(),
|
||||||
sortInfos: state.sortInfos,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: SortChoiceChip(sortInfos: state.sortInfos),
|
child: SortChoiceChip(sortInfos: state.sortInfos),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/setting/setting_button.dart';
|
import 'package:appflowy/plugins/database/widgets/setting/setting_button.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
@ -30,24 +30,16 @@ class GridSettingBar extends StatelessWidget {
|
|||||||
fieldController: controller.fieldController,
|
fieldController: controller.fieldController,
|
||||||
)..add(const GridFilterMenuEvent.initial()),
|
)..add(const GridFilterMenuEvent.initial()),
|
||||||
),
|
),
|
||||||
BlocProvider<SortMenuBloc>(
|
BlocProvider<SortEditorBloc>(
|
||||||
create: (context) => SortMenuBloc(
|
create: (context) => SortEditorBloc(
|
||||||
viewId: controller.viewId,
|
viewId: controller.viewId,
|
||||||
fieldController: controller.fieldController,
|
fieldController: controller.fieldController,
|
||||||
)..add(const SortMenuEvent.initial()),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: MultiBlocListener(
|
child: BlocListener<GridFilterMenuBloc, GridFilterMenuState>(
|
||||||
listeners: [
|
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
||||||
BlocListener<GridFilterMenuBloc, GridFilterMenuState>(
|
listener: (context, state) => toggleExtension.toggle(),
|
||||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
|
||||||
listener: (context, state) => toggleExtension.toggle(),
|
|
||||||
),
|
|
||||||
BlocListener<SortMenuBloc, SortMenuState>(
|
|
||||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
|
||||||
listener: (context, state) => toggleExtension.toggle(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: ValueListenableBuilder<bool>(
|
child: ValueListenableBuilder<bool>(
|
||||||
valueListenable: controller.isLoading,
|
valueListenable: controller.isLoading,
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
@ -61,7 +53,7 @@ class GridSettingBar extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const FilterButton(),
|
const FilterButton(),
|
||||||
const HSpace(2),
|
const HSpace(2),
|
||||||
const SortButton(),
|
SortButton(toggleExtension: toggleExtension),
|
||||||
const HSpace(2),
|
const HSpace(2),
|
||||||
SettingButton(
|
SettingButton(
|
||||||
databaseController: controller,
|
databaseController: controller,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
||||||
|
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
@ -12,7 +13,9 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
|||||||
import '../sort/create_sort_list.dart';
|
import '../sort/create_sort_list.dart';
|
||||||
|
|
||||||
class SortButton extends StatefulWidget {
|
class SortButton extends StatefulWidget {
|
||||||
const SortButton({super.key});
|
const SortButton({super.key, required this.toggleExtension});
|
||||||
|
|
||||||
|
final ToggleExtensionNotifier toggleExtension;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SortButton> createState() => _SortButtonState();
|
State<SortButton> createState() => _SortButtonState();
|
||||||
@ -23,7 +26,7 @@ class _SortButtonState extends State<SortButton> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<SortMenuBloc, SortMenuState>(
|
return BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final textColor = state.sortInfos.isEmpty
|
final textColor = state.sortInfos.isEmpty
|
||||||
? AFThemeExtension.of(context).textColor
|
? AFThemeExtension.of(context).textColor
|
||||||
@ -41,11 +44,10 @@ class _SortButtonState extends State<SortButton> {
|
|||||||
padding: GridSize.toolbarSettingButtonInsets,
|
padding: GridSize.toolbarSettingButtonInsets,
|
||||||
radius: Corners.s4Border,
|
radius: Corners.s4Border,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final bloc = context.read<SortMenuBloc>();
|
if (state.sortInfos.isEmpty) {
|
||||||
if (bloc.state.sortInfos.isEmpty) {
|
|
||||||
_popoverController.show();
|
_popoverController.show();
|
||||||
} else {
|
} else {
|
||||||
bloc.add(const SortMenuEvent.toggleMenu());
|
widget.toggleExtension.toggle();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -54,27 +56,30 @@ class _SortButtonState extends State<SortButton> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget wrapPopover(BuildContext buildContext, Widget child) {
|
Widget wrapPopover(BuildContext context, Widget child) {
|
||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
controller: _popoverController,
|
controller: _popoverController,
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
direction: PopoverDirection.bottomWithLeftAligned,
|
||||||
constraints: BoxConstraints.loose(const Size(200, 300)),
|
constraints: BoxConstraints.loose(const Size(200, 300)),
|
||||||
offset: const Offset(0, 8),
|
offset: const Offset(0, 8),
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
child: child,
|
popupBuilder: (popoverContext) {
|
||||||
popupBuilder: (BuildContext context) {
|
return BlocProvider.value(
|
||||||
final bloc = buildContext.read<SortMenuBloc>();
|
value: context.read<SortEditorBloc>(),
|
||||||
return GridCreateSortList(
|
child: CreateDatabaseViewSortList(
|
||||||
viewId: bloc.viewId,
|
onTap: () {
|
||||||
fieldController: bloc.fieldController,
|
if (!widget.toggleExtension.isToggled) {
|
||||||
onClosed: () => _popoverController.close(),
|
widget.toggleExtension.toggle();
|
||||||
onCreateSort: () {
|
}
|
||||||
if (!bloc.state.isVisible) {
|
_popoverController.close();
|
||||||
bloc.add(const SortMenuEvent.toggleMenu());
|
},
|
||||||
}
|
),
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onClose: () => context
|
||||||
|
.read<SortEditorBloc>()
|
||||||
|
.add(const SortEditorEvent.updateCreateSortFilter("")),
|
||||||
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import 'package:appflowy/mobile/presentation/database/view/database_sort_bottom_
|
|||||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart';
|
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -34,24 +33,16 @@ class MobileDatabaseControls extends StatelessWidget {
|
|||||||
fieldController: controller.fieldController,
|
fieldController: controller.fieldController,
|
||||||
)..add(const GridFilterMenuEvent.initial()),
|
)..add(const GridFilterMenuEvent.initial()),
|
||||||
),
|
),
|
||||||
BlocProvider<SortMenuBloc>(
|
BlocProvider<SortEditorBloc>(
|
||||||
create: (context) => SortMenuBloc(
|
create: (context) => SortEditorBloc(
|
||||||
viewId: controller.viewId,
|
viewId: controller.viewId,
|
||||||
fieldController: controller.fieldController,
|
fieldController: controller.fieldController,
|
||||||
)..add(const SortMenuEvent.initial()),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: MultiBlocListener(
|
child: BlocListener<GridFilterMenuBloc, GridFilterMenuState>(
|
||||||
listeners: [
|
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
||||||
BlocListener<GridFilterMenuBloc, GridFilterMenuState>(
|
listener: (context, state) => toggleExtension.toggle(),
|
||||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
|
||||||
listener: (context, state) => toggleExtension.toggle(),
|
|
||||||
),
|
|
||||||
BlocListener<SortMenuBloc, SortMenuState>(
|
|
||||||
listenWhen: (p, c) => p.isVisible != c.isVisible,
|
|
||||||
listener: (context, state) => toggleExtension.toggle(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: ValueListenableBuilder<bool>(
|
child: ValueListenableBuilder<bool>(
|
||||||
valueListenable: controller.isLoading,
|
valueListenable: controller.isLoading,
|
||||||
builder: (context, isLoading, child) {
|
builder: (context, isLoading, child) {
|
||||||
@ -64,7 +55,7 @@ class MobileDatabaseControls extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_DatabaseControlButton(
|
_DatabaseControlButton(
|
||||||
icon: FlowySvgs.sort_ascending_s,
|
icon: FlowySvgs.sort_ascending_s,
|
||||||
count: context.watch<SortMenuBloc>().state.sortInfos.length,
|
count: context.watch<SortEditorBloc>().state.sortInfos.length,
|
||||||
onTap: () => _showEditSortPanelFromToolbar(
|
onTap: () => _showEditSortPanelFromToolbar(
|
||||||
context,
|
context,
|
||||||
controller,
|
controller,
|
||||||
@ -161,12 +152,8 @@ void _showEditSortPanelFromToolbar(
|
|||||||
showDivider: false,
|
showDivider: false,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return BlocProvider(
|
return BlocProvider.value(
|
||||||
create: (_) => SortEditorBloc(
|
value: context.read<SortEditorBloc>(),
|
||||||
viewId: databaseController.viewId,
|
|
||||||
fieldController: databaseController.fieldController,
|
|
||||||
sortInfos: databaseController.fieldController.sortInfos,
|
|
||||||
)..add(const SortEditorEvent.initial()),
|
|
||||||
child: const MobileSortEditor(),
|
child: const MobileSortEditor(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user