Merge pull request #617 from AppFlowy-IO/feat/add_more_grid_documentation

This commit is contained in:
Nathan.fooo 2022-07-16 21:03:10 +08:00 committed by GitHub
commit c860d1bc0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 82 additions and 74 deletions

View File

@ -1,3 +1,4 @@
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.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 'dart:async'; import 'dart:async';
@ -6,27 +7,32 @@ import 'package:dartz/dartz.dart';
part 'field_editor_bloc.freezed.dart'; part 'field_editor_bloc.freezed.dart';
class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> { class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
final TypeOptionDataController dataController;
FieldEditorBloc({ FieldEditorBloc({
required String gridId, required String gridId,
required String fieldName, required String fieldName,
required IFieldTypeOptionLoader fieldContextLoader, required IFieldTypeOptionLoader loader,
}) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) { }) : dataController = TypeOptionDataController(gridId: gridId, loader: loader),
super(FieldEditorState.initial(gridId, fieldName)) {
on<FieldEditorEvent>( on<FieldEditorEvent>(
(event, emit) async { (event, emit) async {
await event.when( await event.when(
initial: () async { initial: () async {
final fieldContext = GridFieldContext(gridId: gridId, loader: fieldContextLoader); dataController.addFieldListener((field) {
await fieldContext.loadData().then((result) { if (!isClosed) {
result.fold( add(FieldEditorEvent.didReceiveFieldChanged(field));
(l) => emit(state.copyWith(fieldContext: Some(fieldContext), name: fieldContext.field.name)), }
(r) => null,
);
}); });
await dataController.loadData();
}, },
updateName: (name) { updateName: (name) {
state.fieldContext.fold(() => null, (fieldContext) => fieldContext.fieldName = name); dataController.fieldName = name;
emit(state.copyWith(name: name)); emit(state.copyWith(name: name));
}, },
didReceiveFieldChanged: (Field field) {
emit(state.copyWith(field: Some(field)));
},
); );
}, },
); );
@ -42,6 +48,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
class FieldEditorEvent with _$FieldEditorEvent { class FieldEditorEvent with _$FieldEditorEvent {
const factory FieldEditorEvent.initial() = _InitialField; const factory FieldEditorEvent.initial() = _InitialField;
const factory FieldEditorEvent.updateName(String name) = _UpdateName; const factory FieldEditorEvent.updateName(String name) = _UpdateName;
const factory FieldEditorEvent.didReceiveFieldChanged(Field field) = _DidReceiveFieldChanged;
} }
@freezed @freezed
@ -50,13 +57,17 @@ class FieldEditorState with _$FieldEditorState {
required String gridId, required String gridId,
required String errorText, required String errorText,
required String name, required String name,
required Option<GridFieldContext> fieldContext, required Option<Field> field,
}) = _FieldEditorState; }) = _FieldEditorState;
factory FieldEditorState.initial(String gridId, String fieldName, IFieldTypeOptionLoader loader) => FieldEditorState( factory FieldEditorState.initial(
String gridId,
String fieldName,
) =>
FieldEditorState(
gridId: gridId, gridId: gridId,
fieldContext: none(),
errorText: '', errorText: '',
field: none(),
name: fieldName, name: fieldName,
); );
} }

View File

@ -1,4 +1,5 @@
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@ -193,14 +194,14 @@ class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
} }
} }
class GridFieldContext { class TypeOptionDataController {
final String gridId; final String gridId;
final IFieldTypeOptionLoader _loader; final IFieldTypeOptionLoader _loader;
late FieldTypeOptionData _data; late FieldTypeOptionData _data;
ValueNotifier<Field>? _fieldNotifier; final PublishNotifier<Field> _fieldNotifier = PublishNotifier();
GridFieldContext({ TypeOptionDataController({
required this.gridId, required this.gridId,
required IFieldTypeOptionLoader loader, required IFieldTypeOptionLoader loader,
}) : _loader = loader; }) : _loader = loader;
@ -211,13 +212,7 @@ class GridFieldContext {
(data) { (data) {
data.freeze(); data.freeze();
_data = data; _data = data;
_fieldNotifier.value = data.field_2;
if (_fieldNotifier == null) {
_fieldNotifier = ValueNotifier(data.field_2);
} else {
_fieldNotifier?.value = data.field_2;
}
return left(unit); return left(unit);
}, },
(err) { (err) {
@ -260,9 +255,7 @@ class GridFieldContext {
} }
}); });
if (_data.field_2 != _fieldNotifier?.value) { _fieldNotifier.value = _data.field_2;
_fieldNotifier?.value = _data.field_2;
}
FieldService.insertField( FieldService.insertField(
gridId: gridId, gridId: gridId,
@ -292,11 +285,11 @@ class GridFieldContext {
callback(field); callback(field);
} }
_fieldNotifier?.addListener(listener); _fieldNotifier.addListener(listener);
return listener; return listener;
} }
void removeFieldListener(void Function() listener) { void removeFieldListener(void Function() listener) {
_fieldNotifier?.removeListener(listener); _fieldNotifier.removeListener(listener);
} }
} }

View File

@ -8,17 +8,17 @@ import 'field_service.dart';
part 'field_type_option_edit_bloc.freezed.dart'; part 'field_type_option_edit_bloc.freezed.dart';
class FieldTypeOptionEditBloc extends Bloc<FieldTypeOptionEditEvent, FieldTypeOptionEditState> { class FieldTypeOptionEditBloc extends Bloc<FieldTypeOptionEditEvent, FieldTypeOptionEditState> {
final GridFieldContext _fieldContext; final TypeOptionDataController _dataController;
void Function()? _fieldListenFn; void Function()? _fieldListenFn;
FieldTypeOptionEditBloc(GridFieldContext fieldContext) FieldTypeOptionEditBloc(TypeOptionDataController dataController)
: _fieldContext = fieldContext, : _dataController = dataController,
super(FieldTypeOptionEditState.initial(fieldContext)) { super(FieldTypeOptionEditState.initial(dataController)) {
on<FieldTypeOptionEditEvent>( on<FieldTypeOptionEditEvent>(
(event, emit) async { (event, emit) async {
event.when( event.when(
initial: () { initial: () {
_fieldListenFn = fieldContext.addFieldListener((field) { _fieldListenFn = dataController.addFieldListener((field) {
add(FieldTypeOptionEditEvent.didReceiveFieldUpdated(field)); add(FieldTypeOptionEditEvent.didReceiveFieldUpdated(field));
}); });
}, },
@ -33,7 +33,7 @@ class FieldTypeOptionEditBloc extends Bloc<FieldTypeOptionEditEvent, FieldTypeOp
@override @override
Future<void> close() async { Future<void> close() async {
if (_fieldListenFn != null) { if (_fieldListenFn != null) {
_fieldContext.removeFieldListener(_fieldListenFn!); _dataController.removeFieldListener(_fieldListenFn!);
} }
return super.close(); return super.close();
} }
@ -51,7 +51,7 @@ class FieldTypeOptionEditState with _$FieldTypeOptionEditState {
required Field field, required Field field,
}) = _FieldTypeOptionEditState; }) = _FieldTypeOptionEditState;
factory FieldTypeOptionEditState.initial(GridFieldContext fieldContext) => FieldTypeOptionEditState( factory FieldTypeOptionEditState.initial(TypeOptionDataController fieldContext) => FieldTypeOptionEditState(
field: fieldContext.field, field: fieldContext.field,
); );
} }

View File

@ -13,12 +13,12 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTy
MultiSelectTypeOptionContext({ MultiSelectTypeOptionContext({
required MultiSelectTypeOptionWidgetDataParser dataBuilder, required MultiSelectTypeOptionWidgetDataParser dataBuilder,
required GridFieldContext fieldContext, required TypeOptionDataController dataController,
}) : service = TypeOptionService( }) : service = TypeOptionService(
gridId: fieldContext.gridId, gridId: dataController.gridId,
fieldId: fieldContext.field.id, fieldId: dataController.field.id,
), ),
super(dataParser: dataBuilder, fieldContext: fieldContext); super(dataParser: dataBuilder, dataController: dataController);
@override @override
List<SelectOption> Function(SelectOption) get deleteOption { List<SelectOption> Function(SelectOption) get deleteOption {

View File

@ -13,12 +13,12 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelect
SingleSelectTypeOptionContext({ SingleSelectTypeOptionContext({
required SingleSelectTypeOptionWidgetDataParser dataBuilder, required SingleSelectTypeOptionWidgetDataParser dataBuilder,
required GridFieldContext fieldContext, required TypeOptionDataController fieldContext,
}) : service = TypeOptionService( }) : service = TypeOptionService(
gridId: fieldContext.gridId, gridId: fieldContext.gridId,
fieldId: fieldContext.field.id, fieldId: fieldContext.field.id,
), ),
super(dataParser: dataBuilder, fieldContext: fieldContext); super(dataParser: dataBuilder, dataController: fieldContext);
@override @override
List<SelectOption> Function(SelectOption) get deleteOption { List<SelectOption> Function(SelectOption) get deleteOption {

View File

@ -39,30 +39,30 @@ abstract class TypeOptionDataParser<T> {
class TypeOptionWidgetContext<T extends GeneratedMessage> { class TypeOptionWidgetContext<T extends GeneratedMessage> {
T? _typeOptionObject; T? _typeOptionObject;
final GridFieldContext _fieldContext; final TypeOptionDataController _dataController;
final TypeOptionDataParser<T> dataParser; final TypeOptionDataParser<T> dataParser;
TypeOptionWidgetContext({ TypeOptionWidgetContext({
required this.dataParser, required this.dataParser,
required GridFieldContext fieldContext, required TypeOptionDataController dataController,
}) : _fieldContext = fieldContext; }) : _dataController = dataController;
String get gridId => _fieldContext.gridId; String get gridId => _dataController.gridId;
Field get field => _fieldContext.field; Field get field => _dataController.field;
T get typeOption { T get typeOption {
if (_typeOptionObject != null) { if (_typeOptionObject != null) {
return _typeOptionObject!; return _typeOptionObject!;
} }
final T object = dataParser.fromBuffer(_fieldContext.typeOptionData); final T object = dataParser.fromBuffer(_dataController.typeOptionData);
_typeOptionObject = object; _typeOptionObject = object;
return object; return object;
} }
set typeOption(T typeOption) { set typeOption(T typeOption) {
_fieldContext.typeOptionData = typeOption.writeToBuffer(); _dataController.typeOptionData = typeOption.writeToBuffer();
_typeOptionObject = typeOption; _typeOptionObject = typeOption;
} }
} }

View File

@ -65,7 +65,7 @@ class GridFieldCell extends StatelessWidget {
FieldEditor( FieldEditor(
gridId: state.gridId, gridId: state.gridId,
fieldName: field.name, fieldName: field.name,
contextLoader: FieldTypeOptionLoader( typeOptionLoader: FieldTypeOptionLoader(
gridId: state.gridId, gridId: state.gridId,
field: field, field: field,
), ),

View File

@ -14,11 +14,11 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
final String gridId; final String gridId;
final String fieldName; final String fieldName;
final IFieldTypeOptionLoader contextLoader; final IFieldTypeOptionLoader typeOptionLoader;
const FieldEditor({ const FieldEditor({
required this.gridId, required this.gridId,
required this.fieldName, required this.fieldName,
required this.contextLoader, required this.typeOptionLoader,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -28,7 +28,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
create: (context) => FieldEditorBloc( create: (context) => FieldEditorBloc(
gridId: gridId, gridId: gridId,
fieldName: fieldName, fieldName: fieldName,
fieldContextLoader: contextLoader, loader: typeOptionLoader,
)..add(const FieldEditorEvent.initial()), )..add(const FieldEditorEvent.initial()),
child: BlocBuilder<FieldEditorBloc, FieldEditorState>( child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
buildWhen: (p, c) => false, buildWhen: (p, c) => false,
@ -80,11 +80,14 @@ class _FieldTypeOptionCell extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<FieldEditorBloc, FieldEditorState>( return BlocBuilder<FieldEditorBloc, FieldEditorState>(
buildWhen: (p, c) => p.fieldContext != c.fieldContext, buildWhen: (p, c) => p.field != c.field,
builder: (context, state) { builder: (context, state) {
return state.fieldContext.fold( return state.field.fold(
() => const SizedBox(), () => const SizedBox(),
(fieldContext) => FieldTypeOptionEditor(fieldContext: fieldContext), (fieldContext) {
final dataController = context.read<FieldEditorBloc>().dataController;
return FieldTypeOptionEditor(dataController: dataController);
},
); );
}, },
); );

View File

@ -22,10 +22,10 @@ typedef SwitchToFieldCallback = Future<Either<FieldTypeOptionData, FlowyError>>
); );
class FieldTypeOptionEditor extends StatefulWidget { class FieldTypeOptionEditor extends StatefulWidget {
final GridFieldContext fieldContext; final TypeOptionDataController dataController;
const FieldTypeOptionEditor({ const FieldTypeOptionEditor({
required this.fieldContext, required this.dataController,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -39,10 +39,11 @@ class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => FieldTypeOptionEditBloc(widget.fieldContext)..add(const FieldTypeOptionEditEvent.initial()), create: (context) =>
FieldTypeOptionEditBloc(widget.dataController)..add(const FieldTypeOptionEditEvent.initial()),
child: BlocBuilder<FieldTypeOptionEditBloc, FieldTypeOptionEditState>( child: BlocBuilder<FieldTypeOptionEditBloc, FieldTypeOptionEditState>(
builder: (context, state) { builder: (context, state) {
List<Widget> children = [_switchFieldTypeButton(context, widget.fieldContext.field)]; List<Widget> children = [_switchFieldTypeButton(context, widget.dataController.field)];
final typeOptionWidget = _typeOptionWidget(context: context, state: state); final typeOptionWidget = _typeOptionWidget(context: context, state: state);
if (typeOptionWidget != null) { if (typeOptionWidget != null) {
@ -68,7 +69,7 @@ class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () { onTap: () {
final list = FieldTypeList(onSelectField: (newFieldType) { final list = FieldTypeList(onSelectField: (newFieldType) {
widget.fieldContext.switchToField(newFieldType); widget.dataController.switchToField(newFieldType);
}); });
_showOverlay(context, list); _showOverlay(context, list);
}, },
@ -89,7 +90,7 @@ class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
return makeTypeOptionWidget( return makeTypeOptionWidget(
context: context, context: context,
fieldContext: widget.fieldContext, dataController: widget.dataController,
overlayDelegate: overlayDelegate, overlayDelegate: overlayDelegate,
); );
} }

View File

@ -151,7 +151,7 @@ class CreateFieldButton extends StatelessWidget {
onTap: () => FieldEditor( onTap: () => FieldEditor(
gridId: gridId, gridId: gridId,
fieldName: "", fieldName: "",
contextLoader: NewFieldTypeOptionLoader(gridId: gridId), typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
).show(context), ).show(context),
leftIcon: svgWidget("home/add"), leftIcon: svgWidget("home/add"),
); );

View File

@ -36,27 +36,27 @@ abstract class TypeOptionWidgetBuilder {
Widget? makeTypeOptionWidget({ Widget? makeTypeOptionWidget({
required BuildContext context, required BuildContext context,
required GridFieldContext fieldContext, required TypeOptionDataController dataController,
required TypeOptionOverlayDelegate overlayDelegate, required TypeOptionOverlayDelegate overlayDelegate,
}) { }) {
final builder = makeTypeOptionWidgetBuilder(fieldContext, overlayDelegate); final builder = makeTypeOptionWidgetBuilder(dataController, overlayDelegate);
return builder.build(context); return builder.build(context);
} }
TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
GridFieldContext fieldContext, TypeOptionDataController dataController,
TypeOptionOverlayDelegate overlayDelegate, TypeOptionOverlayDelegate overlayDelegate,
) { ) {
switch (fieldContext.field.fieldType) { switch (dataController.field.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
final context = CheckboxTypeOptionContext( final context = CheckboxTypeOptionContext(
fieldContext: fieldContext, dataController: dataController,
dataParser: CheckboxTypeOptionWidgetDataParser(), dataParser: CheckboxTypeOptionWidgetDataParser(),
); );
return CheckboxTypeOptionWidgetBuilder(context); return CheckboxTypeOptionWidgetBuilder(context);
case FieldType.DateTime: case FieldType.DateTime:
final context = DateTypeOptionContext( final context = DateTypeOptionContext(
fieldContext: fieldContext, dataController: dataController,
dataParser: DateTypeOptionDataParser(), dataParser: DateTypeOptionDataParser(),
); );
return DateTypeOptionWidgetBuilder( return DateTypeOptionWidgetBuilder(
@ -65,7 +65,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
); );
case FieldType.SingleSelect: case FieldType.SingleSelect:
final context = SingleSelectTypeOptionContext( final context = SingleSelectTypeOptionContext(
fieldContext: fieldContext, fieldContext: dataController,
dataBuilder: SingleSelectTypeOptionWidgetDataParser(), dataBuilder: SingleSelectTypeOptionWidgetDataParser(),
); );
return SingleSelectTypeOptionWidgetBuilder( return SingleSelectTypeOptionWidgetBuilder(
@ -74,7 +74,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
); );
case FieldType.MultiSelect: case FieldType.MultiSelect:
final context = MultiSelectTypeOptionContext( final context = MultiSelectTypeOptionContext(
fieldContext: fieldContext, dataController: dataController,
dataBuilder: MultiSelectTypeOptionWidgetDataParser(), dataBuilder: MultiSelectTypeOptionWidgetDataParser(),
); );
return MultiSelectTypeOptionWidgetBuilder( return MultiSelectTypeOptionWidgetBuilder(
@ -83,7 +83,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
); );
case FieldType.Number: case FieldType.Number:
final context = NumberTypeOptionContext( final context = NumberTypeOptionContext(
fieldContext: fieldContext, dataController: dataController,
dataParser: NumberTypeOptionWidgetDataParser(), dataParser: NumberTypeOptionWidgetDataParser(),
); );
return NumberTypeOptionWidgetBuilder( return NumberTypeOptionWidgetBuilder(
@ -92,14 +92,14 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
); );
case FieldType.RichText: case FieldType.RichText:
final context = RichTextTypeOptionContext( final context = RichTextTypeOptionContext(
fieldContext: fieldContext, dataController: dataController,
dataParser: RichTextTypeOptionWidgetDataParser(), dataParser: RichTextTypeOptionWidgetDataParser(),
); );
return RichTextTypeOptionWidgetBuilder(context); return RichTextTypeOptionWidgetBuilder(context);
case FieldType.URL: case FieldType.URL:
final context = URLTypeOptionContext( final context = URLTypeOptionContext(
fieldContext: fieldContext, dataController: dataController,
dataParser: URLTypeOptionWidgetDataParser(), dataParser: URLTypeOptionWidgetDataParser(),
); );
return URLTypeOptionWidgetBuilder(context); return URLTypeOptionWidgetBuilder(context);

View File

@ -183,7 +183,7 @@ class _RowDetailCell extends StatelessWidget {
FieldEditor( FieldEditor(
gridId: cellId.gridId, gridId: cellId.gridId,
fieldName: cellId.field.name, fieldName: cellId.field.name,
contextLoader: FieldTypeOptionLoader( typeOptionLoader: FieldTypeOptionLoader(
gridId: cellId.gridId, gridId: cellId.gridId,
field: cellId.field, field: cellId.field,
), ),

View File

@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget {
FieldEditor( FieldEditor(
gridId: gridId, gridId: gridId,
fieldName: field.name, fieldName: field.name,
contextLoader: FieldTypeOptionLoader(gridId: gridId, field: field), typeOptionLoader: FieldTypeOptionLoader(gridId: gridId, field: field),
).show(context, anchorDirection: AnchorDirection.bottomRight); ).show(context, anchorDirection: AnchorDirection.bottomRight);
}, },
); );