mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: add GridFieldContext
This commit is contained in:
@ -15,7 +15,6 @@ import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
|||||||
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
|
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldTypeOptionData;
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||||
@ -157,13 +156,6 @@ void _resolveGridDeps(GetIt getIt) {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<FieldEditorBloc, String, FieldContextLoader>(
|
|
||||||
(gridId, fieldLoader) => FieldEditorBloc(
|
|
||||||
gridId: gridId,
|
|
||||||
fieldLoader: fieldLoader,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
getIt.registerFactoryParam<TextCellBloc, GridCellContext, void>(
|
getIt.registerFactoryParam<TextCellBloc, GridCellContext, void>(
|
||||||
(context, _) => TextCellBloc(
|
(context, _) => TextCellBloc(
|
||||||
cellContext: context,
|
cellContext: context,
|
||||||
@ -195,10 +187,6 @@ void _resolveGridDeps(GetIt getIt) {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<FieldEditorPannelBloc, FieldTypeOptionData, void>(
|
|
||||||
(context, _) => FieldEditorPannelBloc(context),
|
|
||||||
);
|
|
||||||
|
|
||||||
getIt.registerFactoryParam<DateTypeOptionBloc, DateTypeOption, void>(
|
getIt.registerFactoryParam<DateTypeOptionBloc, DateTypeOption, void>(
|
||||||
(typeOption, _) => DateTypeOptionBloc(typeOption: typeOption),
|
(typeOption, _) => DateTypeOptionBloc(typeOption: typeOption),
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,7 @@ class GridCellContextBuilder {
|
|||||||
return GridCellContext(
|
return GridCellContext(
|
||||||
gridCell: _gridCell,
|
gridCell: _gridCell,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: CellDataLoader(gridCell: _gridCell),
|
cellDataLoader: GridCellDataLoader(gridCell: _gridCell),
|
||||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
@ -30,17 +30,24 @@ class GridCellContextBuilder {
|
|||||||
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
|
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
|
||||||
);
|
);
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
|
final cellDataLoader = GridCellDataLoader(
|
||||||
|
gridCell: _gridCell,
|
||||||
|
config: const GridCellDataConfig(
|
||||||
|
reloadOnCellChanged: true,
|
||||||
|
reloadOnFieldChanged: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
return GridCellContext(
|
return GridCellContext(
|
||||||
gridCell: _gridCell,
|
gridCell: _gridCell,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: CellDataLoader(gridCell: _gridCell, reloadOnCellChanged: true),
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||||
);
|
);
|
||||||
case FieldType.RichText:
|
case FieldType.RichText:
|
||||||
return GridCellContext(
|
return GridCellContext(
|
||||||
gridCell: _gridCell,
|
gridCell: _gridCell,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: CellDataLoader(gridCell: _gridCell),
|
cellDataLoader: GridCellDataLoader(gridCell: _gridCell),
|
||||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||||
);
|
);
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
@ -62,7 +69,7 @@ class _GridCellContext<T, D> extends Equatable {
|
|||||||
final GridCell gridCell;
|
final GridCell gridCell;
|
||||||
final GridCellCache cellCache;
|
final GridCellCache cellCache;
|
||||||
final GridCellCacheKey _cacheKey;
|
final GridCellCacheKey _cacheKey;
|
||||||
final _GridCellDataLoader<T> cellDataLoader;
|
final IGridCellDataLoader<T> cellDataLoader;
|
||||||
final _GridCellDataPersistence<D> cellDataPersistence;
|
final _GridCellDataPersistence<D> cellDataPersistence;
|
||||||
final FieldService _fieldService;
|
final FieldService _fieldService;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
part of 'cell_service.dart';
|
part of 'cell_service.dart';
|
||||||
|
|
||||||
abstract class GridCellDataConfig {
|
abstract class IGridCellDataConfig {
|
||||||
// The cell data will reload if it receives the field's change notification.
|
// The cell data will reload if it receives the field's change notification.
|
||||||
bool get reloadOnFieldChanged;
|
bool get reloadOnFieldChanged;
|
||||||
|
|
||||||
@ -11,34 +11,36 @@ abstract class GridCellDataConfig {
|
|||||||
bool get reloadOnCellChanged;
|
bool get reloadOnCellChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultCellDataConfig implements GridCellDataConfig {
|
class GridCellDataConfig implements IGridCellDataConfig {
|
||||||
@override
|
@override
|
||||||
final bool reloadOnCellChanged;
|
final bool reloadOnCellChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final bool reloadOnFieldChanged;
|
final bool reloadOnFieldChanged;
|
||||||
|
|
||||||
DefaultCellDataConfig({
|
const GridCellDataConfig({
|
||||||
this.reloadOnCellChanged = false,
|
this.reloadOnCellChanged = false,
|
||||||
this.reloadOnFieldChanged = false,
|
this.reloadOnFieldChanged = false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _GridCellDataLoader<T> {
|
abstract class IGridCellDataLoader<T> {
|
||||||
Future<T?> loadData();
|
Future<T?> loadData();
|
||||||
|
|
||||||
GridCellDataConfig get config;
|
IGridCellDataConfig get config;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CellDataLoader extends _GridCellDataLoader<Cell> {
|
class GridCellDataLoader extends IGridCellDataLoader<Cell> {
|
||||||
final CellService service = CellService();
|
final CellService service = CellService();
|
||||||
final GridCell gridCell;
|
final GridCell gridCell;
|
||||||
final GridCellDataConfig _config;
|
|
||||||
|
|
||||||
CellDataLoader({
|
@override
|
||||||
|
final IGridCellDataConfig config;
|
||||||
|
|
||||||
|
GridCellDataLoader({
|
||||||
required this.gridCell,
|
required this.gridCell,
|
||||||
bool reloadOnCellChanged = false,
|
this.config = const GridCellDataConfig(),
|
||||||
}) : _config = DefaultCellDataConfig(reloadOnCellChanged: reloadOnCellChanged);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Cell?> loadData() {
|
Future<Cell?> loadData() {
|
||||||
@ -54,20 +56,17 @@ class CellDataLoader extends _GridCellDataLoader<Cell> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
GridCellDataConfig get config => _config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DateCellDataLoader extends _GridCellDataLoader<DateCellData> {
|
class DateCellDataLoader extends IGridCellDataLoader<DateCellData> {
|
||||||
final GridCell gridCell;
|
final GridCell gridCell;
|
||||||
final GridCellDataConfig _config;
|
final IGridCellDataConfig _config;
|
||||||
DateCellDataLoader({
|
DateCellDataLoader({
|
||||||
required this.gridCell,
|
required this.gridCell,
|
||||||
}) : _config = DefaultCellDataConfig(reloadOnFieldChanged: true);
|
}) : _config = const GridCellDataConfig(reloadOnFieldChanged: true);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GridCellDataConfig get config => _config;
|
IGridCellDataConfig get config => _config;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DateCellData?> loadData() {
|
Future<DateCellData?> loadData() {
|
||||||
@ -88,7 +87,7 @@ class DateCellDataLoader extends _GridCellDataLoader<DateCellData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SelectOptionCellDataLoader extends _GridCellDataLoader<SelectOptionCellData> {
|
class SelectOptionCellDataLoader extends IGridCellDataLoader<SelectOptionCellData> {
|
||||||
final SelectOptionService service;
|
final SelectOptionService service;
|
||||||
final GridCell gridCell;
|
final GridCell gridCell;
|
||||||
SelectOptionCellDataLoader({
|
SelectOptionCellDataLoader({
|
||||||
@ -108,5 +107,5 @@ class SelectOptionCellDataLoader extends _GridCellDataLoader<SelectOptionCellDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GridCellDataConfig get config => DefaultCellDataConfig();
|
IGridCellDataConfig get config => const GridCellDataConfig(reloadOnFieldChanged: true);
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,31 @@
|
|||||||
import 'dart:typed_data';
|
|
||||||
import 'package:flowy_sdk/log.dart';
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.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';
|
||||||
import 'field_service.dart';
|
import 'field_service.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:protobuf/protobuf.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 String gridId;
|
|
||||||
final FieldContextLoader _loader;
|
|
||||||
|
|
||||||
FieldEditorBloc({
|
FieldEditorBloc({
|
||||||
required this.gridId,
|
required String gridId,
|
||||||
required FieldContextLoader fieldLoader,
|
required String fieldName,
|
||||||
}) : _loader = fieldLoader,
|
required FieldContextLoader fieldContextLoader,
|
||||||
super(FieldEditorState.initial(gridId)) {
|
}) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) {
|
||||||
on<FieldEditorEvent>(
|
on<FieldEditorEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.map(
|
await event.when(
|
||||||
initial: (_InitialField value) async {
|
initial: () async {
|
||||||
await _getFieldTypeOptionContext(emit);
|
final fieldContext = GridFieldContext(gridId: gridId, loader: fieldContextLoader);
|
||||||
|
await fieldContext.loadData().then((result) {
|
||||||
|
result.fold(
|
||||||
|
(l) => emit(state.copyWith(fieldContext: Some(fieldContext))),
|
||||||
|
(r) => null,
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
updateName: (_UpdateName value) {
|
updateName: (name) {
|
||||||
final newContext = _updateEditContext(name: value.name);
|
state.fieldContext.fold(() => null, (fieldContext) => fieldContext.fieldName = name);
|
||||||
emit(state.copyWith(fieldTypeOptionData: newContext));
|
emit(state.copyWith(name: name));
|
||||||
},
|
|
||||||
updateField: (_UpdateField value) {
|
|
||||||
final data = _updateEditContext(field: value.field, typeOptionData: value.typeOptionData);
|
|
||||||
emit(state.copyWith(fieldTypeOptionData: data));
|
|
||||||
},
|
|
||||||
done: (_Done value) async {
|
|
||||||
await _saveField(emit);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -45,78 +36,12 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Option<FieldTypeOptionData> _updateEditContext({
|
|
||||||
String? name,
|
|
||||||
Field? field,
|
|
||||||
List<int>? typeOptionData,
|
|
||||||
}) {
|
|
||||||
return state.fieldTypeOptionData.fold(
|
|
||||||
() => none(),
|
|
||||||
(context) {
|
|
||||||
context.freeze();
|
|
||||||
final newFieldTypeOptionData = context.rebuild((newContext) {
|
|
||||||
newContext.field_2.rebuild((newField) {
|
|
||||||
if (name != null) {
|
|
||||||
newField.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
newContext.field_2 = newField;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (field != null) {
|
|
||||||
newContext.field_2 = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeOptionData != null) {
|
|
||||||
newContext.typeOptionData = typeOptionData;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
FieldService.insertField(
|
|
||||||
gridId: gridId,
|
|
||||||
field: newFieldTypeOptionData.field_2,
|
|
||||||
typeOptionData: newFieldTypeOptionData.typeOptionData,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Some(newFieldTypeOptionData);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _saveField(Emitter<FieldEditorState> emit) async {
|
|
||||||
await state.fieldTypeOptionData.fold(
|
|
||||||
() async => null,
|
|
||||||
(data) async {
|
|
||||||
final result = await FieldService.insertField(
|
|
||||||
gridId: gridId,
|
|
||||||
field: data.field_2,
|
|
||||||
typeOptionData: data.typeOptionData,
|
|
||||||
);
|
|
||||||
result.fold((l) => null, (r) => null);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _getFieldTypeOptionContext(Emitter<FieldEditorState> emit) async {
|
|
||||||
final result = await _loader.load();
|
|
||||||
result.fold(
|
|
||||||
(context) {
|
|
||||||
emit(state.copyWith(
|
|
||||||
fieldTypeOptionData: Some(context),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
(err) => Log.error(err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
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.updateField(Field field, Uint8List typeOptionData) = _UpdateField;
|
|
||||||
const factory FieldEditorEvent.done() = _Done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
@ -124,12 +49,14 @@ class FieldEditorState with _$FieldEditorState {
|
|||||||
const factory FieldEditorState({
|
const factory FieldEditorState({
|
||||||
required String gridId,
|
required String gridId,
|
||||||
required String errorText,
|
required String errorText,
|
||||||
required Option<FieldTypeOptionData> fieldTypeOptionData,
|
required String name,
|
||||||
|
required Option<GridFieldContext> fieldContext,
|
||||||
}) = _FieldEditorState;
|
}) = _FieldEditorState;
|
||||||
|
|
||||||
factory FieldEditorState.initial(String gridId) => FieldEditorState(
|
factory FieldEditorState.initial(String gridId, String fieldName, FieldContextLoader loader) => FieldEditorState(
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
fieldTypeOptionData: none(),
|
fieldContext: none(),
|
||||||
errorText: '',
|
errorText: '',
|
||||||
|
name: fieldName,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
import 'dart:typed_data';
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.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';
|
||||||
|
|
||||||
|
import 'field_service.dart';
|
||||||
|
|
||||||
part 'field_editor_pannel_bloc.freezed.dart';
|
part 'field_editor_pannel_bloc.freezed.dart';
|
||||||
|
|
||||||
class FieldEditorPannelBloc extends Bloc<FieldEditorPannelEvent, FieldEditorPannelState> {
|
class FieldEditorPannelBloc extends Bloc<FieldEditorPannelEvent, FieldEditorPannelState> {
|
||||||
FieldEditorPannelBloc(FieldTypeOptionData editContext) : super(FieldEditorPannelState.initial(editContext)) {
|
final GridFieldContext _fieldContext;
|
||||||
|
void Function()? _fieldListenFn;
|
||||||
|
|
||||||
|
FieldEditorPannelBloc(GridFieldContext fieldContext)
|
||||||
|
: _fieldContext = fieldContext,
|
||||||
|
super(FieldEditorPannelState.initial(fieldContext)) {
|
||||||
on<FieldEditorPannelEvent>(
|
on<FieldEditorPannelEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.map(
|
event.when(
|
||||||
toFieldType: (_ToFieldType value) async {
|
initial: () {
|
||||||
emit(state.copyWith(
|
_fieldListenFn = fieldContext.addFieldListener((field) {
|
||||||
field: value.field,
|
add(FieldEditorPannelEvent.didReceiveFieldUpdated(field));
|
||||||
typeOptionData: Uint8List.fromList(value.typeOptionData),
|
});
|
||||||
));
|
|
||||||
},
|
},
|
||||||
didUpdateTypeOptionData: (_DidUpdateTypeOptionData value) {
|
didReceiveFieldUpdated: (field) {
|
||||||
emit(state.copyWith(typeOptionData: value.typeOptionData));
|
emit(state.copyWith(field: field));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -27,27 +32,26 @@ class FieldEditorPannelBloc extends Bloc<FieldEditorPannelEvent, FieldEditorPann
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
|
if (_fieldListenFn != null) {
|
||||||
|
_fieldContext.removeFieldListener(_fieldListenFn!);
|
||||||
|
}
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class FieldEditorPannelEvent with _$FieldEditorPannelEvent {
|
class FieldEditorPannelEvent with _$FieldEditorPannelEvent {
|
||||||
const factory FieldEditorPannelEvent.toFieldType(Field field, List<int> typeOptionData) = _ToFieldType;
|
const factory FieldEditorPannelEvent.initial() = _Initial;
|
||||||
const factory FieldEditorPannelEvent.didUpdateTypeOptionData(Uint8List typeOptionData) = _DidUpdateTypeOptionData;
|
const factory FieldEditorPannelEvent.didReceiveFieldUpdated(Field field) = _DidReceiveFieldUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class FieldEditorPannelState with _$FieldEditorPannelState {
|
class FieldEditorPannelState with _$FieldEditorPannelState {
|
||||||
const factory FieldEditorPannelState({
|
const factory FieldEditorPannelState({
|
||||||
required String gridId,
|
|
||||||
required Field field,
|
required Field field,
|
||||||
required Uint8List typeOptionData,
|
|
||||||
}) = _FieldEditorPannelState;
|
}) = _FieldEditorPannelState;
|
||||||
|
|
||||||
factory FieldEditorPannelState.initial(FieldTypeOptionData data) => FieldEditorPannelState(
|
factory FieldEditorPannelState.initial(GridFieldContext fieldContext) => FieldEditorPannelState(
|
||||||
gridId: data.gridId,
|
field: fieldContext.field,
|
||||||
field: data.field_2,
|
|
||||||
typeOptionData: Uint8List.fromList(data.typeOptionData),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.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/protobuf/flowy-error/errors.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:protobuf/protobuf.dart';
|
||||||
part 'field_service.freezed.dart';
|
part 'field_service.freezed.dart';
|
||||||
|
|
||||||
class FieldService {
|
class FieldService {
|
||||||
@ -199,3 +202,111 @@ class DefaultFieldContextLoader extends FieldContextLoader {
|
|||||||
return fieldService.switchToField(fieldType);
|
return fieldService.switchToField(fieldType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GridFieldContext {
|
||||||
|
final String gridId;
|
||||||
|
final FieldContextLoader _loader;
|
||||||
|
|
||||||
|
late FieldTypeOptionData _data;
|
||||||
|
ValueNotifier<Field>? _fieldNotifier;
|
||||||
|
|
||||||
|
GridFieldContext({
|
||||||
|
required this.gridId,
|
||||||
|
required FieldContextLoader loader,
|
||||||
|
}) : _loader = loader;
|
||||||
|
|
||||||
|
Future<Either<Unit, FlowyError>> loadData() async {
|
||||||
|
final result = await _loader.load();
|
||||||
|
return result.fold(
|
||||||
|
(data) {
|
||||||
|
data.freeze();
|
||||||
|
_data = data;
|
||||||
|
|
||||||
|
if (_fieldNotifier == null) {
|
||||||
|
_fieldNotifier = ValueNotifier(data.field_2);
|
||||||
|
} else {
|
||||||
|
_fieldNotifier?.value = data.field_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return left(unit);
|
||||||
|
},
|
||||||
|
(err) {
|
||||||
|
Log.error(err);
|
||||||
|
return right(err);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field get field => _data.field_2;
|
||||||
|
|
||||||
|
set field(Field field) {
|
||||||
|
_updateData(newField: field);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> get typeOptionData => _data.typeOptionData;
|
||||||
|
|
||||||
|
set fieldName(String name) {
|
||||||
|
_updateData(name: name);
|
||||||
|
}
|
||||||
|
|
||||||
|
set typeOptionData(List<int> typeOptionData) {
|
||||||
|
_updateData(typeOptionData: typeOptionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateData({String? name, Field? newField, List<int>? typeOptionData}) {
|
||||||
|
_data = _data.rebuild((rebuildData) {
|
||||||
|
if (name != null) {
|
||||||
|
rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
|
||||||
|
rebuildField.name = name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newField != null) {
|
||||||
|
rebuildData.field_2 = newField;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeOptionData != null) {
|
||||||
|
rebuildData.typeOptionData = typeOptionData;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_data.field_2 != _fieldNotifier?.value) {
|
||||||
|
_fieldNotifier?.value = _data.field_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldService.insertField(
|
||||||
|
gridId: gridId,
|
||||||
|
field: field,
|
||||||
|
typeOptionData: typeOptionData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> switchToField(FieldType newFieldType) {
|
||||||
|
return _loader.switchToField(field.id, newFieldType).then((result) {
|
||||||
|
return result.fold(
|
||||||
|
(fieldTypeOptionData) {
|
||||||
|
_updateData(
|
||||||
|
newField: fieldTypeOptionData.field_2,
|
||||||
|
typeOptionData: fieldTypeOptionData.typeOptionData,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(err) {
|
||||||
|
Log.error(err);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Function() addFieldListener(void Function(Field) callback) {
|
||||||
|
listener() {
|
||||||
|
callback(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fieldNotifier?.addListener(listener);
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFieldListener(void Function() listener) {
|
||||||
|
_fieldNotifier?.removeListener(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -38,15 +38,17 @@ abstract class TypeOptionDataBuilder<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TypeOptionContext {
|
class TypeOptionContext {
|
||||||
final String gridId;
|
final GridFieldContext _fieldContext;
|
||||||
final Field field;
|
|
||||||
final Uint8List data;
|
|
||||||
|
|
||||||
TypeOptionContext({
|
TypeOptionContext({
|
||||||
required this.gridId,
|
required GridFieldContext fieldContext,
|
||||||
required this.field,
|
}) : _fieldContext = fieldContext;
|
||||||
required this.data,
|
|
||||||
});
|
String get gridId => _fieldContext.gridId;
|
||||||
|
|
||||||
|
Field get field => _fieldContext.field;
|
||||||
|
|
||||||
|
Uint8List get data => Uint8List.fromList(_fieldContext.typeOptionData);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TypeOptionFieldDelegate {
|
abstract class TypeOptionFieldDelegate {
|
||||||
|
@ -224,48 +224,46 @@ class _SelectOptionCell extends StatelessWidget {
|
|||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: GridSize.typeOptionItemHeight,
|
height: GridSize.typeOptionItemHeight,
|
||||||
child: Stack(
|
child: Row(
|
||||||
fit: StackFit.expand,
|
|
||||||
children: [
|
children: [
|
||||||
_body(theme, context),
|
Expanded(child: _body(theme, context)),
|
||||||
InkWell(
|
FlowyIconButton(
|
||||||
onTap: () {
|
width: 30,
|
||||||
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.selectOption(option.id));
|
onPressed: () => _showEditPannel(context),
|
||||||
},
|
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
||||||
),
|
icon: svgWidget("editor/details", color: theme.iconColor),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlowyHover _body(AppTheme theme, BuildContext context) {
|
Widget _body(AppTheme theme, BuildContext context) {
|
||||||
return FlowyHover(
|
return Stack(
|
||||||
style: HoverStyle(hoverColor: theme.hover),
|
fit: StackFit.expand,
|
||||||
builder: (_, onHover) {
|
children: [
|
||||||
List<Widget> children = [
|
FlowyHover(
|
||||||
SelectOptionTag(
|
style: HoverStyle(hoverColor: theme.hover),
|
||||||
name: option.name,
|
builder: (_, onHover) {
|
||||||
color: option.color.make(context),
|
return InkWell(
|
||||||
isSelected: isSelected,
|
child: Row(children: [
|
||||||
),
|
const HSpace(6),
|
||||||
const Spacer(),
|
SelectOptionTag(
|
||||||
];
|
name: option.name,
|
||||||
|
color: option.color.make(context),
|
||||||
if (isSelected) {
|
isSelected: isSelected,
|
||||||
children.add(svgWidget("grid/checkmark"));
|
),
|
||||||
}
|
const Spacer(),
|
||||||
|
if (isSelected) svgWidget("grid/checkmark"),
|
||||||
if (onHover) {
|
const HSpace(6),
|
||||||
children.add(FlowyIconButton(
|
]),
|
||||||
width: 30,
|
onTap: () {
|
||||||
onPressed: () => _showEditPannel(context),
|
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.selectOption(option.id));
|
||||||
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
},
|
||||||
icon: svgWidget("editor/details", color: theme.iconColor),
|
);
|
||||||
));
|
},
|
||||||
}
|
),
|
||||||
|
],
|
||||||
return Row(children: children);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ class GridFieldCell extends StatelessWidget {
|
|||||||
|
|
||||||
FieldEditor(
|
FieldEditor(
|
||||||
gridId: state.gridId,
|
gridId: state.gridId,
|
||||||
|
fieldName: state.field.name,
|
||||||
contextLoader: DefaultFieldContextLoader(
|
contextLoader: DefaultFieldContextLoader(
|
||||||
gridId: state.gridId,
|
gridId: state.gridId,
|
||||||
field: state.field,
|
field: state.field,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:app_flowy/startup/startup.dart';
|
|
||||||
import 'package:app_flowy/workspace/application/grid/field/field_editor_bloc.dart';
|
import 'package:app_flowy/workspace/application/grid/field/field_editor_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -11,16 +10,42 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
|
|||||||
import 'field_name_input.dart';
|
import 'field_name_input.dart';
|
||||||
import 'field_editor_pannel.dart';
|
import 'field_editor_pannel.dart';
|
||||||
|
|
||||||
class FieldEditor extends FlowyOverlayDelegate {
|
class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
final String gridId;
|
final String gridId;
|
||||||
final FieldEditorBloc _fieldEditorBloc;
|
final String fieldName;
|
||||||
|
|
||||||
final FieldContextLoader contextLoader;
|
final FieldContextLoader contextLoader;
|
||||||
FieldEditor({
|
const FieldEditor({
|
||||||
required this.gridId,
|
required this.gridId,
|
||||||
|
required this.fieldName,
|
||||||
required this.contextLoader,
|
required this.contextLoader,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : _fieldEditorBloc = getIt<FieldEditorBloc>(param1: gridId, param2: contextLoader) {
|
}) : super(key: key);
|
||||||
_fieldEditorBloc.add(const FieldEditorEvent.initial());
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) => FieldEditorBloc(
|
||||||
|
gridId: gridId,
|
||||||
|
fieldName: fieldName,
|
||||||
|
fieldContextLoader: contextLoader,
|
||||||
|
)..add(const FieldEditorEvent.initial()),
|
||||||
|
child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
|
buildWhen: (p, c) => false,
|
||||||
|
builder: (context, state) {
|
||||||
|
return ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
children: [
|
||||||
|
FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12),
|
||||||
|
const VSpace(10),
|
||||||
|
const _FieldNameTextField(),
|
||||||
|
const VSpace(10),
|
||||||
|
const _FieldPannel(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void show(
|
void show(
|
||||||
@ -28,10 +53,9 @@ class FieldEditor extends FlowyOverlayDelegate {
|
|||||||
AnchorDirection anchorDirection = AnchorDirection.bottomWithLeftAligned,
|
AnchorDirection anchorDirection = AnchorDirection.bottomWithLeftAligned,
|
||||||
}) {
|
}) {
|
||||||
FlowyOverlay.of(context).remove(identifier());
|
FlowyOverlay.of(context).remove(identifier());
|
||||||
final child = _FieldEditorPage(_fieldEditorBloc, contextLoader);
|
|
||||||
FlowyOverlay.of(context).insertWithAnchor(
|
FlowyOverlay.of(context).insertWithAnchor(
|
||||||
widget: OverlayContainer(
|
widget: OverlayContainer(
|
||||||
child: child,
|
child: this,
|
||||||
constraints: BoxConstraints.loose(const Size(280, 400)),
|
constraints: BoxConstraints.loose(const Size(280, 400)),
|
||||||
),
|
),
|
||||||
identifier: identifier(),
|
identifier: identifier(),
|
||||||
@ -46,49 +70,23 @@ class FieldEditor extends FlowyOverlayDelegate {
|
|||||||
return (FieldEditor).toString();
|
return (FieldEditor).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void didRemove() {
|
|
||||||
_fieldEditorBloc.add(const FieldEditorEvent.done());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool asBarrier() => true;
|
bool asBarrier() => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FieldEditorPage extends StatelessWidget {
|
class _FieldPannel extends StatelessWidget {
|
||||||
final FieldEditorBloc editorBloc;
|
const _FieldPannel({Key? key}) : super(key: key);
|
||||||
final FieldContextLoader contextLoader;
|
|
||||||
const _FieldEditorPage(this.editorBloc, this.contextLoader, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider.value(
|
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
value: editorBloc,
|
buildWhen: (p, c) => p.fieldContext != c.fieldContext,
|
||||||
child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
builder: (context, state) {
|
||||||
builder: (context, state) {
|
return state.fieldContext.fold(
|
||||||
return state.fieldTypeOptionData.fold(
|
() => const SizedBox(),
|
||||||
() => const SizedBox(),
|
(fieldContext) => FieldEditorPannel(fieldContext: fieldContext),
|
||||||
(fieldTypeOptionContext) => ListView(
|
);
|
||||||
shrinkWrap: true,
|
},
|
||||||
children: [
|
|
||||||
FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12),
|
|
||||||
const VSpace(10),
|
|
||||||
const _FieldNameTextField(),
|
|
||||||
const VSpace(10),
|
|
||||||
FieldEditorPannel(
|
|
||||||
fieldTypeOptionData: fieldTypeOptionContext,
|
|
||||||
onSwitchToField: (fieldId, fieldType) {
|
|
||||||
return contextLoader.switchToField(fieldId, fieldType);
|
|
||||||
},
|
|
||||||
onUpdated: (field, typeOptionData) {
|
|
||||||
context.read<FieldEditorBloc>().add(FieldEditorEvent.updateField(field, typeOptionData));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,16 +96,11 @@ class _FieldNameTextField extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocSelector<FieldEditorBloc, FieldEditorState, String>(
|
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
selector: (state) {
|
buildWhen: (p, c) => p.name != c.name,
|
||||||
return state.fieldTypeOptionData.fold(
|
builder: (context, state) {
|
||||||
() => "",
|
|
||||||
(fieldTypeOptionContext) => fieldTypeOptionContext.field_2.name,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
builder: (context, name) {
|
|
||||||
return FieldNameTextField(
|
return FieldNameTextField(
|
||||||
name: name,
|
name: state.name,
|
||||||
errorText: context.read<FieldEditorBloc>().state.errorText,
|
errorText: context.read<FieldEditorBloc>().state.errorText,
|
||||||
onNameChanged: (newName) {
|
onNameChanged: (newName) {
|
||||||
context.read<FieldEditorBloc>().add(FieldEditorEvent.updateName(newName));
|
context.read<FieldEditorBloc>().add(FieldEditorEvent.updateName(newName));
|
||||||
|
@ -7,14 +7,12 @@ import 'package:flowy_infra/theme.dart';
|
|||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.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';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pbserver.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pbserver.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.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 'package:app_flowy/startup/startup.dart';
|
|
||||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart';
|
||||||
@ -31,14 +29,10 @@ typedef SwitchToFieldCallback = Future<Either<FieldTypeOptionData, FlowyError>>
|
|||||||
);
|
);
|
||||||
|
|
||||||
class FieldEditorPannel extends StatefulWidget {
|
class FieldEditorPannel extends StatefulWidget {
|
||||||
final FieldTypeOptionData fieldTypeOptionData;
|
final GridFieldContext fieldContext;
|
||||||
final UpdateFieldCallback onUpdated;
|
|
||||||
final SwitchToFieldCallback onSwitchToField;
|
|
||||||
|
|
||||||
const FieldEditorPannel({
|
const FieldEditorPannel({
|
||||||
required this.fieldTypeOptionData,
|
required this.fieldContext,
|
||||||
required this.onUpdated,
|
|
||||||
required this.onSwitchToField,
|
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -52,13 +46,10 @@ class _FieldEditorPannelState extends State<FieldEditorPannel> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => getIt<FieldEditorPannelBloc>(param1: widget.fieldTypeOptionData),
|
create: (context) => FieldEditorPannelBloc(widget.fieldContext)..add(const FieldEditorPannelEvent.initial()),
|
||||||
child: BlocConsumer<FieldEditorPannelBloc, FieldEditorPannelState>(
|
child: BlocBuilder<FieldEditorPannelBloc, FieldEditorPannelState>(
|
||||||
listener: (context, state) {
|
|
||||||
widget.onUpdated(state.field, state.typeOptionData);
|
|
||||||
},
|
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
List<Widget> children = [_switchFieldTypeButton(context, state.field)];
|
List<Widget> children = [_switchFieldTypeButton(context, widget.fieldContext.field)];
|
||||||
final typeOptionWidget = _typeOptionWidget(context: context, state: state);
|
final typeOptionWidget = _typeOptionWidget(context: context, state: state);
|
||||||
|
|
||||||
if (typeOptionWidget != null) {
|
if (typeOptionWidget != null) {
|
||||||
@ -84,19 +75,7 @@ class _FieldEditorPannelState extends State<FieldEditorPannel> {
|
|||||||
hoverColor: theme.hover,
|
hoverColor: theme.hover,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final list = FieldTypeList(onSelectField: (newFieldType) {
|
final list = FieldTypeList(onSelectField: (newFieldType) {
|
||||||
widget.onSwitchToField(field.id, newFieldType).then((result) {
|
widget.fieldContext.switchToField(newFieldType);
|
||||||
result.fold(
|
|
||||||
(fieldTypeOptionContext) {
|
|
||||||
context.read<FieldEditorPannelBloc>().add(
|
|
||||||
FieldEditorPannelEvent.toFieldType(
|
|
||||||
fieldTypeOptionContext.field_2,
|
|
||||||
fieldTypeOptionContext.typeOptionData,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(err) => Log.error(err),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
_showOverlay(context, list);
|
_showOverlay(context, list);
|
||||||
},
|
},
|
||||||
@ -116,15 +95,11 @@ class _FieldEditorPannelState extends State<FieldEditorPannel> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final dataDelegate = TypeOptionDataDelegate(didUpdateTypeOptionData: (data) {
|
final dataDelegate = TypeOptionDataDelegate(didUpdateTypeOptionData: (data) {
|
||||||
context.read<FieldEditorPannelBloc>().add(FieldEditorPannelEvent.didUpdateTypeOptionData(data));
|
widget.fieldContext.typeOptionData = data;
|
||||||
});
|
});
|
||||||
|
|
||||||
final builder = _makeTypeOptionBuild(
|
final builder = _makeTypeOptionBuild(
|
||||||
typeOptionContext: TypeOptionContext(
|
typeOptionContext: TypeOptionContext(fieldContext: widget.fieldContext),
|
||||||
gridId: state.gridId,
|
|
||||||
field: state.field,
|
|
||||||
data: state.typeOptionData,
|
|
||||||
),
|
|
||||||
overlayDelegate: overlayDelegate,
|
overlayDelegate: overlayDelegate,
|
||||||
dataDelegate: dataDelegate,
|
dataDelegate: dataDelegate,
|
||||||
);
|
);
|
||||||
|
@ -150,6 +150,7 @@ class CreateFieldButton extends StatelessWidget {
|
|||||||
hoverColor: theme.hover,
|
hoverColor: theme.hover,
|
||||||
onTap: () => FieldEditor(
|
onTap: () => FieldEditor(
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
|
fieldName: "",
|
||||||
contextLoader: NewFieldContextLoader(gridId: gridId),
|
contextLoader: NewFieldContextLoader(gridId: gridId),
|
||||||
).show(context),
|
).show(context),
|
||||||
leftIcon: svgWidget("home/add"),
|
leftIcon: svgWidget("home/add"),
|
||||||
|
@ -178,6 +178,7 @@ class _RowDetailCell extends StatelessWidget {
|
|||||||
void _showFieldEditor(BuildContext context) {
|
void _showFieldEditor(BuildContext context) {
|
||||||
FieldEditor(
|
FieldEditor(
|
||||||
gridId: gridCell.gridId,
|
gridId: gridCell.gridId,
|
||||||
|
fieldName: gridCell.field.name,
|
||||||
contextLoader: DefaultFieldContextLoader(
|
contextLoader: DefaultFieldContextLoader(
|
||||||
gridId: gridCell.gridId,
|
gridId: gridCell.gridId,
|
||||||
field: gridCell.field,
|
field: gridCell.field,
|
||||||
|
@ -115,6 +115,7 @@ class _GridPropertyCell extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
FieldEditor(
|
FieldEditor(
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
|
fieldName: field.name,
|
||||||
contextLoader: DefaultFieldContextLoader(gridId: gridId, field: field),
|
contextLoader: DefaultFieldContextLoader(gridId: gridId, field: field),
|
||||||
).show(context, anchorDirection: AnchorDirection.bottomRight);
|
).show(context, anchorDirection: AnchorDirection.bottomRight);
|
||||||
},
|
},
|
||||||
|
@ -109,7 +109,7 @@ abstract class HoverWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlowyHover2 extends StatefulWidget {
|
class FlowyHover2 extends StatefulWidget {
|
||||||
final HoverWidget child;
|
final Widget child;
|
||||||
final EdgeInsets contentPadding;
|
final EdgeInsets contentPadding;
|
||||||
const FlowyHover2({
|
const FlowyHover2({
|
||||||
required this.child,
|
required this.child,
|
||||||
@ -127,9 +127,14 @@ class _FlowyHover2State extends State<FlowyHover2> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_hoverState = FlowyHoverState();
|
_hoverState = FlowyHoverState();
|
||||||
widget.child.onFocus.addListener(() {
|
|
||||||
_hoverState.onFocus = widget.child.onFocus.value;
|
if (widget.child is HoverWidget) {
|
||||||
});
|
final hoverWidget = widget.child as HoverWidget;
|
||||||
|
hoverWidget.onFocus.addListener(() {
|
||||||
|
_hoverState.onFocus = hoverWidget.onFocus.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ pub struct FieldTypeOptionData {
|
|||||||
pub grid_id: String,
|
pub grid_id: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub field_id: String,
|
pub field: Field,
|
||||||
|
|
||||||
#[pb(index = 3)]
|
#[pb(index = 3)]
|
||||||
pub type_option_data: Vec<u8>,
|
pub type_option_data: Vec<u8>,
|
||||||
|
@ -2174,7 +2174,7 @@ impl ::protobuf::reflect::ProtobufValue for FieldTypeOptionContext {
|
|||||||
pub struct FieldTypeOptionData {
|
pub struct FieldTypeOptionData {
|
||||||
// message fields
|
// message fields
|
||||||
pub grid_id: ::std::string::String,
|
pub grid_id: ::std::string::String,
|
||||||
pub field_id: ::std::string::String,
|
pub field: ::protobuf::SingularPtrField<Field>,
|
||||||
pub type_option_data: ::std::vec::Vec<u8>,
|
pub type_option_data: ::std::vec::Vec<u8>,
|
||||||
// special fields
|
// special fields
|
||||||
pub unknown_fields: ::protobuf::UnknownFields,
|
pub unknown_fields: ::protobuf::UnknownFields,
|
||||||
@ -2218,30 +2218,37 @@ impl FieldTypeOptionData {
|
|||||||
::std::mem::replace(&mut self.grid_id, ::std::string::String::new())
|
::std::mem::replace(&mut self.grid_id, ::std::string::String::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
// string field_id = 2;
|
// .Field field = 2;
|
||||||
|
|
||||||
|
|
||||||
pub fn get_field_id(&self) -> &str {
|
pub fn get_field(&self) -> &Field {
|
||||||
&self.field_id
|
self.field.as_ref().unwrap_or_else(|| <Field as ::protobuf::Message>::default_instance())
|
||||||
}
|
}
|
||||||
pub fn clear_field_id(&mut self) {
|
pub fn clear_field(&mut self) {
|
||||||
self.field_id.clear();
|
self.field.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_field(&self) -> bool {
|
||||||
|
self.field.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param is passed by value, moved
|
// Param is passed by value, moved
|
||||||
pub fn set_field_id(&mut self, v: ::std::string::String) {
|
pub fn set_field(&mut self, v: Field) {
|
||||||
self.field_id = v;
|
self.field = ::protobuf::SingularPtrField::some(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutable pointer to the field.
|
// Mutable pointer to the field.
|
||||||
// If field is not initialized, it is initialized with default value first.
|
// If field is not initialized, it is initialized with default value first.
|
||||||
pub fn mut_field_id(&mut self) -> &mut ::std::string::String {
|
pub fn mut_field(&mut self) -> &mut Field {
|
||||||
&mut self.field_id
|
if self.field.is_none() {
|
||||||
|
self.field.set_default();
|
||||||
|
}
|
||||||
|
self.field.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take field
|
// Take field
|
||||||
pub fn take_field_id(&mut self) -> ::std::string::String {
|
pub fn take_field(&mut self) -> Field {
|
||||||
::std::mem::replace(&mut self.field_id, ::std::string::String::new())
|
self.field.take().unwrap_or_else(|| Field::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
// bytes type_option_data = 3;
|
// bytes type_option_data = 3;
|
||||||
@ -2273,6 +2280,11 @@ impl FieldTypeOptionData {
|
|||||||
|
|
||||||
impl ::protobuf::Message for FieldTypeOptionData {
|
impl ::protobuf::Message for FieldTypeOptionData {
|
||||||
fn is_initialized(&self) -> bool {
|
fn is_initialized(&self) -> bool {
|
||||||
|
for v in &self.field {
|
||||||
|
if !v.is_initialized() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2284,7 +2296,7 @@ impl ::protobuf::Message for FieldTypeOptionData {
|
|||||||
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?;
|
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?;
|
||||||
},
|
},
|
||||||
2 => {
|
2 => {
|
||||||
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
|
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.field)?;
|
||||||
},
|
},
|
||||||
3 => {
|
3 => {
|
||||||
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?;
|
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?;
|
||||||
@ -2304,8 +2316,9 @@ impl ::protobuf::Message for FieldTypeOptionData {
|
|||||||
if !self.grid_id.is_empty() {
|
if !self.grid_id.is_empty() {
|
||||||
my_size += ::protobuf::rt::string_size(1, &self.grid_id);
|
my_size += ::protobuf::rt::string_size(1, &self.grid_id);
|
||||||
}
|
}
|
||||||
if !self.field_id.is_empty() {
|
if let Some(ref v) = self.field.as_ref() {
|
||||||
my_size += ::protobuf::rt::string_size(2, &self.field_id);
|
let len = v.compute_size();
|
||||||
|
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
||||||
}
|
}
|
||||||
if !self.type_option_data.is_empty() {
|
if !self.type_option_data.is_empty() {
|
||||||
my_size += ::protobuf::rt::bytes_size(3, &self.type_option_data);
|
my_size += ::protobuf::rt::bytes_size(3, &self.type_option_data);
|
||||||
@ -2319,8 +2332,10 @@ impl ::protobuf::Message for FieldTypeOptionData {
|
|||||||
if !self.grid_id.is_empty() {
|
if !self.grid_id.is_empty() {
|
||||||
os.write_string(1, &self.grid_id)?;
|
os.write_string(1, &self.grid_id)?;
|
||||||
}
|
}
|
||||||
if !self.field_id.is_empty() {
|
if let Some(ref v) = self.field.as_ref() {
|
||||||
os.write_string(2, &self.field_id)?;
|
os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
|
||||||
|
os.write_raw_varint32(v.get_cached_size())?;
|
||||||
|
v.write_to_with_cached_sizes(os)?;
|
||||||
}
|
}
|
||||||
if !self.type_option_data.is_empty() {
|
if !self.type_option_data.is_empty() {
|
||||||
os.write_bytes(3, &self.type_option_data)?;
|
os.write_bytes(3, &self.type_option_data)?;
|
||||||
@ -2368,10 +2383,10 @@ impl ::protobuf::Message for FieldTypeOptionData {
|
|||||||
|m: &FieldTypeOptionData| { &m.grid_id },
|
|m: &FieldTypeOptionData| { &m.grid_id },
|
||||||
|m: &mut FieldTypeOptionData| { &mut m.grid_id },
|
|m: &mut FieldTypeOptionData| { &mut m.grid_id },
|
||||||
));
|
));
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Field>>(
|
||||||
"field_id",
|
"field",
|
||||||
|m: &FieldTypeOptionData| { &m.field_id },
|
|m: &FieldTypeOptionData| { &m.field },
|
||||||
|m: &mut FieldTypeOptionData| { &mut m.field_id },
|
|m: &mut FieldTypeOptionData| { &mut m.field },
|
||||||
));
|
));
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
|
||||||
"type_option_data",
|
"type_option_data",
|
||||||
@ -2395,7 +2410,7 @@ impl ::protobuf::Message for FieldTypeOptionData {
|
|||||||
impl ::protobuf::Clear for FieldTypeOptionData {
|
impl ::protobuf::Clear for FieldTypeOptionData {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.grid_id.clear();
|
self.grid_id.clear();
|
||||||
self.field_id.clear();
|
self.field.clear();
|
||||||
self.type_option_data.clear();
|
self.type_option_data.clear();
|
||||||
self.unknown_fields.clear();
|
self.unknown_fields.clear();
|
||||||
}
|
}
|
||||||
@ -8302,25 +8317,25 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
|||||||
ne_of_field_id\"\x82\x01\n\x16FieldTypeOptionContext\x12\x17\n\x07grid_i\
|
ne_of_field_id\"\x82\x01\n\x16FieldTypeOptionContext\x12\x17\n\x07grid_i\
|
||||||
d\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\
|
d\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\
|
||||||
\x06.FieldR\tgridField\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\
|
\x06.FieldR\tgridField\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\
|
||||||
\x0etypeOptionData\"s\n\x13FieldTypeOptionData\x12\x17\n\x07grid_id\x18\
|
\x0etypeOptionData\"v\n\x13FieldTypeOptionData\x12\x17\n\x07grid_id\x18\
|
||||||
\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07\
|
\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.\
|
||||||
fieldId\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionDa\
|
FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etype\
|
||||||
ta\"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.Fiel\
|
OptionData\"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\
|
||||||
dR\x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\
|
\x06.FieldR\x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\
|
||||||
\x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\
|
\x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06ro\
|
||||||
\x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07b\
|
w_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\
|
||||||
lockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\
|
\tR\x07blockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\
|
||||||
\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_fiel\
|
\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_b\
|
||||||
d_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFieldId\
|
y_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFiel\
|
||||||
\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellByFie\
|
dId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellBy\
|
||||||
ldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\
|
FieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05va\
|
||||||
\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\
|
lue\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedR\
|
||||||
\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11Repe\
|
ow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11Re\
|
||||||
atedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05i\
|
peatedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\
|
||||||
tems\"U\n\x0eGridBlockOrder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\
|
\x05items\"U\n\x0eGridBlockOrder\x12\x19\n\x08block_id\x18\x01\x20\x01(\
|
||||||
\x07blockId\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrd\
|
\tR\x07blockId\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trow\
|
||||||
ers\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrd\
|
Orders\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.Row\
|
||||||
erR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\
|
OrderR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\
|
||||||
\x0e\n\x0cone_of_index\"Q\n\x0fUpdatedRowOrder\x12&\n\trow_order\x18\x01\
|
\x0e\n\x0cone_of_index\"Q\n\x0fUpdatedRowOrder\x12&\n\trow_order\x18\x01\
|
||||||
\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x03row\x18\x02\x20\x01(\
|
\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x03row\x18\x02\x20\x01(\
|
||||||
\x0b2\x04.RowR\x03row\"\xc6\x01\n\x11GridRowsChangeset\x12\x19\n\x08bloc\
|
\x0b2\x04.RowR\x03row\"\xc6\x01\n\x11GridRowsChangeset\x12\x19\n\x08bloc\
|
||||||
|
@ -45,7 +45,7 @@ message FieldTypeOptionContext {
|
|||||||
}
|
}
|
||||||
message FieldTypeOptionData {
|
message FieldTypeOptionData {
|
||||||
string grid_id = 1;
|
string grid_id = 1;
|
||||||
string field_id = 2;
|
Field field = 2;
|
||||||
bytes type_option_data = 3;
|
bytes type_option_data = 3;
|
||||||
}
|
}
|
||||||
message RepeatedField {
|
message RepeatedField {
|
||||||
|
Reference in New Issue
Block a user