mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: disable edit primary field (#2695)
* refactor: field editor * chore: disable edit type option of primary field
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
part of 'cell_service.dart';
|
part of 'cell_service.dart';
|
||||||
|
|
||||||
typedef CellByFieldId = LinkedHashMap<String, CellIdentifier>;
|
typedef CellContextByFieldId = LinkedHashMap<String, DatabaseCellContext>;
|
||||||
|
|
||||||
class DatabaseCell {
|
class DatabaseCell {
|
||||||
dynamic object;
|
dynamic object;
|
||||||
|
@ -22,7 +22,7 @@ import 'cell_service.dart';
|
|||||||
///
|
///
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class CellController<T, D> extends Equatable {
|
class CellController<T, D> extends Equatable {
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
final CellCache _cellCache;
|
final CellCache _cellCache;
|
||||||
final CellCacheKey _cacheKey;
|
final CellCacheKey _cacheKey;
|
||||||
final FieldBackendService _fieldBackendSvc;
|
final FieldBackendService _fieldBackendSvc;
|
||||||
@ -37,37 +37,37 @@ class CellController<T, D> extends Equatable {
|
|||||||
Timer? _loadDataOperation;
|
Timer? _loadDataOperation;
|
||||||
Timer? _saveDataOperation;
|
Timer? _saveDataOperation;
|
||||||
|
|
||||||
String get viewId => cellId.viewId;
|
String get viewId => cellContext.viewId;
|
||||||
|
|
||||||
RowId get rowId => cellId.rowId;
|
RowId get rowId => cellContext.rowId;
|
||||||
|
|
||||||
String get fieldId => cellId.fieldInfo.id;
|
String get fieldId => cellContext.fieldInfo.id;
|
||||||
|
|
||||||
FieldInfo get fieldInfo => cellId.fieldInfo;
|
FieldInfo get fieldInfo => cellContext.fieldInfo;
|
||||||
|
|
||||||
FieldType get fieldType => cellId.fieldInfo.fieldType;
|
FieldType get fieldType => cellContext.fieldInfo.fieldType;
|
||||||
|
|
||||||
CellController({
|
CellController({
|
||||||
required this.cellId,
|
required this.cellContext,
|
||||||
required CellCache cellCache,
|
required CellCache cellCache,
|
||||||
required CellDataLoader<T> cellDataLoader,
|
required CellDataLoader<T> cellDataLoader,
|
||||||
required CellDataPersistence<D> cellDataPersistence,
|
required CellDataPersistence<D> cellDataPersistence,
|
||||||
}) : _cellCache = cellCache,
|
}) : _cellCache = cellCache,
|
||||||
_cellDataLoader = cellDataLoader,
|
_cellDataLoader = cellDataLoader,
|
||||||
_cellDataPersistence = cellDataPersistence,
|
_cellDataPersistence = cellDataPersistence,
|
||||||
_fieldListener = SingleFieldListener(fieldId: cellId.fieldId),
|
_fieldListener = SingleFieldListener(fieldId: cellContext.fieldId),
|
||||||
_fieldBackendSvc = FieldBackendService(
|
_fieldBackendSvc = FieldBackendService(
|
||||||
viewId: cellId.viewId,
|
viewId: cellContext.viewId,
|
||||||
fieldId: cellId.fieldInfo.id,
|
fieldId: cellContext.fieldInfo.id,
|
||||||
),
|
),
|
||||||
_cacheKey = CellCacheKey(
|
_cacheKey = CellCacheKey(
|
||||||
rowId: cellId.rowId,
|
rowId: cellContext.rowId,
|
||||||
fieldId: cellId.fieldInfo.id,
|
fieldId: cellContext.fieldInfo.id,
|
||||||
) {
|
) {
|
||||||
_cellDataNotifier = CellDataNotifier(value: _cellCache.get(_cacheKey));
|
_cellDataNotifier = CellDataNotifier(value: _cellCache.get(_cacheKey));
|
||||||
_cellListener = CellListener(
|
_cellListener = CellListener(
|
||||||
rowId: cellId.rowId,
|
rowId: cellContext.rowId,
|
||||||
fieldId: cellId.fieldInfo.id,
|
fieldId: cellContext.fieldInfo.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// 1.Listen on user edit event and load the new cell data if needed.
|
/// 1.Listen on user edit event and load the new cell data if needed.
|
||||||
@ -195,8 +195,10 @@ class CellController<T, D> extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props =>
|
List<Object> get props => [
|
||||||
[_cellCache.get(_cacheKey) ?? "", cellId.rowId + cellId.fieldInfo.id];
|
_cellCache.get(_cacheKey) ?? "",
|
||||||
|
cellContext.rowId + cellContext.fieldInfo.id
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class CellDataNotifier<T> extends ChangeNotifier {
|
class CellDataNotifier<T> extends ChangeNotifier {
|
||||||
|
@ -17,104 +17,111 @@ typedef DateCellController = CellController<DateCellDataPB, DateCellData>;
|
|||||||
typedef URLCellController = CellController<URLCellDataPB, String>;
|
typedef URLCellController = CellController<URLCellDataPB, String>;
|
||||||
|
|
||||||
class CellControllerBuilder {
|
class CellControllerBuilder {
|
||||||
final CellIdentifier _cellId;
|
final DatabaseCellContext _cellContext;
|
||||||
final CellCache _cellCache;
|
final CellCache _cellCache;
|
||||||
|
|
||||||
CellControllerBuilder({
|
CellControllerBuilder({
|
||||||
required CellIdentifier cellId,
|
required DatabaseCellContext cellContext,
|
||||||
required CellCache cellCache,
|
required CellCache cellCache,
|
||||||
}) : _cellCache = cellCache,
|
}) : _cellCache = cellCache,
|
||||||
_cellId = cellId;
|
_cellContext = cellContext;
|
||||||
|
|
||||||
CellController build() {
|
CellController build() {
|
||||||
switch (_cellId.fieldType) {
|
switch (_cellContext.fieldType) {
|
||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: StringCellDataParser(),
|
parser: StringCellDataParser(),
|
||||||
);
|
);
|
||||||
return TextCellController(
|
return TextCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
TextCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
case FieldType.LastEditedTime:
|
case FieldType.LastEditedTime:
|
||||||
case FieldType.CreatedTime:
|
case FieldType.CreatedTime:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: DateCellDataParser(),
|
parser: DateCellDataParser(),
|
||||||
reloadOnFieldChanged: true,
|
reloadOnFieldChanged: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return DateCellController(
|
return DateCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
DateCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: NumberCellDataParser(),
|
parser: NumberCellDataParser(),
|
||||||
reloadOnFieldChanged: true,
|
reloadOnFieldChanged: true,
|
||||||
);
|
);
|
||||||
return NumberCellController(
|
return NumberCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
TextCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
case FieldType.RichText:
|
case FieldType.RichText:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: StringCellDataParser(),
|
parser: StringCellDataParser(),
|
||||||
);
|
);
|
||||||
return TextCellController(
|
return TextCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
TextCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
case FieldType.SingleSelect:
|
case FieldType.SingleSelect:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: SelectOptionCellDataParser(),
|
parser: SelectOptionCellDataParser(),
|
||||||
reloadOnFieldChanged: true,
|
reloadOnFieldChanged: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return SelectOptionCellController(
|
return SelectOptionCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
TextCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
|
|
||||||
case FieldType.Checklist:
|
case FieldType.Checklist:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: ChecklistCellDataParser(),
|
parser: ChecklistCellDataParser(),
|
||||||
reloadOnFieldChanged: true,
|
reloadOnFieldChanged: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return ChecklistCellController(
|
return ChecklistCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
TextCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
parser: URLCellDataParser(),
|
parser: URLCellDataParser(),
|
||||||
);
|
);
|
||||||
return URLCellController(
|
return URLCellController(
|
||||||
cellId: _cellId,
|
cellContext: _cellContext,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: cellDataLoader,
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence:
|
||||||
|
TextCellDataPersistence(cellContext: _cellContext),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
throw UnimplementedError;
|
throw UnimplementedError;
|
||||||
|
@ -11,18 +11,18 @@ abstract class CellDataParser<T> {
|
|||||||
|
|
||||||
class CellDataLoader<T> {
|
class CellDataLoader<T> {
|
||||||
final CellBackendService service = CellBackendService();
|
final CellBackendService service = CellBackendService();
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
final CellDataParser<T> parser;
|
final CellDataParser<T> parser;
|
||||||
final bool reloadOnFieldChanged;
|
final bool reloadOnFieldChanged;
|
||||||
|
|
||||||
CellDataLoader({
|
CellDataLoader({
|
||||||
required this.cellId,
|
required this.cellContext,
|
||||||
required this.parser,
|
required this.parser,
|
||||||
this.reloadOnFieldChanged = false,
|
this.reloadOnFieldChanged = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<T?> loadData() {
|
Future<T?> loadData() {
|
||||||
final fut = service.getCell(cellId: cellId);
|
final fut = service.getCell(cellContext: cellContext);
|
||||||
return fut.then(
|
return fut.then(
|
||||||
(result) => result.fold(
|
(result) => result.fold(
|
||||||
(CellPB cell) {
|
(CellPB cell) {
|
||||||
|
@ -7,16 +7,17 @@ abstract class CellDataPersistence<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TextCellDataPersistence implements CellDataPersistence<String> {
|
class TextCellDataPersistence implements CellDataPersistence<String> {
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
final _cellBackendSvc = CellBackendService();
|
final _cellBackendSvc = CellBackendService();
|
||||||
|
|
||||||
TextCellDataPersistence({
|
TextCellDataPersistence({
|
||||||
required this.cellId,
|
required this.cellContext,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Option<FlowyError>> save(String data) async {
|
Future<Option<FlowyError>> save(String data) async {
|
||||||
final fut = _cellBackendSvc.updateCell(cellId: cellId, data: data);
|
final fut =
|
||||||
|
_cellBackendSvc.updateCell(cellContext: cellContext, data: data);
|
||||||
return fut.then((result) {
|
return fut.then((result) {
|
||||||
return result.fold(
|
return result.fold(
|
||||||
(l) => none(),
|
(l) => none(),
|
||||||
@ -36,14 +37,15 @@ class DateCellData with _$DateCellData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
DateCellDataPersistence({
|
DateCellDataPersistence({
|
||||||
required this.cellId,
|
required this.cellContext,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Option<FlowyError>> save(DateCellData data) {
|
Future<Option<FlowyError>> save(DateCellData data) {
|
||||||
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
|
var payload = DateChangesetPB.create()
|
||||||
|
..cellPath = _makeCellPath(cellContext);
|
||||||
if (data.dateTime != null) {
|
if (data.dateTime != null) {
|
||||||
final date = (data.dateTime!.millisecondsSinceEpoch ~/ 1000).toString();
|
final date = (data.dateTime!.millisecondsSinceEpoch ~/ 1000).toString();
|
||||||
payload.date = date;
|
payload.date = date;
|
||||||
@ -62,7 +64,7 @@ class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CellIdPB _makeCellPath(CellIdentifier cellId) {
|
CellIdPB _makeCellPath(DatabaseCellContext cellId) {
|
||||||
return CellIdPB.create()
|
return CellIdPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellId.viewId
|
||||||
..fieldId = cellId.fieldId
|
..fieldId = cellId.fieldId
|
||||||
|
@ -25,40 +25,39 @@ class CellBackendService {
|
|||||||
CellBackendService();
|
CellBackendService();
|
||||||
|
|
||||||
Future<Either<void, FlowyError>> updateCell({
|
Future<Either<void, FlowyError>> updateCell({
|
||||||
required CellIdentifier cellId,
|
required DatabaseCellContext cellContext,
|
||||||
required String data,
|
required String data,
|
||||||
}) {
|
}) {
|
||||||
final payload = CellChangesetPB.create()
|
final payload = CellChangesetPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..fieldId = cellId.fieldId
|
..fieldId = cellContext.fieldId
|
||||||
..rowId = cellId.rowId
|
..rowId = cellContext.rowId
|
||||||
..cellChangeset = data;
|
..cellChangeset = data;
|
||||||
return DatabaseEventUpdateCell(payload).send();
|
return DatabaseEventUpdateCell(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<CellPB, FlowyError>> getCell({
|
Future<Either<CellPB, FlowyError>> getCell({
|
||||||
required CellIdentifier cellId,
|
required DatabaseCellContext cellContext,
|
||||||
}) {
|
}) {
|
||||||
final payload = CellIdPB.create()
|
final payload = CellIdPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..fieldId = cellId.fieldId
|
..fieldId = cellContext.fieldId
|
||||||
..rowId = cellId.rowId;
|
..rowId = cellContext.rowId;
|
||||||
return DatabaseEventGetCell(payload).send();
|
return DatabaseEventGetCell(payload).send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Id of the cell
|
|
||||||
/// We can locate the cell by using database + rowId + field.id.
|
/// We can locate the cell by using database + rowId + field.id.
|
||||||
@freezed
|
@freezed
|
||||||
class CellIdentifier with _$CellIdentifier {
|
class DatabaseCellContext with _$DatabaseCellContext {
|
||||||
const factory CellIdentifier({
|
const factory DatabaseCellContext({
|
||||||
required String viewId,
|
required String viewId,
|
||||||
required RowId rowId,
|
required RowId rowId,
|
||||||
required FieldInfo fieldInfo,
|
required FieldInfo fieldInfo,
|
||||||
}) = _CellIdentifier;
|
}) = _DatabaseCellContext;
|
||||||
|
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
const CellIdentifier._();
|
const DatabaseCellContext._();
|
||||||
|
|
||||||
String get fieldId => fieldInfo.id;
|
String get fieldId => fieldInfo.id;
|
||||||
|
|
||||||
|
@ -7,17 +7,17 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
|||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
|
|
||||||
class ChecklistCellBackendService {
|
class ChecklistCellBackendService {
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
|
|
||||||
ChecklistCellBackendService({required this.cellId});
|
ChecklistCellBackendService({required this.cellContext});
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> create({
|
Future<Either<Unit, FlowyError>> create({
|
||||||
required String name,
|
required String name,
|
||||||
}) {
|
}) {
|
||||||
final payload = ChecklistCellDataChangesetPB.create()
|
final payload = ChecklistCellDataChangesetPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..fieldId = cellId.fieldInfo.id
|
..fieldId = cellContext.fieldInfo.id
|
||||||
..rowId = cellId.rowId
|
..rowId = cellContext.rowId
|
||||||
..insertOptions.add(name);
|
..insertOptions.add(name);
|
||||||
|
|
||||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||||
@ -27,9 +27,9 @@ class ChecklistCellBackendService {
|
|||||||
required List<String> optionIds,
|
required List<String> optionIds,
|
||||||
}) {
|
}) {
|
||||||
final payload = ChecklistCellDataChangesetPB.create()
|
final payload = ChecklistCellDataChangesetPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..fieldId = cellId.fieldInfo.id
|
..fieldId = cellContext.fieldInfo.id
|
||||||
..rowId = cellId.rowId
|
..rowId = cellContext.rowId
|
||||||
..deleteOptionIds.addAll(optionIds);
|
..deleteOptionIds.addAll(optionIds);
|
||||||
|
|
||||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||||
@ -39,9 +39,9 @@ class ChecklistCellBackendService {
|
|||||||
required String optionId,
|
required String optionId,
|
||||||
}) {
|
}) {
|
||||||
final payload = ChecklistCellDataChangesetPB.create()
|
final payload = ChecklistCellDataChangesetPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..fieldId = cellId.fieldInfo.id
|
..fieldId = cellContext.fieldInfo.id
|
||||||
..rowId = cellId.rowId
|
..rowId = cellContext.rowId
|
||||||
..selectedOptionIds.add(optionId);
|
..selectedOptionIds.add(optionId);
|
||||||
|
|
||||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||||
@ -51,9 +51,9 @@ class ChecklistCellBackendService {
|
|||||||
required SelectOptionPB option,
|
required SelectOptionPB option,
|
||||||
}) {
|
}) {
|
||||||
final payload = ChecklistCellDataChangesetPB.create()
|
final payload = ChecklistCellDataChangesetPB.create()
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..fieldId = cellId.fieldInfo.id
|
..fieldId = cellContext.fieldInfo.id
|
||||||
..rowId = cellId.rowId
|
..rowId = cellContext.rowId
|
||||||
..updateOptions.add(option);
|
..updateOptions.add(option);
|
||||||
|
|
||||||
return DatabaseEventUpdateChecklistCell(payload).send();
|
return DatabaseEventUpdateChecklistCell(payload).send();
|
||||||
@ -61,10 +61,10 @@ class ChecklistCellBackendService {
|
|||||||
|
|
||||||
Future<Either<ChecklistCellDataPB, FlowyError>> getCellData() {
|
Future<Either<ChecklistCellDataPB, FlowyError>> getCellData() {
|
||||||
final payload = CellIdPB.create()
|
final payload = CellIdPB.create()
|
||||||
..fieldId = cellId.fieldInfo.id
|
..fieldId = cellContext.fieldInfo.id
|
||||||
..viewId = cellId.viewId
|
..viewId = cellContext.viewId
|
||||||
..rowId = cellId.rowId
|
..rowId = cellContext.rowId
|
||||||
..rowId = cellId.rowId;
|
..rowId = cellContext.rowId;
|
||||||
|
|
||||||
return DatabaseEventGetChecklistCellData(payload).send();
|
return DatabaseEventGetChecklistCellData(payload).send();
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
|||||||
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
|
||||||
|
|
||||||
class SelectOptionCellBackendService {
|
class SelectOptionCellBackendService {
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
SelectOptionCellBackendService({required this.cellId});
|
SelectOptionCellBackendService({required this.cellContext});
|
||||||
|
|
||||||
String get viewId => cellId.viewId;
|
String get viewId => cellContext.viewId;
|
||||||
String get fieldId => cellId.fieldInfo.id;
|
String get fieldId => cellContext.fieldInfo.id;
|
||||||
RowId get rowId => cellId.rowId;
|
RowId get rowId => cellContext.rowId;
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> create({
|
Future<Either<Unit, FlowyError>> create({
|
||||||
required String name,
|
required String name,
|
||||||
|
@ -10,7 +10,7 @@ class FieldActionSheetBloc
|
|||||||
extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
|
extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
|
||||||
final FieldBackendService fieldService;
|
final FieldBackendService fieldService;
|
||||||
|
|
||||||
FieldActionSheetBloc({required FieldCellContext fieldCellContext})
|
FieldActionSheetBloc({required FieldContext fieldCellContext})
|
||||||
: fieldService = FieldBackendService(
|
: fieldService = FieldBackendService(
|
||||||
viewId: fieldCellContext.viewId,
|
viewId: fieldCellContext.viewId,
|
||||||
fieldId: fieldCellContext.field.id,
|
fieldId: fieldCellContext.field.id,
|
||||||
|
@ -14,7 +14,7 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
|||||||
final FieldBackendService _fieldBackendSvc;
|
final FieldBackendService _fieldBackendSvc;
|
||||||
|
|
||||||
FieldCellBloc({
|
FieldCellBloc({
|
||||||
required FieldCellContext cellContext,
|
required FieldContext cellContext,
|
||||||
}) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
|
}) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
|
||||||
_fieldBackendSvc = FieldBackendService(
|
_fieldBackendSvc = FieldBackendService(
|
||||||
viewId: cellContext.viewId,
|
viewId: cellContext.viewId,
|
||||||
@ -83,8 +83,7 @@ class FieldCellState with _$FieldCellState {
|
|||||||
required double width,
|
required double width,
|
||||||
}) = _FieldCellState;
|
}) = _FieldCellState;
|
||||||
|
|
||||||
factory FieldCellState.initial(FieldCellContext cellContext) =>
|
factory FieldCellState.initial(FieldContext cellContext) => FieldCellState(
|
||||||
FieldCellState(
|
|
||||||
viewId: cellContext.viewId,
|
viewId: cellContext.viewId,
|
||||||
field: cellContext.field,
|
field: cellContext.field,
|
||||||
width: cellContext.field.width.toDouble(),
|
width: cellContext.field.width.toDouble(),
|
||||||
|
@ -12,12 +12,20 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
final TypeOptionController dataController;
|
final TypeOptionController dataController;
|
||||||
|
|
||||||
FieldEditorBloc({
|
FieldEditorBloc({
|
||||||
required String viewId,
|
|
||||||
required String fieldName,
|
|
||||||
required bool isGroupField,
|
required bool isGroupField,
|
||||||
required ITypeOptionLoader loader,
|
required FieldPB field,
|
||||||
}) : dataController = TypeOptionController(viewId: viewId, loader: loader),
|
required FieldTypeOptionLoader loader,
|
||||||
super(FieldEditorState.initial(viewId, fieldName, isGroupField)) {
|
}) : dataController = TypeOptionController(
|
||||||
|
field: field,
|
||||||
|
loader: loader,
|
||||||
|
),
|
||||||
|
super(
|
||||||
|
FieldEditorState.initial(
|
||||||
|
loader.viewId,
|
||||||
|
loader.field.name,
|
||||||
|
isGroupField,
|
||||||
|
),
|
||||||
|
) {
|
||||||
on<FieldEditorEvent>(
|
on<FieldEditorEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.when(
|
await event.when(
|
||||||
@ -27,7 +35,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
add(FieldEditorEvent.didReceiveFieldChanged(field));
|
add(FieldEditorEvent.didReceiveFieldChanged(field));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await dataController.loadTypeOptionData();
|
await dataController.reloadTypeOption();
|
||||||
add(FieldEditorEvent.didReceiveFieldChanged(dataController.field));
|
add(FieldEditorEvent.didReceiveFieldChanged(dataController.field));
|
||||||
},
|
},
|
||||||
updateName: (name) {
|
updateName: (name) {
|
||||||
@ -50,7 +58,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
() => null,
|
() => null,
|
||||||
(field) {
|
(field) {
|
||||||
final fieldService = FieldBackendService(
|
final fieldService = FieldBackendService(
|
||||||
viewId: viewId,
|
viewId: loader.viewId,
|
||||||
fieldId: field.id,
|
fieldId: field.id,
|
||||||
);
|
);
|
||||||
fieldService.deleteField();
|
fieldService.deleteField();
|
||||||
|
@ -107,8 +107,8 @@ class FieldBackendService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class FieldCellContext with _$FieldCellContext {
|
class FieldContext with _$FieldContext {
|
||||||
const factory FieldCellContext({
|
const factory FieldContext({
|
||||||
required String viewId,
|
required String viewId,
|
||||||
required FieldPB field,
|
required FieldPB field,
|
||||||
}) = _FieldCellContext;
|
}) = _FieldCellContext;
|
||||||
|
@ -113,7 +113,7 @@ class TypeOptionContext<T extends GeneratedMessage> {
|
|||||||
required TypeOptionController dataController,
|
required TypeOptionController dataController,
|
||||||
}) : _dataController = dataController;
|
}) : _dataController = dataController;
|
||||||
|
|
||||||
String get viewId => _dataController.viewId;
|
String get viewId => _dataController.loader.viewId;
|
||||||
|
|
||||||
String get fieldId => _dataController.field.id;
|
String get fieldId => _dataController.field.id;
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ class TypeOptionContext<T extends GeneratedMessage> {
|
|||||||
void Function(T)? onCompleted,
|
void Function(T)? onCompleted,
|
||||||
required void Function(FlowyError) onError,
|
required void Function(FlowyError) onError,
|
||||||
}) async {
|
}) async {
|
||||||
await _dataController.loadTypeOptionData().then((result) {
|
await _dataController.reloadTypeOption().then((result) {
|
||||||
result.fold((l) => null, (err) => onError(err));
|
result.fold((l) => null, (err) => onError(err));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,54 +153,12 @@ abstract class TypeOptionFieldDelegate {
|
|||||||
abstract class ITypeOptionLoader {
|
abstract class ITypeOptionLoader {
|
||||||
String get viewId;
|
String get viewId;
|
||||||
String get fieldName;
|
String get fieldName;
|
||||||
|
|
||||||
Future<Either<TypeOptionPB, FlowyError>> initialize();
|
Future<Either<TypeOptionPB, FlowyError>> initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses when creating a new field
|
|
||||||
class NewFieldTypeOptionLoader extends ITypeOptionLoader {
|
|
||||||
TypeOptionPB? fieldTypeOption;
|
|
||||||
|
|
||||||
@override
|
|
||||||
final String viewId;
|
|
||||||
NewFieldTypeOptionLoader({
|
|
||||||
required this.viewId,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Creates the field type option if the fieldTypeOption is null.
|
|
||||||
/// Otherwise, it loads the type option data from the backend.
|
|
||||||
@override
|
|
||||||
Future<Either<TypeOptionPB, FlowyError>> initialize() {
|
|
||||||
if (fieldTypeOption != null) {
|
|
||||||
final payload = TypeOptionPathPB.create()
|
|
||||||
..viewId = viewId
|
|
||||||
..fieldId = fieldTypeOption!.field_2.id
|
|
||||||
..fieldType = fieldTypeOption!.field_2.fieldType;
|
|
||||||
|
|
||||||
return DatabaseEventGetTypeOption(payload).send();
|
|
||||||
} else {
|
|
||||||
final payload = CreateFieldPayloadPB.create()
|
|
||||||
..viewId = viewId
|
|
||||||
..fieldType = FieldType.RichText;
|
|
||||||
|
|
||||||
return DatabaseEventCreateTypeOption(payload).send().then((result) {
|
|
||||||
return result.fold(
|
|
||||||
(newFieldTypeOption) {
|
|
||||||
fieldTypeOption = newFieldTypeOption;
|
|
||||||
return left(newFieldTypeOption);
|
|
||||||
},
|
|
||||||
(err) => right(err),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fieldName => fieldTypeOption?.field_2.name ?? '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Uses when editing a existing field
|
/// Uses when editing a existing field
|
||||||
class FieldTypeOptionLoader extends ITypeOptionLoader {
|
class FieldTypeOptionLoader {
|
||||||
@override
|
|
||||||
final String viewId;
|
final String viewId;
|
||||||
final FieldPB field;
|
final FieldPB field;
|
||||||
|
|
||||||
@ -209,8 +167,7 @@ class FieldTypeOptionLoader extends ITypeOptionLoader {
|
|||||||
required this.field,
|
required this.field,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
Future<Either<TypeOptionPB, FlowyError>> load() {
|
||||||
Future<Either<TypeOptionPB, FlowyError>> initialize() {
|
|
||||||
final payload = TypeOptionPathPB.create()
|
final payload = TypeOptionPathPB.create()
|
||||||
..viewId = viewId
|
..viewId = viewId
|
||||||
..fieldId = field.id
|
..fieldId = field.id
|
||||||
@ -218,7 +175,4 @@ class FieldTypeOptionLoader extends ITypeOptionLoader {
|
|||||||
|
|
||||||
return DatabaseEventGetTypeOption(payload).send();
|
return DatabaseEventGetTypeOption(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
String get fieldName => field.name;
|
|
||||||
}
|
}
|
||||||
|
@ -11,31 +11,27 @@ import '../field_service.dart';
|
|||||||
import 'type_option_context.dart';
|
import 'type_option_context.dart';
|
||||||
|
|
||||||
class TypeOptionController {
|
class TypeOptionController {
|
||||||
final String viewId;
|
|
||||||
late TypeOptionPB _typeOption;
|
late TypeOptionPB _typeOption;
|
||||||
final ITypeOptionLoader loader;
|
final FieldTypeOptionLoader loader;
|
||||||
final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
|
final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
|
||||||
|
|
||||||
/// Returns a [TypeOptionController] used to modify the specified
|
/// Returns a [TypeOptionController] used to modify the specified
|
||||||
/// [FieldPB]'s data
|
/// [FieldPB]'s data
|
||||||
///
|
///
|
||||||
/// Should call [loadTypeOptionData] if the passed-in [FieldInfo]
|
/// Should call [reloadTypeOption] if the passed-in [FieldInfo]
|
||||||
/// is null
|
/// is null
|
||||||
///
|
///
|
||||||
TypeOptionController({
|
TypeOptionController({
|
||||||
required this.viewId,
|
|
||||||
required this.loader,
|
required this.loader,
|
||||||
FieldInfo? fieldInfo,
|
required FieldPB field,
|
||||||
}) {
|
}) {
|
||||||
if (fieldInfo != null) {
|
_typeOption = TypeOptionPB.create()
|
||||||
_typeOption = TypeOptionPB.create()
|
..viewId = loader.viewId
|
||||||
..viewId = viewId
|
..field_2 = field;
|
||||||
..field_2 = fieldInfo.field;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<TypeOptionPB, FlowyError>> loadTypeOptionData() async {
|
Future<Either<TypeOptionPB, FlowyError>> reloadTypeOption() async {
|
||||||
final result = await loader.initialize();
|
final result = await loader.load();
|
||||||
return result.fold(
|
return result.fold(
|
||||||
(data) {
|
(data) {
|
||||||
data.freeze();
|
data.freeze();
|
||||||
@ -67,7 +63,7 @@ class TypeOptionController {
|
|||||||
|
|
||||||
_fieldNotifier.value = _typeOption.field_2;
|
_fieldNotifier.value = _typeOption.field_2;
|
||||||
|
|
||||||
FieldBackendService(viewId: viewId, fieldId: field.id)
|
FieldBackendService(viewId: loader.viewId, fieldId: field.id)
|
||||||
.updateField(name: name);
|
.updateField(name: name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +75,7 @@ class TypeOptionController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
FieldBackendService.updateFieldTypeOption(
|
FieldBackendService.updateFieldTypeOption(
|
||||||
viewId: viewId,
|
viewId: loader.viewId,
|
||||||
fieldId: field.id,
|
fieldId: field.id,
|
||||||
typeOptionData: typeOptionData,
|
typeOptionData: typeOptionData,
|
||||||
);
|
);
|
||||||
@ -87,7 +83,7 @@ class TypeOptionController {
|
|||||||
|
|
||||||
Future<void> switchToField(FieldType newFieldType) async {
|
Future<void> switchToField(FieldType newFieldType) async {
|
||||||
final payload = UpdateFieldTypePayloadPB.create()
|
final payload = UpdateFieldTypePayloadPB.create()
|
||||||
..viewId = viewId
|
..viewId = loader.viewId
|
||||||
..fieldId = field.id
|
..fieldId = field.id
|
||||||
..fieldType = newFieldType;
|
..fieldType = newFieldType;
|
||||||
|
|
||||||
@ -97,7 +93,7 @@ class TypeOptionController {
|
|||||||
// Should load the type-option data after switching to a new field.
|
// Should load the type-option data after switching to a new field.
|
||||||
// After loading the type-option data, the editor widget that uses
|
// After loading the type-option data, the editor widget that uses
|
||||||
// the type-option data will be rebuild.
|
// the type-option data will be rebuild.
|
||||||
loadTypeOptionData();
|
reloadTypeOption();
|
||||||
},
|
},
|
||||||
(err) => Future(() => Log.error(err)),
|
(err) => Future(() => Log.error(err)),
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/cell_entities.pb.dart';
|
|
||||||
|
|
||||||
class TypeOptionBackendService {
|
class TypeOptionBackendService {
|
||||||
final String viewId;
|
final String viewId;
|
||||||
@ -23,4 +22,15 @@ class TypeOptionBackendService {
|
|||||||
|
|
||||||
return DatabaseEventCreateSelectOption(payload).send();
|
return DatabaseEventCreateSelectOption(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<Either<TypeOptionPB, FlowyError>> createFieldTypeOption({
|
||||||
|
required String viewId,
|
||||||
|
FieldType fieldType = FieldType.RichText,
|
||||||
|
}) {
|
||||||
|
final payload = CreateFieldPayloadPB.create()
|
||||||
|
..viewId = viewId
|
||||||
|
..fieldType = FieldType.RichText;
|
||||||
|
|
||||||
|
return DatabaseEventCreateTypeOption(payload).send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ class RowCache {
|
|||||||
|
|
||||||
RowUpdateCallback addListener({
|
RowUpdateCallback addListener({
|
||||||
required RowId rowId,
|
required RowId rowId,
|
||||||
void Function(CellByFieldId, RowsChangedReason)? onCellUpdated,
|
void Function(CellContextByFieldId, RowsChangedReason)? onCellUpdated,
|
||||||
bool Function()? listenWhen,
|
bool Function()? listenWhen,
|
||||||
}) {
|
}) {
|
||||||
listenerHandler() async {
|
listenerHandler() async {
|
||||||
@ -197,7 +197,7 @@ class RowCache {
|
|||||||
if (onCellUpdated != null) {
|
if (onCellUpdated != null) {
|
||||||
final rowInfo = _rowList.get(rowId);
|
final rowInfo = _rowList.get(rowId);
|
||||||
if (rowInfo != null) {
|
if (rowInfo != null) {
|
||||||
final CellByFieldId cellDataMap =
|
final CellContextByFieldId cellDataMap =
|
||||||
_makeGridCells(rowId, rowInfo.rowPB);
|
_makeGridCells(rowId, rowInfo.rowPB);
|
||||||
onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason);
|
onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason);
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ class RowCache {
|
|||||||
_rowChangeReasonNotifier.removeListener(callback);
|
_rowChangeReasonNotifier.removeListener(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
CellByFieldId loadGridCells(RowId rowId) {
|
CellContextByFieldId loadGridCells(RowId rowId) {
|
||||||
final RowPB? data = _rowList.get(rowId)?.rowPB;
|
final RowPB? data = _rowList.get(rowId)?.rowPB;
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
_loadRow(rowId);
|
_loadRow(rowId);
|
||||||
@ -240,12 +240,12 @@ class RowCache {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CellByFieldId _makeGridCells(RowId rowId, RowPB? row) {
|
CellContextByFieldId _makeGridCells(RowId rowId, RowPB? row) {
|
||||||
// ignore: prefer_collection_literals
|
// ignore: prefer_collection_literals
|
||||||
var cellDataMap = CellByFieldId();
|
var cellDataMap = CellContextByFieldId();
|
||||||
for (final field in _delegate.fields) {
|
for (final field in _delegate.fields) {
|
||||||
if (field.visibility) {
|
if (field.visibility) {
|
||||||
cellDataMap[field.id] = CellIdentifier(
|
cellDataMap[field.id] = DatabaseCellContext(
|
||||||
rowId: rowId,
|
rowId: rowId,
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
fieldInfo: field,
|
fieldInfo: field,
|
||||||
|
@ -3,7 +3,7 @@ import '../cell/cell_service.dart';
|
|||||||
import 'row_cache.dart';
|
import 'row_cache.dart';
|
||||||
import 'row_service.dart';
|
import 'row_service.dart';
|
||||||
|
|
||||||
typedef OnRowChanged = void Function(CellByFieldId, RowsChangedReason);
|
typedef OnRowChanged = void Function(CellContextByFieldId, RowsChangedReason);
|
||||||
|
|
||||||
class RowController {
|
class RowController {
|
||||||
final RowId rowId;
|
final RowId rowId;
|
||||||
@ -21,7 +21,7 @@ class RowController {
|
|||||||
this.groupId,
|
this.groupId,
|
||||||
}) : _rowCache = rowCache;
|
}) : _rowCache = rowCache;
|
||||||
|
|
||||||
CellByFieldId loadData() {
|
CellContextByFieldId loadData() {
|
||||||
return _rowCache.loadGridCells(rowId);
|
return _rowCache.loadGridCells(rowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class RowEvent with _$RowEvent {
|
|||||||
const factory RowEvent.initial() = _InitialRow;
|
const factory RowEvent.initial() = _InitialRow;
|
||||||
const factory RowEvent.createRow() = _CreateRow;
|
const factory RowEvent.createRow() = _CreateRow;
|
||||||
const factory RowEvent.didReceiveCells(
|
const factory RowEvent.didReceiveCells(
|
||||||
CellByFieldId cellsByFieldId,
|
CellContextByFieldId cellsByFieldId,
|
||||||
RowsChangedReason reason,
|
RowsChangedReason reason,
|
||||||
) = _DidReceiveCells;
|
) = _DidReceiveCells;
|
||||||
}
|
}
|
||||||
@ -79,12 +79,15 @@ class RowEvent with _$RowEvent {
|
|||||||
class RowState with _$RowState {
|
class RowState with _$RowState {
|
||||||
const factory RowState({
|
const factory RowState({
|
||||||
required RowInfo rowInfo,
|
required RowInfo rowInfo,
|
||||||
required CellByFieldId cellByFieldId,
|
required CellContextByFieldId cellByFieldId,
|
||||||
required UnmodifiableListView<GridCellEquatable> cells,
|
required UnmodifiableListView<GridCellEquatable> cells,
|
||||||
RowsChangedReason? changeReason,
|
RowsChangedReason? changeReason,
|
||||||
}) = _RowState;
|
}) = _RowState;
|
||||||
|
|
||||||
factory RowState.initial(RowInfo rowInfo, CellByFieldId cellByFieldId) =>
|
factory RowState.initial(
|
||||||
|
RowInfo rowInfo,
|
||||||
|
CellContextByFieldId cellByFieldId,
|
||||||
|
) =>
|
||||||
RowState(
|
RowState(
|
||||||
rowInfo: rowInfo,
|
rowInfo: rowInfo,
|
||||||
cellByFieldId: cellByFieldId,
|
cellByFieldId: cellByFieldId,
|
||||||
|
@ -88,14 +88,14 @@ class RowDetailEvent with _$RowDetailEvent {
|
|||||||
const factory RowDetailEvent.duplicateRow(String rowId, String? groupId) =
|
const factory RowDetailEvent.duplicateRow(String rowId, String? groupId) =
|
||||||
_DuplicateRow;
|
_DuplicateRow;
|
||||||
const factory RowDetailEvent.didReceiveCellDatas(
|
const factory RowDetailEvent.didReceiveCellDatas(
|
||||||
List<CellIdentifier> gridCells,
|
List<DatabaseCellContext> gridCells,
|
||||||
) = _DidReceiveCellDatas;
|
) = _DidReceiveCellDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class RowDetailState with _$RowDetailState {
|
class RowDetailState with _$RowDetailState {
|
||||||
const factory RowDetailState({
|
const factory RowDetailState({
|
||||||
required List<CellIdentifier> gridCells,
|
required List<DatabaseCellContext> gridCells,
|
||||||
}) = _RowDetailState;
|
}) = _RowDetailState;
|
||||||
|
|
||||||
factory RowDetailState.initial() => RowDetailState(
|
factory RowDetailState.initial() => RowDetailState(
|
||||||
|
@ -14,7 +14,7 @@ import 'field_cell_action_sheet.dart';
|
|||||||
import 'field_type_extension.dart';
|
import 'field_type_extension.dart';
|
||||||
|
|
||||||
class GridFieldCell extends StatefulWidget {
|
class GridFieldCell extends StatefulWidget {
|
||||||
final FieldCellContext cellContext;
|
final FieldContext cellContext;
|
||||||
const GridFieldCell({
|
const GridFieldCell({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.cellContext,
|
required this.cellContext,
|
||||||
|
@ -19,7 +19,7 @@ import '../../layout/sizes.dart';
|
|||||||
import 'field_editor.dart';
|
import 'field_editor.dart';
|
||||||
|
|
||||||
class GridFieldCellActionSheet extends StatefulWidget {
|
class GridFieldCellActionSheet extends StatefulWidget {
|
||||||
final FieldCellContext cellContext;
|
final FieldContext cellContext;
|
||||||
const GridFieldCellActionSheet({required this.cellContext, Key? key})
|
const GridFieldCellActionSheet({required this.cellContext, Key? key})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ class _GridFieldCellActionSheetState extends State<GridFieldCellActionSheet> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _EditFieldButton extends StatelessWidget {
|
class _EditFieldButton extends StatelessWidget {
|
||||||
final FieldCellContext cellContext;
|
final FieldContext cellContext;
|
||||||
final void Function()? onTap;
|
final void Function()? onTap;
|
||||||
const _EditFieldButton({required this.cellContext, Key? key, this.onTap})
|
const _EditFieldButton({required this.cellContext, Key? key, this.onTap})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
@ -95,7 +95,7 @@ class _EditFieldButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _FieldOperationList extends StatelessWidget {
|
class _FieldOperationList extends StatelessWidget {
|
||||||
final FieldCellContext fieldInfo;
|
final FieldContext fieldInfo;
|
||||||
const _FieldOperationList(this.fieldInfo, {Key? key}) : super(key: key);
|
const _FieldOperationList(this.fieldInfo, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -138,7 +138,7 @@ class _FieldOperationList extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FieldActionCell extends StatelessWidget {
|
class FieldActionCell extends StatelessWidget {
|
||||||
final FieldCellContext fieldInfo;
|
final FieldContext fieldInfo;
|
||||||
final FieldAction action;
|
final FieldAction action;
|
||||||
final bool enable;
|
final bool enable;
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ extension _FieldActionExtension on FieldAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(BuildContext context, FieldCellContext fieldInfo) {
|
void run(BuildContext context, FieldContext fieldInfo) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case FieldAction.hide:
|
case FieldAction.hide:
|
||||||
context
|
context
|
||||||
|
@ -19,7 +19,7 @@ class FieldEditor extends StatefulWidget {
|
|||||||
final bool isGroupingField;
|
final bool isGroupingField;
|
||||||
final Function(String)? onDeleted;
|
final Function(String)? onDeleted;
|
||||||
final Function(String)? onHidden;
|
final Function(String)? onHidden;
|
||||||
final ITypeOptionLoader typeOptionLoader;
|
final FieldTypeOptionLoader typeOptionLoader;
|
||||||
|
|
||||||
const FieldEditor({
|
const FieldEditor({
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
@ -53,22 +53,25 @@ class _FieldEditorState extends State<FieldEditor> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
List<Widget> children = [
|
List<Widget> children = [
|
||||||
_FieldNameTextField(popoverMutex: popoverMutex),
|
_FieldNameTextField(popoverMutex: popoverMutex),
|
||||||
const VSpace(10),
|
|
||||||
if (widget.onDeleted != null) _addDeleteFieldButton(),
|
if (widget.onDeleted != null) _addDeleteFieldButton(),
|
||||||
if (widget.onHidden != null) _addHideFieldButton(),
|
if (widget.onHidden != null) _addHideFieldButton(),
|
||||||
_FieldTypeOptionCell(popoverMutex: popoverMutex),
|
if (!widget.typeOptionLoader.field.isPrimary)
|
||||||
|
_FieldTypeOptionCell(popoverMutex: popoverMutex),
|
||||||
];
|
];
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => FieldEditorBloc(
|
create: (context) {
|
||||||
viewId: widget.viewId,
|
return FieldEditorBloc(
|
||||||
fieldName: widget.typeOptionLoader.fieldName,
|
isGroupField: widget.isGroupingField,
|
||||||
isGroupField: widget.isGroupingField,
|
loader: widget.typeOptionLoader,
|
||||||
loader: widget.typeOptionLoader,
|
field: widget.typeOptionLoader.field,
|
||||||
)..add(const FieldEditorEvent.initial()),
|
)..add(const FieldEditorEvent.initial());
|
||||||
child: ListView.builder(
|
},
|
||||||
|
child: ListView.separated(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: children.length,
|
itemCount: children.length,
|
||||||
itemBuilder: (context, index) => children[index],
|
itemBuilder: (context, index) => children[index],
|
||||||
|
separatorBuilder: (context, index) =>
|
||||||
|
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -4,6 +4,7 @@ import 'package:appflowy/plugins/database_view/application/field/field_service.d
|
|||||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
||||||
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';
|
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
@ -13,6 +14,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:reorderables/reorderables.dart';
|
import 'package:reorderables/reorderables.dart';
|
||||||
|
import '../../../../application/field/type_option/type_option_service.dart';
|
||||||
import '../../layout/sizes.dart';
|
import '../../layout/sizes.dart';
|
||||||
import 'field_editor.dart';
|
import 'field_editor.dart';
|
||||||
import 'field_cell.dart';
|
import 'field_cell.dart';
|
||||||
@ -101,8 +103,10 @@ class _GridHeaderState extends State<_GridHeader> {
|
|||||||
final cells = state.fields
|
final cells = state.fields
|
||||||
.where((field) => field.visibility)
|
.where((field) => field.visibility)
|
||||||
.map(
|
.map(
|
||||||
(field) =>
|
(field) => FieldContext(
|
||||||
FieldCellContext(viewId: widget.viewId, field: field.field),
|
viewId: widget.viewId,
|
||||||
|
field: field.field,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
(ctx) => GridFieldCell(
|
(ctx) => GridFieldCell(
|
||||||
@ -177,28 +181,52 @@ class _CellTrailing extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateFieldButton extends StatelessWidget {
|
class CreateFieldButton extends StatefulWidget {
|
||||||
final String viewId;
|
final String viewId;
|
||||||
const CreateFieldButton({required this.viewId, Key? key}) : super(key: key);
|
const CreateFieldButton({required this.viewId, Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CreateFieldButton> createState() => _CreateFieldButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateFieldButtonState extends State<CreateFieldButton> {
|
||||||
|
final popoverController = PopoverController();
|
||||||
|
late TypeOptionPB typeOption;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
|
controller: popoverController,
|
||||||
direction: PopoverDirection.bottomWithRightAligned,
|
direction: PopoverDirection.bottomWithRightAligned,
|
||||||
asBarrier: true,
|
asBarrier: true,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
constraints: BoxConstraints.loose(const Size(240, 600)),
|
constraints: BoxConstraints.loose(const Size(240, 600)),
|
||||||
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
child: FlowyButton(
|
child: FlowyButton(
|
||||||
radius: BorderRadius.zero,
|
radius: BorderRadius.zero,
|
||||||
text: FlowyText.medium(LocaleKeys.grid_field_newProperty.tr()),
|
text: FlowyText.medium(LocaleKeys.grid_field_newProperty.tr()),
|
||||||
hoverColor: AFThemeExtension.of(context).greyHover,
|
hoverColor: AFThemeExtension.of(context).greyHover,
|
||||||
onTap: () {},
|
onTap: () async {
|
||||||
|
final result = await TypeOptionBackendService.createFieldTypeOption(
|
||||||
|
viewId: widget.viewId,
|
||||||
|
);
|
||||||
|
result.fold(
|
||||||
|
(l) {
|
||||||
|
typeOption = l;
|
||||||
|
popoverController.show();
|
||||||
|
},
|
||||||
|
(r) => Log.error("Failed to create field type option: $r"),
|
||||||
|
);
|
||||||
|
},
|
||||||
leftIcon: const FlowySvg(name: 'home/add'),
|
leftIcon: const FlowySvg(name: 'home/add'),
|
||||||
),
|
),
|
||||||
popupBuilder: (BuildContext popover) {
|
popupBuilder: (BuildContext popover) {
|
||||||
return FieldEditor(
|
return FieldEditor(
|
||||||
viewId: viewId,
|
viewId: widget.viewId,
|
||||||
typeOptionLoader: NewFieldTypeOptionLoader(viewId: viewId),
|
typeOptionLoader: FieldTypeOptionLoader(
|
||||||
|
viewId: widget.viewId,
|
||||||
|
field: typeOption.field_2,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -60,7 +60,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
|
|||||||
required TypeOptionController dataController,
|
required TypeOptionController dataController,
|
||||||
required PopoverMutex popoverMutex,
|
required PopoverMutex popoverMutex,
|
||||||
}) {
|
}) {
|
||||||
final viewId = dataController.viewId;
|
final viewId = dataController.loader.viewId;
|
||||||
final fieldType = dataController.field.fieldType;
|
final fieldType = dataController.field.fieldType;
|
||||||
|
|
||||||
switch (dataController.field.fieldType) {
|
switch (dataController.field.fieldType) {
|
||||||
@ -146,9 +146,8 @@ TypeOptionContext<T> makeTypeOptionContext<T extends GeneratedMessage>({
|
|||||||
}) {
|
}) {
|
||||||
final loader = FieldTypeOptionLoader(viewId: viewId, field: fieldInfo.field);
|
final loader = FieldTypeOptionLoader(viewId: viewId, field: fieldInfo.field);
|
||||||
final dataController = TypeOptionController(
|
final dataController = TypeOptionController(
|
||||||
viewId: viewId,
|
|
||||||
loader: loader,
|
loader: loader,
|
||||||
fieldInfo: fieldInfo,
|
field: fieldInfo.field,
|
||||||
);
|
);
|
||||||
return makeTypeOptionContextWithDataController(
|
return makeTypeOptionContextWithDataController(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
@ -180,8 +179,8 @@ TypeOptionContext<T> makeSelectTypeOptionContext<T extends GeneratedMessage>({
|
|||||||
field: fieldPB,
|
field: fieldPB,
|
||||||
);
|
);
|
||||||
final dataController = TypeOptionController(
|
final dataController = TypeOptionController(
|
||||||
viewId: viewId,
|
|
||||||
loader: loader,
|
loader: loader,
|
||||||
|
field: fieldPB,
|
||||||
);
|
);
|
||||||
final typeOptionContext = makeTypeOptionContextWithDataController<T>(
|
final typeOptionContext = makeTypeOptionContextWithDataController<T>(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
|
@ -255,7 +255,10 @@ class RowContent extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _makeCells(BuildContext context, CellByFieldId cellByFieldId) {
|
List<Widget> _makeCells(
|
||||||
|
BuildContext context,
|
||||||
|
CellContextByFieldId cellByFieldId,
|
||||||
|
) {
|
||||||
return cellByFieldId.values.map(
|
return cellByFieldId.values.map(
|
||||||
(cellId) {
|
(cellId) {
|
||||||
final GridCellWidget child = builder.build(cellId);
|
final GridCellWidget child = builder.build(cellId);
|
||||||
|
@ -194,7 +194,7 @@ class _RowCardState<T> extends State<RowCard<T>> {
|
|||||||
class _CardContent<CustomCardData> extends StatelessWidget {
|
class _CardContent<CustomCardData> extends StatelessWidget {
|
||||||
final CardCellBuilder<CustomCardData> cellBuilder;
|
final CardCellBuilder<CustomCardData> cellBuilder;
|
||||||
final EditableRowNotifier rowNotifier;
|
final EditableRowNotifier rowNotifier;
|
||||||
final List<CellIdentifier> cells;
|
final List<DatabaseCellContext> cells;
|
||||||
final RowCardRenderHook<CustomCardData>? renderHook;
|
final RowCardRenderHook<CustomCardData>? renderHook;
|
||||||
final CustomCardData? cardData;
|
final CustomCardData? cardData;
|
||||||
final RowCardStyleConfiguration styleConfiguration;
|
final RowCardStyleConfiguration styleConfiguration;
|
||||||
@ -233,28 +233,28 @@ class _CardContent<CustomCardData> extends StatelessWidget {
|
|||||||
|
|
||||||
List<Widget> _makeCells(
|
List<Widget> _makeCells(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
List<CellIdentifier> cells,
|
List<DatabaseCellContext> cells,
|
||||||
) {
|
) {
|
||||||
final List<Widget> children = [];
|
final List<Widget> children = [];
|
||||||
// Remove all the cell listeners.
|
// Remove all the cell listeners.
|
||||||
rowNotifier.unbind();
|
rowNotifier.unbind();
|
||||||
|
|
||||||
cells.asMap().forEach(
|
cells.asMap().forEach(
|
||||||
(int index, CellIdentifier cell) {
|
(int index, DatabaseCellContext cellContext) {
|
||||||
final isEditing = index == 0 ? rowNotifier.isEditing.value : false;
|
final isEditing = index == 0 ? rowNotifier.isEditing.value : false;
|
||||||
final cellNotifier = EditableCardNotifier(isEditing: isEditing);
|
final cellNotifier = EditableCardNotifier(isEditing: isEditing);
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
// Only use the first cell to receive user's input when click the edit
|
// Only use the first cell to receive user's input when click the edit
|
||||||
// button
|
// button
|
||||||
rowNotifier.bindCell(cell, cellNotifier);
|
rowNotifier.bindCell(cellContext, cellNotifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
final child = Padding(
|
final child = Padding(
|
||||||
key: cell.key(),
|
key: cellContext.key(),
|
||||||
padding: styleConfiguration.cellPadding,
|
padding: styleConfiguration.cellPadding,
|
||||||
child: cellBuilder.buildCell(
|
child: cellBuilder.buildCell(
|
||||||
cellId: cell,
|
cellContext: cellContext,
|
||||||
cellNotifier: cellNotifier,
|
cellNotifier: cellNotifier,
|
||||||
renderHook: renderHook,
|
renderHook: renderHook,
|
||||||
cardData: cardData,
|
cardData: cardData,
|
||||||
|
@ -87,11 +87,11 @@ class CardBloc extends Bloc<RowCardEvent, RowCardState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CellIdentifier> _makeCells(
|
List<DatabaseCellContext> _makeCells(
|
||||||
String? groupFieldId,
|
String? groupFieldId,
|
||||||
CellByFieldId originalCellMap,
|
CellContextByFieldId originalCellMap,
|
||||||
) {
|
) {
|
||||||
List<CellIdentifier> cells = [];
|
List<DatabaseCellContext> cells = [];
|
||||||
for (final entry in originalCellMap.entries) {
|
for (final entry in originalCellMap.entries) {
|
||||||
// Filter out the cell if it's fieldId equal to the groupFieldId
|
// Filter out the cell if it's fieldId equal to the groupFieldId
|
||||||
if (groupFieldId != null) {
|
if (groupFieldId != null) {
|
||||||
@ -110,7 +110,7 @@ class RowCardEvent with _$RowCardEvent {
|
|||||||
const factory RowCardEvent.initial() = _InitialRow;
|
const factory RowCardEvent.initial() = _InitialRow;
|
||||||
const factory RowCardEvent.setIsEditing(bool isEditing) = _IsEditing;
|
const factory RowCardEvent.setIsEditing(bool isEditing) = _IsEditing;
|
||||||
const factory RowCardEvent.didReceiveCells(
|
const factory RowCardEvent.didReceiveCells(
|
||||||
List<CellIdentifier> cells,
|
List<DatabaseCellContext> cells,
|
||||||
RowsChangedReason reason,
|
RowsChangedReason reason,
|
||||||
) = _DidReceiveCells;
|
) = _DidReceiveCells;
|
||||||
}
|
}
|
||||||
@ -119,14 +119,14 @@ class RowCardEvent with _$RowCardEvent {
|
|||||||
class RowCardState with _$RowCardState {
|
class RowCardState with _$RowCardState {
|
||||||
const factory RowCardState({
|
const factory RowCardState({
|
||||||
required RowPB rowPB,
|
required RowPB rowPB,
|
||||||
required List<CellIdentifier> cells,
|
required List<DatabaseCellContext> cells,
|
||||||
required bool isEditing,
|
required bool isEditing,
|
||||||
RowsChangedReason? changeReason,
|
RowsChangedReason? changeReason,
|
||||||
}) = _RowCardState;
|
}) = _RowCardState;
|
||||||
|
|
||||||
factory RowCardState.initial(
|
factory RowCardState.initial(
|
||||||
RowPB rowPB,
|
RowPB rowPB,
|
||||||
List<CellIdentifier> cells,
|
List<DatabaseCellContext> cells,
|
||||||
bool isEditing,
|
bool isEditing,
|
||||||
) =>
|
) =>
|
||||||
RowCardState(
|
RowCardState(
|
||||||
|
@ -21,18 +21,18 @@ class CardCellBuilder<CustomCardData> {
|
|||||||
|
|
||||||
Widget buildCell({
|
Widget buildCell({
|
||||||
CustomCardData? cardData,
|
CustomCardData? cardData,
|
||||||
required CellIdentifier cellId,
|
required DatabaseCellContext cellContext,
|
||||||
EditableCardNotifier? cellNotifier,
|
EditableCardNotifier? cellNotifier,
|
||||||
RowCardRenderHook<CustomCardData>? renderHook,
|
RowCardRenderHook<CustomCardData>? renderHook,
|
||||||
}) {
|
}) {
|
||||||
final cellControllerBuilder = CellControllerBuilder(
|
final cellControllerBuilder = CellControllerBuilder(
|
||||||
cellId: cellId,
|
cellContext: cellContext,
|
||||||
cellCache: cellCache,
|
cellCache: cellCache,
|
||||||
);
|
);
|
||||||
|
|
||||||
final key = cellId.key();
|
final key = cellContext.key();
|
||||||
final style = styles?[cellId.fieldType];
|
final style = styles?[cellContext.fieldType];
|
||||||
switch (cellId.fieldType) {
|
switch (cellContext.fieldType) {
|
||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
return CheckboxCardCell(
|
return CheckboxCardCell(
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
|
@ -106,7 +106,7 @@ class EditableRowNotifier {
|
|||||||
: isEditing = ValueNotifier(isEditing);
|
: isEditing = ValueNotifier(isEditing);
|
||||||
|
|
||||||
void bindCell(
|
void bindCell(
|
||||||
CellIdentifier cellIdentifier,
|
DatabaseCellContext cellIdentifier,
|
||||||
EditableCardNotifier notifier,
|
EditableCardNotifier notifier,
|
||||||
) {
|
) {
|
||||||
assert(
|
assert(
|
||||||
@ -171,7 +171,8 @@ class EditableCellId {
|
|||||||
|
|
||||||
EditableCellId(this.rowId, this.fieldId);
|
EditableCellId(this.rowId, this.fieldId);
|
||||||
|
|
||||||
factory EditableCellId.from(CellIdentifier cellIdentifier) => EditableCellId(
|
factory EditableCellId.from(DatabaseCellContext cellIdentifier) =>
|
||||||
|
EditableCellId(
|
||||||
cellIdentifier.rowId,
|
cellIdentifier.rowId,
|
||||||
cellIdentifier.fieldId,
|
cellIdentifier.fieldId,
|
||||||
);
|
);
|
||||||
|
@ -20,14 +20,17 @@ class GridCellBuilder {
|
|||||||
required this.cellCache,
|
required this.cellCache,
|
||||||
});
|
});
|
||||||
|
|
||||||
GridCellWidget build(CellIdentifier cellId, {GridCellStyle? style}) {
|
GridCellWidget build(
|
||||||
|
DatabaseCellContext cellContext, {
|
||||||
|
GridCellStyle? style,
|
||||||
|
}) {
|
||||||
final cellControllerBuilder = CellControllerBuilder(
|
final cellControllerBuilder = CellControllerBuilder(
|
||||||
cellId: cellId,
|
cellContext: cellContext,
|
||||||
cellCache: cellCache,
|
cellCache: cellCache,
|
||||||
);
|
);
|
||||||
|
|
||||||
final key = cellId.key();
|
final key = cellContext.key();
|
||||||
switch (cellId.fieldType) {
|
switch (cellContext.fieldType) {
|
||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
return GridCheckboxCell(
|
return GridCheckboxCell(
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
|
@ -15,8 +15,9 @@ class ChecklistCardCellBloc
|
|||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
ChecklistCardCellBloc({
|
ChecklistCardCellBloc({
|
||||||
required this.cellController,
|
required this.cellController,
|
||||||
}) : _checklistCellSvc =
|
}) : _checklistCellSvc = ChecklistCellBackendService(
|
||||||
ChecklistCellBackendService(cellId: cellController.cellId),
|
cellContext: cellController.cellContext,
|
||||||
|
),
|
||||||
super(ChecklistCellState.initial(cellController)) {
|
super(ChecklistCellState.initial(cellController)) {
|
||||||
on<ChecklistCellEvent>(
|
on<ChecklistCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
|
@ -18,8 +18,9 @@ class ChecklistCellEditorBloc
|
|||||||
|
|
||||||
ChecklistCellEditorBloc({
|
ChecklistCellEditorBloc({
|
||||||
required this.cellController,
|
required this.cellController,
|
||||||
}) : _checklistCellService =
|
}) : _checklistCellService = ChecklistCellBackendService(
|
||||||
ChecklistCellBackendService(cellId: cellController.cellId),
|
cellContext: cellController.cellContext,
|
||||||
|
),
|
||||||
super(ChecklistCellEditorState.initial(cellController)) {
|
super(ChecklistCellEditorState.initial(cellController)) {
|
||||||
on<ChecklistCellEditorEvent>(
|
on<ChecklistCellEditorEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
|
@ -16,8 +16,9 @@ class SelectOptionCellEditorBloc
|
|||||||
|
|
||||||
SelectOptionCellEditorBloc({
|
SelectOptionCellEditorBloc({
|
||||||
required this.cellController,
|
required this.cellController,
|
||||||
}) : _selectOptionService =
|
}) : _selectOptionService = SelectOptionCellBackendService(
|
||||||
SelectOptionCellBackendService(cellId: cellController.cellId),
|
cellContext: cellController.cellContext,
|
||||||
|
),
|
||||||
super(SelectOptionEditorState.initial(cellController)) {
|
super(SelectOptionEditorState.initial(cellController)) {
|
||||||
on<SelectOptionEditorEvent>(
|
on<SelectOptionEditorEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
||||||
|
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
|
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
|
||||||
import 'package:appflowy/plugins/database_view/grid/application/row/row_detail_bloc.dart';
|
import 'package:appflowy/plugins/database_view/grid/application/row/row_detail_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||||
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
@ -134,7 +136,7 @@ class _PropertyColumn extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_RowTitle(
|
_RowTitle(
|
||||||
cellId: state.gridCells
|
cellContext: state.gridCells
|
||||||
.firstWhereOrNull((e) => e.fieldInfo.isPrimary),
|
.firstWhereOrNull((e) => e.fieldInfo.isPrimary),
|
||||||
cellBuilder: cellBuilder,
|
cellBuilder: cellBuilder,
|
||||||
),
|
),
|
||||||
@ -145,7 +147,7 @@ class _PropertyColumn extends StatelessWidget {
|
|||||||
(cell) => Padding(
|
(cell) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 4.0),
|
padding: const EdgeInsets.only(bottom: 4.0),
|
||||||
child: _PropertyCell(
|
child: _PropertyCell(
|
||||||
cellId: cell,
|
cellContext: cell,
|
||||||
cellBuilder: cellBuilder,
|
cellBuilder: cellBuilder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -161,14 +163,14 @@ class _PropertyColumn extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RowTitle extends StatelessWidget {
|
class _RowTitle extends StatelessWidget {
|
||||||
final CellIdentifier? cellId;
|
final DatabaseCellContext? cellContext;
|
||||||
final GridCellBuilder cellBuilder;
|
final GridCellBuilder cellBuilder;
|
||||||
const _RowTitle({this.cellId, required this.cellBuilder, Key? key})
|
const _RowTitle({this.cellContext, required this.cellBuilder, Key? key})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (cellId == null) {
|
if (cellContext == null) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
final style = GridTextCellStyle(
|
final style = GridTextCellStyle(
|
||||||
@ -176,7 +178,7 @@ class _RowTitle extends StatelessWidget {
|
|||||||
textStyle: Theme.of(context).textTheme.titleLarge,
|
textStyle: Theme.of(context).textTheme.titleLarge,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
);
|
);
|
||||||
return cellBuilder.build(cellId!, style: style);
|
return cellBuilder.build(cellContext!, style: style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,6 +196,7 @@ class _CreatePropertyButton extends StatefulWidget {
|
|||||||
|
|
||||||
class _CreatePropertyButtonState extends State<_CreatePropertyButton> {
|
class _CreatePropertyButtonState extends State<_CreatePropertyButton> {
|
||||||
late PopoverController popoverController;
|
late PopoverController popoverController;
|
||||||
|
late TypeOptionPB typeOption;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -207,6 +210,7 @@ class _CreatePropertyButtonState extends State<_CreatePropertyButton> {
|
|||||||
constraints: BoxConstraints.loose(const Size(240, 200)),
|
constraints: BoxConstraints.loose(const Size(240, 200)),
|
||||||
controller: popoverController,
|
controller: popoverController,
|
||||||
direction: PopoverDirection.topWithLeftAligned,
|
direction: PopoverDirection.topWithLeftAligned,
|
||||||
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
@ -216,7 +220,18 @@ class _CreatePropertyButtonState extends State<_CreatePropertyButton> {
|
|||||||
color: AFThemeExtension.of(context).textColor,
|
color: AFThemeExtension.of(context).textColor,
|
||||||
),
|
),
|
||||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
onTap: () {},
|
onTap: () async {
|
||||||
|
final result = await TypeOptionBackendService.createFieldTypeOption(
|
||||||
|
viewId: widget.viewId,
|
||||||
|
);
|
||||||
|
result.fold(
|
||||||
|
(l) {
|
||||||
|
typeOption = l;
|
||||||
|
popoverController.show();
|
||||||
|
},
|
||||||
|
(r) => Log.error("Failed to create field type option: $r"),
|
||||||
|
);
|
||||||
|
},
|
||||||
leftIcon: svgWidget(
|
leftIcon: svgWidget(
|
||||||
"home/add",
|
"home/add",
|
||||||
color: AFThemeExtension.of(context).textColor,
|
color: AFThemeExtension.of(context).textColor,
|
||||||
@ -226,7 +241,10 @@ class _CreatePropertyButtonState extends State<_CreatePropertyButton> {
|
|||||||
popupBuilder: (BuildContext popOverContext) {
|
popupBuilder: (BuildContext popOverContext) {
|
||||||
return FieldEditor(
|
return FieldEditor(
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
typeOptionLoader: NewFieldTypeOptionLoader(viewId: widget.viewId),
|
typeOptionLoader: FieldTypeOptionLoader(
|
||||||
|
viewId: widget.viewId,
|
||||||
|
field: typeOption.field_2,
|
||||||
|
),
|
||||||
onDeleted: (fieldId) {
|
onDeleted: (fieldId) {
|
||||||
popoverController.close();
|
popoverController.close();
|
||||||
NavigatorAlertDialog(
|
NavigatorAlertDialog(
|
||||||
@ -245,10 +263,10 @@ class _CreatePropertyButtonState extends State<_CreatePropertyButton> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PropertyCell extends StatefulWidget {
|
class _PropertyCell extends StatefulWidget {
|
||||||
final CellIdentifier cellId;
|
final DatabaseCellContext cellContext;
|
||||||
final GridCellBuilder cellBuilder;
|
final GridCellBuilder cellBuilder;
|
||||||
const _PropertyCell({
|
const _PropertyCell({
|
||||||
required this.cellId,
|
required this.cellContext,
|
||||||
required this.cellBuilder,
|
required this.cellBuilder,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@ -262,8 +280,8 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final style = _customCellStyle(widget.cellId.fieldType);
|
final style = _customCellStyle(widget.cellContext.fieldType);
|
||||||
final cell = widget.cellBuilder.build(widget.cellId, style: style);
|
final cell = widget.cellBuilder.build(widget.cellContext, style: style);
|
||||||
|
|
||||||
final gesture = GestureDetector(
|
final gesture = GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
@ -290,7 +308,7 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 150,
|
width: 150,
|
||||||
child: FieldCellButton(
|
child: FieldCellButton(
|
||||||
field: widget.cellId.fieldInfo.field,
|
field: widget.cellContext.fieldInfo.field,
|
||||||
onTap: () => popover.show(),
|
onTap: () => popover.show(),
|
||||||
radius: BorderRadius.circular(6),
|
radius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
@ -306,11 +324,11 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
|
|
||||||
Widget buildFieldEditor() {
|
Widget buildFieldEditor() {
|
||||||
return FieldEditor(
|
return FieldEditor(
|
||||||
viewId: widget.cellId.viewId,
|
viewId: widget.cellContext.viewId,
|
||||||
isGroupingField: widget.cellId.fieldInfo.isGroupField,
|
isGroupingField: widget.cellContext.fieldInfo.isGroupField,
|
||||||
typeOptionLoader: FieldTypeOptionLoader(
|
typeOptionLoader: FieldTypeOptionLoader(
|
||||||
viewId: widget.cellId.viewId,
|
viewId: widget.cellContext.viewId,
|
||||||
field: widget.cellId.fieldInfo.field,
|
field: widget.cellContext.fieldInfo.field,
|
||||||
),
|
),
|
||||||
onHidden: (fieldId) {
|
onHidden: (fieldId) {
|
||||||
popover.close();
|
popover.close();
|
||||||
|
@ -171,7 +171,7 @@ void _resolveGridDeps(GetIt getIt) {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<FieldActionSheetBloc, FieldCellContext, void>(
|
getIt.registerFactoryParam<FieldActionSheetBloc, FieldContext, void>(
|
||||||
(data, _) => FieldActionSheetBloc(fieldCellContext: data),
|
(data, _) => FieldActionSheetBloc(fieldCellContext: data),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -35,10 +35,9 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final editorBloc = FieldEditorBloc(
|
final editorBloc = FieldEditorBloc(
|
||||||
viewId: context.gridView.id,
|
|
||||||
fieldName: fieldInfo.name,
|
|
||||||
isGroupField: fieldInfo.isGroupField,
|
isGroupField: fieldInfo.isGroupField,
|
||||||
loader: loader,
|
loader: loader,
|
||||||
|
field: fieldInfo.field,
|
||||||
)..add(const FieldEditorEvent.initial());
|
)..add(const FieldEditorEvent.initial());
|
||||||
await boardResponseFuture();
|
await boardResponseFuture();
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ void main() {
|
|||||||
boardTest = await AppFlowyBoardTest.ensureInitialized();
|
boardTest = await AppFlowyBoardTest.ensureInitialized();
|
||||||
context = await boardTest.createTestBoard();
|
context = await boardTest.createTestBoard();
|
||||||
final fieldInfo = context.singleSelectFieldContext();
|
final fieldInfo = context.singleSelectFieldContext();
|
||||||
editorBloc = context.createFieldEditor(
|
editorBloc = context.makeFieldEditor(
|
||||||
fieldInfo: fieldInfo,
|
fieldInfo: fieldInfo,
|
||||||
)..add(const FieldEditorEvent.initial());
|
)..add(const FieldEditorEvent.initial());
|
||||||
|
|
||||||
|
@ -76,22 +76,18 @@ class BoardTestContext {
|
|||||||
return _boardDataController.fieldController;
|
return _boardDataController.fieldController;
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldEditorBloc createFieldEditor({
|
FieldEditorBloc makeFieldEditor({
|
||||||
FieldInfo? fieldInfo,
|
required FieldInfo fieldInfo,
|
||||||
}) {
|
}) {
|
||||||
ITypeOptionLoader loader;
|
final loader = FieldTypeOptionLoader(
|
||||||
if (fieldInfo == null) {
|
viewId: gridView.id,
|
||||||
loader = NewFieldTypeOptionLoader(viewId: gridView.id);
|
field: fieldInfo.field,
|
||||||
} else {
|
);
|
||||||
loader =
|
|
||||||
FieldTypeOptionLoader(viewId: gridView.id, field: fieldInfo.field);
|
|
||||||
}
|
|
||||||
|
|
||||||
final editorBloc = FieldEditorBloc(
|
final editorBloc = FieldEditorBloc(
|
||||||
fieldName: fieldInfo?.name ?? '',
|
isGroupField: fieldInfo.isGroupField,
|
||||||
isGroupField: fieldInfo?.isGroupField ?? false,
|
|
||||||
loader: loader,
|
loader: loader,
|
||||||
viewId: gridView.id,
|
field: fieldInfo.field,
|
||||||
);
|
);
|
||||||
return editorBloc;
|
return editorBloc;
|
||||||
}
|
}
|
||||||
@ -120,13 +116,13 @@ class BoardTestContext {
|
|||||||
await gridResponseFuture();
|
await gridResponseFuture();
|
||||||
|
|
||||||
return CellControllerBuilder(
|
return CellControllerBuilder(
|
||||||
cellId: rowBloc.state.cellByFieldId[fieldId]!,
|
cellContext: rowBloc.state.cellByFieldId[fieldId]!,
|
||||||
cellCache: rowCache.cellCache,
|
cellCache: rowCache.cellCache,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<FieldEditorBloc> createField(FieldType fieldType) async {
|
Future<FieldEditorBloc> createField(FieldType fieldType) async {
|
||||||
final editorBloc = createFieldEditor()
|
final editorBloc = await createFieldEditor(viewId: gridView.id)
|
||||||
..add(const FieldEditorEvent.initial());
|
..add(const FieldEditorEvent.initial());
|
||||||
await gridResponseFuture();
|
await gridResponseFuture();
|
||||||
editorBloc.add(FieldEditorEvent.switchToField(fieldType));
|
editorBloc.add(FieldEditorEvent.switchToField(fieldType));
|
||||||
@ -140,9 +136,9 @@ class BoardTestContext {
|
|||||||
return fieldInfo;
|
return fieldInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldCellContext singleSelectFieldCellContext() {
|
FieldContext singleSelectFieldCellContext() {
|
||||||
final field = singleSelectFieldContext().field;
|
final field = singleSelectFieldContext().field;
|
||||||
return FieldCellContext(viewId: gridView.id, field: field);
|
return FieldContext(viewId: gridView.id, field: field);
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldInfo textFieldContext() {
|
FieldInfo textFieldContext() {
|
||||||
|
@ -13,10 +13,9 @@ Future<FieldEditorBloc> createEditorBloc(AppFlowyGridTest gridTest) async {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return FieldEditorBloc(
|
return FieldEditorBloc(
|
||||||
viewId: context.gridView.id,
|
|
||||||
fieldName: fieldInfo.name,
|
|
||||||
isGroupField: fieldInfo.isGroupField,
|
isGroupField: fieldInfo.isGroupField,
|
||||||
loader: loader,
|
loader: loader,
|
||||||
|
field: fieldInfo.field,
|
||||||
)..add(const FieldEditorEvent.initial());
|
)..add(const FieldEditorEvent.initial());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,10 +82,9 @@ Future<FieldEditorBloc> makeEditorBloc(AppFlowyGridTest gridTest) async {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final editorBloc = FieldEditorBloc(
|
final editorBloc = FieldEditorBloc(
|
||||||
viewId: context.gridView.id,
|
|
||||||
fieldName: fieldInfo.name,
|
|
||||||
isGroupField: fieldInfo.isGroupField,
|
isGroupField: fieldInfo.isGroupField,
|
||||||
loader: loader,
|
loader: loader,
|
||||||
|
field: fieldInfo.field,
|
||||||
)..add(const FieldEditorEvent.initial());
|
)..add(const FieldEditorEvent.initial());
|
||||||
|
|
||||||
await gridResponseFuture();
|
await gridResponseFuture();
|
||||||
|
@ -41,10 +41,9 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final editorBloc = FieldEditorBloc(
|
final editorBloc = FieldEditorBloc(
|
||||||
viewId: context.gridView.id,
|
|
||||||
fieldName: textField.field.name,
|
|
||||||
isGroupField: false,
|
isGroupField: false,
|
||||||
loader: loader,
|
loader: loader,
|
||||||
|
field: textField.field,
|
||||||
)..add(const FieldEditorEvent.initial());
|
)..add(const FieldEditorEvent.initial());
|
||||||
await gridResponseFuture();
|
await gridResponseFuture();
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import 'package:appflowy/plugins/database_view/application/field/field_controlle
|
|||||||
import 'package:appflowy/plugins/database_view/application/field/field_editor_bloc.dart';
|
import 'package:appflowy/plugins/database_view/application/field/field_editor_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
|
||||||
|
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
|
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
||||||
@ -38,26 +39,6 @@ class GridTestContext {
|
|||||||
return gridController.createRow();
|
return gridController.createRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldEditorBloc createFieldEditor({
|
|
||||||
FieldInfo? fieldInfo,
|
|
||||||
}) {
|
|
||||||
ITypeOptionLoader loader;
|
|
||||||
if (fieldInfo == null) {
|
|
||||||
loader = NewFieldTypeOptionLoader(viewId: gridView.id);
|
|
||||||
} else {
|
|
||||||
loader =
|
|
||||||
FieldTypeOptionLoader(viewId: gridView.id, field: fieldInfo.field);
|
|
||||||
}
|
|
||||||
|
|
||||||
final editorBloc = FieldEditorBloc(
|
|
||||||
fieldName: fieldInfo?.name ?? '',
|
|
||||||
isGroupField: fieldInfo?.isGroupField ?? false,
|
|
||||||
loader: loader,
|
|
||||||
viewId: gridView.id,
|
|
||||||
);
|
|
||||||
return editorBloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<CellController> makeCellController(
|
Future<CellController> makeCellController(
|
||||||
String fieldId,
|
String fieldId,
|
||||||
int rowIndex,
|
int rowIndex,
|
||||||
@ -86,13 +67,13 @@ class GridTestContext {
|
|||||||
await gridResponseFuture();
|
await gridResponseFuture();
|
||||||
|
|
||||||
return CellControllerBuilder(
|
return CellControllerBuilder(
|
||||||
cellId: rowBloc.state.cellByFieldId[fieldId]!,
|
cellContext: rowBloc.state.cellByFieldId[fieldId]!,
|
||||||
cellCache: rowCache.cellCache,
|
cellCache: rowCache.cellCache,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<FieldEditorBloc> createField(FieldType fieldType) async {
|
Future<FieldEditorBloc> createField(FieldType fieldType) async {
|
||||||
final editorBloc = createFieldEditor()
|
final editorBloc = await createFieldEditor(viewId: gridView.id)
|
||||||
..add(const FieldEditorEvent.initial());
|
..add(const FieldEditorEvent.initial());
|
||||||
await gridResponseFuture();
|
await gridResponseFuture();
|
||||||
editorBloc.add(FieldEditorEvent.switchToField(fieldType));
|
editorBloc.add(FieldEditorEvent.switchToField(fieldType));
|
||||||
@ -106,9 +87,9 @@ class GridTestContext {
|
|||||||
return fieldInfo;
|
return fieldInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldCellContext singleSelectFieldCellContext() {
|
FieldContext singleSelectFieldCellContext() {
|
||||||
final field = singleSelectFieldContext().field;
|
final field = singleSelectFieldContext().field;
|
||||||
return FieldCellContext(viewId: gridView.id, field: field);
|
return FieldContext(viewId: gridView.id, field: field);
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldInfo textFieldContext() {
|
FieldInfo textFieldContext() {
|
||||||
@ -155,6 +136,28 @@ class GridTestContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<FieldEditorBloc> createFieldEditor({
|
||||||
|
required String viewId,
|
||||||
|
}) async {
|
||||||
|
final result = await TypeOptionBackendService.createFieldTypeOption(
|
||||||
|
viewId: viewId,
|
||||||
|
);
|
||||||
|
return result.fold(
|
||||||
|
(data) {
|
||||||
|
final loader = FieldTypeOptionLoader(
|
||||||
|
viewId: viewId,
|
||||||
|
field: data.field_2,
|
||||||
|
);
|
||||||
|
return FieldEditorBloc(
|
||||||
|
isGroupField: FieldInfo(field: data.field_2).isGroupField,
|
||||||
|
loader: loader,
|
||||||
|
field: data.field_2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(err) => throw Exception(err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a empty Grid for test
|
/// Create a empty Grid for test
|
||||||
class AppFlowyGridTest {
|
class AppFlowyGridTest {
|
||||||
final AppFlowyUnitTest unitTest;
|
final AppFlowyUnitTest unitTest;
|
||||||
|
@ -196,16 +196,27 @@ impl DatabaseEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_field(&self, params: FieldChangesetParams) -> FlowyResult<()> {
|
pub async fn update_field(&self, params: FieldChangesetParams) -> FlowyResult<()> {
|
||||||
|
let is_primary = self
|
||||||
|
.database
|
||||||
|
.lock()
|
||||||
|
.fields
|
||||||
|
.get_field(¶ms.field_id)
|
||||||
|
.map(|field| field.is_primary)
|
||||||
|
.unwrap_or(false);
|
||||||
self
|
self
|
||||||
.database
|
.database
|
||||||
.lock()
|
.lock()
|
||||||
.fields
|
.fields
|
||||||
.update_field(¶ms.field_id, |update| {
|
.update_field(¶ms.field_id, |mut update| {
|
||||||
update
|
update = update
|
||||||
.set_name_if_not_none(params.name)
|
.set_name_if_not_none(params.name)
|
||||||
.set_field_type_if_not_none(params.field_type.map(|field_type| field_type.into()))
|
|
||||||
.set_width_at_if_not_none(params.width.map(|value| value as i64))
|
.set_width_at_if_not_none(params.width.map(|value| value as i64))
|
||||||
.set_visibility_if_not_none(params.visibility);
|
.set_visibility_if_not_none(params.visibility);
|
||||||
|
if is_primary {
|
||||||
|
tracing::warn!("Cannot update primary field type");
|
||||||
|
} else {
|
||||||
|
update.set_field_type_if_not_none(params.field_type.map(|field_type| field_type.into()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
.notify_did_update_database_field(¶ms.field_id)
|
.notify_did_update_database_field(¶ms.field_id)
|
||||||
@ -238,10 +249,15 @@ impl DatabaseEditor {
|
|||||||
.lock()
|
.lock()
|
||||||
.fields
|
.fields
|
||||||
.update_field(field_id, |update| {
|
.update_field(field_id, |update| {
|
||||||
update.update_type_options(|type_options_update| {
|
if old_field.is_primary {
|
||||||
type_options_update.insert(&field_type.to_string(), type_option_data);
|
tracing::warn!("Cannot update primary field type");
|
||||||
});
|
} else {
|
||||||
|
update.update_type_options(|type_options_update| {
|
||||||
|
type_options_update.insert(&field_type.to_string(), type_option_data);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self
|
self
|
||||||
.database_views
|
.database_views
|
||||||
.did_update_field_type_option(view_id, field_id, &old_field)
|
.did_update_field_type_option(view_id, field_id, &old_field)
|
||||||
|
@ -43,7 +43,7 @@ async fn update_at_field_test() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let old_updated_at = DateCellData::from(&cell).timestamp.unwrap();
|
let old_updated_at = DateCellData::from(&cell).timestamp.unwrap();
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
tokio::time::sleep(Duration::from_millis(1000)).await;
|
||||||
test
|
test
|
||||||
.run_script(UpdateTextCell {
|
.run_script(UpdateTextCell {
|
||||||
row_id: row.id.clone(),
|
row_id: row.id.clone(),
|
||||||
|
Reference in New Issue
Block a user