mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
commit
b3764e601f
@ -168,34 +168,34 @@ void _resolveGridDeps(GetIt getIt) {
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<TextCellBloc, GridCell, void>(
|
||||
(cellData, _) => TextCellBloc(
|
||||
cellData: cellData,
|
||||
getIt.registerFactoryParam<TextCellBloc, GridDefaultCellContext, void>(
|
||||
(context, _) => TextCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SelectionCellBloc, GridCell, void>(
|
||||
(cellData, _) => SelectionCellBloc(
|
||||
cellData: cellData,
|
||||
getIt.registerFactoryParam<SelectionCellBloc, GridSelectOptionCellContext, void>(
|
||||
(context, _) => SelectionCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<NumberCellBloc, GridCell, void>(
|
||||
(cellData, _) => NumberCellBloc(
|
||||
cellData: cellData,
|
||||
getIt.registerFactoryParam<NumberCellBloc, GridDefaultCellContext, void>(
|
||||
(context, _) => NumberCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<DateCellBloc, GridCell, void>(
|
||||
(cellData, _) => DateCellBloc(
|
||||
cellData: cellData,
|
||||
getIt.registerFactoryParam<DateCellBloc, GridDefaultCellContext, void>(
|
||||
(context, _) => DateCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, GridCell, void>(
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, GridDefaultCellContext, void>(
|
||||
(cellData, _) => CheckboxCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
cellContext: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
@ -7,16 +6,17 @@ import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<CellNotificationData, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<Unit, FlowyError>;
|
||||
|
||||
class CellListener {
|
||||
final String rowId;
|
||||
final String fieldId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue>? updateCellNotifier = PublishNotifier();
|
||||
PublishNotifier<UpdateFieldNotifiedValue>? _updateCellNotifier = PublishNotifier();
|
||||
GridNotificationListener? _listener;
|
||||
CellListener({required this.rowId, required this.fieldId});
|
||||
|
||||
void start() {
|
||||
void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) {
|
||||
_updateCellNotifier?.addPublishListener(onCellChanged);
|
||||
_listener = GridNotificationListener(objectId: "$rowId:$fieldId", handler: _handler);
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@ class CellListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateCell:
|
||||
result.fold(
|
||||
(payload) => updateCellNotifier?.value = left(CellNotificationData.fromBuffer(payload)),
|
||||
(error) => updateCellNotifier?.value = right(error),
|
||||
(payload) => _updateCellNotifier?.value = left(unit),
|
||||
(error) => _updateCellNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@ -35,7 +35,7 @@ class CellListener {
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
updateCellNotifier?.dispose();
|
||||
updateCellNotifier = null;
|
||||
_updateCellNotifier?.dispose();
|
||||
_updateCellNotifier = null;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,290 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.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/log.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/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
part 'cell_service.freezed.dart';
|
||||
|
||||
typedef GridDefaultCellContext = GridCellContext<Cell>;
|
||||
typedef GridSelectOptionCellContext = GridCellContext<SelectOptionContext>;
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class GridCellContext<T> extends Equatable {
|
||||
final GridCell gridCell;
|
||||
final GridCellCache cellCache;
|
||||
final GridCellCacheKey _cacheKey;
|
||||
final GridCellDataLoader<T> cellDataLoader;
|
||||
final CellService _cellService = CellService();
|
||||
|
||||
late final CellListener _cellListener;
|
||||
late final ValueNotifier<T?> _cellDataNotifier;
|
||||
bool isListening = false;
|
||||
VoidCallback? _onFieldChangedFn;
|
||||
Timer? _delayOperation;
|
||||
|
||||
GridCellContext({
|
||||
required this.gridCell,
|
||||
required this.cellCache,
|
||||
required this.cellDataLoader,
|
||||
}) : _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id);
|
||||
|
||||
GridCellContext<T> clone() {
|
||||
return GridCellContext(
|
||||
gridCell: gridCell,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellCache: cellCache,
|
||||
);
|
||||
}
|
||||
|
||||
String get gridId => gridCell.gridId;
|
||||
|
||||
String get rowId => gridCell.rowId;
|
||||
|
||||
String get cellId => gridCell.rowId + gridCell.field.id;
|
||||
|
||||
String get fieldId => gridCell.field.id;
|
||||
|
||||
Field get field => gridCell.field;
|
||||
|
||||
FieldType get fieldType => gridCell.field.fieldType;
|
||||
|
||||
GridCellCacheKey get cacheKey => _cacheKey;
|
||||
|
||||
VoidCallback? startListening({required void Function(T) onCellChanged}) {
|
||||
if (isListening) {
|
||||
Log.error("Already started. It seems like you should call clone first");
|
||||
return null;
|
||||
}
|
||||
|
||||
isListening = true;
|
||||
_cellDataNotifier = ValueNotifier(cellCache.get(cacheKey));
|
||||
_cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id);
|
||||
_cellListener.start(onCellChanged: (result) {
|
||||
result.fold(
|
||||
(_) => _loadData(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
if (cellDataLoader.reloadOnFieldChanged) {
|
||||
_onFieldChangedFn = () {
|
||||
_loadData();
|
||||
};
|
||||
cellCache.addListener(cacheKey, _onFieldChangedFn!);
|
||||
}
|
||||
|
||||
onCellChangedFn() {
|
||||
final value = _cellDataNotifier.value;
|
||||
if (value is T) {
|
||||
onCellChanged(value);
|
||||
}
|
||||
|
||||
if (cellDataLoader.reloadOnCellChanged) {
|
||||
_loadData();
|
||||
}
|
||||
}
|
||||
|
||||
_cellDataNotifier.addListener(onCellChangedFn);
|
||||
return onCellChangedFn;
|
||||
}
|
||||
|
||||
void removeListener(VoidCallback fn) {
|
||||
_cellDataNotifier.removeListener(fn);
|
||||
}
|
||||
|
||||
T? getCellData() {
|
||||
final data = cellCache.get(cacheKey);
|
||||
if (data == null) {
|
||||
_loadData();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void saveCellData(String data) {
|
||||
_cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data).then((result) {
|
||||
result.fold((l) => null, (err) => Log.error(err));
|
||||
});
|
||||
}
|
||||
|
||||
void _loadData() {
|
||||
_delayOperation?.cancel();
|
||||
_delayOperation = Timer(const Duration(milliseconds: 10), () {
|
||||
cellDataLoader.loadData().then((data) {
|
||||
_cellDataNotifier.value = data;
|
||||
cellCache.insert(GridCellCacheData(key: cacheKey, object: data));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_delayOperation?.cancel();
|
||||
|
||||
if (_onFieldChangedFn != null) {
|
||||
cellCache.removeListener(cacheKey, _onFieldChangedFn!);
|
||||
_onFieldChangedFn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [cellCache.get(cacheKey) ?? "", cellId];
|
||||
}
|
||||
|
||||
abstract class GridCellDataLoader<T> {
|
||||
Future<T?> loadData();
|
||||
|
||||
bool get reloadOnFieldChanged => true;
|
||||
bool get reloadOnCellChanged => false;
|
||||
}
|
||||
|
||||
abstract class GridCellDataConfig {
|
||||
bool get reloadOnFieldChanged => true;
|
||||
bool get reloadOnCellChanged => false;
|
||||
}
|
||||
|
||||
class DefaultCellDataLoader extends GridCellDataLoader<Cell> {
|
||||
final CellService service = CellService();
|
||||
final GridCell gridCell;
|
||||
@override
|
||||
final bool reloadOnCellChanged;
|
||||
|
||||
DefaultCellDataLoader({
|
||||
required this.gridCell,
|
||||
this.reloadOnCellChanged = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Cell?> loadData() {
|
||||
final fut = service.getCell(
|
||||
gridId: gridCell.gridId,
|
||||
fieldId: gridCell.field.id,
|
||||
rowId: gridCell.rowId,
|
||||
);
|
||||
return fut.then((result) {
|
||||
return result.fold((data) => data, (err) {
|
||||
Log.error(err);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// key: rowId
|
||||
typedef GridCellMap = LinkedHashMap<String, GridCell>;
|
||||
|
||||
class GridCellCacheData {
|
||||
GridCellCacheKey key;
|
||||
dynamic object;
|
||||
GridCellCacheData({
|
||||
required this.key,
|
||||
required this.object,
|
||||
});
|
||||
}
|
||||
|
||||
class GridCellCacheKey {
|
||||
final String fieldId;
|
||||
final String objectId;
|
||||
GridCellCacheKey({
|
||||
required this.fieldId,
|
||||
required this.objectId,
|
||||
});
|
||||
}
|
||||
|
||||
abstract class GridCellFieldDelegate {
|
||||
void onFieldChanged(void Function(String) callback);
|
||||
void dispose();
|
||||
}
|
||||
|
||||
class GridCellCache {
|
||||
final String gridId;
|
||||
final GridCellFieldDelegate fieldDelegate;
|
||||
|
||||
/// fieldId: {objectId: callback}
|
||||
final Map<String, Map<String, List<VoidCallback>>> _listenerByFieldId = {};
|
||||
|
||||
/// fieldId: {cacheKey: cacheData}
|
||||
final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
|
||||
GridCellCache({
|
||||
required this.gridId,
|
||||
required this.fieldDelegate,
|
||||
}) {
|
||||
fieldDelegate.onFieldChanged((fieldId) {
|
||||
_cellDataByFieldId.remove(fieldId);
|
||||
final map = _listenerByFieldId[fieldId];
|
||||
if (map != null) {
|
||||
for (final callbacks in map.values) {
|
||||
for (final callback in callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void addListener(GridCellCacheKey cacheKey, VoidCallback callback) {
|
||||
var map = _listenerByFieldId[cacheKey.fieldId];
|
||||
if (map == null) {
|
||||
_listenerByFieldId[cacheKey.fieldId] = {};
|
||||
map = _listenerByFieldId[cacheKey.fieldId];
|
||||
map![cacheKey.objectId] = [callback];
|
||||
} else {
|
||||
var objects = map[cacheKey.objectId];
|
||||
if (objects == null) {
|
||||
map[cacheKey.objectId] = [callback];
|
||||
} else {
|
||||
objects.add(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeListener(GridCellCacheKey cacheKey, VoidCallback fn) {
|
||||
var callbacks = _listenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId];
|
||||
final index = callbacks?.indexWhere((callback) => callback == fn);
|
||||
if (index != null && index != -1) {
|
||||
callbacks?.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
void insert<T extends GridCellCacheData>(T item) {
|
||||
var map = _cellDataByFieldId[item.key.fieldId];
|
||||
if (map == null) {
|
||||
_cellDataByFieldId[item.key.fieldId] = {};
|
||||
map = _cellDataByFieldId[item.key.fieldId];
|
||||
}
|
||||
|
||||
map![item.key.objectId] = item.object;
|
||||
}
|
||||
|
||||
T? get<T>(GridCellCacheKey key) {
|
||||
final map = _cellDataByFieldId[key.fieldId];
|
||||
if (map == null) {
|
||||
return null;
|
||||
} else {
|
||||
final object = map[key.objectId];
|
||||
if (object is T) {
|
||||
return object;
|
||||
} else {
|
||||
if (object != null) {
|
||||
Log.error("Cache data type does not match the cache data type");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
fieldDelegate.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class CellService {
|
||||
CellService();
|
||||
@ -38,38 +316,12 @@ class CellService {
|
||||
}
|
||||
}
|
||||
|
||||
class CellCache {
|
||||
final CellService _cellService;
|
||||
final HashMap<String, Cell> _cellDataMap = HashMap();
|
||||
|
||||
CellCache() : _cellService = CellService();
|
||||
|
||||
Future<Option<Cell>> getCellData(GridCell identifier) async {
|
||||
final cellId = _cellId(identifier);
|
||||
final Cell? data = _cellDataMap[cellId];
|
||||
if (data != null) {
|
||||
return Future(() => Some(data));
|
||||
}
|
||||
|
||||
final result = await _cellService.getCell(
|
||||
gridId: identifier.gridId,
|
||||
fieldId: identifier.field.id,
|
||||
rowId: identifier.rowId,
|
||||
);
|
||||
|
||||
return result.fold(
|
||||
(cell) {
|
||||
_cellDataMap[_cellId(identifier)] = cell;
|
||||
return Some(cell);
|
||||
},
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return none();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String _cellId(GridCell identifier) {
|
||||
return "${identifier.rowId}/${identifier.field.id}";
|
||||
}
|
||||
@freezed
|
||||
class GridCell with _$GridCell {
|
||||
const factory GridCell({
|
||||
required String gridId,
|
||||
required String rowId,
|
||||
required Field field,
|
||||
Cell? cell,
|
||||
}) = _GridCell;
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -10,15 +7,13 @@ import 'cell_service.dart';
|
||||
part 'checkbox_cell_bloc.freezed.dart';
|
||||
|
||||
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
final CellService _service;
|
||||
final CellListener _cellListener;
|
||||
final GridDefaultCellContext cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
CheckboxCellBloc({
|
||||
required CellService service,
|
||||
required GridCell cellData,
|
||||
}) : _service = service,
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(CheckboxCellState.initial(cellData)) {
|
||||
required this.cellContext,
|
||||
}) : super(CheckboxCellState.initial(cellContext)) {
|
||||
on<CheckboxCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -38,42 +33,25 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _cellListener.stop();
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
|
||||
cellContext.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) async => await _loadCellData(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadCellData() async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
_onCellChangedFn = cellContext.startListening(onCellChanged: ((cell) {
|
||||
if (!isClosed) {
|
||||
add(CheckboxCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void _updateCellData() {
|
||||
_service.updateCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
data: !state.isSelected ? "Yes" : "No",
|
||||
);
|
||||
cellContext.saveCellData(!state.isSelected ? "Yes" : "No");
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,12 +65,11 @@ class CheckboxCellEvent with _$CheckboxCellEvent {
|
||||
@freezed
|
||||
class CheckboxCellState with _$CheckboxCellState {
|
||||
const factory CheckboxCellState({
|
||||
required GridCell cellData,
|
||||
required bool isSelected,
|
||||
}) = _CheckboxCellState;
|
||||
|
||||
factory CheckboxCellState.initial(GridCell cellData) {
|
||||
return CheckboxCellState(cellData: cellData, isSelected: _isSelected(cellData.cell));
|
||||
factory CheckboxCellState.initial(GridCellContext context) {
|
||||
return CheckboxCellState(isSelected: _isSelected(context.getCellData()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,3 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -11,15 +7,10 @@ import 'cell_service.dart';
|
||||
part 'date_cell_bloc.freezed.dart';
|
||||
|
||||
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
final CellService _service;
|
||||
final CellListener _cellListener;
|
||||
final SingleFieldListener _fieldListener;
|
||||
final GridDefaultCellContext cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
DateCellBloc({required GridCell cellData})
|
||||
: _service = CellService(),
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
_fieldListener = SingleFieldListener(fieldId: cellData.field.id),
|
||||
super(DateCellState.initial(cellData)) {
|
||||
DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) {
|
||||
on<DateCellEvent>(
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
@ -31,13 +22,11 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
},
|
||||
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
|
||||
emit(state.copyWith(
|
||||
cellData: state.cellData.copyWith(cell: value.cell),
|
||||
content: value.cell.content,
|
||||
));
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(field: value.field));
|
||||
_loadCellData();
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -46,52 +35,27 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _cellListener.stop();
|
||||
await _fieldListener.stop();
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
cellContext.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) => _loadCellData(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}, listenWhen: () => !isClosed);
|
||||
_cellListener.start();
|
||||
|
||||
_fieldListener.updateFieldNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(field) => add(DateCellEvent.didReceiveFieldUpdate(field)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}, listenWhen: () => !isClosed);
|
||||
_fieldListener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadCellData() async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(cell) => add(DateCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
_onCellChangedFn = cellContext.startListening(
|
||||
onCellChanged: ((cell) {
|
||||
if (!isClosed) {
|
||||
add(DateCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateCellData(DateTime day) {
|
||||
final data = day.millisecondsSinceEpoch ~/ 1000;
|
||||
_service.updateCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
data: data.toString(),
|
||||
);
|
||||
cellContext.saveCellData(data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,15 +70,13 @@ class DateCellEvent with _$DateCellEvent {
|
||||
@freezed
|
||||
class DateCellState with _$DateCellState {
|
||||
const factory DateCellState({
|
||||
required GridCell cellData,
|
||||
required String content,
|
||||
required Field field,
|
||||
DateTime? selectedDay,
|
||||
}) = _DateCellState;
|
||||
|
||||
factory DateCellState.initial(GridCell cellData) => DateCellState(
|
||||
cellData: cellData,
|
||||
field: cellData.field,
|
||||
content: cellData.cell?.content ?? "",
|
||||
factory DateCellState.initial(GridCellContext context) => DateCellState(
|
||||
field: context.field,
|
||||
content: context.getCellData()?.content ?? "",
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,3 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.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';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -11,16 +7,12 @@ import 'cell_service.dart';
|
||||
part 'number_cell_bloc.freezed.dart';
|
||||
|
||||
class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
final CellService _service;
|
||||
final CellListener _cellListener;
|
||||
final SingleFieldListener _fieldListener;
|
||||
final GridDefaultCellContext cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
NumberCellBloc({
|
||||
required GridCell cellData,
|
||||
}) : _service = CellService(),
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
_fieldListener = SingleFieldListener(fieldId: cellData.field.id),
|
||||
super(NumberCellState.initial(cellData)) {
|
||||
required this.cellContext,
|
||||
}) : super(NumberCellState.initial(cellContext)) {
|
||||
on<NumberCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -39,58 +31,26 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
}
|
||||
|
||||
Future<void> _updateCellValue(_UpdateCell value, Emitter<NumberCellState> emit) async {
|
||||
final result = await _service.updateCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
data: value.text,
|
||||
);
|
||||
result.fold(
|
||||
(field) => _getCellData(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
cellContext.saveCellData(value.text);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _cellListener.stop();
|
||||
await _fieldListener.stop();
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
cellContext.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) async {
|
||||
await _getCellData();
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener.start();
|
||||
|
||||
_fieldListener.updateFieldNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(field) => _getCellData(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start();
|
||||
}
|
||||
|
||||
Future<void> _getCellData() async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
_onCellChangedFn = cellContext.startListening(
|
||||
onCellChanged: ((cell) {
|
||||
if (!isClosed) {
|
||||
add(NumberCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -105,11 +65,11 @@ class NumberCellEvent with _$NumberCellEvent {
|
||||
@freezed
|
||||
class NumberCellState with _$NumberCellState {
|
||||
const factory NumberCellState({
|
||||
required GridCell cellData,
|
||||
required String content,
|
||||
}) = _NumberCellState;
|
||||
|
||||
factory NumberCellState.initial(GridCell cellData) {
|
||||
return NumberCellState(cellData: cellData, content: cellData.cell?.content ?? "");
|
||||
factory NumberCellState.initial(GridDefaultCellContext context) {
|
||||
final cell = context.getCellData();
|
||||
return NumberCellState(content: cell?.content ?? "");
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,43 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.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/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
|
||||
class SelectOptionService {
|
||||
SelectOptionService();
|
||||
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart';
|
||||
|
||||
Future<Either<Unit, FlowyError>> create({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String name,
|
||||
}) {
|
||||
import 'cell_service.dart';
|
||||
|
||||
class SelectOptionCellDataLoader extends GridCellDataLoader<SelectOptionContext> {
|
||||
final SelectOptionService service;
|
||||
final GridCell gridCell;
|
||||
SelectOptionCellDataLoader({
|
||||
required this.gridCell,
|
||||
}) : service = SelectOptionService(gridCell: gridCell);
|
||||
@override
|
||||
Future<SelectOptionContext?> loadData() async {
|
||||
return service.getOpitonContext().then((result) {
|
||||
return result.fold(
|
||||
(data) => data,
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return null;
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SelectOptionService {
|
||||
final GridCell gridCell;
|
||||
SelectOptionService({required this.gridCell});
|
||||
|
||||
String get gridId => gridCell.gridId;
|
||||
String get fieldId => gridCell.field.id;
|
||||
String get rowId => gridCell.rowId;
|
||||
|
||||
Future<Either<Unit, FlowyError>> create({required String name}) {
|
||||
return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then(
|
||||
(result) {
|
||||
return result.fold(
|
||||
@ -34,9 +58,6 @@ class SelectOptionService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> update({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required SelectOption option,
|
||||
}) {
|
||||
final cellIdentifier = CellIdentifierPayload.create()
|
||||
@ -50,9 +71,6 @@ class SelectOptionService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> delete({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required SelectOption option,
|
||||
}) {
|
||||
final cellIdentifier = CellIdentifierPayload.create()
|
||||
@ -67,11 +85,7 @@ class SelectOptionService {
|
||||
return GridEventUpdateSelectOption(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<SelectOptionContext, FlowyError>> getOpitonContext({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
}) {
|
||||
Future<Either<SelectOptionContext, FlowyError>> getOpitonContext() {
|
||||
final payload = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
@ -80,12 +94,7 @@ class SelectOptionService {
|
||||
return GridEventGetSelectOptionContext(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<void, FlowyError>> select({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String optionId,
|
||||
}) {
|
||||
Future<Either<void, FlowyError>> select({required String optionId}) {
|
||||
final payload = SelectOptionCellChangesetPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
@ -94,12 +103,7 @@ class SelectOptionService {
|
||||
return GridEventUpdateCellSelectOption(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<void, FlowyError>> remove({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String optionId,
|
||||
}) {
|
||||
Future<Either<void, FlowyError>> unSelect({required String optionId}) {
|
||||
final payload = SelectOptionCellChangesetPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
|
@ -1,35 +1,29 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'dart:async';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
|
||||
part 'selection_cell_bloc.freezed.dart';
|
||||
|
||||
class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||
final SelectOptionService _service;
|
||||
final CellListener _cellListener;
|
||||
final SingleFieldListener _fieldListener;
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
SelectionCellBloc({
|
||||
required GridCell cellData,
|
||||
}) : _service = SelectOptionService(),
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
_fieldListener = SingleFieldListener(fieldId: cellData.field.id),
|
||||
super(SelectionCellState.initial(cellData)) {
|
||||
required this.cellContext,
|
||||
}) : super(SelectionCellState.initial(cellContext)) {
|
||||
on<SelectionCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialCell value) async {
|
||||
_loadOptions();
|
||||
_startListening();
|
||||
},
|
||||
didReceiveOptions: (_DidReceiveOptions value) {
|
||||
emit(state.copyWith(options: value.options, selectedOptions: value.selectedOptions));
|
||||
emit(state.copyWith(
|
||||
options: value.options,
|
||||
selectedOptions: value.selectedOptions,
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -38,46 +32,25 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _cellListener.stop();
|
||||
await _fieldListener.stop();
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
cellContext.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _loadOptions() async {
|
||||
final result = await _service.getOpitonContext(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.fold(
|
||||
(selectOptionContext) => add(SelectionCellEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) => _loadOptions(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener.start();
|
||||
|
||||
_fieldListener.updateFieldNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(field) => _loadOptions(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start();
|
||||
_onCellChangedFn = cellContext.startListening(
|
||||
onCellChanged: ((selectOptionContext) {
|
||||
if (!isClosed) {
|
||||
add(SelectionCellEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,14 +66,16 @@ class SelectionCellEvent with _$SelectionCellEvent {
|
||||
@freezed
|
||||
class SelectionCellState with _$SelectionCellState {
|
||||
const factory SelectionCellState({
|
||||
required GridCell cellData,
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> selectedOptions,
|
||||
}) = _SelectionCellState;
|
||||
|
||||
factory SelectionCellState.initial(GridCell cellData) => SelectionCellState(
|
||||
cellData: cellData,
|
||||
options: [],
|
||||
selectedOptions: [],
|
||||
);
|
||||
factory SelectionCellState.initial(GridSelectOptionCellContext context) {
|
||||
final data = context.getCellData();
|
||||
|
||||
return SelectionCellState(
|
||||
options: data?.options ?? [],
|
||||
selectedOptions: data?.selectOptions ?? [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
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/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -13,28 +10,19 @@ part 'selection_editor_bloc.freezed.dart';
|
||||
|
||||
class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
|
||||
final SelectOptionService _selectOptionService;
|
||||
final SingleFieldListener _fieldListener;
|
||||
final CellListener _cellListener;
|
||||
Timer? _delayOperation;
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
SelectOptionEditorBloc({
|
||||
required GridCell cellData,
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> selectedOptions,
|
||||
}) : _selectOptionService = SelectOptionService(),
|
||||
_fieldListener = SingleFieldListener(fieldId: cellData.field.id),
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(SelectOptionEditorState.initial(cellData, options, selectedOptions)) {
|
||||
required this.cellContext,
|
||||
}) : _selectOptionService = SelectOptionService(gridCell: cellContext.gridCell),
|
||||
super(SelectOptionEditorState.initial(cellContext)) {
|
||||
on<SelectOptionEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_Initial value) async {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(field: value.field));
|
||||
_loadOptions();
|
||||
},
|
||||
didReceiveOptions: (_DidReceiveOptions value) {
|
||||
emit(state.copyWith(
|
||||
options: value.options,
|
||||
@ -51,7 +39,7 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
|
||||
_updateOption(value.option);
|
||||
},
|
||||
selectOption: (_SelectOption value) {
|
||||
_makeOptionAsSelected(value.optionId);
|
||||
_onSelectOption(value.optionId);
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -60,27 +48,21 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
_delayOperation?.cancel();
|
||||
await _fieldListener.stop();
|
||||
await _cellListener.stop();
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
cellContext.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _createOption(String name) async {
|
||||
final result = await _selectOptionService.create(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
name: name,
|
||||
);
|
||||
result.fold((l) => _loadOptions(), (err) => Log.error(err));
|
||||
final result = await _selectOptionService.create(name: name);
|
||||
result.fold((l) => {}, (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _deleteOption(SelectOption option) async {
|
||||
final result = await _selectOptionService.delete(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
option: option,
|
||||
);
|
||||
|
||||
@ -89,72 +71,38 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
|
||||
|
||||
void _updateOption(SelectOption option) async {
|
||||
final result = await _selectOptionService.update(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
option: option,
|
||||
);
|
||||
|
||||
result.fold((l) => null, (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _makeOptionAsSelected(String optionId) {
|
||||
_selectOptionService.select(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
optionId: optionId,
|
||||
);
|
||||
}
|
||||
|
||||
void _loadOptions() async {
|
||||
_delayOperation?.cancel();
|
||||
_delayOperation = Timer(
|
||||
const Duration(milliseconds: 1),
|
||||
() async {
|
||||
final result = await _selectOptionService.getOpitonContext(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
);
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.fold(
|
||||
(selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
void _onSelectOption(String optionId) {
|
||||
final hasSelected = state.selectedOptions.firstWhereOrNull((option) => option.id == optionId);
|
||||
if (hasSelected != null) {
|
||||
_selectOptionService.unSelect(optionId: optionId);
|
||||
} else {
|
||||
_selectOptionService.select(optionId: optionId);
|
||||
}
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) => _loadOptions(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener.start();
|
||||
|
||||
_fieldListener.updateFieldNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(field) => add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}, listenWhen: () => !isClosed);
|
||||
_fieldListener.start();
|
||||
_onCellChangedFn = cellContext.startListening(
|
||||
onCellChanged: ((selectOptionContext) {
|
||||
if (!isClosed) {
|
||||
add(SelectOptionEditorEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionEditorEvent with _$SelectOptionEditorEvent {
|
||||
const factory SelectOptionEditorEvent.initial() = _Initial;
|
||||
const factory SelectOptionEditorEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||
const factory SelectOptionEditorEvent.didReceiveOptions(
|
||||
List<SelectOption> options, List<SelectOption> selectedOptions) = _DidReceiveOptions;
|
||||
const factory SelectOptionEditorEvent.newOption(String optionName) = _NewOption;
|
||||
@ -166,24 +114,15 @@ class SelectOptionEditorEvent with _$SelectOptionEditorEvent {
|
||||
@freezed
|
||||
class SelectOptionEditorState with _$SelectOptionEditorState {
|
||||
const factory SelectOptionEditorState({
|
||||
required String gridId,
|
||||
required Field field,
|
||||
required String rowId,
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> selectedOptions,
|
||||
}) = _SelectOptionEditorState;
|
||||
|
||||
factory SelectOptionEditorState.initial(
|
||||
GridCell cellData,
|
||||
List<SelectOption> options,
|
||||
List<SelectOption> selectedOptions,
|
||||
) {
|
||||
factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) {
|
||||
final data = context.getCellData();
|
||||
return SelectOptionEditorState(
|
||||
gridId: cellData.gridId,
|
||||
field: cellData.field,
|
||||
rowId: cellData.rowId,
|
||||
options: options,
|
||||
selectedOptions: selectedOptions,
|
||||
options: data?.options ?? [],
|
||||
selectedOptions: data?.selectOptions ?? [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,17 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'cell_listener.dart';
|
||||
import 'cell_service.dart';
|
||||
|
||||
part 'text_cell_bloc.freezed.dart';
|
||||
|
||||
class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
final CellService _service;
|
||||
final CellListener _cellListener;
|
||||
|
||||
final GridDefaultCellContext cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
TextCellBloc({
|
||||
required GridCell cellData,
|
||||
}) : _service = CellService(),
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(TextCellState.initial(cellData)) {
|
||||
required this.cellContext,
|
||||
}) : super(TextCellState.initial(cellContext)) {
|
||||
on<TextCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -25,18 +19,14 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
_startListening();
|
||||
},
|
||||
updateText: (_UpdateText value) {
|
||||
updateCellContent(value.text);
|
||||
cellContext.saveCellData(value.text);
|
||||
emit(state.copyWith(content: value.text));
|
||||
},
|
||||
didReceiveCellData: (_DidReceiveCellData value) {
|
||||
emit(state.copyWith(
|
||||
cellData: value.cellData,
|
||||
content: value.cellData.cell?.content ?? "",
|
||||
));
|
||||
emit(state.copyWith(content: value.cellData.cell?.content ?? ""));
|
||||
},
|
||||
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
|
||||
emit(state.copyWith(
|
||||
cellData: state.cellData.copyWith(cell: value.cell),
|
||||
content: value.cell.content,
|
||||
));
|
||||
},
|
||||
@ -47,44 +37,21 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _cellListener.stop();
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
cellContext.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void updateCellContent(String content) {
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) async => await _loadCellData(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadCellData() async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(cell) => add(TextCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
_onCellChangedFn = cellContext.startListening(
|
||||
onCellChanged: ((cell) {
|
||||
if (!isClosed) {
|
||||
add(TextCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -101,11 +68,9 @@ class TextCellEvent with _$TextCellEvent {
|
||||
class TextCellState with _$TextCellState {
|
||||
const factory TextCellState({
|
||||
required String content,
|
||||
required GridCell cellData,
|
||||
}) = _TextCellState;
|
||||
|
||||
factory TextCellState.initial(GridCell cellData) => TextCellState(
|
||||
content: cellData.cell?.content ?? "",
|
||||
cellData: cellData,
|
||||
factory TextCellState.initial(GridDefaultCellContext context) => TextCellState(
|
||||
content: context.getCellData()?.content ?? "",
|
||||
);
|
||||
}
|
||||
|
@ -45,13 +45,15 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_fieldListener.updateFieldNotifier?.addPublishListener((result) {
|
||||
_fieldListener.start(onFieldChanged: (result) {
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
result.fold(
|
||||
(field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}, listenWhen: () => !isClosed);
|
||||
_fieldListener.start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,13 @@ typedef UpdateFieldNotifiedValue = Either<Field, FlowyError>;
|
||||
|
||||
class SingleFieldListener {
|
||||
final String fieldId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue>? updateFieldNotifier = PublishNotifier();
|
||||
PublishNotifier<UpdateFieldNotifiedValue>? _updateFieldNotifier = PublishNotifier();
|
||||
GridNotificationListener? _listener;
|
||||
|
||||
SingleFieldListener({required this.fieldId});
|
||||
|
||||
void start() {
|
||||
void start({required void Function(UpdateFieldNotifiedValue) onFieldChanged}) {
|
||||
_updateFieldNotifier?.addPublishListener(onFieldChanged);
|
||||
_listener = GridNotificationListener(
|
||||
objectId: fieldId,
|
||||
handler: _handler,
|
||||
@ -30,8 +31,8 @@ class SingleFieldListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateField:
|
||||
result.fold(
|
||||
(payload) => updateFieldNotifier?.value = left(Field.fromBuffer(payload)),
|
||||
(error) => updateFieldNotifier?.value = right(error),
|
||||
(payload) => _updateFieldNotifier?.value = left(Field.fromBuffer(payload)),
|
||||
(error) => _updateFieldNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@ -41,7 +42,7 @@ class SingleFieldListener {
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
updateFieldNotifier?.dispose();
|
||||
updateFieldNotifier = null;
|
||||
_updateFieldNotifier?.dispose();
|
||||
_updateFieldNotifier = null;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ class GridFieldsListener {
|
||||
GridNotificationListener? _listener;
|
||||
GridFieldsListener({required this.gridId});
|
||||
|
||||
void start() {
|
||||
void start({required void Function(UpdateFieldNotifiedValue) onFieldsChanged}) {
|
||||
updateFieldsNotifier?.addPublishListener(onFieldsChanged);
|
||||
_listener = GridNotificationListener(
|
||||
objectId: gridId,
|
||||
handler: _handler,
|
||||
|
@ -5,6 +5,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 'cell/cell_service.dart';
|
||||
import 'grid_service.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
||||
@ -14,6 +15,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final GridService _gridService;
|
||||
final GridFieldCache fieldCache;
|
||||
late final GridRowCache rowCache;
|
||||
late final GridCellCache cellCache;
|
||||
|
||||
GridBloc({required View view})
|
||||
: _gridService = GridService(gridId: view.id),
|
||||
@ -21,7 +23,12 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
super(GridState.initial(view.id)) {
|
||||
rowCache = GridRowCache(
|
||||
gridId: view.id,
|
||||
dataDelegate: GridRowDataDelegateAdaptor(fieldCache),
|
||||
fieldDelegate: GridRowCacheDelegateImpl(fieldCache),
|
||||
);
|
||||
|
||||
cellCache = GridCellCache(
|
||||
gridId: view.id,
|
||||
fieldDelegate: GridCellCacheDelegateImpl(fieldCache),
|
||||
);
|
||||
|
||||
on<GridEvent>(
|
||||
@ -48,8 +55,9 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _gridService.closeGrid();
|
||||
await fieldCache.dispose();
|
||||
await cellCache.dispose();
|
||||
await rowCache.dispose();
|
||||
await fieldCache.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@ -81,7 +89,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
() => result.fold(
|
||||
(fields) {
|
||||
fieldCache.fields = fields.items;
|
||||
rowCache.updateWithBlock(grid.blockOrders);
|
||||
rowCache.resetRows(grid.blockOrders);
|
||||
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
|
@ -8,6 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import 'cell/cell_service.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
||||
class GridService {
|
||||
@ -53,23 +54,29 @@ class FieldsNotifier extends ChangeNotifier {
|
||||
List<Field> get fields => _fields;
|
||||
}
|
||||
|
||||
typedef ChangesetListener = void Function(GridFieldChangeset);
|
||||
|
||||
class GridFieldCache {
|
||||
final String gridId;
|
||||
late final GridFieldsListener _fieldListener;
|
||||
final FieldsNotifier _fieldNotifier = FieldsNotifier();
|
||||
final List<ChangesetListener> _changesetListener = [];
|
||||
|
||||
GridFieldCache({required this.gridId}) {
|
||||
_fieldListener = GridFieldsListener(gridId: gridId);
|
||||
_fieldListener.updateFieldsNotifier?.addPublishListener((result) {
|
||||
_fieldListener.start(onFieldsChanged: (result) {
|
||||
result.fold(
|
||||
(changeset) {
|
||||
_deleteFields(changeset.deletedFields);
|
||||
_insertFields(changeset.insertedFields);
|
||||
_updateFields(changeset.updatedFields);
|
||||
for (final listener in _changesetListener) {
|
||||
listener(changeset);
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start();
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
@ -77,8 +84,6 @@ class GridFieldCache {
|
||||
_fieldNotifier.dispose();
|
||||
}
|
||||
|
||||
void applyChangeset(GridFieldChangeset changeset) {}
|
||||
|
||||
UnmodifiableListView<Field> get unmodifiableFields => UnmodifiableListView(_fieldNotifier.fields);
|
||||
|
||||
List<Field> get clonedFields => [..._fieldNotifier.fields];
|
||||
@ -111,6 +116,17 @@ class GridFieldCache {
|
||||
_fieldNotifier.removeListener(f);
|
||||
}
|
||||
|
||||
void addChangesetListener(ChangesetListener listener) {
|
||||
_changesetListener.add(listener);
|
||||
}
|
||||
|
||||
void removeChangesetListener(ChangesetListener listener) {
|
||||
final index = _changesetListener.indexWhere((element) => element == listener);
|
||||
if (index != -1) {
|
||||
_changesetListener.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteFields(List<FieldOrder> deletedFields) {
|
||||
if (deletedFields.isEmpty) {
|
||||
return;
|
||||
@ -155,43 +171,43 @@ class GridFieldCache {
|
||||
}
|
||||
}
|
||||
|
||||
class GridRowDataDelegateAdaptor extends GridRowDataDelegate {
|
||||
class GridRowCacheDelegateImpl extends GridRowFieldDelegate {
|
||||
final GridFieldCache _cache;
|
||||
GridRowCacheDelegateImpl(GridFieldCache cache) : _cache = cache;
|
||||
|
||||
GridRowDataDelegateAdaptor(GridFieldCache cache) : _cache = cache;
|
||||
@override
|
||||
UnmodifiableListView<Field> get fields => _cache.unmodifiableFields;
|
||||
|
||||
@override
|
||||
GridRow buildGridRow(RowOrder rowOrder) {
|
||||
return GridRow(
|
||||
gridId: _cache.gridId,
|
||||
fields: _cache.unmodifiableFields,
|
||||
rowId: rowOrder.rowId,
|
||||
height: rowOrder.height.toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onFieldChanged(FieldDidUpdateCallback callback) {
|
||||
_cache.addListener(listener: () {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class GridCellCacheDelegateImpl extends GridCellFieldDelegate {
|
||||
final GridFieldCache _cache;
|
||||
ChangesetListener? _changesetFn;
|
||||
GridCellCacheDelegateImpl(GridFieldCache cache) : _cache = cache;
|
||||
|
||||
@override
|
||||
CellDataMap buildCellDataMap(Row rowData) {
|
||||
var map = CellDataMap.new();
|
||||
for (final field in fields) {
|
||||
if (field.visibility) {
|
||||
map[field.id] = GridCell(
|
||||
rowId: rowData.id,
|
||||
gridId: _cache.gridId,
|
||||
cell: rowData.cellByFieldId[field.id],
|
||||
field: field,
|
||||
);
|
||||
void onFieldChanged(void Function(String) callback) {
|
||||
changesetFn(GridFieldChangeset changeset) {
|
||||
for (final updatedField in changeset.updatedFields) {
|
||||
callback(updatedField.id);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
|
||||
_cache.addChangesetListener(changesetFn);
|
||||
_changesetFn = changesetFn;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_changesetFn != null) {
|
||||
_cache.removeChangesetListener(_changesetFn!);
|
||||
_changesetFn = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'dart:collection';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'row_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'row_bloc.freezed.dart';
|
||||
|
||||
@ -17,19 +17,18 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
required GridRowCache rowCache,
|
||||
}) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
|
||||
_rowCache = rowCache,
|
||||
super(RowState.initial(rowData)) {
|
||||
super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) {
|
||||
on<RowEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialRow value) async {
|
||||
await _startListening();
|
||||
await _loadRow(emit);
|
||||
},
|
||||
createRow: (_CreateRow value) {
|
||||
_rowService.createRow();
|
||||
},
|
||||
didReceiveCellDatas: (_DidReceiveCellDatas value) async {
|
||||
emit(state.copyWith(cellDataMap: Some(value.cellData)));
|
||||
emit(state.copyWith(cellDataMap: value.cellData));
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -41,6 +40,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
if (_rowListenFn != null) {
|
||||
_rowCache.removeRowListener(_rowListenFn!);
|
||||
}
|
||||
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@ -51,33 +51,24 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
listenWhen: () => !isClosed,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadRow(Emitter<RowState> emit) async {
|
||||
final data = _rowCache.loadCellData(state.rowData.rowId);
|
||||
data.foldRight(null, (cellDatas, _) {
|
||||
if (!isClosed) {
|
||||
add(RowEvent.didReceiveCellDatas(cellDatas));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowEvent with _$RowEvent {
|
||||
const factory RowEvent.initial() = _InitialRow;
|
||||
const factory RowEvent.createRow() = _CreateRow;
|
||||
const factory RowEvent.didReceiveCellDatas(CellDataMap cellData) = _DidReceiveCellDatas;
|
||||
const factory RowEvent.didReceiveCellDatas(GridCellMap cellData) = _DidReceiveCellDatas;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowState with _$RowState {
|
||||
const factory RowState({
|
||||
required GridRow rowData,
|
||||
required Option<CellDataMap> cellDataMap,
|
||||
required GridCellMap cellDataMap,
|
||||
}) = _RowState;
|
||||
|
||||
factory RowState.initial(GridRow rowData) => RowState(
|
||||
factory RowState.initial(GridRow rowData, GridCellMap cellDataMap) => RowState(
|
||||
rowData: rowData,
|
||||
cellDataMap: none(),
|
||||
cellDataMap: cellDataMap,
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -23,7 +24,7 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
|
||||
_loadCellData();
|
||||
},
|
||||
didReceiveCellDatas: (_DidReceiveCellDatas value) {
|
||||
emit(state.copyWith(cellDatas: value.cellDatas));
|
||||
emit(state.copyWith(gridCells: value.gridCells));
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -47,28 +48,26 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
|
||||
}
|
||||
|
||||
Future<void> _loadCellData() async {
|
||||
final data = _rowCache.loadCellData(rowData.rowId);
|
||||
data.foldRight(null, (cellDataMap, _) {
|
||||
if (!isClosed) {
|
||||
add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList()));
|
||||
}
|
||||
});
|
||||
final cellDataMap = _rowCache.loadGridCells(rowData.rowId);
|
||||
if (!isClosed) {
|
||||
add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowDetailEvent with _$RowDetailEvent {
|
||||
const factory RowDetailEvent.initial() = _Initial;
|
||||
const factory RowDetailEvent.didReceiveCellDatas(List<GridCell> cellDatas) = _DidReceiveCellDatas;
|
||||
const factory RowDetailEvent.didReceiveCellDatas(List<GridCell> gridCells) = _DidReceiveCellDatas;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowDetailState with _$RowDetailState {
|
||||
const factory RowDetailState({
|
||||
required List<GridCell> cellDatas,
|
||||
required List<GridCell> gridCells,
|
||||
}) = _RowDetailState;
|
||||
|
||||
factory RowDetailState.initial() => RowDetailState(
|
||||
cellDatas: List.empty(),
|
||||
gridCells: List.empty(),
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
@ -13,38 +14,43 @@ part 'row_service.freezed.dart';
|
||||
|
||||
typedef RowUpdateCallback = void Function();
|
||||
typedef FieldDidUpdateCallback = void Function();
|
||||
typedef CellDataMap = LinkedHashMap<String, GridCell>;
|
||||
|
||||
abstract class GridRowDataDelegate {
|
||||
abstract class GridRowFieldDelegate {
|
||||
UnmodifiableListView<Field> get fields;
|
||||
GridRow buildGridRow(RowOrder rowOrder);
|
||||
CellDataMap buildCellDataMap(Row rowData);
|
||||
void onFieldChanged(FieldDidUpdateCallback callback);
|
||||
}
|
||||
|
||||
class GridRowCache {
|
||||
final String gridId;
|
||||
final RowsNotifier _rowNotifier;
|
||||
final RowsNotifier _rowsNotifier;
|
||||
final GridRowListener _rowsListener;
|
||||
final GridRowDataDelegate _dataDelegate;
|
||||
final GridRowFieldDelegate _fieldDelegate;
|
||||
List<GridRow> get clonedRows => _rowsNotifier.clonedRows;
|
||||
|
||||
List<GridRow> get clonedRows => _rowNotifier.clonedRows;
|
||||
|
||||
GridRowCache({required this.gridId, required GridRowDataDelegate dataDelegate})
|
||||
: _rowNotifier = RowsNotifier(rowBuilder: dataDelegate.buildGridRow),
|
||||
GridRowCache({required this.gridId, required GridRowFieldDelegate fieldDelegate})
|
||||
: _rowsNotifier = RowsNotifier(
|
||||
rowBuilder: (rowOrder) {
|
||||
return GridRow(
|
||||
gridId: gridId,
|
||||
fields: fieldDelegate.fields,
|
||||
rowId: rowOrder.rowId,
|
||||
height: rowOrder.height.toDouble(),
|
||||
);
|
||||
},
|
||||
),
|
||||
_rowsListener = GridRowListener(gridId: gridId),
|
||||
_dataDelegate = dataDelegate {
|
||||
_fieldDelegate = fieldDelegate {
|
||||
//
|
||||
dataDelegate.onFieldChanged(() => _rowNotifier.fieldDidChange());
|
||||
fieldDelegate.onFieldChanged(() => _rowsNotifier.fieldDidChange());
|
||||
|
||||
// listen on the row update
|
||||
_rowsListener.rowsUpdateNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(changesets) {
|
||||
for (final changeset in changesets) {
|
||||
_rowNotifier.deleteRows(changeset.deletedRows);
|
||||
_rowNotifier.insertRows(changeset.insertedRows);
|
||||
_rowNotifier.updateRows(changeset.updatedRows);
|
||||
_rowsNotifier.deleteRows(changeset.deletedRows);
|
||||
_rowsNotifier.insertRows(changeset.insertedRows);
|
||||
_rowsNotifier.updateRows(changeset.updatedRows);
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
@ -55,14 +61,14 @@ class GridRowCache {
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _rowsListener.stop();
|
||||
_rowNotifier.dispose();
|
||||
_rowsNotifier.dispose();
|
||||
}
|
||||
|
||||
void addListener({
|
||||
void Function(List<GridRow>, GridRowChangeReason)? onChanged,
|
||||
bool Function()? listenWhen,
|
||||
}) {
|
||||
_rowNotifier.addListener(() {
|
||||
_rowsNotifier.addListener(() {
|
||||
if (onChanged == null) {
|
||||
return;
|
||||
}
|
||||
@ -71,16 +77,16 @@ class GridRowCache {
|
||||
return;
|
||||
}
|
||||
|
||||
onChanged(clonedRows, _rowNotifier._changeReason);
|
||||
onChanged(clonedRows, _rowsNotifier._changeReason);
|
||||
});
|
||||
}
|
||||
|
||||
RowUpdateCallback addRowListener({
|
||||
required String rowId,
|
||||
void Function(CellDataMap)? onUpdated,
|
||||
void Function(GridCellMap)? onUpdated,
|
||||
bool Function()? listenWhen,
|
||||
}) {
|
||||
listenrHandler() {
|
||||
listenrHandler() async {
|
||||
if (onUpdated == null) {
|
||||
return;
|
||||
}
|
||||
@ -90,14 +96,14 @@ class GridRowCache {
|
||||
}
|
||||
|
||||
notify() {
|
||||
final row = _rowNotifier.rowDataWithId(rowId);
|
||||
final row = _rowsNotifier.rowDataWithId(rowId);
|
||||
if (row != null) {
|
||||
final cellDataMap = _dataDelegate.buildCellDataMap(row);
|
||||
final GridCellMap cellDataMap = _makeGridCells(rowId, row);
|
||||
onUpdated(cellDataMap);
|
||||
}
|
||||
}
|
||||
|
||||
_rowNotifier._changeReason.whenOrNull(
|
||||
_rowsNotifier._changeReason.whenOrNull(
|
||||
update: (indexs) {
|
||||
if (indexs[rowId] != null) {
|
||||
notify();
|
||||
@ -107,36 +113,52 @@ class GridRowCache {
|
||||
);
|
||||
}
|
||||
|
||||
_rowNotifier.addListener(listenrHandler);
|
||||
_rowsNotifier.addListener(listenrHandler);
|
||||
return listenrHandler;
|
||||
}
|
||||
|
||||
void removeRowListener(VoidCallback callback) {
|
||||
_rowNotifier.removeListener(callback);
|
||||
_rowsNotifier.removeListener(callback);
|
||||
}
|
||||
|
||||
Option<CellDataMap> loadCellData(String rowId) {
|
||||
final Row? data = _rowNotifier.rowDataWithId(rowId);
|
||||
if (data != null) {
|
||||
return Some(_dataDelegate.buildCellDataMap(data));
|
||||
GridCellMap loadGridCells(String rowId) {
|
||||
final Row? data = _rowsNotifier.rowDataWithId(rowId);
|
||||
if (data == null) {
|
||||
_loadRow(rowId);
|
||||
}
|
||||
return _makeGridCells(rowId, data);
|
||||
}
|
||||
|
||||
void resetRows(List<GridBlockOrder> blocks) {
|
||||
final rowOrders = blocks.expand((block) => block.rowOrders).toList();
|
||||
_rowsNotifier.reset(rowOrders);
|
||||
}
|
||||
|
||||
Future<void> _loadRow(String rowId) async {
|
||||
final payload = RowIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..rowId = rowId;
|
||||
|
||||
GridEventGetRow(payload).send().then((result) {
|
||||
result.fold(
|
||||
(rowData) => _rowNotifier.rowData = rowData,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
return none();
|
||||
final result = await GridEventGetRow(payload).send();
|
||||
result.fold(
|
||||
(rowData) => _rowsNotifier.rowData = rowData,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
||||
void updateWithBlock(List<GridBlockOrder> blocks) {
|
||||
final rowOrders = blocks.expand((block) => block.rowOrders).toList();
|
||||
_rowNotifier.reset(rowOrders);
|
||||
GridCellMap _makeGridCells(String rowId, Row? row) {
|
||||
var cellDataMap = GridCellMap.new();
|
||||
for (final field in _fieldDelegate.fields) {
|
||||
if (field.visibility) {
|
||||
cellDataMap[field.id] = GridCell(
|
||||
rowId: rowId,
|
||||
gridId: gridId,
|
||||
cell: row?.cellByFieldId[field.id],
|
||||
field: field,
|
||||
);
|
||||
}
|
||||
}
|
||||
return cellDataMap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,18 +216,18 @@ class RowsNotifier extends ChangeNotifier {
|
||||
_update(newRows, GridRowChangeReason.insert(insertIndexs));
|
||||
}
|
||||
|
||||
void updateRows(List<RowOrder> updatedRows) {
|
||||
void updateRows(List<UpdatedRowOrder> updatedRows) {
|
||||
if (updatedRows.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
|
||||
final List<GridRow> newRows = clonedRows;
|
||||
for (final rowOrder in updatedRows) {
|
||||
for (final updatedRow in updatedRows) {
|
||||
final rowOrder = updatedRow.rowOrder;
|
||||
final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId);
|
||||
if (index != -1) {
|
||||
// Remove the old row data, the data will be filled if the loadRow method gets called.
|
||||
_rowDataMap.remove(rowOrder.rowId);
|
||||
_rowDataMap[rowOrder.rowId] = updatedRow.row;
|
||||
|
||||
newRows.removeAt(index);
|
||||
newRows.insert(index, rowBuilder(rowOrder));
|
||||
@ -323,16 +345,6 @@ class GridRow with _$GridRow {
|
||||
}) = _GridRow;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridCell with _$GridCell {
|
||||
const factory GridCell({
|
||||
required String gridId,
|
||||
required String rowId,
|
||||
required Field field,
|
||||
Cell? cell,
|
||||
}) = _GridCell;
|
||||
}
|
||||
|
||||
typedef InsertedIndexs = List<InsertedIndex>;
|
||||
typedef DeletedIndexs = List<DeletedIndex>;
|
||||
typedef UpdatedIndexs = LinkedHashMap<String, UpdatedIndex>;
|
||||
|
@ -213,7 +213,7 @@ class _GridRowsState extends State<_GridRows> {
|
||||
key: _key,
|
||||
initialItemCount: context.read<GridBloc>().state.rows.length,
|
||||
itemBuilder: (BuildContext context, int index, Animation<double> animation) {
|
||||
final rowData = context.read<GridBloc>().state.rows[index];
|
||||
final GridRow rowData = context.read<GridBloc>().state.rows[index];
|
||||
return _renderRow(context, rowData, animation);
|
||||
},
|
||||
);
|
||||
@ -227,11 +227,13 @@ class _GridRowsState extends State<_GridRows> {
|
||||
Animation<double> animation,
|
||||
) {
|
||||
final rowCache = context.read<GridBloc>().rowCache;
|
||||
final cellCache = context.read<GridBloc>().cellCache;
|
||||
return SizeTransition(
|
||||
sizeFactor: animation,
|
||||
child: GridRowWidget(
|
||||
rowData: rowData,
|
||||
rowCache: rowCache,
|
||||
cellCache: cellCache,
|
||||
key: ValueKey(rowData.rowId),
|
||||
),
|
||||
);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType;
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -8,21 +9,52 @@ import 'number_cell.dart';
|
||||
import 'selection_cell/selection_cell.dart';
|
||||
import 'text_cell.dart';
|
||||
|
||||
GridCellWidget buildGridCell(GridCell cellData, {GridCellStyle? style}) {
|
||||
final key = ValueKey(cellData.field.id + cellData.rowId);
|
||||
switch (cellData.field.fieldType) {
|
||||
GridCellWidget buildGridCellWidget(GridCell gridCell, GridCellCache cellCache, {GridCellStyle? style}) {
|
||||
final key = ValueKey(gridCell.rowId + gridCell.field.id);
|
||||
|
||||
final cellContext = makeCellContext(gridCell, cellCache);
|
||||
|
||||
switch (gridCell.field.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return CheckboxCell(cellData: cellData, key: key);
|
||||
return CheckboxCell(cellContext: cellContext, key: key);
|
||||
case FieldType.DateTime:
|
||||
return DateCell(cellData: cellData, key: key);
|
||||
return DateCell(cellContext: cellContext, key: key);
|
||||
case FieldType.MultiSelect:
|
||||
return MultiSelectCell(cellData: cellData, key: key);
|
||||
return MultiSelectCell(cellContext: cellContext as GridSelectOptionCellContext, style: style, key: key);
|
||||
case FieldType.Number:
|
||||
return NumberCell(cellData: cellData, key: key);
|
||||
return NumberCell(cellContext: cellContext, key: key);
|
||||
case FieldType.RichText:
|
||||
return GridTextCell(cellData: cellData, key: key, style: style);
|
||||
return GridTextCell(cellContext: cellContext, style: style, key: key);
|
||||
case FieldType.SingleSelect:
|
||||
return SingleSelectCell(cellData: cellData, key: key);
|
||||
return SingleSelectCell(cellContext: cellContext as GridSelectOptionCellContext, style: style, key: key);
|
||||
default:
|
||||
throw UnimplementedError;
|
||||
}
|
||||
}
|
||||
|
||||
GridCellContext makeCellContext(GridCell gridCell, GridCellCache cellCache) {
|
||||
switch (gridCell.field.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
case FieldType.DateTime:
|
||||
case FieldType.Number:
|
||||
return GridDefaultCellContext(
|
||||
gridCell: gridCell,
|
||||
cellCache: cellCache,
|
||||
cellDataLoader: DefaultCellDataLoader(gridCell: gridCell, reloadOnCellChanged: true),
|
||||
);
|
||||
case FieldType.RichText:
|
||||
return GridDefaultCellContext(
|
||||
gridCell: gridCell,
|
||||
cellCache: cellCache,
|
||||
cellDataLoader: DefaultCellDataLoader(gridCell: gridCell),
|
||||
);
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.SingleSelect:
|
||||
return GridSelectOptionCellContext(
|
||||
gridCell: gridCell,
|
||||
cellCache: cellCache,
|
||||
cellDataLoader: SelectOptionCellDataLoader(gridCell: gridCell),
|
||||
);
|
||||
default:
|
||||
throw UnimplementedError;
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'cell_builder.dart';
|
||||
|
||||
class CheckboxCell extends GridCellWidget {
|
||||
final GridCell cellData;
|
||||
final GridCellContext cellContext;
|
||||
|
||||
CheckboxCell({
|
||||
required this.cellData,
|
||||
required this.cellContext,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -23,7 +23,7 @@ class _CheckboxCellState extends State<CheckboxCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<CheckboxCellBloc>(param1: widget.cellData)..add(const CheckboxCellEvent.initial());
|
||||
_cellBloc = getIt<CheckboxCellBloc>(param1: widget.cellContext)..add(const CheckboxCellEvent.initial());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,10 @@ abstract class GridCellDelegate {
|
||||
}
|
||||
|
||||
class DateCell extends GridCellWidget {
|
||||
final GridCell cellData;
|
||||
final GridCellContext cellContext;
|
||||
|
||||
DateCell({
|
||||
required this.cellData,
|
||||
required this.cellContext,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -30,7 +30,7 @@ class _DateCellState extends State<DateCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<DateCellBloc>(param1: widget.cellData)..add(const DateCellEvent.initial());
|
||||
_cellBloc = getIt<DateCellBloc>(param1: widget.cellContext)..add(const DateCellEvent.initial());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'cell_builder.dart';
|
||||
|
||||
class NumberCell extends GridCellWidget {
|
||||
final GridCell cellData;
|
||||
final GridCellContext cellContext;
|
||||
|
||||
NumberCell({
|
||||
required this.cellData,
|
||||
required this.cellContext,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -27,7 +27,7 @@ class _NumberCellState extends State<NumberCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<NumberCellBloc>(param1: widget.cellData)..add(const NumberCellEvent.initial());
|
||||
_cellBloc = getIt<NumberCellBloc>(param1: widget.cellContext)..add(const NumberCellEvent.initial());
|
||||
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||
_focusNode = FocusNode();
|
||||
_focusNode.addListener(() {
|
||||
|
@ -1,19 +1,39 @@
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
// ignore: unused_import
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'extension.dart';
|
||||
import 'selection_editor.dart';
|
||||
|
||||
class SelectOptionCellStyle extends GridCellStyle {
|
||||
String placeholder;
|
||||
|
||||
SelectOptionCellStyle({
|
||||
required this.placeholder,
|
||||
});
|
||||
}
|
||||
|
||||
class SingleSelectCell extends GridCellWidget {
|
||||
final GridCell cellData;
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
late final SelectOptionCellStyle? cellStyle;
|
||||
|
||||
SingleSelectCell({
|
||||
required this.cellData,
|
||||
required this.cellContext,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
}) : super(key: key) {
|
||||
if (style != null) {
|
||||
cellStyle = (style as SelectOptionCellStyle);
|
||||
} else {
|
||||
cellStyle = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
State<SingleSelectCell> createState() => _SingleSelectCellState();
|
||||
@ -24,26 +44,32 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellData)..add(const SelectionCellEvent.initial());
|
||||
// Log.trace("init widget $hashCode");
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellContext)..add(const SelectionCellEvent.initial());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
// Log.trace("build widget $hashCode");
|
||||
return BlocProvider.value(
|
||||
value: _cellBloc,
|
||||
child: BlocBuilder<SelectionCellBloc, SelectionCellState>(
|
||||
builder: (context, state) {
|
||||
final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList();
|
||||
List<Widget> children = [];
|
||||
children.addAll(state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList());
|
||||
|
||||
if (children.isEmpty && widget.cellStyle != null) {
|
||||
children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14, color: theme.shader3));
|
||||
}
|
||||
return SizedBox.expand(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
widget.onFocus.value = true;
|
||||
SelectOptionCellEditor.show(
|
||||
context,
|
||||
state.cellData,
|
||||
state.options,
|
||||
state.selectedOptions,
|
||||
widget.cellContext.clone(),
|
||||
() => widget.onFocus.value = false,
|
||||
);
|
||||
},
|
||||
@ -55,8 +81,17 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant SingleSelectCell oldWidget) {
|
||||
if (oldWidget.cellContext != widget.cellContext) {
|
||||
// Log.trace("did update widget $hashCode");
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
// Log.trace("dispose widget $hashCode");
|
||||
_cellBloc.close();
|
||||
super.dispose();
|
||||
}
|
||||
@ -64,12 +99,20 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||
|
||||
//----------------------------------------------------------------
|
||||
class MultiSelectCell extends GridCellWidget {
|
||||
final GridCell cellData;
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
late final SelectOptionCellStyle? cellStyle;
|
||||
|
||||
MultiSelectCell({
|
||||
required this.cellData,
|
||||
required this.cellContext,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
}) : super(key: key) {
|
||||
if (style != null) {
|
||||
cellStyle = (style as SelectOptionCellStyle);
|
||||
} else {
|
||||
cellStyle = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
State<MultiSelectCell> createState() => _MultiSelectCellState();
|
||||
@ -80,7 +123,7 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellData)..add(const SelectionCellEvent.initial());
|
||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellContext)..add(const SelectionCellEvent.initial());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@ -90,16 +133,19 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
|
||||
value: _cellBloc,
|
||||
child: BlocBuilder<SelectionCellBloc, SelectionCellState>(
|
||||
builder: (context, state) {
|
||||
final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList();
|
||||
List<Widget> children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList();
|
||||
|
||||
if (children.isEmpty && widget.cellStyle != null) {
|
||||
children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14));
|
||||
}
|
||||
|
||||
return SizedBox.expand(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
widget.onFocus.value = true;
|
||||
SelectOptionCellEditor.show(
|
||||
context,
|
||||
state.cellData,
|
||||
state.options,
|
||||
state.selectedOptions,
|
||||
widget.cellContext,
|
||||
() => widget.onFocus.value = false,
|
||||
);
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'dart:collection';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/selection_editor_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart';
|
||||
@ -25,15 +25,11 @@ import 'text_field.dart';
|
||||
const double _editorPannelWidth = 300;
|
||||
|
||||
class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||
final GridCell cellData;
|
||||
final List<SelectOption> options;
|
||||
final List<SelectOption> selectedOptions;
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
final VoidCallback onDismissed;
|
||||
|
||||
const SelectOptionCellEditor({
|
||||
required this.cellData,
|
||||
required this.options,
|
||||
required this.selectedOptions,
|
||||
required this.cellContext,
|
||||
required this.onDismissed,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
@ -42,9 +38,7 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => SelectOptionEditorBloc(
|
||||
cellData: cellData,
|
||||
options: options,
|
||||
selectedOptions: selectedOptions,
|
||||
cellContext: cellContext,
|
||||
)..add(const SelectOptionEditorEvent.initial()),
|
||||
child: BlocBuilder<SelectOptionEditorBloc, SelectOptionEditorState>(
|
||||
builder: (context, state) {
|
||||
@ -66,16 +60,12 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||
|
||||
static void show(
|
||||
BuildContext context,
|
||||
GridCell cellData,
|
||||
List<SelectOption> options,
|
||||
List<SelectOption> selectedOptions,
|
||||
GridSelectOptionCellContext cellContext,
|
||||
VoidCallback onDismissed,
|
||||
) {
|
||||
SelectOptionCellEditor.remove(context);
|
||||
final editor = SelectOptionCellEditor(
|
||||
cellData: cellData,
|
||||
options: options,
|
||||
selectedOptions: selectedOptions,
|
||||
cellContext: cellContext,
|
||||
onDismissed: onDismissed,
|
||||
);
|
||||
|
||||
|
@ -14,10 +14,10 @@ class GridTextCellStyle extends GridCellStyle {
|
||||
}
|
||||
|
||||
class GridTextCell extends GridCellWidget {
|
||||
final GridCell cellData;
|
||||
final GridCellContext cellContext;
|
||||
late final GridTextCellStyle? cellStyle;
|
||||
GridTextCell({
|
||||
required this.cellData,
|
||||
required this.cellContext,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key) {
|
||||
@ -41,7 +41,7 @@ class _GridTextCellState extends State<GridTextCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cellBloc = getIt<TextCellBloc>(param1: widget.cellData);
|
||||
_cellBloc = getIt<TextCellBloc>(param1: widget.cellContext);
|
||||
_cellBloc.add(const TextCellEvent.initial());
|
||||
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||
_focusNode = FocusNode();
|
||||
|
@ -8,17 +8,18 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'row_action_sheet.dart';
|
||||
import 'package:dartz/dartz.dart' show Option;
|
||||
|
||||
import 'row_detail.dart';
|
||||
|
||||
class GridRowWidget extends StatefulWidget {
|
||||
final GridRow rowData;
|
||||
final GridRowCache rowCache;
|
||||
final GridCellCache cellCache;
|
||||
|
||||
const GridRowWidget({
|
||||
required this.rowData,
|
||||
required this.rowCache,
|
||||
required this.cellCache,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -49,7 +50,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
||||
builder: (context, state) {
|
||||
final children = [
|
||||
const _RowLeading(),
|
||||
_RowCells(onExpand: () => onExpandCell(context)),
|
||||
_RowCells(cellCache: widget.cellCache, onExpand: () => onExpandCell(context)),
|
||||
const _RowTrailing(),
|
||||
];
|
||||
|
||||
@ -73,7 +74,11 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
||||
}
|
||||
|
||||
void onExpandCell(BuildContext context) {
|
||||
final page = RowDetailPage(rowData: widget.rowData, rowCache: widget.rowCache);
|
||||
final page = RowDetailPage(
|
||||
rowData: widget.rowData,
|
||||
rowCache: widget.rowCache,
|
||||
cellCache: widget.cellCache,
|
||||
);
|
||||
page.show(context);
|
||||
}
|
||||
}
|
||||
@ -147,13 +152,14 @@ class _DeleteRowButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _RowCells extends StatelessWidget {
|
||||
final GridCellCache cellCache;
|
||||
final VoidCallback onExpand;
|
||||
const _RowCells({required this.onExpand, Key? key}) : super(key: key);
|
||||
const _RowCells({required this.cellCache, required this.onExpand, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RowBloc, RowState>(
|
||||
buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap,
|
||||
buildWhen: (previous, current) => previous.cellDataMap.length != current.cellDataMap.length,
|
||||
builder: (context, state) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -164,24 +170,21 @@ class _RowCells extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _makeCells(Option<CellDataMap> data) {
|
||||
return data.fold(
|
||||
() => [],
|
||||
(cellDataMap) => cellDataMap.values.map(
|
||||
(cellData) {
|
||||
Widget? expander;
|
||||
if (cellData.field.isPrimary) {
|
||||
expander = _CellExpander(onExpand: onExpand);
|
||||
}
|
||||
List<Widget> _makeCells(GridCellMap gridCellMap) {
|
||||
return gridCellMap.values.map(
|
||||
(gridCell) {
|
||||
Widget? expander;
|
||||
if (gridCell.field.isPrimary) {
|
||||
expander = _CellExpander(onExpand: onExpand);
|
||||
}
|
||||
|
||||
return CellContainer(
|
||||
width: cellData.field.width.toDouble(),
|
||||
child: buildGridCell(cellData),
|
||||
expander: expander,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
);
|
||||
return CellContainer(
|
||||
width: gridCell.field.width.toDouble(),
|
||||
child: buildGridCellWidget(gridCell, cellCache),
|
||||
expander: expander,
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -18,10 +21,12 @@ import 'package:window_size/window_size.dart';
|
||||
class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate {
|
||||
final GridRow rowData;
|
||||
final GridRowCache rowCache;
|
||||
final GridCellCache cellCache;
|
||||
|
||||
const RowDetailPage({
|
||||
required this.rowData,
|
||||
required this.rowCache,
|
||||
required this.cellCache,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -59,32 +64,45 @@ class _RowDetailPageState extends State<RowDetailPage> {
|
||||
bloc.add(const RowDetailEvent.initial());
|
||||
return bloc;
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 80, vertical: 40),
|
||||
child: _PropertyList(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 80, vertical: 40),
|
||||
child: _PropertyList(cellCache: widget.cellCache),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PropertyList extends StatelessWidget {
|
||||
const _PropertyList({
|
||||
final GridCellCache cellCache;
|
||||
final ScrollController _scrollController;
|
||||
_PropertyList({
|
||||
required this.cellCache,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
}) : _scrollController = ScrollController(),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RowDetailBloc, RowDetailState>(
|
||||
buildWhen: (previous, current) => previous.cellDatas != current.cellDatas,
|
||||
buildWhen: (previous, current) => previous.gridCells != current.gridCells,
|
||||
builder: (context, state) {
|
||||
return ListView.separated(
|
||||
itemCount: state.cellDatas.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return _RowDetailCell(cellData: state.cellDatas[index]);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return const VSpace(2);
|
||||
},
|
||||
return ScrollbarListStack(
|
||||
axis: Axis.vertical,
|
||||
controller: _scrollController,
|
||||
barSize: GridSize.scrollBarSize,
|
||||
child: ListView.separated(
|
||||
controller: _scrollController,
|
||||
itemCount: state.gridCells.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return _RowDetailCell(
|
||||
gridCell: state.gridCells[index],
|
||||
cellCache: cellCache,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return const VSpace(2);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -92,15 +110,22 @@ class _PropertyList extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _RowDetailCell extends StatelessWidget {
|
||||
final GridCell cellData;
|
||||
const _RowDetailCell({required this.cellData, Key? key}) : super(key: key);
|
||||
final GridCell gridCell;
|
||||
final GridCellCache cellCache;
|
||||
const _RowDetailCell({
|
||||
required this.gridCell,
|
||||
required this.cellCache,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
final cell = buildGridCell(
|
||||
cellData,
|
||||
style: _buildCellStyle(theme, cellData.field.fieldType),
|
||||
|
||||
final cell = buildGridCellWidget(
|
||||
gridCell,
|
||||
cellCache,
|
||||
style: _buildCellStyle(theme, gridCell.field.fieldType),
|
||||
);
|
||||
return SizedBox(
|
||||
height: 36,
|
||||
@ -110,7 +135,7 @@ class _RowDetailCell extends StatelessWidget {
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 150,
|
||||
child: FieldCellButton(field: cellData.field, onTap: () => _showFieldEditor(context)),
|
||||
child: FieldCellButton(field: gridCell.field, onTap: () => _showFieldEditor(context)),
|
||||
),
|
||||
const HSpace(10),
|
||||
Expanded(
|
||||
@ -126,10 +151,10 @@ class _RowDetailCell extends StatelessWidget {
|
||||
|
||||
void _showFieldEditor(BuildContext context) {
|
||||
FieldEditor(
|
||||
gridId: cellData.gridId,
|
||||
gridId: gridCell.gridId,
|
||||
fieldContextLoader: FieldContextLoaderAdaptor(
|
||||
gridId: cellData.gridId,
|
||||
field: cellData.field,
|
||||
gridId: gridCell.gridId,
|
||||
field: gridCell.field,
|
||||
),
|
||||
).show(context);
|
||||
}
|
||||
@ -142,7 +167,9 @@ GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) {
|
||||
case FieldType.DateTime:
|
||||
return null;
|
||||
case FieldType.MultiSelect:
|
||||
return null;
|
||||
return SelectOptionCellStyle(
|
||||
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
|
||||
);
|
||||
case FieldType.Number:
|
||||
return null;
|
||||
case FieldType.RichText:
|
||||
@ -150,7 +177,9 @@ GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) {
|
||||
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
|
||||
);
|
||||
case FieldType.SingleSelect:
|
||||
return null;
|
||||
return SelectOptionCellStyle(
|
||||
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class FlowyText extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
color: color ?? theme.textColor,
|
||||
fontWeight: fontWeight,
|
||||
fontSize: fontSize + 2,
|
||||
fontSize: fontSize,
|
||||
fontFamily: 'Mulish',
|
||||
));
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class Log {
|
||||
}
|
||||
|
||||
static void trace(dynamic msg) {
|
||||
Log.shared._logger.d(msg);
|
||||
Log.shared._logger.v(msg);
|
||||
}
|
||||
|
||||
static void error(dynamic msg) {
|
||||
|
@ -1081,12 +1081,77 @@ class IndexRowOrder extends $pb.GeneratedMessage {
|
||||
void clearIndex() => clearField(2);
|
||||
}
|
||||
|
||||
class UpdatedRowOrder extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdatedRowOrder', createEmptyInstance: create)
|
||||
..aOM<RowOrder>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrder', subBuilder: RowOrder.create)
|
||||
..aOM<Row>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'row', subBuilder: Row.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
UpdatedRowOrder._() : super();
|
||||
factory UpdatedRowOrder({
|
||||
RowOrder? rowOrder,
|
||||
Row? row,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (rowOrder != null) {
|
||||
_result.rowOrder = rowOrder;
|
||||
}
|
||||
if (row != null) {
|
||||
_result.row = row;
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory UpdatedRowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory UpdatedRowOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
UpdatedRowOrder clone() => UpdatedRowOrder()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
UpdatedRowOrder copyWith(void Function(UpdatedRowOrder) updates) => super.copyWith((message) => updates(message as UpdatedRowOrder)) as UpdatedRowOrder; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static UpdatedRowOrder create() => UpdatedRowOrder._();
|
||||
UpdatedRowOrder createEmptyInstance() => create();
|
||||
static $pb.PbList<UpdatedRowOrder> createRepeated() => $pb.PbList<UpdatedRowOrder>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static UpdatedRowOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdatedRowOrder>(create);
|
||||
static UpdatedRowOrder? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
RowOrder get rowOrder => $_getN(0);
|
||||
@$pb.TagNumber(1)
|
||||
set rowOrder(RowOrder v) { setField(1, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasRowOrder() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearRowOrder() => clearField(1);
|
||||
@$pb.TagNumber(1)
|
||||
RowOrder ensureRowOrder() => $_ensure(0);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
Row get row => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set row(Row v) { setField(2, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasRow() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearRow() => clearField(2);
|
||||
@$pb.TagNumber(2)
|
||||
Row ensureRow() => $_ensure(1);
|
||||
}
|
||||
|
||||
class GridRowsChangeset extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridRowsChangeset', createEmptyInstance: create)
|
||||
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
|
||||
..pc<IndexRowOrder>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedRows', $pb.PbFieldType.PM, subBuilder: IndexRowOrder.create)
|
||||
..pc<RowOrder>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
|
||||
..pc<RowOrder>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
|
||||
..pc<UpdatedRowOrder>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: UpdatedRowOrder.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@ -1095,7 +1160,7 @@ class GridRowsChangeset extends $pb.GeneratedMessage {
|
||||
$core.String? blockId,
|
||||
$core.Iterable<IndexRowOrder>? insertedRows,
|
||||
$core.Iterable<RowOrder>? deletedRows,
|
||||
$core.Iterable<RowOrder>? updatedRows,
|
||||
$core.Iterable<UpdatedRowOrder>? updatedRows,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (blockId != null) {
|
||||
@ -1149,7 +1214,7 @@ class GridRowsChangeset extends $pb.GeneratedMessage {
|
||||
$core.List<RowOrder> get deletedRows => $_getList(2);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.List<RowOrder> get updatedRows => $_getList(3);
|
||||
$core.List<UpdatedRowOrder> get updatedRows => $_getList(3);
|
||||
}
|
||||
|
||||
class GridBlock extends $pb.GeneratedMessage {
|
||||
@ -1268,108 +1333,6 @@ class Cell extends $pb.GeneratedMessage {
|
||||
void clearContent() => clearField(2);
|
||||
}
|
||||
|
||||
enum CellNotificationData_OneOfContent {
|
||||
content,
|
||||
notSet
|
||||
}
|
||||
|
||||
class CellNotificationData extends $pb.GeneratedMessage {
|
||||
static const $core.Map<$core.int, CellNotificationData_OneOfContent> _CellNotificationData_OneOfContentByTag = {
|
||||
4 : CellNotificationData_OneOfContent.content,
|
||||
0 : CellNotificationData_OneOfContent.notSet
|
||||
};
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellNotificationData', createEmptyInstance: create)
|
||||
..oo(0, [4])
|
||||
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
|
||||
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
|
||||
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId')
|
||||
..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content')
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
CellNotificationData._() : super();
|
||||
factory CellNotificationData({
|
||||
$core.String? gridId,
|
||||
$core.String? fieldId,
|
||||
$core.String? rowId,
|
||||
$core.String? content,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (gridId != null) {
|
||||
_result.gridId = gridId;
|
||||
}
|
||||
if (fieldId != null) {
|
||||
_result.fieldId = fieldId;
|
||||
}
|
||||
if (rowId != null) {
|
||||
_result.rowId = rowId;
|
||||
}
|
||||
if (content != null) {
|
||||
_result.content = content;
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory CellNotificationData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory CellNotificationData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
CellNotificationData clone() => CellNotificationData()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
CellNotificationData copyWith(void Function(CellNotificationData) updates) => super.copyWith((message) => updates(message as CellNotificationData)) as CellNotificationData; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static CellNotificationData create() => CellNotificationData._();
|
||||
CellNotificationData createEmptyInstance() => create();
|
||||
static $pb.PbList<CellNotificationData> createRepeated() => $pb.PbList<CellNotificationData>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static CellNotificationData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CellNotificationData>(create);
|
||||
static CellNotificationData? _defaultInstance;
|
||||
|
||||
CellNotificationData_OneOfContent whichOneOfContent() => _CellNotificationData_OneOfContentByTag[$_whichOneof(0)]!;
|
||||
void clearOneOfContent() => clearField($_whichOneof(0));
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get gridId => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set gridId($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasGridId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearGridId() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get fieldId => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set fieldId($core.String v) { $_setString(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasFieldId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearFieldId() => clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get rowId => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set rowId($core.String v) { $_setString(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasRowId() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearRowId() => clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.String get content => $_getSZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
set content($core.String v) { $_setString(3, v); }
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasContent() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearContent() => clearField(4);
|
||||
}
|
||||
|
||||
class RepeatedCell extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedCell', createEmptyInstance: create)
|
||||
..pc<Cell>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Cell.create)
|
||||
|
@ -236,6 +236,17 @@ const IndexRowOrder$json = const {
|
||||
|
||||
/// Descriptor for `IndexRowOrder`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List indexRowOrderDescriptor = $convert.base64Decode('Cg1JbmRleFJvd09yZGVyEiYKCXJvd19vcmRlchgBIAEoCzIJLlJvd09yZGVyUghyb3dPcmRlchIWCgVpbmRleBgCIAEoBUgAUgVpbmRleEIOCgxvbmVfb2ZfaW5kZXg=');
|
||||
@$core.Deprecated('Use updatedRowOrderDescriptor instead')
|
||||
const UpdatedRowOrder$json = const {
|
||||
'1': 'UpdatedRowOrder',
|
||||
'2': const [
|
||||
const {'1': 'row_order', '3': 1, '4': 1, '5': 11, '6': '.RowOrder', '10': 'rowOrder'},
|
||||
const {'1': 'row', '3': 2, '4': 1, '5': 11, '6': '.Row', '10': 'row'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `UpdatedRowOrder`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List updatedRowOrderDescriptor = $convert.base64Decode('Cg9VcGRhdGVkUm93T3JkZXISJgoJcm93X29yZGVyGAEgASgLMgkuUm93T3JkZXJSCHJvd09yZGVyEhYKA3JvdxgCIAEoCzIELlJvd1IDcm93');
|
||||
@$core.Deprecated('Use gridRowsChangesetDescriptor instead')
|
||||
const GridRowsChangeset$json = const {
|
||||
'1': 'GridRowsChangeset',
|
||||
@ -243,12 +254,12 @@ const GridRowsChangeset$json = const {
|
||||
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
|
||||
const {'1': 'inserted_rows', '3': 2, '4': 3, '5': 11, '6': '.IndexRowOrder', '10': 'insertedRows'},
|
||||
const {'1': 'deleted_rows', '3': 3, '4': 3, '5': 11, '6': '.RowOrder', '10': 'deletedRows'},
|
||||
const {'1': 'updated_rows', '3': 4, '4': 3, '5': 11, '6': '.RowOrder', '10': 'updatedRows'},
|
||||
const {'1': 'updated_rows', '3': 4, '4': 3, '5': 11, '6': '.UpdatedRowOrder', '10': 'updatedRows'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `GridRowsChangeset`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M=');
|
||||
final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIzCgx1cGRhdGVkX3Jvd3MYBCADKAsyEC5VcGRhdGVkUm93T3JkZXJSC3VwZGF0ZWRSb3dz');
|
||||
@$core.Deprecated('Use gridBlockDescriptor instead')
|
||||
const GridBlock$json = const {
|
||||
'1': 'GridBlock',
|
||||
@ -271,22 +282,6 @@ const Cell$json = const {
|
||||
|
||||
/// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ=');
|
||||
@$core.Deprecated('Use cellNotificationDataDescriptor instead')
|
||||
const CellNotificationData$json = const {
|
||||
'1': 'CellNotificationData',
|
||||
'2': const [
|
||||
const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
|
||||
const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'},
|
||||
const {'1': 'row_id', '3': 3, '4': 1, '5': 9, '10': 'rowId'},
|
||||
const {'1': 'content', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'content'},
|
||||
],
|
||||
'8': const [
|
||||
const {'1': 'one_of_content'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `CellNotificationData`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List cellNotificationDataDescriptor = $convert.base64Decode('ChRDZWxsTm90aWZpY2F0aW9uRGF0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSGQoIZmllbGRfaWQYAiABKAlSB2ZpZWxkSWQSFQoGcm93X2lkGAMgASgJUgVyb3dJZBIaCgdjb250ZW50GAQgASgJSABSB2NvbnRlbnRCEAoOb25lX29mX2NvbnRlbnQ=');
|
||||
@$core.Deprecated('Use repeatedCellDescriptor instead')
|
||||
const RepeatedCell$json = const {
|
||||
'1': 'RepeatedCell',
|
||||
|
@ -96,6 +96,12 @@ impl ClientGridBlockMetaEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_row_meta(&self, row_id: &str) -> FlowyResult<Option<Arc<RowMeta>>> {
|
||||
let row_ids = vec![Cow::Borrowed(row_id)];
|
||||
let row_meta = self.get_row_metas(Some(row_ids)).await?.pop();
|
||||
Ok(row_meta)
|
||||
}
|
||||
|
||||
pub async fn get_row_metas<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<Arc<RowMeta>>>
|
||||
where
|
||||
T: AsRef<str> + ToOwned + ?Sized,
|
||||
@ -113,6 +119,11 @@ impl ClientGridBlockMetaEditor {
|
||||
Ok(cell_metas)
|
||||
}
|
||||
|
||||
pub async fn get_row_order(&self, row_id: &str) -> FlowyResult<Option<RowOrder>> {
|
||||
let row_ids = Some(vec![Cow::Borrowed(row_id)]);
|
||||
Ok(self.get_row_orders(row_ids).await?.pop())
|
||||
}
|
||||
|
||||
pub async fn get_row_orders<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowOrder>>
|
||||
where
|
||||
T: AsRef<str> + ToOwned + ?Sized,
|
||||
|
@ -3,16 +3,15 @@ use crate::manager::GridUser;
|
||||
use crate::services::block_meta_editor::ClientGridBlockMetaEditor;
|
||||
use crate::services::persistence::block_index::BlockIndexPersistence;
|
||||
use crate::services::row::{group_row_orders, GridBlockSnapshot};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::entities::{
|
||||
CellChangeset, CellMeta, CellNotificationData, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset,
|
||||
IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder,
|
||||
CellChangeset, CellMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, IndexRowOrder, Row, RowMeta,
|
||||
RowMetaChangeset, RowOrder, UpdatedRowOrder,
|
||||
};
|
||||
use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence;
|
||||
use flowy_revision::{RevisionManager, RevisionPersistence};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -108,10 +107,22 @@ impl GridBlockMetaEditorManager {
|
||||
Ok(changesets)
|
||||
}
|
||||
|
||||
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||
pub async fn update_row<F>(&self, changeset: RowMetaChangeset, row_builder: F) -> FlowyResult<()>
|
||||
where
|
||||
F: FnOnce(Arc<RowMeta>) -> Option<Row>,
|
||||
{
|
||||
let editor = self.get_editor_from_row_id(&changeset.row_id).await?;
|
||||
let _ = editor.update_row(changeset.clone()).await?;
|
||||
let _ = self.notify_did_update_block_row(&changeset.row_id).await?;
|
||||
match editor.get_row_meta(&changeset.row_id).await? {
|
||||
None => tracing::error!("Internal error: can't find the row with id: {}", changeset.row_id),
|
||||
Some(row_meta) => {
|
||||
if let Some(row) = row_builder(row_meta.clone()) {
|
||||
let row_order = UpdatedRowOrder::new(&row_meta, row);
|
||||
let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]);
|
||||
let _ = self.notify_did_update_block(block_order_changeset).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -119,11 +130,15 @@ impl GridBlockMetaEditorManager {
|
||||
let row_id = row_id.to_owned();
|
||||
let block_id = self.persistence.get_block_id(&row_id)?;
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let row_orders = editor.get_row_orders(Some(vec![Cow::Borrowed(&row_id)])).await?;
|
||||
let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
|
||||
let _ = self
|
||||
.notify_did_update_block(GridRowsChangeset::delete(&block_id, row_orders))
|
||||
.await?;
|
||||
match editor.get_row_order(&row_id).await? {
|
||||
None => {}
|
||||
Some(row_order) => {
|
||||
let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
|
||||
let _ = self
|
||||
.notify_did_update_block(GridRowsChangeset::delete(&block_id, vec![row_order]))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -171,18 +186,13 @@ impl GridBlockMetaEditorManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> {
|
||||
pub async fn update_cell<F>(&self, changeset: CellChangeset, row_builder: F) -> FlowyResult<()>
|
||||
where
|
||||
F: FnOnce(Arc<RowMeta>) -> Option<Row>,
|
||||
{
|
||||
let row_changeset: RowMetaChangeset = changeset.clone().into();
|
||||
let _ = self.update_row(row_changeset).await?;
|
||||
|
||||
let cell_notification_data = CellNotificationData {
|
||||
grid_id: changeset.grid_id,
|
||||
field_id: changeset.field_id,
|
||||
row_id: changeset.row_id,
|
||||
content: changeset.data,
|
||||
};
|
||||
self.notify_did_update_cell(cell_notification_data).await?;
|
||||
|
||||
let _ = self.update_row(row_changeset, row_builder).await?;
|
||||
self.notify_did_update_cell(changeset).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -229,20 +239,6 @@ impl GridBlockMetaEditorManager {
|
||||
Ok(block_cell_metas)
|
||||
}
|
||||
|
||||
async fn notify_did_update_block_row(&self, row_id: &str) -> FlowyResult<()> {
|
||||
let editor = self.get_editor_from_row_id(row_id).await?;
|
||||
let row_ids = Some(vec![Cow::Borrowed(&row_id)]);
|
||||
match editor.get_row_orders(row_ids).await?.pop() {
|
||||
None => {}
|
||||
Some(row_order) => {
|
||||
let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]);
|
||||
let _ = self.notify_did_update_block(block_order_changeset).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn notify_did_update_block(&self, changeset: GridRowsChangeset) -> FlowyResult<()> {
|
||||
send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridRow)
|
||||
.payload(changeset)
|
||||
@ -250,11 +246,9 @@ impl GridBlockMetaEditorManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn notify_did_update_cell(&self, data: CellNotificationData) -> FlowyResult<()> {
|
||||
let id = format!("{}:{}", data.row_id, data.field_id);
|
||||
send_dart_notification(&id, GridNotification::DidUpdateCell)
|
||||
.payload(data)
|
||||
.send();
|
||||
async fn notify_did_update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> {
|
||||
let id = format!("{}:{}", changeset.row_id, changeset.field_id);
|
||||
send_dart_notification(&id, GridNotification::DidUpdateCell).send();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -247,7 +247,10 @@ impl ClientGridEditor {
|
||||
}
|
||||
|
||||
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||
self.block_meta_manager.update_row(changeset).await
|
||||
let field_metas = self.get_field_metas::<FieldOrder>(None).await?;
|
||||
self.block_meta_manager
|
||||
.update_row(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_rows(&self, block_id: &str) -> FlowyResult<RepeatedRow> {
|
||||
@ -322,7 +325,11 @@ impl ClientGridEditor {
|
||||
Some((_, field_meta)) => {
|
||||
// Update the changeset.data property with the return value.
|
||||
changeset.data = Some(apply_cell_data_changeset(cell_data_changeset, cell_meta, field_meta)?);
|
||||
let _ = self.block_meta_manager.update_cell(changeset).await?;
|
||||
let field_metas = self.get_field_metas::<FieldOrder>(None).await?;
|
||||
let _ = self
|
||||
.block_meta_manager
|
||||
.update_cell(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,10 @@ pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc<RowMeta>]) -> Vec<
|
||||
row_metas.iter().map(RowOrder::from).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn make_row_from_row_meta(fields: &[FieldMeta], row_meta: Arc<RowMeta>) -> Option<Row> {
|
||||
make_rows_from_row_metas(fields, &[row_meta]).pop()
|
||||
}
|
||||
|
||||
pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &[Arc<RowMeta>]) -> Vec<Row> {
|
||||
let field_meta_map = fields
|
||||
.iter()
|
||||
|
@ -352,7 +352,25 @@ pub struct IndexRowOrder {
|
||||
pub index: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct UpdatedRowOrder {
|
||||
#[pb(index = 1)]
|
||||
pub row_order: RowOrder,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row: Row,
|
||||
}
|
||||
|
||||
impl UpdatedRowOrder {
|
||||
pub fn new(row_meta: &RowMeta, row: Row) -> Self {
|
||||
Self {
|
||||
row_order: RowOrder::from(row_meta),
|
||||
row,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct GridRowsChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
@ -364,7 +382,7 @@ pub struct GridRowsChangeset {
|
||||
pub deleted_rows: Vec<RowOrder>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub updated_rows: Vec<RowOrder>,
|
||||
pub updated_rows: Vec<UpdatedRowOrder>,
|
||||
}
|
||||
|
||||
impl std::convert::From<RowOrder> for IndexRowOrder {
|
||||
@ -399,7 +417,7 @@ impl GridRowsChangeset {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(block_id: &str, updated_rows: Vec<RowOrder>) -> Self {
|
||||
pub fn update(block_id: &str, updated_rows: Vec<UpdatedRowOrder>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
@ -445,21 +463,6 @@ impl Cell {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct CellNotificationData {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub content: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedCell {
|
||||
#[pb(index = 1)]
|
||||
|
@ -3701,13 +3701,244 @@ impl ::protobuf::reflect::ProtobufValue for IndexRowOrder {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct UpdatedRowOrder {
|
||||
// message fields
|
||||
pub row_order: ::protobuf::SingularPtrField<RowOrder>,
|
||||
pub row: ::protobuf::SingularPtrField<Row>,
|
||||
// special fields
|
||||
pub unknown_fields: ::protobuf::UnknownFields,
|
||||
pub cached_size: ::protobuf::CachedSize,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a UpdatedRowOrder {
|
||||
fn default() -> &'a UpdatedRowOrder {
|
||||
<UpdatedRowOrder as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl UpdatedRowOrder {
|
||||
pub fn new() -> UpdatedRowOrder {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
// .RowOrder row_order = 1;
|
||||
|
||||
|
||||
pub fn get_row_order(&self) -> &RowOrder {
|
||||
self.row_order.as_ref().unwrap_or_else(|| <RowOrder as ::protobuf::Message>::default_instance())
|
||||
}
|
||||
pub fn clear_row_order(&mut self) {
|
||||
self.row_order.clear();
|
||||
}
|
||||
|
||||
pub fn has_row_order(&self) -> bool {
|
||||
self.row_order.is_some()
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_row_order(&mut self, v: RowOrder) {
|
||||
self.row_order = ::protobuf::SingularPtrField::some(v);
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
// If field is not initialized, it is initialized with default value first.
|
||||
pub fn mut_row_order(&mut self) -> &mut RowOrder {
|
||||
if self.row_order.is_none() {
|
||||
self.row_order.set_default();
|
||||
}
|
||||
self.row_order.as_mut().unwrap()
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_row_order(&mut self) -> RowOrder {
|
||||
self.row_order.take().unwrap_or_else(|| RowOrder::new())
|
||||
}
|
||||
|
||||
// .Row row = 2;
|
||||
|
||||
|
||||
pub fn get_row(&self) -> &Row {
|
||||
self.row.as_ref().unwrap_or_else(|| <Row as ::protobuf::Message>::default_instance())
|
||||
}
|
||||
pub fn clear_row(&mut self) {
|
||||
self.row.clear();
|
||||
}
|
||||
|
||||
pub fn has_row(&self) -> bool {
|
||||
self.row.is_some()
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_row(&mut self, v: Row) {
|
||||
self.row = ::protobuf::SingularPtrField::some(v);
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
// If field is not initialized, it is initialized with default value first.
|
||||
pub fn mut_row(&mut self) -> &mut Row {
|
||||
if self.row.is_none() {
|
||||
self.row.set_default();
|
||||
}
|
||||
self.row.as_mut().unwrap()
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_row(&mut self) -> Row {
|
||||
self.row.take().unwrap_or_else(|| Row::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for UpdatedRowOrder {
|
||||
fn is_initialized(&self) -> bool {
|
||||
for v in &self.row_order {
|
||||
if !v.is_initialized() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
for v in &self.row {
|
||||
if !v.is_initialized() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
while !is.eof()? {
|
||||
let (field_number, wire_type) = is.read_tag_unpack()?;
|
||||
match field_number {
|
||||
1 => {
|
||||
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.row_order)?;
|
||||
},
|
||||
2 => {
|
||||
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.row)?;
|
||||
},
|
||||
_ => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u32 {
|
||||
let mut my_size = 0;
|
||||
if let Some(ref v) = self.row_order.as_ref() {
|
||||
let len = v.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
||||
}
|
||||
if let Some(ref v) = self.row.as_ref() {
|
||||
let len = v.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||
self.cached_size.set(my_size);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
if let Some(ref v) = self.row_order.as_ref() {
|
||||
os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
|
||||
os.write_raw_varint32(v.get_cached_size())?;
|
||||
v.write_to_with_cached_sizes(os)?;
|
||||
}
|
||||
if let Some(ref v) = self.row.as_ref() {
|
||||
os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
|
||||
os.write_raw_varint32(v.get_cached_size())?;
|
||||
v.write_to_with_cached_sizes(os)?;
|
||||
}
|
||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn get_cached_size(&self) -> u32 {
|
||||
self.cached_size.get()
|
||||
}
|
||||
|
||||
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
|
||||
&self.unknown_fields
|
||||
}
|
||||
|
||||
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
|
||||
&mut self.unknown_fields
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn (::std::any::Any) {
|
||||
self as &dyn (::std::any::Any)
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
|
||||
self as &mut dyn (::std::any::Any)
|
||||
}
|
||||
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
|
||||
self
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
Self::descriptor_static()
|
||||
}
|
||||
|
||||
fn new() -> UpdatedRowOrder {
|
||||
UpdatedRowOrder::new()
|
||||
}
|
||||
|
||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||
descriptor.get(|| {
|
||||
let mut fields = ::std::vec::Vec::new();
|
||||
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
|
||||
"row_order",
|
||||
|m: &UpdatedRowOrder| { &m.row_order },
|
||||
|m: &mut UpdatedRowOrder| { &mut m.row_order },
|
||||
));
|
||||
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Row>>(
|
||||
"row",
|
||||
|m: &UpdatedRowOrder| { &m.row },
|
||||
|m: &mut UpdatedRowOrder| { &mut m.row },
|
||||
));
|
||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<UpdatedRowOrder>(
|
||||
"UpdatedRowOrder",
|
||||
fields,
|
||||
file_descriptor_proto()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static UpdatedRowOrder {
|
||||
static instance: ::protobuf::rt::LazyV2<UpdatedRowOrder> = ::protobuf::rt::LazyV2::INIT;
|
||||
instance.get(UpdatedRowOrder::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Clear for UpdatedRowOrder {
|
||||
fn clear(&mut self) {
|
||||
self.row_order.clear();
|
||||
self.row.clear();
|
||||
self.unknown_fields.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for UpdatedRowOrder {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for UpdatedRowOrder {
|
||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct GridRowsChangeset {
|
||||
// message fields
|
||||
pub block_id: ::std::string::String,
|
||||
pub inserted_rows: ::protobuf::RepeatedField<IndexRowOrder>,
|
||||
pub deleted_rows: ::protobuf::RepeatedField<RowOrder>,
|
||||
pub updated_rows: ::protobuf::RepeatedField<RowOrder>,
|
||||
pub updated_rows: ::protobuf::RepeatedField<UpdatedRowOrder>,
|
||||
// special fields
|
||||
pub unknown_fields: ::protobuf::UnknownFields,
|
||||
pub cached_size: ::protobuf::CachedSize,
|
||||
@ -3800,10 +4031,10 @@ impl GridRowsChangeset {
|
||||
::std::mem::replace(&mut self.deleted_rows, ::protobuf::RepeatedField::new())
|
||||
}
|
||||
|
||||
// repeated .RowOrder updated_rows = 4;
|
||||
// repeated .UpdatedRowOrder updated_rows = 4;
|
||||
|
||||
|
||||
pub fn get_updated_rows(&self) -> &[RowOrder] {
|
||||
pub fn get_updated_rows(&self) -> &[UpdatedRowOrder] {
|
||||
&self.updated_rows
|
||||
}
|
||||
pub fn clear_updated_rows(&mut self) {
|
||||
@ -3811,17 +4042,17 @@ impl GridRowsChangeset {
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
|
||||
pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField<UpdatedRowOrder>) {
|
||||
self.updated_rows = v;
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
|
||||
pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField<UpdatedRowOrder> {
|
||||
&mut self.updated_rows
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
|
||||
pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField<UpdatedRowOrder> {
|
||||
::std::mem::replace(&mut self.updated_rows, ::protobuf::RepeatedField::new())
|
||||
}
|
||||
}
|
||||
@ -3966,7 +4197,7 @@ impl ::protobuf::Message for GridRowsChangeset {
|
||||
|m: &GridRowsChangeset| { &m.deleted_rows },
|
||||
|m: &mut GridRowsChangeset| { &mut m.deleted_rows },
|
||||
));
|
||||
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
|
||||
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<UpdatedRowOrder>>(
|
||||
"updated_rows",
|
||||
|m: &GridRowsChangeset| { &m.updated_rows },
|
||||
|m: &mut GridRowsChangeset| { &mut m.updated_rows },
|
||||
@ -4416,331 +4647,6 @@ impl ::protobuf::reflect::ProtobufValue for Cell {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct CellNotificationData {
|
||||
// message fields
|
||||
pub grid_id: ::std::string::String,
|
||||
pub field_id: ::std::string::String,
|
||||
pub row_id: ::std::string::String,
|
||||
// message oneof groups
|
||||
pub one_of_content: ::std::option::Option<CellNotificationData_oneof_one_of_content>,
|
||||
// special fields
|
||||
pub unknown_fields: ::protobuf::UnknownFields,
|
||||
pub cached_size: ::protobuf::CachedSize,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a CellNotificationData {
|
||||
fn default() -> &'a CellNotificationData {
|
||||
<CellNotificationData as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,PartialEq,Debug)]
|
||||
pub enum CellNotificationData_oneof_one_of_content {
|
||||
content(::std::string::String),
|
||||
}
|
||||
|
||||
impl CellNotificationData {
|
||||
pub fn new() -> CellNotificationData {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
// string grid_id = 1;
|
||||
|
||||
|
||||
pub fn get_grid_id(&self) -> &str {
|
||||
&self.grid_id
|
||||
}
|
||||
pub fn clear_grid_id(&mut self) {
|
||||
self.grid_id.clear();
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_grid_id(&mut self, v: ::std::string::String) {
|
||||
self.grid_id = v;
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
// If field is not initialized, it is initialized with default value first.
|
||||
pub fn mut_grid_id(&mut self) -> &mut ::std::string::String {
|
||||
&mut self.grid_id
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_grid_id(&mut self) -> ::std::string::String {
|
||||
::std::mem::replace(&mut self.grid_id, ::std::string::String::new())
|
||||
}
|
||||
|
||||
// string field_id = 2;
|
||||
|
||||
|
||||
pub fn get_field_id(&self) -> &str {
|
||||
&self.field_id
|
||||
}
|
||||
pub fn clear_field_id(&mut self) {
|
||||
self.field_id.clear();
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_field_id(&mut self, v: ::std::string::String) {
|
||||
self.field_id = v;
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
// If field is not initialized, it is initialized with default value first.
|
||||
pub fn mut_field_id(&mut self) -> &mut ::std::string::String {
|
||||
&mut self.field_id
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_field_id(&mut self) -> ::std::string::String {
|
||||
::std::mem::replace(&mut self.field_id, ::std::string::String::new())
|
||||
}
|
||||
|
||||
// string row_id = 3;
|
||||
|
||||
|
||||
pub fn get_row_id(&self) -> &str {
|
||||
&self.row_id
|
||||
}
|
||||
pub fn clear_row_id(&mut self) {
|
||||
self.row_id.clear();
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_row_id(&mut self, v: ::std::string::String) {
|
||||
self.row_id = v;
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
// If field is not initialized, it is initialized with default value first.
|
||||
pub fn mut_row_id(&mut self) -> &mut ::std::string::String {
|
||||
&mut self.row_id
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_row_id(&mut self) -> ::std::string::String {
|
||||
::std::mem::replace(&mut self.row_id, ::std::string::String::new())
|
||||
}
|
||||
|
||||
// string content = 4;
|
||||
|
||||
|
||||
pub fn get_content(&self) -> &str {
|
||||
match self.one_of_content {
|
||||
::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(ref v)) => v,
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
pub fn clear_content(&mut self) {
|
||||
self.one_of_content = ::std::option::Option::None;
|
||||
}
|
||||
|
||||
pub fn has_content(&self) -> bool {
|
||||
match self.one_of_content {
|
||||
::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(..)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_content(&mut self, v: ::std::string::String) {
|
||||
self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(v))
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
pub fn mut_content(&mut self) -> &mut ::std::string::String {
|
||||
if let ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(_)) = self.one_of_content {
|
||||
} else {
|
||||
self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(::std::string::String::new()));
|
||||
}
|
||||
match self.one_of_content {
|
||||
::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(ref mut v)) => v,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_content(&mut self) -> ::std::string::String {
|
||||
if self.has_content() {
|
||||
match self.one_of_content.take() {
|
||||
::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(v)) => v,
|
||||
_ => panic!(),
|
||||
}
|
||||
} else {
|
||||
::std::string::String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for CellNotificationData {
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
while !is.eof()? {
|
||||
let (field_number, wire_type) = is.read_tag_unpack()?;
|
||||
match field_number {
|
||||
1 => {
|
||||
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?;
|
||||
},
|
||||
2 => {
|
||||
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
|
||||
},
|
||||
3 => {
|
||||
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?;
|
||||
},
|
||||
4 => {
|
||||
if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
|
||||
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
|
||||
}
|
||||
self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(is.read_string()?));
|
||||
},
|
||||
_ => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u32 {
|
||||
let mut my_size = 0;
|
||||
if !self.grid_id.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.grid_id);
|
||||
}
|
||||
if !self.field_id.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(2, &self.field_id);
|
||||
}
|
||||
if !self.row_id.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(3, &self.row_id);
|
||||
}
|
||||
if let ::std::option::Option::Some(ref v) = self.one_of_content {
|
||||
match v {
|
||||
&CellNotificationData_oneof_one_of_content::content(ref v) => {
|
||||
my_size += ::protobuf::rt::string_size(4, &v);
|
||||
},
|
||||
};
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||
self.cached_size.set(my_size);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
if !self.grid_id.is_empty() {
|
||||
os.write_string(1, &self.grid_id)?;
|
||||
}
|
||||
if !self.field_id.is_empty() {
|
||||
os.write_string(2, &self.field_id)?;
|
||||
}
|
||||
if !self.row_id.is_empty() {
|
||||
os.write_string(3, &self.row_id)?;
|
||||
}
|
||||
if let ::std::option::Option::Some(ref v) = self.one_of_content {
|
||||
match v {
|
||||
&CellNotificationData_oneof_one_of_content::content(ref v) => {
|
||||
os.write_string(4, v)?;
|
||||
},
|
||||
};
|
||||
}
|
||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn get_cached_size(&self) -> u32 {
|
||||
self.cached_size.get()
|
||||
}
|
||||
|
||||
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
|
||||
&self.unknown_fields
|
||||
}
|
||||
|
||||
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
|
||||
&mut self.unknown_fields
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn (::std::any::Any) {
|
||||
self as &dyn (::std::any::Any)
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
|
||||
self as &mut dyn (::std::any::Any)
|
||||
}
|
||||
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
|
||||
self
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
Self::descriptor_static()
|
||||
}
|
||||
|
||||
fn new() -> CellNotificationData {
|
||||
CellNotificationData::new()
|
||||
}
|
||||
|
||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||
descriptor.get(|| {
|
||||
let mut fields = ::std::vec::Vec::new();
|
||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
||||
"grid_id",
|
||||
|m: &CellNotificationData| { &m.grid_id },
|
||||
|m: &mut CellNotificationData| { &mut m.grid_id },
|
||||
));
|
||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
||||
"field_id",
|
||||
|m: &CellNotificationData| { &m.field_id },
|
||||
|m: &mut CellNotificationData| { &mut m.field_id },
|
||||
));
|
||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
||||
"row_id",
|
||||
|m: &CellNotificationData| { &m.row_id },
|
||||
|m: &mut CellNotificationData| { &mut m.row_id },
|
||||
));
|
||||
fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
|
||||
"content",
|
||||
CellNotificationData::has_content,
|
||||
CellNotificationData::get_content,
|
||||
));
|
||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<CellNotificationData>(
|
||||
"CellNotificationData",
|
||||
fields,
|
||||
file_descriptor_proto()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static CellNotificationData {
|
||||
static instance: ::protobuf::rt::LazyV2<CellNotificationData> = ::protobuf::rt::LazyV2::INIT;
|
||||
instance.get(CellNotificationData::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Clear for CellNotificationData {
|
||||
fn clear(&mut self) {
|
||||
self.grid_id.clear();
|
||||
self.field_id.clear();
|
||||
self.row_id.clear();
|
||||
self.one_of_content = ::std::option::Option::None;
|
||||
self.unknown_fields.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for CellNotificationData {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for CellNotificationData {
|
||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct RepeatedCell {
|
||||
// message fields
|
||||
@ -7843,56 +7749,54 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\
|
||||
\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\tro\
|
||||
w_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05index\
|
||||
\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"\xbf\x01\n\
|
||||
\x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07block\
|
||||
Id\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cins\
|
||||
ertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bde\
|
||||
letedRows\x12,\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bup\
|
||||
datedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\
|
||||
\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\
|
||||
\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07conte\
|
||||
nt\x18\x02\x20\x01(\tR\x07content\"\x8f\x01\n\x14CellNotificationData\
|
||||
\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_i\
|
||||
d\x18\x02\x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\
|
||||
\x05rowId\x12\x1a\n\x07content\x18\x04\x20\x01(\tH\0R\x07contentB\x10\n\
|
||||
\x0eone_of_content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\
|
||||
\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04nam\
|
||||
e\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\
|
||||
\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\
|
||||
\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\
|
||||
\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0\
|
||||
R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12InsertFieldPa\
|
||||
yload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05fi\
|
||||
eld\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\
|
||||
\x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\
|
||||
\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\
|
||||
\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\
|
||||
\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\
|
||||
\x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\
|
||||
\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\
|
||||
\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\
|
||||
\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\
|
||||
id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\
|
||||
R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\
|
||||
ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\
|
||||
frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\
|
||||
\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\
|
||||
\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\
|
||||
\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\
|
||||
_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\
|
||||
\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\
|
||||
emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\
|
||||
\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\
|
||||
\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\
|
||||
\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\
|
||||
\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\
|
||||
Id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_i\
|
||||
d\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0\
|
||||
R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\
|
||||
\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\
|
||||
\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0c\
|
||||
SingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Check\
|
||||
box\x10\x05b\x06proto3\
|
||||
\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"Q\n\x0fUpdate\
|
||||
dRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrde\
|
||||
r\x12\x16\n\x03row\x18\x02\x20\x01(\x0b2\x04.RowR\x03row\"\xc6\x01\n\x11\
|
||||
GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\
|
||||
\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cinser\
|
||||
tedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdele\
|
||||
tedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.UpdatedRowOrder\
|
||||
R\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02\
|
||||
id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\
|
||||
\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\
|
||||
\x07content\x18\x02\x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\x1b\
|
||||
\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridP\
|
||||
ayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\
|
||||
\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\
|
||||
\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\
|
||||
\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row\
|
||||
_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\
|
||||
\xb6\x01\n\x12InsertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\t\
|
||||
R\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\
|
||||
\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\
|
||||
\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15on\
|
||||
e_of_start_field_id\"d\n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\
|
||||
\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\
|
||||
\x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\
|
||||
\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orde\
|
||||
rs\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\
|
||||
\x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07f\
|
||||
ieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04n\
|
||||
ame\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\
|
||||
\x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\
|
||||
\tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\
|
||||
\x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05w\
|
||||
idth\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\
|
||||
\t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_\
|
||||
of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_\
|
||||
of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\
|
||||
\x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
|
||||
\x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\
|
||||
\nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\
|
||||
\x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.Mo\
|
||||
veItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\
|
||||
\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\
|
||||
\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\
|
||||
\x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\
|
||||
\x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\
|
||||
\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08Date\
|
||||
Time\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\
|
||||
\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\
|
||||
";
|
||||
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||
|
@ -73,11 +73,15 @@ message IndexRowOrder {
|
||||
RowOrder row_order = 1;
|
||||
oneof one_of_index { int32 index = 2; };
|
||||
}
|
||||
message UpdatedRowOrder {
|
||||
RowOrder row_order = 1;
|
||||
Row row = 2;
|
||||
}
|
||||
message GridRowsChangeset {
|
||||
string block_id = 1;
|
||||
repeated IndexRowOrder inserted_rows = 2;
|
||||
repeated RowOrder deleted_rows = 3;
|
||||
repeated RowOrder updated_rows = 4;
|
||||
repeated UpdatedRowOrder updated_rows = 4;
|
||||
}
|
||||
message GridBlock {
|
||||
string id = 1;
|
||||
@ -87,12 +91,6 @@ message Cell {
|
||||
string field_id = 1;
|
||||
string content = 2;
|
||||
}
|
||||
message CellNotificationData {
|
||||
string grid_id = 1;
|
||||
string field_id = 2;
|
||||
string row_id = 3;
|
||||
oneof one_of_content { string content = 4; };
|
||||
}
|
||||
message RepeatedCell {
|
||||
repeated Cell items = 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user