mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: lazy load cell
This commit is contained in:
parent
28948e567c
commit
16598650ff
@ -149,8 +149,8 @@ void _resolveGridDeps(GetIt getIt) {
|
||||
|
||||
getIt.registerFactoryParam<RowBloc, GridRowData, void>(
|
||||
(data, _) => RowBloc(
|
||||
rowService: RowService(data),
|
||||
listener: RowListener(rowId: data.rowId),
|
||||
rowData: data,
|
||||
rowlistener: RowListener(rowId: data.rowId),
|
||||
),
|
||||
);
|
||||
|
||||
@ -174,38 +174,43 @@ void _resolveGridDeps(GetIt getIt) {
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<TextCellBloc, GridCellData, void>(
|
||||
(context, _) => TextCellBloc(
|
||||
service: CellService(context),
|
||||
getIt.registerFactoryParam<TextCellBloc, FutureCellData, void>(
|
||||
(cellData, _) => TextCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SelectionCellBloc, GridCellData, void>(
|
||||
(context, _) => SelectionCellBloc(
|
||||
service: CellService(context),
|
||||
getIt.registerFactoryParam<SelectionCellBloc, FutureCellData, void>(
|
||||
(cellData, _) => SelectionCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<NumberCellBloc, GridCellData, void>(
|
||||
(context, _) => NumberCellBloc(
|
||||
service: CellService(context),
|
||||
getIt.registerFactoryParam<NumberCellBloc, FutureCellData, void>(
|
||||
(cellData, _) => NumberCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<DateCellBloc, GridCellData, void>(
|
||||
(context, _) => DateCellBloc(
|
||||
service: CellService(context),
|
||||
getIt.registerFactoryParam<DateCellBloc, FutureCellData, void>(
|
||||
(cellData, _) => DateCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, GridCellData, void>(
|
||||
(context, _) => CheckboxCellBloc(
|
||||
service: CellService(context),
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, FutureCellData, void>(
|
||||
(cellData, _) => CheckboxCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SwitchFieldTypeBloc, EditFieldContext, void>(
|
||||
(editContext, _) => SwitchFieldTypeBloc(editContext),
|
||||
getIt.registerFactoryParam<SwitchFieldTypeBloc, SwitchFieldContext, void>(
|
||||
(context, _) => SwitchFieldTypeBloc(context),
|
||||
);
|
||||
|
||||
getIt.registerFactory<SelectionTypeOptionBloc>(
|
||||
|
@ -112,7 +112,7 @@ class ApplicationBlocObserver extends BlocObserver {
|
||||
// ignore: unnecessary_overrides
|
||||
void onTransition(Bloc bloc, Transition transition) {
|
||||
// Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}");
|
||||
//Log.debug("${transition.nextState}");
|
||||
Log.debug("${transition.nextState}");
|
||||
super.onTransition(bloc, transition);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/dart_notification.pb.dart' as user;
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
|
||||
typedef UserProfileUpdatedNotifierValue = Either<UserProfile, FlowyError>;
|
||||
typedef AuthNotifierValue = Either<Unit, FlowyError>;
|
||||
typedef WorkspaceUpdatedNotifierValue = Either<List<Workspace>, FlowyError>;
|
||||
@ -23,8 +22,8 @@ class UserListener {
|
||||
final authDidChangedNotifier = PublishNotifier<AuthNotifierValue>();
|
||||
final workspaceUpdatedNotifier = PublishNotifier<WorkspaceUpdatedNotifierValue>();
|
||||
|
||||
late FolderNotificationParser _workspaceParser;
|
||||
late UserNotificationParser _userParser;
|
||||
FolderNotificationParser? _workspaceParser;
|
||||
UserNotificationParser? _userParser;
|
||||
late UserProfile _user;
|
||||
UserListener({
|
||||
required UserProfile user,
|
||||
@ -36,12 +35,14 @@ class UserListener {
|
||||
_workspaceParser = FolderNotificationParser(id: _user.token, callback: _notificationCallback);
|
||||
_userParser = UserNotificationParser(id: _user.token, callback: _userNotificationCallback);
|
||||
_subscription = RustStreamReceiver.listen((observable) {
|
||||
_workspaceParser.parse(observable);
|
||||
_userParser.parse(observable);
|
||||
_workspaceParser?.parse(observable);
|
||||
_userParser?.parse(observable);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
_workspaceParser = null;
|
||||
_userParser = null;
|
||||
await _subscription?.cancel();
|
||||
profileUpdatedNotifier.dispose();
|
||||
authDidChangedNotifier.dispose();
|
||||
|
@ -17,7 +17,7 @@ class AppListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
ViewsDidChangeCallback? _viewsChanged;
|
||||
AppDidUpdateCallback? _updated;
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
String appId;
|
||||
|
||||
AppListener({
|
||||
@ -28,7 +28,7 @@ class AppListener {
|
||||
_viewsChanged = viewsChanged;
|
||||
_updated = appUpdated;
|
||||
_parser = FolderNotificationParser(id: appId, callback: _bservableCallback);
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _bservableCallback(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -61,6 +61,7 @@ class AppListener {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
_viewsChanged = null;
|
||||
_updated = null;
|
||||
|
@ -1,19 +1,21 @@
|
||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
|
||||
|
||||
class CellService {
|
||||
final GridCellData context;
|
||||
CellService();
|
||||
|
||||
CellService(this.context);
|
||||
|
||||
Future<Either<void, FlowyError>> updateCell({required String data}) {
|
||||
Future<Either<void, FlowyError>> updateCell({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String data,
|
||||
}) {
|
||||
final payload = CellMetaChangeset.create()
|
||||
..gridId = context.gridId
|
||||
..fieldId = context.field.id
|
||||
..rowId = context.rowId
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId
|
||||
..data = data;
|
||||
return GridEventUpdateCell(payload).send();
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -8,10 +9,14 @@ part 'checkbox_cell_bloc.freezed.dart';
|
||||
|
||||
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
final CellService service;
|
||||
// final FutureCellData cellData;
|
||||
|
||||
CheckboxCellBloc({
|
||||
required this.service,
|
||||
}) : super(CheckboxCellState.initial(service.context.cell)) {
|
||||
required FutureCellData cellData,
|
||||
}) : super(CheckboxCellState.initial()) {
|
||||
cellData.then((a) {});
|
||||
|
||||
on<CheckboxCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -38,5 +43,5 @@ class CheckboxCellState with _$CheckboxCellState {
|
||||
required Cell? cell,
|
||||
}) = _CheckboxCellState;
|
||||
|
||||
factory CheckboxCellState.initial(Cell? cell) => CheckboxCellState(cell: cell);
|
||||
factory CheckboxCellState.initial() => const CheckboxCellState(cell: null);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -8,10 +9,12 @@ part 'date_cell_bloc.freezed.dart';
|
||||
|
||||
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
final CellService service;
|
||||
final FutureCellData cellData;
|
||||
|
||||
DateCellBloc({
|
||||
required this.service,
|
||||
}) : super(DateCellState.initial(service.context.cell)) {
|
||||
required this.cellData,
|
||||
}) : super(DateCellState.initial()) {
|
||||
on<DateCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -35,8 +38,8 @@ class DateCellEvent with _$DateCellEvent {
|
||||
@freezed
|
||||
class DateCellState with _$DateCellState {
|
||||
const factory DateCellState({
|
||||
required Cell? cell,
|
||||
Cell? cell,
|
||||
}) = _DateCellState;
|
||||
|
||||
factory DateCellState.initial(Cell? cell) => DateCellState(cell: cell);
|
||||
factory DateCellState.initial() => const DateCellState();
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -11,7 +12,8 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
|
||||
NumberCellBloc({
|
||||
required this.service,
|
||||
}) : super(NumberCellState.initial(service.context.cell)) {
|
||||
required FutureCellData cellData,
|
||||
}) : super(NumberCellState.initial()) {
|
||||
on<NumberCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -35,8 +37,8 @@ class NumberCellEvent with _$NumberCellEvent {
|
||||
@freezed
|
||||
class NumberCellState with _$NumberCellState {
|
||||
const factory NumberCellState({
|
||||
required Cell? cell,
|
||||
Cell? cell,
|
||||
}) = _NumberCellState;
|
||||
|
||||
factory NumberCellState.initial(Cell? cell) => NumberCellState(cell: cell);
|
||||
factory NumberCellState.initial() => const NumberCellState();
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -11,7 +12,8 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||
|
||||
SelectionCellBloc({
|
||||
required this.service,
|
||||
}) : super(SelectionCellState.initial(service.context.cell)) {
|
||||
required FutureCellData cellData,
|
||||
}) : super(SelectionCellState.initial()) {
|
||||
on<SelectionCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -35,8 +37,8 @@ class SelectionCellEvent with _$SelectionCellEvent {
|
||||
@freezed
|
||||
class SelectionCellState with _$SelectionCellState {
|
||||
const factory SelectionCellState({
|
||||
required Cell? cell,
|
||||
Cell? cell,
|
||||
}) = _SelectionCellState;
|
||||
|
||||
factory SelectionCellState.initial(Cell? cell) => SelectionCellState(cell: cell);
|
||||
factory SelectionCellState.initial() => const SelectionCellState();
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -10,20 +11,47 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
|
||||
TextCellBloc({
|
||||
required this.service,
|
||||
}) : super(TextCellState.initial(service.context.cell?.content ?? "")) {
|
||||
required FutureCellData cellData,
|
||||
}) : super(TextCellState.initial()) {
|
||||
cellData.then((cellData) {
|
||||
if (cellData != null) {
|
||||
add(TextCellEvent.didReceiveCellData(cellData));
|
||||
}
|
||||
});
|
||||
|
||||
on<TextCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialCell value) async {},
|
||||
updateText: (_UpdateText value) {
|
||||
service.updateCell(data: value.text);
|
||||
updateCellContent(value.text);
|
||||
emit(state.copyWith(content: value.text));
|
||||
},
|
||||
didReceiveCellData: (_DidReceiveCellData value) {
|
||||
emit(state.copyWith(
|
||||
cellData: value.cellData,
|
||||
content: value.cellData.cell?.content ?? "",
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void updateCellContent(String content) {
|
||||
if (state.cellData != null) {
|
||||
final fieldId = state.cellData!.field.id;
|
||||
final gridId = state.cellData!.gridId;
|
||||
final rowId = state.cellData!.rowId;
|
||||
service.updateCell(
|
||||
data: content,
|
||||
fieldId: fieldId,
|
||||
gridId: gridId,
|
||||
rowId: rowId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
@ -33,6 +61,7 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
@freezed
|
||||
class TextCellEvent with _$TextCellEvent {
|
||||
const factory TextCellEvent.initial() = _InitialCell;
|
||||
const factory TextCellEvent.didReceiveCellData(GridCellData cellData) = _DidReceiveCellData;
|
||||
const factory TextCellEvent.updateText(String text) = _UpdateText;
|
||||
}
|
||||
|
||||
@ -40,7 +69,8 @@ class TextCellEvent with _$TextCellEvent {
|
||||
class TextCellState with _$TextCellState {
|
||||
const factory TextCellState({
|
||||
required String content,
|
||||
GridCellData? cellData,
|
||||
}) = _TextCellState;
|
||||
|
||||
factory TextCellState.initial(String content) => TextCellState(content: content);
|
||||
factory TextCellState.initial() => const TextCellState(content: "");
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
|
||||
@ -12,19 +14,22 @@ part 'create_field_bloc.freezed.dart';
|
||||
class CreateFieldBloc extends Bloc<CreateFieldEvent, CreateFieldState> {
|
||||
final FieldService service;
|
||||
|
||||
CreateFieldBloc({required this.service}) : super(CreateFieldState.initial()) {
|
||||
CreateFieldBloc({required this.service}) : super(CreateFieldState.initial(service.gridId)) {
|
||||
on<CreateFieldEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialField value) async {
|
||||
final result = await service.getEditFieldContext(FieldType.RichText);
|
||||
result.fold(
|
||||
(editContext) => emit(state.copyWith(editContext: Some(editContext))),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
await _getEditFieldContext(emit);
|
||||
},
|
||||
updateName: (_UpdateName value) {
|
||||
emit(state.copyWith(fieldName: value.name));
|
||||
},
|
||||
switchField: (_SwitchField value) {
|
||||
emit(state.copyWith(field: Some(value.field), typeOptionData: value.typeOptionData));
|
||||
},
|
||||
done: (_Done value) async {
|
||||
await _saveField(emit);
|
||||
},
|
||||
updateName: (_UpdateName value) {},
|
||||
done: (_Done value) {},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -34,24 +39,54 @@ class CreateFieldBloc extends Bloc<CreateFieldEvent, CreateFieldState> {
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _saveField(Emitter<CreateFieldState> emit) async {
|
||||
await state.field.fold(
|
||||
() async => null,
|
||||
(field) async {
|
||||
final result = await service.createField(field: field, typeOptionData: state.typeOptionData);
|
||||
result.fold((l) => null, (r) => null);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _getEditFieldContext(Emitter<CreateFieldState> emit) async {
|
||||
final result = await service.getEditFieldContext(FieldType.RichText);
|
||||
result.fold(
|
||||
(editContext) {
|
||||
emit(state.copyWith(
|
||||
field: Some(editContext.gridField),
|
||||
typeOptionData: editContext.typeOptionData,
|
||||
));
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class CreateFieldEvent with _$CreateFieldEvent {
|
||||
const factory CreateFieldEvent.initial() = _InitialField;
|
||||
const factory CreateFieldEvent.updateName(String newName) = _UpdateName;
|
||||
const factory CreateFieldEvent.updateName(String name) = _UpdateName;
|
||||
const factory CreateFieldEvent.switchField(Field field, Uint8List typeOptionData) = _SwitchField;
|
||||
const factory CreateFieldEvent.done() = _Done;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class CreateFieldState with _$CreateFieldState {
|
||||
const factory CreateFieldState({
|
||||
required String fieldName,
|
||||
required String gridId,
|
||||
required String errorText,
|
||||
required Option<EditFieldContext> editContext,
|
||||
required Option<Field> field,
|
||||
required List<int> typeOptionData,
|
||||
}) = _CreateFieldState;
|
||||
|
||||
factory CreateFieldState.initial() => CreateFieldState(
|
||||
editContext: none(),
|
||||
factory CreateFieldState.initial(String gridId) => CreateFieldState(
|
||||
gridId: gridId,
|
||||
fieldName: '',
|
||||
field: none(),
|
||||
errorText: '',
|
||||
typeOptionData: List<int>.empty(),
|
||||
);
|
||||
}
|
||||
|
@ -21,66 +21,19 @@ class FieldService {
|
||||
return GridEventCreateEditFieldContext(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> createTextField(
|
||||
String gridId,
|
||||
Field field,
|
||||
RichTextTypeOption typeOption,
|
||||
Future<Either<Unit, FlowyError>> createField({
|
||||
required Field field,
|
||||
List<int>? typeOptionData,
|
||||
String? startFieldId,
|
||||
) {
|
||||
final typeOptionData = typeOption.writeToBuffer();
|
||||
return createField(field, typeOptionData, startFieldId);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> createSingleSelectField(
|
||||
String gridId,
|
||||
Field field,
|
||||
SingleSelectTypeOption typeOption,
|
||||
String? startFieldId,
|
||||
) {
|
||||
final typeOptionData = typeOption.writeToBuffer();
|
||||
return createField(field, typeOptionData, startFieldId);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> createMultiSelectField(
|
||||
String gridId,
|
||||
Field field,
|
||||
MultiSelectTypeOption typeOption,
|
||||
String? startFieldId,
|
||||
) {
|
||||
final typeOptionData = typeOption.writeToBuffer();
|
||||
return createField(field, typeOptionData, startFieldId);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> createNumberField(
|
||||
String gridId,
|
||||
Field field,
|
||||
NumberTypeOption typeOption,
|
||||
String? startFieldId,
|
||||
) {
|
||||
final typeOptionData = typeOption.writeToBuffer();
|
||||
return createField(field, typeOptionData, startFieldId);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> createDateField(
|
||||
String gridId,
|
||||
Field field,
|
||||
DateTypeOption typeOption,
|
||||
String? startFieldId,
|
||||
) {
|
||||
final typeOptionData = typeOption.writeToBuffer();
|
||||
return createField(field, typeOptionData, startFieldId);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> createField(
|
||||
Field field,
|
||||
Uint8List? typeOptionData,
|
||||
String? startFieldId,
|
||||
) {
|
||||
final payload = CreateFieldPayload.create()
|
||||
}) {
|
||||
var payload = CreateFieldPayload.create()
|
||||
..gridId = gridId
|
||||
..field_2 = field
|
||||
..typeOptionData = typeOptionData ?? Uint8List.fromList([])
|
||||
..startFieldId = startFieldId ?? "";
|
||||
..typeOptionData = typeOptionData ?? [];
|
||||
|
||||
if (startFieldId != null) {
|
||||
payload.startFieldId = startFieldId;
|
||||
}
|
||||
|
||||
return GridEventCreateField(payload).send();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import 'field_service.dart';
|
||||
part 'switch_field_type_bloc.freezed.dart';
|
||||
|
||||
class SwitchFieldTypeBloc extends Bloc<SwitchFieldTypeEvent, SwitchFieldTypeState> {
|
||||
SwitchFieldTypeBloc(EditFieldContext editContext) : super(SwitchFieldTypeState.initial(editContext)) {
|
||||
SwitchFieldTypeBloc(SwitchFieldContext editContext) : super(SwitchFieldTypeState.initial(editContext)) {
|
||||
on<SwitchFieldTypeEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -53,9 +53,17 @@ class SwitchFieldTypeState with _$SwitchFieldTypeState {
|
||||
required Uint8List typeOptionData,
|
||||
}) = _SwitchFieldTypeState;
|
||||
|
||||
factory SwitchFieldTypeState.initial(EditFieldContext editContext) => SwitchFieldTypeState(
|
||||
gridId: editContext.gridId,
|
||||
field: editContext.gridField,
|
||||
typeOptionData: Uint8List.fromList(editContext.typeOptionData),
|
||||
factory SwitchFieldTypeState.initial(SwitchFieldContext switchContext) => SwitchFieldTypeState(
|
||||
gridId: switchContext.gridId,
|
||||
field: switchContext.field,
|
||||
typeOptionData: Uint8List.fromList(switchContext.typeOptionData),
|
||||
);
|
||||
}
|
||||
|
||||
class SwitchFieldContext {
|
||||
final String gridId;
|
||||
final Field field;
|
||||
final List<int> typeOptionData;
|
||||
|
||||
SwitchFieldContext(this.gridId, this.field, this.typeOptionData);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'grid_block_service.dart';
|
||||
import 'grid_listenr.dart';
|
||||
import 'grid_service.dart';
|
||||
@ -63,6 +64,20 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
await _loadGrid(emit);
|
||||
}
|
||||
|
||||
Future<void> _initGridBlock(Grid grid) async {
|
||||
_blockService = GridBlockService(
|
||||
gridId: grid.id,
|
||||
blockOrders: grid.blockOrders,
|
||||
);
|
||||
|
||||
_blockService.blocksUpdateNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(blockMap) => add(GridEvent.rowsDidUpdate(_buildRows(blockMap))),
|
||||
(err) => Log.error('$err'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadGrid(Emitter<GridState> emit) async {
|
||||
final result = await service.openGrid(gridId: view.id);
|
||||
return Future(
|
||||
@ -78,7 +93,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(fields) {
|
||||
_initGridBlockService(grid);
|
||||
_initGridBlock(grid);
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
fields: fields.items,
|
||||
@ -90,29 +105,12 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _initGridBlockService(Grid grid) async {
|
||||
_blockService = GridBlockService(
|
||||
gridId: grid.id,
|
||||
blockOrders: grid.blockOrders,
|
||||
);
|
||||
|
||||
_blockService.blocksUpdateNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(blockMap) => add(GridEvent.rowsDidUpdate(_buildRows(blockMap))),
|
||||
(err) => Log.error('$err'),
|
||||
);
|
||||
});
|
||||
|
||||
_gridListener.start();
|
||||
}
|
||||
|
||||
List<GridRowData> _buildRows(GridBlockMap blockMap) {
|
||||
List<GridRowData> rows = [];
|
||||
List<GridBlockRow> _buildRows(GridBlockMap blockMap) {
|
||||
List<GridBlockRow> rows = [];
|
||||
blockMap.forEach((_, GridBlock gridBlock) {
|
||||
rows.addAll(gridBlock.rowOrders.map(
|
||||
(rowOrder) => GridRowData(
|
||||
(rowOrder) => GridBlockRow(
|
||||
gridId: view.id,
|
||||
fields: state.fields,
|
||||
blockId: gridBlock.id,
|
||||
rowId: rowOrder.rowId,
|
||||
height: rowOrder.height.toDouble(),
|
||||
@ -130,7 +128,7 @@ class GridEvent with _$GridEvent {
|
||||
const factory GridEvent.updateDesc(String gridId, String desc) = _Desc;
|
||||
const factory GridEvent.delete(String gridId) = _Delete;
|
||||
const factory GridEvent.createRow() = _CreateRow;
|
||||
const factory GridEvent.rowsDidUpdate(List<GridRowData> rows) = _RowsDidUpdate;
|
||||
const factory GridEvent.rowsDidUpdate(List<GridBlockRow> rows) = _RowsDidUpdate;
|
||||
const factory GridEvent.fieldsDidUpdate(List<Field> fields) = _FieldsDidUpdate;
|
||||
}
|
||||
|
||||
@ -139,7 +137,7 @@ class GridState with _$GridState {
|
||||
const factory GridState({
|
||||
required GridLoadingState loadingState,
|
||||
required List<Field> fields,
|
||||
required List<GridRowData> rows,
|
||||
required List<GridBlockRow> rows,
|
||||
required Option<Grid> grid,
|
||||
}) = _GridState;
|
||||
|
||||
@ -156,3 +154,46 @@ class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
}
|
||||
|
||||
class GridBlockRow {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final double height;
|
||||
|
||||
const GridBlockRow({
|
||||
required this.gridId,
|
||||
required this.rowId,
|
||||
required this.blockId,
|
||||
required this.height,
|
||||
});
|
||||
}
|
||||
|
||||
class GridRowData extends Equatable {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final List<Field> fields;
|
||||
final double height;
|
||||
|
||||
const GridRowData({
|
||||
required this.gridId,
|
||||
required this.rowId,
|
||||
required this.blockId,
|
||||
required this.fields,
|
||||
required this.height,
|
||||
});
|
||||
|
||||
factory GridRowData.fromBlockRow(GridBlockRow row, List<Field> fields) {
|
||||
return GridRowData(
|
||||
gridId: row.gridId,
|
||||
rowId: row.rowId,
|
||||
blockId: row.blockId,
|
||||
fields: fields,
|
||||
height: row.height,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [rowId, fields];
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class GridBlockService {
|
||||
String gridId;
|
||||
GridBlockMap blockMap = GridBlockMap();
|
||||
late GridBlockListener _blockListener;
|
||||
PublishNotifier<BlocksUpdateNotifierValue> blocksUpdateNotifier = PublishNotifier();
|
||||
PublishNotifier<BlocksUpdateNotifierValue>? blocksUpdateNotifier = PublishNotifier();
|
||||
|
||||
GridBlockService({required this.gridId, required List<GridBlockOrder> blockOrders}) {
|
||||
_loadGridBlocks(blockOrders);
|
||||
@ -36,6 +36,8 @@ class GridBlockService {
|
||||
|
||||
Future<void> stop() async {
|
||||
await _blockListener.stop();
|
||||
blocksUpdateNotifier?.dispose();
|
||||
blocksUpdateNotifier = null;
|
||||
}
|
||||
|
||||
void _loadGridBlocks(List<GridBlockOrder> blockOrders) {
|
||||
@ -49,9 +51,9 @@ class GridBlockService {
|
||||
for (final gridBlock in repeatedBlocks.items) {
|
||||
blockMap[gridBlock.id] = gridBlock;
|
||||
}
|
||||
blocksUpdateNotifier.value = left(blockMap);
|
||||
blocksUpdateNotifier?.value = left(blockMap);
|
||||
},
|
||||
(err) => blocksUpdateNotifier.value = right(err),
|
||||
(err) => blocksUpdateNotifier?.value = right(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -61,7 +63,7 @@ class GridBlockListener {
|
||||
final String gridId;
|
||||
PublishNotifier<Either<List<GridBlockOrder>, FlowyError>> blockUpdateNotifier = PublishNotifier(comparable: null);
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
late GridNotificationParser _parser;
|
||||
GridNotificationParser? _parser;
|
||||
|
||||
GridBlockListener({required this.gridId});
|
||||
|
||||
@ -73,7 +75,7 @@ class GridBlockListener {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -91,6 +93,7 @@ class GridBlockListener {
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
blockUpdateNotifier.dispose();
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ import 'package:app_flowy/core/notification_helper.dart';
|
||||
|
||||
class GridListener {
|
||||
final String gridId;
|
||||
PublishNotifier<Either<List<Field>, FlowyError>> fieldsUpdateNotifier = PublishNotifier(comparable: null);
|
||||
PublishNotifier<Either<List<Field>, FlowyError>> fieldsUpdateNotifier = PublishNotifier();
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
late GridNotificationParser _parser;
|
||||
GridNotificationParser? _parser;
|
||||
GridListener({required this.gridId});
|
||||
|
||||
void start() {
|
||||
@ -26,7 +26,7 @@ class GridListener {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -43,6 +43,7 @@ class GridListener {
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
fieldsUpdateNotifier.dispose();
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.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';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class GridService {
|
||||
Future<Either<Grid, FlowyError>> openGrid({required String gridId}) async {
|
||||
@ -34,22 +33,3 @@ class GridService {
|
||||
return GridEventGetFields(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
class GridRowData extends Equatable {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final List<Field> fields;
|
||||
final double height;
|
||||
|
||||
const GridRowData({
|
||||
required this.gridId,
|
||||
required this.rowId,
|
||||
required this.blockId,
|
||||
required this.fields,
|
||||
required this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [rowId];
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import 'package:app_flowy/workspace/application/grid/grid_service.dart';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart';
|
||||
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';
|
||||
@ -6,20 +8,34 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'row_listener.dart';
|
||||
import 'row_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'row_bloc.freezed.dart';
|
||||
|
||||
typedef CellDataMap = HashMap<String, GridCellData>;
|
||||
|
||||
class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
final RowService rowService;
|
||||
final RowListener listener;
|
||||
final RowListener rowlistener;
|
||||
final RowFieldListener fieldListener;
|
||||
|
||||
RowBloc({required this.rowService, required this.listener}) : super(RowState.initial(rowService.rowData)) {
|
||||
RowBloc({required GridRowData rowData, required this.rowlistener})
|
||||
: rowService = RowService(
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
rowId: rowData.rowId,
|
||||
),
|
||||
fieldListener = RowFieldListener(
|
||||
gridId: rowData.gridId,
|
||||
),
|
||||
super(RowState.initial(rowData)) {
|
||||
on<RowEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialRow value) async {
|
||||
_startRowListening();
|
||||
_startListening();
|
||||
await _loadRow(emit);
|
||||
add(const RowEvent.didUpdateCell());
|
||||
},
|
||||
createRow: (_CreateRow value) {
|
||||
rowService.createRow();
|
||||
@ -30,6 +46,19 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
disactiveRow: (_DisactiveRow value) {
|
||||
emit(state.copyWith(active: false));
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(fields: value.fields));
|
||||
add(const RowEvent.didUpdateCell());
|
||||
},
|
||||
didUpdateCell: (_DidUpdateCell value) {
|
||||
final Future<CellDataMap> cellDataMap = state.row.then(
|
||||
(someRow) => someRow.fold(
|
||||
() => HashMap.identity(),
|
||||
(row) => _makeCellDatas(row),
|
||||
),
|
||||
);
|
||||
emit(state.copyWith(cellDataMap: cellDataMap));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -37,53 +66,66 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await listener.close();
|
||||
await rowlistener.close();
|
||||
await fieldListener.close();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _startRowListening() async {
|
||||
listener.updateRowNotifier.addPublishListener((result) {
|
||||
result.fold((row) {
|
||||
//
|
||||
}, (err) => null);
|
||||
Future<void> _startListening() async {
|
||||
rowlistener.updateRowNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(row) {
|
||||
//
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
listener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold((repeatedCvell) {
|
||||
//
|
||||
Log.info("$repeatedCvell");
|
||||
}, (r) => null);
|
||||
rowlistener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(repeatedCell) {
|
||||
Log.info("$repeatedCell");
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
listener.start();
|
||||
fieldListener.updateFieldNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(fields) => add(RowEvent.didReceiveFieldUpdate(fields)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
rowlistener.start();
|
||||
fieldListener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadRow(Emitter<RowState> emit) async {
|
||||
final Future<List<GridCellData>> cellDatas = rowService.getRow().then((result) {
|
||||
final Future<Option<Row>> row = rowService.getRow().then((result) {
|
||||
return result.fold(
|
||||
(row) => _makeCellDatas(row),
|
||||
(e) {
|
||||
Log.error(e);
|
||||
return [];
|
||||
(row) => Some(row),
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return none();
|
||||
},
|
||||
);
|
||||
});
|
||||
emit(state.copyWith(cellDatas: cellDatas));
|
||||
emit(state.copyWith(row: row));
|
||||
}
|
||||
|
||||
List<GridCellData> _makeCellDatas(Row row) {
|
||||
return rowService.rowData.fields.map((field) {
|
||||
final cell = row.cellByFieldId[field.id];
|
||||
final rowData = rowService.rowData;
|
||||
|
||||
return GridCellData(
|
||||
CellDataMap _makeCellDatas(Row row) {
|
||||
var map = CellDataMap.new();
|
||||
for (final field in state.fields) {
|
||||
map[field.id] = GridCellData(
|
||||
rowId: row.id,
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
cell: cell,
|
||||
gridId: rowService.gridId,
|
||||
blockId: rowService.blockId,
|
||||
cell: row.cellByFieldId[field.id],
|
||||
field: field,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,21 +135,27 @@ class RowEvent with _$RowEvent {
|
||||
const factory RowEvent.createRow() = _CreateRow;
|
||||
const factory RowEvent.activeRow() = _ActiveRow;
|
||||
const factory RowEvent.disactiveRow() = _DisactiveRow;
|
||||
const factory RowEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
const factory RowEvent.didUpdateCell() = _DidUpdateCell;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowState with _$RowState {
|
||||
const factory RowState({
|
||||
required String rowId,
|
||||
required double rowHeight,
|
||||
required Future<List<GridCellData>> cellDatas,
|
||||
required bool active,
|
||||
required double rowHeight,
|
||||
required List<Field> fields,
|
||||
required Future<Option<Row>> row,
|
||||
required Future<CellDataMap> cellDataMap,
|
||||
}) = _RowState;
|
||||
|
||||
factory RowState.initial(GridRowData data) => RowState(
|
||||
rowId: data.rowId,
|
||||
rowHeight: data.height,
|
||||
cellDatas: Future(() => []),
|
||||
active: false,
|
||||
rowHeight: data.height,
|
||||
fields: data.fields,
|
||||
row: Future(() => none()),
|
||||
cellDataMap: Future(() => CellDataMap.identity()),
|
||||
);
|
||||
}
|
||||
|
@ -11,13 +11,14 @@ import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef UpdateCellNotifiedValue = Either<RepeatedCell, FlowyError>;
|
||||
typedef UpdateRowNotifiedValue = Either<Row, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<List<Field>, FlowyError>;
|
||||
|
||||
class RowListener {
|
||||
final String rowId;
|
||||
PublishNotifier<UpdateCellNotifiedValue> updateCellNotifier = PublishNotifier<UpdateCellNotifiedValue>();
|
||||
PublishNotifier<UpdateRowNotifiedValue> updateRowNotifier = PublishNotifier<UpdateRowNotifiedValue>();
|
||||
PublishNotifier<UpdateCellNotifiedValue> updateCellNotifier = PublishNotifier();
|
||||
PublishNotifier<UpdateRowNotifiedValue> updateRowNotifier = PublishNotifier();
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
late GridNotificationParser _parser;
|
||||
GridNotificationParser? _parser;
|
||||
|
||||
RowListener({required this.rowId});
|
||||
|
||||
@ -29,7 +30,7 @@ class RowListener {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -40,15 +41,54 @@ class RowListener {
|
||||
(error) => updateCellNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
updateCellNotifier.dispose();
|
||||
updateRowNotifier.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class RowFieldListener {
|
||||
final String gridId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue> updateFieldNotifier = PublishNotifier();
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
GridNotificationParser? _parser;
|
||||
|
||||
RowFieldListener({required this.gridId});
|
||||
|
||||
void start() {
|
||||
_parser = GridNotificationParser(
|
||||
id: gridId,
|
||||
callback: (ty, result) {
|
||||
_handleObservableType(ty, result);
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateFields:
|
||||
result.fold(
|
||||
(payload) => updateFieldNotifier.value = left(RepeatedField.fromBuffer(payload).items),
|
||||
(error) => updateFieldNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
updateFieldNotifier.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,51 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.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:app_flowy/workspace/application/grid/prelude.dart';
|
||||
|
||||
class RowService {
|
||||
final GridRowData rowData;
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
|
||||
RowService(this.rowData);
|
||||
RowService({required this.gridId, required this.rowId, required this.blockId});
|
||||
|
||||
Future<Either<Row, FlowyError>> createRow() {
|
||||
CreateRowPayload payload = CreateRowPayload.create()
|
||||
..gridId = rowData.gridId
|
||||
..startRowId = rowData.rowId;
|
||||
..gridId = gridId
|
||||
..startRowId = rowId;
|
||||
|
||||
return GridEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Row, FlowyError>> getRow() {
|
||||
QueryRowPayload payload = QueryRowPayload.create()
|
||||
..gridId = rowData.gridId
|
||||
..blockId = rowData.blockId
|
||||
..rowId = rowData.rowId;
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
|
||||
return GridEventGetRow(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
class GridCellData {
|
||||
typedef FutureCellData = Future<GridCellData?>;
|
||||
|
||||
class GridCellData extends Equatable {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final Field field;
|
||||
final Cell? cell;
|
||||
|
||||
GridCellData({
|
||||
const GridCellData({
|
||||
required this.rowId,
|
||||
required this.gridId,
|
||||
required this.blockId,
|
||||
required this.field,
|
||||
required this.cell,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [cell, field];
|
||||
}
|
||||
|
@ -13,12 +13,12 @@ typedef TrashUpdatedCallback = void Function(Either<List<Trash>, FlowyError> tra
|
||||
class TrashListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
TrashUpdatedCallback? _trashUpdated;
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
|
||||
void start({TrashUpdatedCallback? trashUpdated}) {
|
||||
_trashUpdated = trashUpdated;
|
||||
_parser = FolderNotificationParser(callback: _bservableCallback);
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _bservableCallback(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -40,6 +40,7 @@ class TrashListener {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
_trashUpdated = null;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class ViewListener {
|
||||
PublishNotifier<UpdateViewNotifiedValue> updatedNotifier = PublishNotifier<UpdateViewNotifiedValue>();
|
||||
PublishNotifier<DeleteViewNotifyValue> deletedNotifier = PublishNotifier<DeleteViewNotifyValue>();
|
||||
PublishNotifier<RestoreViewNotifiedValue> restoredNotifier = PublishNotifier<RestoreViewNotifiedValue>();
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
View view;
|
||||
|
||||
ViewListener({
|
||||
@ -33,7 +33,7 @@ class ViewListener {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -62,6 +62,7 @@ class ViewListener {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
updatedNotifier.dispose();
|
||||
deletedNotifier.dispose();
|
||||
|
@ -12,7 +12,6 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
|
||||
typedef WorkspaceAppsChangedCallback = void Function(Either<List<App>, FlowyError> appsOrFail);
|
||||
typedef WorkspaceUpdatedCallback = void Function(String name, String desc);
|
||||
|
||||
@ -31,12 +30,11 @@ class WorkspaceListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class WorkspaceListenerService {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
WorkspaceAppsChangedCallback? _appsChanged;
|
||||
WorkspaceUpdatedCallback? _update;
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
final UserProfile user;
|
||||
final String workspaceId;
|
||||
|
||||
@ -59,7 +57,7 @@ class WorkspaceListenerService {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -91,6 +89,7 @@ class WorkspaceListenerService {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
// _appsChanged = null;
|
||||
// _update = null;
|
||||
|
@ -1,15 +1,13 @@
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/grid_service.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart';
|
||||
import 'package:flowy_infra_ui/widget/error_page.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';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
import 'controller/grid_scroll.dart';
|
||||
import 'layout/layout.dart';
|
||||
import 'layout/sizes.dart';
|
||||
@ -92,16 +90,33 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
return const Center(child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
|
||||
return _wrapScrollbar(state.fields, [
|
||||
_buildHeader(gridId, state.fields),
|
||||
_buildRows(context),
|
||||
const GridFooter(),
|
||||
]);
|
||||
final child = BlocBuilder<GridBloc, GridState>(
|
||||
builder: (context, state) {
|
||||
return SizedBox(
|
||||
width: GridLayout.headerWidth(state.fields),
|
||||
child: ScrollConfiguration(
|
||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
||||
child: CustomScrollView(
|
||||
shrinkWrap: true,
|
||||
physics: StyledScrollPhysics(),
|
||||
controller: _scrollController.verticalController,
|
||||
slivers: [
|
||||
_buildHeader(gridId),
|
||||
_buildRows(context),
|
||||
const GridFooter(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return _wrapScrollbar(child);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _wrapScrollbar(List<Field> fields, List<Widget> children) {
|
||||
Widget _wrapScrollbar(Widget child) {
|
||||
return ScrollbarListStack(
|
||||
axis: Axis.vertical,
|
||||
controller: _scrollController.verticalController,
|
||||
@ -109,38 +124,39 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
child: StyledSingleChildScrollView(
|
||||
controller: _scrollController.horizontalController,
|
||||
axis: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: GridLayout.headerWidth(fields),
|
||||
child: ScrollConfiguration(
|
||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
||||
child: CustomScrollView(
|
||||
physics: StyledScrollPhysics(),
|
||||
controller: _scrollController.verticalController,
|
||||
slivers: <Widget>[...children],
|
||||
),
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
).padding(right: 0, top: GridSize.headerHeight, bottom: GridSize.scrollBarSize);
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader(String gridId, List<Field> fields) {
|
||||
return SliverPersistentHeader(
|
||||
delegate: GridHeaderDelegate(gridId: gridId, fields: fields),
|
||||
floating: true,
|
||||
pinned: true,
|
||||
Widget _buildHeader(String gridId) {
|
||||
return BlocBuilder<GridBloc, GridState>(
|
||||
buildWhen: (previous, current) => previous.fields.length != current.fields.length,
|
||||
builder: (context, state) {
|
||||
return SliverPersistentHeader(
|
||||
delegate: GridHeaderDelegate(gridId: gridId, fields: state.fields),
|
||||
floating: true,
|
||||
pinned: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRows(BuildContext context) {
|
||||
return BlocBuilder<GridBloc, GridState>(
|
||||
buildWhen: (previous, current) => previous.rows.length != current.rows.length,
|
||||
buildWhen: (previous, current) {
|
||||
final rowChanged = previous.rows.length != current.rows.length;
|
||||
// final fieldChanged = previous.fields.length != current.fields.length;
|
||||
return rowChanged;
|
||||
},
|
||||
builder: (context, state) {
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final rowData = context.read<GridBloc>().state.rows[index];
|
||||
return GridRowWidget(data: rowData);
|
||||
final blockRow = context.read<GridBloc>().state.rows[index];
|
||||
final fields = context.read<GridBloc>().state.fields;
|
||||
final rowData = GridRowData.fromBlockRow(blockRow, fields);
|
||||
return GridRowWidget(data: rowData, key: ValueKey(rowData.rowId));
|
||||
},
|
||||
childCount: context.read<GridBloc>().state.rows.length,
|
||||
addRepaintBoundaries: true,
|
||||
|
@ -7,20 +7,20 @@ import 'number_cell.dart';
|
||||
import 'selection_cell.dart';
|
||||
import 'text_cell.dart';
|
||||
|
||||
Widget buildGridCell(GridCellData cellData) {
|
||||
switch (cellData.field.fieldType) {
|
||||
Widget buildGridCell(FieldType fieldType, FutureCellData cellData) {
|
||||
switch (fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return CheckboxCell(cellData: cellData);
|
||||
return CheckboxCell(cellData: cellData, key: ObjectKey(cellData));
|
||||
case FieldType.DateTime:
|
||||
return DateCell(cellData: cellData);
|
||||
return DateCell(cellData: cellData, key: ObjectKey(cellData));
|
||||
case FieldType.MultiSelect:
|
||||
return MultiSelectCell(cellContext: cellData);
|
||||
return MultiSelectCell(cellData: cellData, key: ObjectKey(cellData));
|
||||
case FieldType.Number:
|
||||
return NumberCell(cellData: cellData);
|
||||
return NumberCell(cellData: cellData, key: ObjectKey(cellData));
|
||||
case FieldType.RichText:
|
||||
return GridTextCell(cellData: cellData);
|
||||
return GridTextCell(cellData: cellData, key: ObjectKey(cellData));
|
||||
case FieldType.SingleSelect:
|
||||
return SingleSelectCell(cellContext: cellData);
|
||||
return SingleSelectCell(cellData: cellData, key: ObjectKey(cellData));
|
||||
default:
|
||||
throw UnimplementedError;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class CheckboxCell extends StatefulWidget {
|
||||
final GridCellData cellData;
|
||||
final FutureCellData cellData;
|
||||
|
||||
const CheckboxCell({
|
||||
required this.cellData,
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DateCell extends StatefulWidget {
|
||||
final GridCellData cellData;
|
||||
final FutureCellData cellData;
|
||||
|
||||
const DateCell({
|
||||
required this.cellData,
|
||||
|
@ -4,61 +4,38 @@ import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.d
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'cell_builder.dart';
|
||||
import 'cell_container.dart';
|
||||
|
||||
class GridRowWidget extends StatefulWidget {
|
||||
class GridRowWidget extends StatelessWidget {
|
||||
final GridRowData data;
|
||||
GridRowWidget({required this.data, Key? key}) : super(key: ValueKey(data.rowId));
|
||||
|
||||
@override
|
||||
State<GridRowWidget> createState() => _GridRowWidgetState();
|
||||
}
|
||||
|
||||
class _GridRowWidgetState extends State<GridRowWidget> {
|
||||
late RowBloc _rowBloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_rowBloc = getIt<RowBloc>(param1: widget.data)..add(const RowEvent.initial());
|
||||
super.initState();
|
||||
}
|
||||
const GridRowWidget({required this.data, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider.value(
|
||||
value: _rowBloc,
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (p) => _rowBloc.add(const RowEvent.activeRow()),
|
||||
onExit: (p) => _rowBloc.add(const RowEvent.disactiveRow()),
|
||||
child: BlocBuilder<RowBloc, RowState>(
|
||||
buildWhen: (p, c) => p.rowHeight != c.rowHeight,
|
||||
builder: (context, state) {
|
||||
return SizedBox(
|
||||
height: _rowBloc.state.rowHeight,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: const [
|
||||
_RowLeading(),
|
||||
_RowCells(),
|
||||
_RowTrailing(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<RowBloc>(param1: data)..add(const RowEvent.initial()),
|
||||
child: BlocBuilder<RowBloc, RowState>(
|
||||
buildWhen: (p, c) => p.rowHeight != c.rowHeight,
|
||||
builder: (context, state) {
|
||||
return SizedBox(
|
||||
height: state.rowHeight,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: const [
|
||||
_RowLeading(),
|
||||
_RowCells(),
|
||||
_RowTrailing(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
_rowBloc.close();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class _RowLeading extends StatelessWidget {
|
||||
@ -115,30 +92,19 @@ class _RowCells extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RowBloc, RowState>(
|
||||
buildWhen: (previous, current) => previous.cellDatas != current.cellDatas,
|
||||
builder: (context, state) {
|
||||
return FutureBuilder(
|
||||
future: state.cellDatas,
|
||||
builder: builder,
|
||||
);
|
||||
return Row(children: [
|
||||
...state.fields.map(
|
||||
(field) {
|
||||
final cellData = state.cellDataMap.then((fut) => fut[field.id]);
|
||||
return CellContainer(
|
||||
width: field.width.toDouble(),
|
||||
child: buildGridCell(field.fieldType, cellData),
|
||||
);
|
||||
},
|
||||
),
|
||||
]);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget builder(context, AsyncSnapshot<dynamic> snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.done:
|
||||
List<GridCellData> cellDatas = snapshot.data;
|
||||
return Row(children: cellDatas.map(_toCell).toList());
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _toCell(GridCellData data) {
|
||||
return CellContainer(
|
||||
width: data.field.width.toDouble(),
|
||||
child: buildGridCell(data),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class NumberCell extends StatefulWidget {
|
||||
final GridCellData cellData;
|
||||
final FutureCellData cellData;
|
||||
|
||||
const NumberCell({
|
||||
required this.cellData,
|
||||
|
@ -3,10 +3,10 @@ import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SingleSelectCell extends StatefulWidget {
|
||||
final GridCellData cellContext;
|
||||
final FutureCellData cellData;
|
||||
|
||||
const SingleSelectCell({
|
||||
required this.cellContext,
|
||||
required this.cellData,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -19,7 +19,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellContext);
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellData);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@ -37,10 +37,10 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||
|
||||
//----------------------------------------------------------------
|
||||
class MultiSelectCell extends StatefulWidget {
|
||||
final GridCellData cellContext;
|
||||
final FutureCellData cellData;
|
||||
|
||||
const MultiSelectCell({
|
||||
required this.cellContext,
|
||||
required this.cellData,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -53,7 +53,7 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellContext);
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellData);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
/// The interface of base cell.
|
||||
|
||||
class GridTextCell extends StatefulWidget {
|
||||
final GridCellData cellData;
|
||||
final FutureCellData cellData;
|
||||
const GridTextCell({
|
||||
required this.cellData,
|
||||
Key? key,
|
||||
@ -36,9 +36,11 @@ class _GridTextCellState extends State<GridTextCell> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider.value(
|
||||
value: _cellBloc!,
|
||||
child: BlocBuilder<TextCellBloc, TextCellState>(
|
||||
buildWhen: (previous, current) {
|
||||
return _controller.text != current.content;
|
||||
child: BlocConsumer<TextCellBloc, TextCellState>(
|
||||
listener: (context, state) {
|
||||
if (_controller.text != state.content) {
|
||||
_controller.text = state.content;
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return TextField(
|
||||
|
@ -1,10 +1,10 @@
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/create_field_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/switch_field_type_bloc.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row;
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'field_name_input.dart';
|
||||
@ -21,7 +21,7 @@ class CreateFieldPannel extends FlowyOverlayDelegate {
|
||||
FlowyOverlay.of(context).insertWithAnchor(
|
||||
widget: OverlayContainer(
|
||||
child: _CreateFieldPannelWidget(_createFieldBloc),
|
||||
constraints: BoxConstraints.loose(const Size(220, 200)),
|
||||
constraints: BoxConstraints.loose(const Size(220, 400)),
|
||||
),
|
||||
identifier: identifier(),
|
||||
anchorContext: context,
|
||||
@ -36,7 +36,7 @@ class CreateFieldPannel extends FlowyOverlayDelegate {
|
||||
}
|
||||
|
||||
@override
|
||||
void didRemove() async {
|
||||
void didRemove() {
|
||||
_createFieldBloc.add(const CreateFieldEvent.done());
|
||||
}
|
||||
}
|
||||
@ -51,16 +51,16 @@ class _CreateFieldPannelWidget extends StatelessWidget {
|
||||
value: createFieldBloc,
|
||||
child: BlocBuilder<CreateFieldBloc, CreateFieldState>(
|
||||
builder: (context, state) {
|
||||
return state.editContext.fold(
|
||||
return state.field.fold(
|
||||
() => const SizedBox(),
|
||||
(editContext) => ListView(
|
||||
(field) => ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
const FlowyText.medium("Edit property", fontSize: 12),
|
||||
const VSpace(10),
|
||||
_FieldNameTextField(editContext.gridField),
|
||||
const _FieldNameTextField(),
|
||||
const VSpace(10),
|
||||
_FieldTypeSwitcher(editContext),
|
||||
_FieldTypeSwitcher(SwitchFieldContext(state.gridId, field, state.typeOptionData)),
|
||||
const VSpace(10),
|
||||
],
|
||||
),
|
||||
@ -72,26 +72,35 @@ class _CreateFieldPannelWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _FieldTypeSwitcher extends StatelessWidget {
|
||||
final EditFieldContext editContext;
|
||||
const _FieldTypeSwitcher(this.editContext, {Key? key}) : super(key: key);
|
||||
final SwitchFieldContext switchContext;
|
||||
const _FieldTypeSwitcher(this.switchContext, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FieldTypeSwitcher(editContext: editContext);
|
||||
}
|
||||
}
|
||||
|
||||
class _FieldNameTextField extends StatelessWidget {
|
||||
final Field field;
|
||||
const _FieldNameTextField(this.field, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FieldNameTextField(
|
||||
name: field.name,
|
||||
errorText: context.read<CreateFieldBloc>().state.errorText,
|
||||
onNameChanged: (newName) {
|
||||
context.read<CreateFieldBloc>().add(CreateFieldEvent.updateName(newName));
|
||||
return FieldTypeSwitcher(
|
||||
switchContext: switchContext,
|
||||
onSelected: (field, typeOptionData) {
|
||||
context.read<CreateFieldBloc>().add(CreateFieldEvent.switchField(field, typeOptionData));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FieldNameTextField extends StatelessWidget {
|
||||
const _FieldNameTextField({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<CreateFieldBloc, CreateFieldState>(
|
||||
buildWhen: (previous, current) => previous.fieldName != current.fieldName,
|
||||
builder: (context, state) {
|
||||
return FieldNameTextField(
|
||||
name: state.fieldName,
|
||||
errorText: context.read<CreateFieldBloc>().state.errorText,
|
||||
onNameChanged: (newName) {
|
||||
context.read<CreateFieldBloc>().add(CreateFieldEvent.updateName(newName));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -60,7 +60,12 @@ class _FieldTypeSwitcher extends StatelessWidget {
|
||||
return BlocBuilder<EditFieldBloc, EditFieldState>(
|
||||
builder: (context, state) {
|
||||
final editContext = context.read<EditFieldBloc>().state.editContext;
|
||||
return FieldTypeSwitcher(editContext: editContext);
|
||||
final switchContext = SwitchFieldContext(
|
||||
editContext.gridId,
|
||||
editContext.gridField,
|
||||
editContext.typeOptionData,
|
||||
);
|
||||
return FieldTypeSwitcher(switchContext: switchContext, onSelected: (field, typeOptionData) {});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -17,20 +17,22 @@ import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
typedef SelectFieldCallback = void Function(FieldType);
|
||||
typedef SelectFieldCallback = void Function(Field, Uint8List);
|
||||
|
||||
class FieldTypeSwitcher extends StatelessWidget {
|
||||
final EditFieldContext editContext;
|
||||
final SwitchFieldContext switchContext;
|
||||
final SelectFieldCallback onSelected;
|
||||
|
||||
const FieldTypeSwitcher({
|
||||
required this.editContext,
|
||||
required this.switchContext,
|
||||
required this.onSelected,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<SwitchFieldTypeBloc>(param1: editContext),
|
||||
create: (context) => getIt<SwitchFieldTypeBloc>(param1: switchContext),
|
||||
child: BlocBuilder<SwitchFieldTypeBloc, SwitchFieldTypeState>(
|
||||
builder: (context, state) {
|
||||
List<Widget> children = [
|
||||
@ -133,7 +135,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<NumberTypeOptionBloc>(),
|
||||
child: Container(),
|
||||
child: Container(height: 30, color: Colors.green),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -157,7 +159,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<DateTypeOptionBloc>(),
|
||||
child: Container(),
|
||||
child: Container(height: 80, color: Colors.red),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -194,7 +196,7 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<SelectionTypeOptionBloc>(),
|
||||
child: Container(),
|
||||
child: Container(height: 100, color: Colors.yellow),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -219,7 +221,7 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<SelectionTypeOptionBloc>(),
|
||||
child: Container(),
|
||||
child: Container(height: 100, color: Colors.blue),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class GridHeaderDelegate extends SliverPersistentHeaderDelegate {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
return GridHeader(gridId: gridId, fields: fields);
|
||||
return GridHeader(gridId: gridId, fields: fields, key: ObjectKey(fields));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -63,13 +63,11 @@ class _StyledSingleChildScrollViewState extends State<StyledSingleChildScrollVie
|
||||
barSize: widget.barSize,
|
||||
trackColor: widget.trackColor,
|
||||
handleColor: widget.handleColor,
|
||||
child: SizedBox.expand(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: widget.axis,
|
||||
physics: StyledScrollPhysics(),
|
||||
controller: scrollController,
|
||||
child: widget.child,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: widget.axis,
|
||||
physics: StyledScrollPhysics(),
|
||||
controller: scrollController,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#[macro_export]
|
||||
macro_rules! impl_into_box_type_option_builder {
|
||||
($target: ident) => {
|
||||
impl std::convert::Into<BoxTypeOptionBuilder> for $target {
|
||||
fn into(self) -> Box<dyn TypeOptionBuilder> {
|
||||
Box::new(self)
|
||||
impl std::convert::From<$target> for BoxTypeOptionBuilder {
|
||||
fn from(target: $target) -> BoxTypeOptionBuilder {
|
||||
Box::new(target)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -6,8 +6,7 @@ use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::{
|
||||
FieldMeta, GridBlockId, GridBlockMeta, GridBlockMetaChangeset, GridBlockOrder, RepeatedCell, RowMeta,
|
||||
RowMetaChangeset, RowOrder,
|
||||
FieldMeta, GridBlockMeta, GridBlockMetaChangeset, GridBlockOrder, RepeatedCell, RowMeta, RowMetaChangeset, RowOrder,
|
||||
};
|
||||
use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence;
|
||||
use flowy_revision::{
|
||||
@ -71,7 +70,7 @@ impl GridBlockMetaEditorManager {
|
||||
.insert(row_meta.id.clone(), row_meta.block_id.clone());
|
||||
let editor = self.get_editor(&row_meta.block_id).await?;
|
||||
let row_count = editor.create_row(row_meta, start_row_id).await?;
|
||||
self.notify_block_did_update_row(&block_id).await?;
|
||||
self.notify_block_did_update_row(block_id).await?;
|
||||
Ok(row_count)
|
||||
}
|
||||
|
||||
|
@ -69,20 +69,20 @@ fn string_to_bool(bool_str: &str) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::services::cell::CheckboxTypeOption;
|
||||
use crate::services::field::CheckboxTypeOption;
|
||||
use crate::services::row::CellDataSerde;
|
||||
|
||||
#[test]
|
||||
fn checkout_box_description_test() {
|
||||
let type_option = CheckboxTypeOption::default();
|
||||
assert_eq!(description.serialize_cell_data("true").unwrap(), "1".to_owned());
|
||||
assert_eq!(description.serialize_cell_data("1").unwrap(), "1".to_owned());
|
||||
assert_eq!(description.serialize_cell_data("yes").unwrap(), "1".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("true").unwrap(), "1".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("1").unwrap(), "1".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("yes").unwrap(), "1".to_owned());
|
||||
|
||||
assert_eq!(description.serialize_cell_data("false").unwrap(), "0".to_owned());
|
||||
assert_eq!(description.serialize_cell_data("no").unwrap(), "0".to_owned());
|
||||
assert_eq!(description.serialize_cell_data("123").unwrap(), "0".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("false").unwrap(), "0".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("no").unwrap(), "0".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("123").unwrap(), "0".to_owned());
|
||||
|
||||
assert_eq!(description.deserialize_cell_data("1".to_owned()), "1".to_owned());
|
||||
assert_eq!(type_option.deserialize_cell_data("1".to_owned()), "1".to_owned());
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ impl std::default::Default for TimeFormat {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::services::cell::{DateFormat, DateTypeOption, TimeFormat};
|
||||
use crate::services::field::{DateFormat, DateTypeOption, TimeFormat};
|
||||
use crate::services::row::CellDataSerde;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
@ -267,6 +267,6 @@ mod tests {
|
||||
#[should_panic]
|
||||
fn date_description_invalid_data_test() {
|
||||
let type_option = DateTypeOption::default();
|
||||
description.serialize_cell_data("he").unwrap();
|
||||
type_option.serialize_cell_data("he").unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -192,41 +192,41 @@ fn make_strip_symbol() -> Vec<String> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::services::cell::{NumberFormat, NumberTypeOption};
|
||||
use crate::services::field::{NumberFormat, NumberTypeOption};
|
||||
use crate::services::row::CellDataSerde;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
#[test]
|
||||
fn number_description_test() {
|
||||
let mut description = NumberTypeOption::default();
|
||||
assert_eq!(description.serialize_cell_data("¥18,443").unwrap(), "18443".to_owned());
|
||||
assert_eq!(description.serialize_cell_data("$18,443").unwrap(), "18443".to_owned());
|
||||
assert_eq!(description.serialize_cell_data("€18.443").unwrap(), "18443".to_owned());
|
||||
let mut type_option = NumberTypeOption::default();
|
||||
assert_eq!(type_option.serialize_cell_data("¥18,443").unwrap(), "18443".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("$18,443").unwrap(), "18443".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("€18.443").unwrap(), "18443".to_owned());
|
||||
|
||||
for format in NumberFormat::iter() {
|
||||
description.format = format;
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Number => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"18443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::USD => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"$18,443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::CNY => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"¥18,443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::EUR => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"€18.443".to_owned()
|
||||
);
|
||||
}
|
||||
@ -236,35 +236,35 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn number_description_scale_test() {
|
||||
let mut description = NumberTypeOption {
|
||||
let mut type_option = NumberTypeOption {
|
||||
scale: 1,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
for format in NumberFormat::iter() {
|
||||
description.format = format;
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Number => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"18443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::USD => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"$1,844.3".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::CNY => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"¥1,844.3".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::EUR => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"€1.844,3".to_owned()
|
||||
);
|
||||
}
|
||||
@ -274,35 +274,35 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn number_description_sign_test() {
|
||||
let mut description = NumberTypeOption {
|
||||
let mut type_option = NumberTypeOption {
|
||||
sign_positive: false,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
for format in NumberFormat::iter() {
|
||||
description.format = format;
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Number => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"18443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::USD => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"-$18,443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::CNY => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"-¥18,443".to_owned()
|
||||
);
|
||||
}
|
||||
NumberFormat::EUR => {
|
||||
assert_eq!(
|
||||
description.deserialize_cell_data("18443".to_owned()),
|
||||
type_option.deserialize_cell_data("18443".to_owned()),
|
||||
"-€18.443".to_owned()
|
||||
);
|
||||
}
|
||||
|
@ -166,16 +166,16 @@ impl SelectOption {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::services::cell::{MultiSelectDescription, SingleSelectTypeOption};
|
||||
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
|
||||
use crate::services::row::CellDataSerde;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn selection_description_test() {
|
||||
let type_option = SingleSelectTypeOption::default();
|
||||
assert_eq!(description.serialize_cell_data("1,2,3").unwrap(), "1".to_owned());
|
||||
assert_eq!(type_option.serialize_cell_data("1,2,3").unwrap(), "1".to_owned());
|
||||
|
||||
let type_option = MultiSelectDescription::default();
|
||||
assert_eq!(description.serialize_cell_data("1,2,3").unwrap(), "1,2,3".to_owned());
|
||||
let type_option = MultiSelectTypeOption::default();
|
||||
assert_eq!(type_option.serialize_cell_data("1,2,3").unwrap(), "1,2,3".to_owned());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::block_meta_editor::GridBlockMetaEditorManager;
|
||||
use crate::services::field::{default_type_option_builder_from_type, type_option_json_str_from_bytes, FieldBuilder};
|
||||
use crate::services::field::{type_option_json_str_from_bytes, FieldBuilder};
|
||||
use crate::services::row::*;
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
@ -78,8 +78,8 @@ impl ClientGridEditor {
|
||||
}
|
||||
|
||||
pub async fn default_field_meta(&self, field_type: &FieldType) -> FlowyResult<FieldMeta> {
|
||||
let name = format!("Property {}", self.pad.read().await.fields().len());
|
||||
let field_meta = FieldBuilder::from_field_type(&field_type).name(&name).build();
|
||||
let name = format!("Property {}", self.pad.read().await.fields().len() + 1);
|
||||
let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build();
|
||||
Ok(field_meta)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::services::field::*;
|
||||
use flowy_grid_data_model::entities::{BuildGridContext, FieldType};
|
||||
use flowy_grid_data_model::entities::BuildGridContext;
|
||||
use flowy_sync::client_grid::GridBuilder;
|
||||
|
||||
pub fn make_default_grid() -> BuildGridContext {
|
||||
|
@ -254,19 +254,19 @@ async fn grid_row_add_cells_test() {
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field);
|
||||
let options = description.options.first().unwrap();
|
||||
let data = description.serialize_cell_data(&options.id).unwrap();
|
||||
let options = type_option.options.first().unwrap();
|
||||
let data = type_option.serialize_cell_data(&options.id).unwrap();
|
||||
builder.add_cell(&field.id, data).unwrap();
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let type_option = MultiSelectTypeOption::from(field);
|
||||
let options = description
|
||||
let options = type_option
|
||||
.options
|
||||
.iter()
|
||||
.map(|option| option.id.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(SELECTION_IDS_SEPARATOR);
|
||||
let data = description.serialize_cell_data(&options).unwrap();
|
||||
let data = type_option.serialize_cell_data(&options).unwrap();
|
||||
builder.add_cell(&field.id, data).unwrap();
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
@ -383,11 +383,11 @@ async fn grid_cell_update() {
|
||||
FieldType::DateTime => "123".to_string(),
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field_meta);
|
||||
description.options.first().unwrap().id.clone()
|
||||
type_option.options.first().unwrap().id.clone()
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let type_option = MultiSelectTypeOption::from(field_meta);
|
||||
description.options.first().unwrap().id.clone()
|
||||
type_option.options.first().unwrap().id.clone()
|
||||
}
|
||||
FieldType::Checkbox => "1".to_string(),
|
||||
};
|
||||
|
@ -3,8 +3,8 @@ use flowy_grid::services::field::*;
|
||||
use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
|
||||
use flowy_grid::services::row::CreateRowMetaPayload;
|
||||
use flowy_grid_data_model::entities::{
|
||||
BuildGridContext, CellMetaChangeset, CreateFieldPayload, Field, FieldChangeset, FieldMeta, FieldType,
|
||||
GridBlockMeta, GridBlockMetaChangeset, RowMeta, RowMetaChangeset, RowOrder,
|
||||
BuildGridContext, CellMetaChangeset, Field, FieldChangeset, FieldMeta, FieldType, GridBlockMeta,
|
||||
GridBlockMetaChangeset, RowMeta, RowMetaChangeset, RowOrder,
|
||||
};
|
||||
use flowy_grid_data_model::parser::CreateFieldParams;
|
||||
use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
|
||||
|
@ -4,6 +4,7 @@ mod op_test;
|
||||
mod serde_test;
|
||||
mod undo_redo_test;
|
||||
|
||||
use derive_more::Display;
|
||||
use flowy_sync::client_document::{ClientDocument, InitialDocumentText};
|
||||
use lib_ot::{
|
||||
core::*,
|
||||
|
@ -39,20 +39,6 @@ pub struct Field {
|
||||
pub width: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldOrder {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
}
|
||||
|
||||
impl std::convert::From<&FieldMeta> for FieldOrder {
|
||||
fn from(field_meta: &FieldMeta) -> Self {
|
||||
Self {
|
||||
field_id: field_meta.id.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<FieldMeta> for Field {
|
||||
fn from(field_meta: FieldMeta) -> Self {
|
||||
Self {
|
||||
@ -67,6 +53,20 @@ impl std::convert::From<FieldMeta> for Field {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldOrder {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
}
|
||||
|
||||
impl std::convert::From<&FieldMeta> for FieldOrder {
|
||||
fn from(field_meta: &FieldMeta) -> Self {
|
||||
Self {
|
||||
field_id: field_meta.id.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct CreateEditFieldContextParams {
|
||||
#[pb(index = 1)]
|
||||
|
@ -4,12 +4,11 @@ use uuid::Uuid;
|
||||
pub struct NotEmptyUuid(pub String);
|
||||
|
||||
impl NotEmptyUuid {
|
||||
pub fn parse(s: String) -> Result<NotEmptyUuid, ()> {
|
||||
debug_assert!(Uuid::parse_str(&s).is_ok());
|
||||
|
||||
pub fn parse(s: String) -> Result<Self, String> {
|
||||
if s.trim().is_empty() {
|
||||
return Err(());
|
||||
return Err("Input string is empty".to_owned());
|
||||
}
|
||||
debug_assert!(Uuid::parse_str(&s).is_ok());
|
||||
|
||||
Ok(Self(s))
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use bytes::Bytes;
|
||||
use flowy_grid_data_model::entities::{
|
||||
FieldChangeset, FieldMeta, FieldOrder, GridBlockMeta, GridBlockMetaChangeset, GridMeta, RepeatedFieldOrder,
|
||||
};
|
||||
use flowy_grid_data_model::parser::CreateFieldParams;
|
||||
|
||||
use lib_infra::uuid;
|
||||
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
||||
use std::collections::HashMap;
|
||||
@ -43,12 +43,7 @@ impl GridMetaPad {
|
||||
) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid| {
|
||||
// Check if the field exists or not
|
||||
if grid
|
||||
.fields
|
||||
.iter()
|
||||
.find(|field_meta| field_meta.id == new_field_meta.id)
|
||||
.is_some()
|
||||
{
|
||||
if grid.fields.iter().any(|field_meta| field_meta.id == new_field_meta.id) {
|
||||
tracing::warn!("Duplicate grid field");
|
||||
return Ok(None);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user