mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #800 from AppFlowy-IO/fix/create_column
fix: create column errors
This commit is contained in:
commit
fd1bbaa6fd
@ -1,17 +1,161 @@
|
||||
// ignore_for_file: unused_field
|
||||
|
||||
import 'package:appflowy_board/appflowy_board.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BoardPage extends StatelessWidget {
|
||||
class BoardPage extends StatefulWidget {
|
||||
final ViewPB _view;
|
||||
|
||||
const BoardPage({required ViewPB view, Key? key})
|
||||
: _view = view,
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
State<BoardPage> createState() => _BoardPageState();
|
||||
}
|
||||
|
||||
class _BoardPageState extends State<BoardPage> {
|
||||
final BoardDataController boardDataController = BoardDataController(
|
||||
onMoveColumn: (fromIndex, toIndex) {
|
||||
debugPrint('Move column from $fromIndex to $toIndex');
|
||||
},
|
||||
onMoveColumnItem: (columnId, fromIndex, toIndex) {
|
||||
debugPrint('Move $columnId:$fromIndex to $columnId:$toIndex');
|
||||
},
|
||||
onMoveColumnItemToColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
|
||||
debugPrint('Move $fromColumnId:$fromIndex to $toColumnId:$toIndex');
|
||||
},
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
final column1 = BoardColumnData(id: "To Do", items: [
|
||||
TextItem("Card 1"),
|
||||
TextItem("Card 2"),
|
||||
RichTextItem(title: "Card 3", subtitle: 'Aug 1, 2020 4:05 PM'),
|
||||
TextItem("Card 4"),
|
||||
]);
|
||||
final column2 = BoardColumnData(id: "In Progress", items: [
|
||||
RichTextItem(title: "Card 5", subtitle: 'Aug 1, 2020 4:05 PM'),
|
||||
TextItem("Card 6"),
|
||||
]);
|
||||
|
||||
final column3 = BoardColumnData(id: "Done", items: []);
|
||||
|
||||
boardDataController.addColumn(column1);
|
||||
boardDataController.addColumn(column2);
|
||||
boardDataController.addColumn(column3);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
final config = BoardConfig(
|
||||
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||
);
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
||||
child: Board(
|
||||
dataController: boardDataController,
|
||||
footBuilder: (context, columnData) {
|
||||
return AppFlowyColumnFooter(
|
||||
icon: const Icon(Icons.add, size: 20),
|
||||
title: const Text('New'),
|
||||
height: 50,
|
||||
margin: config.columnItemPadding,
|
||||
);
|
||||
},
|
||||
headerBuilder: (context, columnData) {
|
||||
return AppFlowyColumnHeader(
|
||||
icon: const Icon(Icons.lightbulb_circle),
|
||||
title: Text(columnData.id),
|
||||
addIcon: const Icon(Icons.add, size: 20),
|
||||
moreIcon: const Icon(Icons.more_horiz, size: 20),
|
||||
height: 50,
|
||||
margin: config.columnItemPadding,
|
||||
);
|
||||
},
|
||||
cardBuilder: (context, item) {
|
||||
return AppFlowyColumnItemCard(
|
||||
key: ObjectKey(item),
|
||||
child: _buildCard(item),
|
||||
);
|
||||
},
|
||||
columnConstraints: const BoxConstraints.tightFor(width: 240),
|
||||
config: BoardConfig(
|
||||
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCard(ColumnItem item) {
|
||||
if (item is TextItem) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text(item.s),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (item is RichTextItem) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
item.title,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
item.subtitle,
|
||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class TextItem extends ColumnItem {
|
||||
final String s;
|
||||
|
||||
TextItem(this.s);
|
||||
|
||||
@override
|
||||
String get id => s;
|
||||
}
|
||||
|
||||
class RichTextItem extends ColumnItem {
|
||||
final String title;
|
||||
final String subtitle;
|
||||
|
||||
RichTextItem({required this.title, required this.subtitle});
|
||||
|
||||
@override
|
||||
String get id => title;
|
||||
}
|
||||
|
||||
extension HexColor on Color {
|
||||
static Color fromHex(String hexString) {
|
||||
final buffer = StringBuffer();
|
||||
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
|
||||
buffer.write(hexString.replaceFirst('#', ''));
|
||||
return Color(int.parse(buffer.toString(), radix: 16));
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
class DocumentBanner extends StatelessWidget {
|
||||
final void Function() onRestore;
|
||||
final void Function() onDelete;
|
||||
const DocumentBanner({required this.onRestore, required this.onDelete, Key? key}) : super(key: key);
|
||||
const DocumentBanner(
|
||||
{required this.onRestore, required this.onDelete, Key? key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -26,7 +28,8 @@ class DocumentBanner extends StatelessWidget {
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Row(
|
||||
children: [
|
||||
FlowyText.medium(LocaleKeys.deletePagePrompt_text.tr(), color: Colors.white),
|
||||
FlowyText.medium(LocaleKeys.deletePagePrompt_text.tr(),
|
||||
color: Colors.white),
|
||||
const HSpace(20),
|
||||
BaseStyledButton(
|
||||
minWidth: 160,
|
||||
@ -37,7 +40,10 @@ class DocumentBanner extends StatelessWidget {
|
||||
downColor: theme.main1,
|
||||
outlineColor: Colors.white,
|
||||
borderRadius: Corners.s8Border,
|
||||
child: FlowyText.medium(LocaleKeys.deletePagePrompt_restore.tr(), color: Colors.white, fontSize: 14),
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.deletePagePrompt_restore.tr(),
|
||||
color: Colors.white,
|
||||
fontSize: 14),
|
||||
onPressed: onRestore),
|
||||
const HSpace(20),
|
||||
BaseStyledButton(
|
||||
@ -49,8 +55,10 @@ class DocumentBanner extends StatelessWidget {
|
||||
downColor: theme.main1,
|
||||
outlineColor: Colors.white,
|
||||
borderRadius: Corners.s8Border,
|
||||
child: FlowyText.medium(LocaleKeys.deletePagePrompt_deletePermanent.tr(),
|
||||
color: Colors.white, fontSize: 14),
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.deletePagePrompt_deletePermanent.tr(),
|
||||
color: Colors.white,
|
||||
fontSize: 14),
|
||||
onPressed: onDelete),
|
||||
],
|
||||
),
|
||||
|
@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'cell_service.dart';
|
||||
|
||||
abstract class GridFieldChangedNotifier {
|
||||
abstract class IGridFieldChangedNotifier {
|
||||
void onFieldChanged(void Function(GridFieldPB) callback);
|
||||
void dispose();
|
||||
}
|
||||
@ -12,9 +12,10 @@ abstract class GridFieldChangedNotifier {
|
||||
/// You Register an onFieldChanged callback to listen to the cell changes, and unregister if you don't want to listen.
|
||||
class GridCellFieldNotifier {
|
||||
/// fieldId: {objectId: callback}
|
||||
final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId = {};
|
||||
final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId =
|
||||
{};
|
||||
|
||||
GridCellFieldNotifier({required GridFieldChangedNotifier notifier}) {
|
||||
GridCellFieldNotifier({required IGridFieldChangedNotifier notifier}) {
|
||||
notifier.onFieldChanged(
|
||||
(field) {
|
||||
final map = _fieldListenerByFieldId[field.id];
|
||||
|
@ -246,7 +246,7 @@ class IGridCellController<T, D> extends Equatable {
|
||||
}
|
||||
|
||||
/// Save the cell data to disk
|
||||
/// You can set [dedeplicate] to true (default is false) to reduce the save operation.
|
||||
/// You can set [deduplicate] to true (default is false) to reduce the save operation.
|
||||
/// It's useful when you call this method when user editing the [TextField].
|
||||
/// The default debounce interval is 300 milliseconds.
|
||||
void saveCellData(D data,
|
||||
@ -304,7 +304,7 @@ class IGridCellController<T, D> extends Equatable {
|
||||
[_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id];
|
||||
}
|
||||
|
||||
class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {
|
||||
class _GridFieldChangedNotifierImpl extends IGridFieldChangedNotifier {
|
||||
final GridFieldCache _cache;
|
||||
FieldChangesetCallback? _onChangesetFn;
|
||||
|
||||
|
@ -1,40 +1,23 @@
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'block/block_cache.dart';
|
||||
import 'grid_service.dart';
|
||||
import 'grid_data_controller.dart';
|
||||
import 'row/row_service.dart';
|
||||
import 'dart:collection';
|
||||
|
||||
part 'grid_bloc.freezed.dart';
|
||||
|
||||
class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final String gridId;
|
||||
final GridService _gridService;
|
||||
final GridFieldCache fieldCache;
|
||||
|
||||
// key: the block id
|
||||
final LinkedHashMap<String, GridBlockCache> _blocks;
|
||||
|
||||
List<GridRowInfo> get rowInfos {
|
||||
final List<GridRowInfo> rows = [];
|
||||
for (var block in _blocks.values) {
|
||||
rows.addAll(block.rows);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
final GridDataController dataController;
|
||||
|
||||
GridBloc({required ViewPB view})
|
||||
: gridId = view.id,
|
||||
_blocks = LinkedHashMap.identity(),
|
||||
_gridService = GridService(gridId: view.id),
|
||||
fieldCache = GridFieldCache(gridId: view.id),
|
||||
: dataController = GridDataController(view: view),
|
||||
super(GridState.initial(view.id)) {
|
||||
on<GridEvent>(
|
||||
(event, emit) async {
|
||||
@ -44,13 +27,21 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
await _loadGrid(emit);
|
||||
},
|
||||
createRow: () {
|
||||
_gridService.createRow();
|
||||
dataController.createRow();
|
||||
},
|
||||
didReceiveRowUpdate: (newRowInfos, reason) {
|
||||
emit(state.copyWith(rowInfos: newRowInfos, reason: reason));
|
||||
didReceiveGridUpdate: (grid) {
|
||||
emit(state.copyWith(grid: Some(grid)));
|
||||
},
|
||||
didReceiveFieldUpdate: (fields) {
|
||||
emit(state.copyWith(rowInfos: rowInfos, fields: GridFieldEquatable(fields)));
|
||||
emit(state.copyWith(
|
||||
fields: GridFieldEquatable(fields),
|
||||
));
|
||||
},
|
||||
didReceiveRowUpdate: (newRowInfos, reason) {
|
||||
emit(state.copyWith(
|
||||
rowInfos: newRowInfos,
|
||||
reason: reason,
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -59,89 +50,63 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _gridService.closeGrid();
|
||||
await fieldCache.dispose();
|
||||
|
||||
for (final blockCache in _blocks.values) {
|
||||
blockCache.dispose();
|
||||
}
|
||||
await dataController.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
GridRowCache? getRowCache(String blockId, String rowId) {
|
||||
final GridBlockCache? blockCache = _blocks[blockId];
|
||||
final GridBlockCache? blockCache = dataController.blocks[blockId];
|
||||
return blockCache?.rowCache;
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
fieldCache.addListener(
|
||||
listenWhen: () => !isClosed,
|
||||
onFields: (fields) => add(GridEvent.didReceiveFieldUpdate(fields)),
|
||||
dataController.addListener(
|
||||
onGridChanged: (grid) {
|
||||
if (!isClosed) {
|
||||
add(GridEvent.didReceiveGridUpdate(grid));
|
||||
}
|
||||
},
|
||||
onRowsChanged: (rowInfos, reason) {
|
||||
if (!isClosed) {
|
||||
add(GridEvent.didReceiveRowUpdate(rowInfos, reason));
|
||||
}
|
||||
},
|
||||
onFieldsChanged: (fields) {
|
||||
if (!isClosed) {
|
||||
add(GridEvent.didReceiveFieldUpdate(fields));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadGrid(Emitter<GridState> emit) async {
|
||||
final result = await _gridService.loadGrid();
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(grid) async {
|
||||
_initialBlocks(grid.blocks);
|
||||
await _loadFields(grid, emit);
|
||||
},
|
||||
(err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
|
||||
final result = await dataController.loadData();
|
||||
result.fold(
|
||||
(grid) => emit(
|
||||
state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
|
||||
),
|
||||
(err) => emit(
|
||||
state.copyWith(loadingState: GridLoadingState.finish(right(err))),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadFields(GridPB grid, Emitter<GridState> emit) async {
|
||||
final result = await _gridService.getFields(fieldIds: grid.fields);
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(fields) {
|
||||
fieldCache.fields = fields.items;
|
||||
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
fields: GridFieldEquatable(fieldCache.fields),
|
||||
rowInfos: rowInfos,
|
||||
loadingState: GridLoadingState.finish(left(unit)),
|
||||
));
|
||||
},
|
||||
(err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _initialBlocks(List<GridBlockPB> blocks) {
|
||||
for (final block in blocks) {
|
||||
if (_blocks[block.id] != null) {
|
||||
Log.warn("Intial duplicate block's cache: ${block.id}");
|
||||
return;
|
||||
}
|
||||
|
||||
final cache = GridBlockCache(
|
||||
gridId: gridId,
|
||||
block: block,
|
||||
fieldCache: fieldCache,
|
||||
);
|
||||
|
||||
cache.addListener(
|
||||
listenWhen: () => !isClosed,
|
||||
onChangeReason: (reason) => add(GridEvent.didReceiveRowUpdate(rowInfos, reason)),
|
||||
);
|
||||
|
||||
_blocks[block.id] = cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridEvent with _$GridEvent {
|
||||
const factory GridEvent.initial() = InitialGrid;
|
||||
const factory GridEvent.createRow() = _CreateRow;
|
||||
const factory GridEvent.didReceiveRowUpdate(List<GridRowInfo> rows, GridRowChangeReason listState) =
|
||||
_DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveFieldUpdate(List<GridFieldPB> fields) = _DidReceiveFieldUpdate;
|
||||
const factory GridEvent.didReceiveRowUpdate(
|
||||
List<GridRowInfo> rows,
|
||||
GridRowChangeReason listState,
|
||||
) = _DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveFieldUpdate(
|
||||
UnmodifiableListView<GridFieldPB> fields,
|
||||
) = _DidReceiveFieldUpdate;
|
||||
|
||||
const factory GridEvent.didReceiveGridUpdate(
|
||||
GridPB grid,
|
||||
) = _DidReceiveGridUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -156,7 +121,7 @@ class GridState with _$GridState {
|
||||
}) = _GridState;
|
||||
|
||||
factory GridState.initial(String gridId) => GridState(
|
||||
fields: const GridFieldEquatable([]),
|
||||
fields: GridFieldEquatable(UnmodifiableListView([])),
|
||||
rowInfos: [],
|
||||
grid: none(),
|
||||
gridId: gridId,
|
||||
@ -168,18 +133,27 @@ class GridState with _$GridState {
|
||||
@freezed
|
||||
class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
const factory GridLoadingState.finish(
|
||||
Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
}
|
||||
|
||||
class GridFieldEquatable extends Equatable {
|
||||
final List<GridFieldPB> _fields;
|
||||
const GridFieldEquatable(List<GridFieldPB> fields) : _fields = fields;
|
||||
final UnmodifiableListView<GridFieldPB> _fields;
|
||||
const GridFieldEquatable(
|
||||
UnmodifiableListView<GridFieldPB> fields,
|
||||
) : _fields = fields;
|
||||
|
||||
@override
|
||||
List<Object?> get props {
|
||||
if (_fields.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
_fields.length,
|
||||
_fields.map((field) => field.width).reduce((value, element) => value + element),
|
||||
_fields
|
||||
.map((field) => field.width)
|
||||
.reduce((value, element) => value + element),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,128 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'block/block_cache.dart';
|
||||
import 'prelude.dart';
|
||||
|
||||
typedef OnFieldsChanged = void Function(UnmodifiableListView<GridFieldPB>);
|
||||
typedef OnGridChanged = void Function(GridPB);
|
||||
|
||||
typedef OnRowsChanged = void Function(
|
||||
List<GridRowInfo> rowInfos,
|
||||
GridRowChangeReason,
|
||||
);
|
||||
typedef ListenONRowChangedCondition = bool Function();
|
||||
|
||||
class GridDataController {
|
||||
final String gridId;
|
||||
final GridService _gridFFIService;
|
||||
final GridFieldCache fieldCache;
|
||||
|
||||
// key: the block id
|
||||
final LinkedHashMap<String, GridBlockCache> _blocks;
|
||||
UnmodifiableMapView<String, GridBlockCache> get blocks =>
|
||||
UnmodifiableMapView(_blocks);
|
||||
|
||||
OnRowsChanged? _onRowChanged;
|
||||
OnFieldsChanged? _onFieldsChanged;
|
||||
OnGridChanged? _onGridChanged;
|
||||
|
||||
List<GridRowInfo> get rowInfos {
|
||||
final List<GridRowInfo> rows = [];
|
||||
for (var block in _blocks.values) {
|
||||
rows.addAll(block.rows);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
GridDataController({required ViewPB view})
|
||||
: gridId = view.id,
|
||||
_blocks = LinkedHashMap.identity(),
|
||||
_gridFFIService = GridService(gridId: view.id),
|
||||
fieldCache = GridFieldCache(gridId: view.id);
|
||||
|
||||
void addListener({
|
||||
required OnGridChanged onGridChanged,
|
||||
required OnRowsChanged onRowsChanged,
|
||||
required OnFieldsChanged onFieldsChanged,
|
||||
}) {
|
||||
_onGridChanged = onGridChanged;
|
||||
_onRowChanged = onRowsChanged;
|
||||
_onFieldsChanged = onFieldsChanged;
|
||||
|
||||
fieldCache.addListener(onFields: (fields) {
|
||||
_onFieldsChanged?.call(UnmodifiableListView(fields));
|
||||
});
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> loadData() async {
|
||||
final result = await _gridFFIService.loadGrid();
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(grid) async {
|
||||
_initialBlocks(grid.blocks);
|
||||
_onGridChanged?.call(grid);
|
||||
return await _loadFields(grid);
|
||||
},
|
||||
(err) => right(err),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void createRow() {
|
||||
_gridFFIService.createRow();
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _gridFFIService.closeGrid();
|
||||
await fieldCache.dispose();
|
||||
|
||||
for (final blockCache in _blocks.values) {
|
||||
blockCache.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void _initialBlocks(List<GridBlockPB> blocks) {
|
||||
for (final block in blocks) {
|
||||
if (_blocks[block.id] != null) {
|
||||
Log.warn("Initial duplicate block's cache: ${block.id}");
|
||||
return;
|
||||
}
|
||||
|
||||
final cache = GridBlockCache(
|
||||
gridId: gridId,
|
||||
block: block,
|
||||
fieldCache: fieldCache,
|
||||
);
|
||||
|
||||
cache.addListener(
|
||||
onChangeReason: (reason) {
|
||||
_onRowChanged?.call(rowInfos, reason);
|
||||
},
|
||||
);
|
||||
|
||||
_blocks[block.id] = cache;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> _loadFields(GridPB grid) async {
|
||||
final result = await _gridFFIService.getFields(fieldIds: grid.fields);
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(fields) {
|
||||
fieldCache.fields = fields.items;
|
||||
_onFieldsChanged?.call(UnmodifiableListView(fieldCache.fields));
|
||||
return left(unit);
|
||||
},
|
||||
(err) => right(err),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -5,25 +5,25 @@ import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'row_data_controller.dart';
|
||||
import 'row_service.dart';
|
||||
|
||||
part 'row_bloc.freezed.dart';
|
||||
|
||||
class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
final RowService _rowService;
|
||||
final GridRowCache _rowCache;
|
||||
void Function()? _rowListenFn;
|
||||
final GridRowDataController _dataController;
|
||||
|
||||
RowBloc({
|
||||
required GridRowInfo rowInfo,
|
||||
required GridRowCache rowCache,
|
||||
required GridRowDataController dataController,
|
||||
}) : _rowService = RowService(
|
||||
gridId: rowInfo.gridId,
|
||||
blockId: rowInfo.blockId,
|
||||
rowId: rowInfo.id,
|
||||
),
|
||||
_rowCache = rowCache,
|
||||
super(RowState.initial(rowInfo, rowCache.loadGridCells(rowInfo.id))) {
|
||||
_dataController = dataController,
|
||||
super(RowState.initial(rowInfo, dataController.loadData())) {
|
||||
on<RowEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -33,7 +33,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
createRow: (_CreateRow value) {
|
||||
_rowService.createRow();
|
||||
},
|
||||
didReceiveCellDatas: (_DidReceiveCellDatas value) async {
|
||||
didReceiveCells: (_DidReceiveCells value) async {
|
||||
final fields = value.gridCellMap.values
|
||||
.map((e) => GridCellEquatable(e.field))
|
||||
.toList();
|
||||
@ -51,19 +51,17 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_rowListenFn != null) {
|
||||
_rowCache.removeRowListener(_rowListenFn!);
|
||||
}
|
||||
|
||||
_dataController.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _startListening() async {
|
||||
_rowListenFn = _rowCache.addListener(
|
||||
rowId: state.rowInfo.id,
|
||||
onCellUpdated: (cellDatas, reason) =>
|
||||
add(RowEvent.didReceiveCellDatas(cellDatas, reason)),
|
||||
listenWhen: () => !isClosed,
|
||||
_dataController.addListener(
|
||||
onRowChanged: (cells, reason) {
|
||||
if (!isClosed) {
|
||||
add(RowEvent.didReceiveCells(cells, reason));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -72,9 +70,8 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
class RowEvent with _$RowEvent {
|
||||
const factory RowEvent.initial() = _InitialRow;
|
||||
const factory RowEvent.createRow() = _CreateRow;
|
||||
const factory RowEvent.didReceiveCellDatas(
|
||||
GridCellMap gridCellMap, GridRowChangeReason reason) =
|
||||
_DidReceiveCellDatas;
|
||||
const factory RowEvent.didReceiveCells(
|
||||
GridCellMap gridCellMap, GridRowChangeReason reason) = _DidReceiveCells;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../cell/cell_service/cell_service.dart';
|
||||
import '../grid_service.dart';
|
||||
import 'row_service.dart';
|
||||
|
||||
typedef OnRowChanged = void Function(GridCellMap, GridRowChangeReason);
|
||||
|
||||
class GridRowDataController {
|
||||
final String rowId;
|
||||
VoidCallback? _onRowChangedListener;
|
||||
final GridFieldCache _fieldCache;
|
||||
final GridRowCache _rowCache;
|
||||
|
||||
GridFieldCache get fieldCache => _fieldCache;
|
||||
|
||||
GridRowCache get rowCache => _rowCache;
|
||||
|
||||
GridRowDataController({
|
||||
required this.rowId,
|
||||
required GridFieldCache fieldCache,
|
||||
required GridRowCache rowCache,
|
||||
}) : _fieldCache = fieldCache,
|
||||
_rowCache = rowCache;
|
||||
|
||||
GridCellMap loadData() {
|
||||
return _rowCache.loadGridCells(rowId);
|
||||
}
|
||||
|
||||
void addListener({OnRowChanged? onRowChanged}) {
|
||||
_onRowChangedListener = _rowCache.addListener(
|
||||
rowId: rowId,
|
||||
onCellUpdated: onRowChanged,
|
||||
);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (_onRowChangedListener != null) {
|
||||
_rowCache.removeRowListener(_onRowChangedListener!);
|
||||
}
|
||||
}
|
||||
}
|
@ -158,7 +158,7 @@ class GridRowCache {
|
||||
void Function(GridCellMap, GridRowChangeReason)? onCellUpdated,
|
||||
bool Function()? listenWhen,
|
||||
}) {
|
||||
listenrHandler() async {
|
||||
listenerHandler() async {
|
||||
if (listenWhen != null && listenWhen() == false) {
|
||||
return;
|
||||
}
|
||||
@ -181,8 +181,8 @@ class GridRowCache {
|
||||
);
|
||||
}
|
||||
|
||||
_rowChangeReasonNotifier.addListener(listenrHandler);
|
||||
return listenrHandler;
|
||||
_rowChangeReasonNotifier.addListener(listenerHandler);
|
||||
return listenerHandler;
|
||||
}
|
||||
|
||||
void removeRowListener(VoidCallback callback) {
|
||||
|
@ -2,19 +2,20 @@ import 'package:flutter/material.dart';
|
||||
import 'package:linked_scroll_controller/linked_scroll_controller.dart';
|
||||
|
||||
class GridScrollController {
|
||||
final LinkedScrollControllerGroup _scrollGroupContorller;
|
||||
final LinkedScrollControllerGroup _scrollGroupController;
|
||||
final ScrollController verticalController;
|
||||
final ScrollController horizontalController;
|
||||
|
||||
final List<ScrollController> _linkHorizontalControllers = [];
|
||||
|
||||
GridScrollController({required LinkedScrollControllerGroup scrollGroupContorller})
|
||||
: _scrollGroupContorller = scrollGroupContorller,
|
||||
GridScrollController(
|
||||
{required LinkedScrollControllerGroup scrollGroupController})
|
||||
: _scrollGroupController = scrollGroupController,
|
||||
verticalController = ScrollController(),
|
||||
horizontalController = scrollGroupContorller.addAndGet();
|
||||
horizontalController = scrollGroupController.addAndGet();
|
||||
|
||||
ScrollController linkHorizontalController() {
|
||||
final controller = _scrollGroupContorller.addAndGet();
|
||||
final controller = _scrollGroupController.addAndGet();
|
||||
_linkHorizontalControllers.add(controller);
|
||||
return controller;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/plugins/grid/application/row/row_data_controller.dart';
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/grid_bloc.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
|
||||
@ -79,7 +80,7 @@ class FlowyGrid extends StatefulWidget {
|
||||
|
||||
class _FlowyGridState extends State<FlowyGrid> {
|
||||
final _scrollController = GridScrollController(
|
||||
scrollGroupContorller: LinkedScrollControllerGroup());
|
||||
scrollGroupController: LinkedScrollControllerGroup());
|
||||
late ScrollController headerScrollController;
|
||||
|
||||
@override
|
||||
@ -153,7 +154,7 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
}
|
||||
|
||||
Widget _gridHeader(BuildContext context, String gridId) {
|
||||
final fieldCache = context.read<GridBloc>().fieldCache;
|
||||
final fieldCache = context.read<GridBloc>().dataController.fieldCache;
|
||||
return GridHeaderSliverAdaptor(
|
||||
gridId: gridId,
|
||||
fieldCache: fieldCache,
|
||||
@ -169,7 +170,7 @@ class _GridToolbarAdaptor extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocSelector<GridBloc, GridState, GridToolbarContext>(
|
||||
selector: (state) {
|
||||
final fieldCache = context.read<GridBloc>().fieldCache;
|
||||
final fieldCache = context.read<GridBloc>().dataController.fieldCache;
|
||||
return GridToolbarContext(
|
||||
gridId: state.gridId,
|
||||
fieldCache: fieldCache,
|
||||
@ -237,14 +238,20 @@ class _GridRowsState extends State<_GridRows> {
|
||||
) {
|
||||
final rowCache =
|
||||
context.read<GridBloc>().getRowCache(rowInfo.blockId, rowInfo.id);
|
||||
final fieldCache = context.read<GridBloc>().fieldCache;
|
||||
|
||||
final fieldCache = context.read<GridBloc>().dataController.fieldCache;
|
||||
if (rowCache != null) {
|
||||
final dataController = GridRowDataController(
|
||||
rowId: rowInfo.id,
|
||||
fieldCache: fieldCache,
|
||||
rowCache: rowCache,
|
||||
);
|
||||
|
||||
return SizeTransition(
|
||||
sizeFactor: animation,
|
||||
child: GridRowWidget(
|
||||
rowData: rowInfo,
|
||||
rowCache: rowCache,
|
||||
fieldCache: fieldCache,
|
||||
dataController: dataController,
|
||||
key: ValueKey(rowInfo.id),
|
||||
),
|
||||
);
|
||||
|
@ -27,39 +27,49 @@ class GridCellBuilder {
|
||||
cellCache: cellCache,
|
||||
fieldCache: fieldCache,
|
||||
);
|
||||
|
||||
final key = cell.key();
|
||||
switch (cell.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return GridCheckboxCell(
|
||||
cellControllerBuilder: cellControllerBuilder, key: key);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
return GridDateCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
style: style);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
style: style,
|
||||
);
|
||||
case FieldType.SingleSelect:
|
||||
return GridSingleSelectCell(
|
||||
cellContorllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.MultiSelect:
|
||||
return GridMultiSelectCell(
|
||||
cellContorllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.Number:
|
||||
return GridNumberCell(
|
||||
cellContorllerBuilder: cellControllerBuilder, key: key);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.RichText:
|
||||
return GridTextCell(
|
||||
cellContorllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
case FieldType.URL:
|
||||
return GridURLCell(
|
||||
cellContorllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key);
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
style: style,
|
||||
key: key,
|
||||
);
|
||||
}
|
||||
throw UnimplementedError;
|
||||
}
|
||||
@ -93,7 +103,7 @@ abstract class GridCellWidget extends StatefulWidget
|
||||
@override
|
||||
final ValueNotifier<bool> onCellFocus = ValueNotifier<bool>(false);
|
||||
|
||||
// When the cell is focused, we assume that the accessory alse be hovered.
|
||||
// When the cell is focused, we assume that the accessory also be hovered.
|
||||
@override
|
||||
ValueNotifier<bool> get onAccessoryHover => onCellFocus;
|
||||
|
||||
@ -150,7 +160,7 @@ abstract class GridCellState<T extends GridCellWidget> extends State<T> {
|
||||
|
||||
abstract class GridFocusNodeCellState<T extends GridCellWidget>
|
||||
extends GridCellState<T> {
|
||||
SingleListenrFocusNode focusNode = SingleListenrFocusNode();
|
||||
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -219,7 +229,7 @@ class GridCellFocusListener extends ChangeNotifier {
|
||||
|
||||
abstract class GridCellStyle {}
|
||||
|
||||
class SingleListenrFocusNode extends FocusNode {
|
||||
class SingleListenerFocusNode extends FocusNode {
|
||||
VoidCallback? _listener;
|
||||
|
||||
void setListener(VoidCallback listener) {
|
||||
|
@ -7,10 +7,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'cell_builder.dart';
|
||||
|
||||
class GridNumberCell extends GridCellWidget {
|
||||
final GridCellControllerBuilder cellContorllerBuilder;
|
||||
final GridCellControllerBuilder cellControllerBuilder;
|
||||
|
||||
GridNumberCell({
|
||||
required this.cellContorllerBuilder,
|
||||
required this.cellControllerBuilder,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -25,7 +25,7 @@ class _NumberCellState extends GridFocusNodeCellState<GridNumberCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
final cellContext = widget.cellContorllerBuilder.build();
|
||||
final cellContext = widget.cellControllerBuilder.build();
|
||||
_cellBloc = getIt<NumberCellBloc>(param1: cellContext)
|
||||
..add(const NumberCellEvent.initial());
|
||||
_controller =
|
||||
|
@ -22,11 +22,11 @@ class SelectOptionCellStyle extends GridCellStyle {
|
||||
}
|
||||
|
||||
class GridSingleSelectCell extends GridCellWidget {
|
||||
final GridCellControllerBuilder cellContorllerBuilder;
|
||||
final GridCellControllerBuilder cellControllerBuilder;
|
||||
late final SelectOptionCellStyle? cellStyle;
|
||||
|
||||
GridSingleSelectCell({
|
||||
required this.cellContorllerBuilder,
|
||||
required this.cellControllerBuilder,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key) {
|
||||
@ -47,7 +47,7 @@ class _SingleSelectCellState extends State<GridSingleSelectCell> {
|
||||
@override
|
||||
void initState() {
|
||||
final cellContext =
|
||||
widget.cellContorllerBuilder.build() as GridSelectOptionCellController;
|
||||
widget.cellControllerBuilder.build() as GridSelectOptionCellController;
|
||||
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellContext)
|
||||
..add(const SelectOptionCellEvent.initial());
|
||||
super.initState();
|
||||
@ -63,7 +63,7 @@ class _SingleSelectCellState extends State<GridSingleSelectCell> {
|
||||
selectOptions: state.selectedOptions,
|
||||
cellStyle: widget.cellStyle,
|
||||
onFocus: (value) => widget.onCellEditing.value = value,
|
||||
cellContorllerBuilder: widget.cellContorllerBuilder);
|
||||
cellControllerBuilder: widget.cellControllerBuilder);
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -78,11 +78,11 @@ class _SingleSelectCellState extends State<GridSingleSelectCell> {
|
||||
|
||||
//----------------------------------------------------------------
|
||||
class GridMultiSelectCell extends GridCellWidget {
|
||||
final GridCellControllerBuilder cellContorllerBuilder;
|
||||
final GridCellControllerBuilder cellControllerBuilder;
|
||||
late final SelectOptionCellStyle? cellStyle;
|
||||
|
||||
GridMultiSelectCell({
|
||||
required this.cellContorllerBuilder,
|
||||
required this.cellControllerBuilder,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key) {
|
||||
@ -103,7 +103,7 @@ class _MultiSelectCellState extends State<GridMultiSelectCell> {
|
||||
@override
|
||||
void initState() {
|
||||
final cellContext =
|
||||
widget.cellContorllerBuilder.build() as GridSelectOptionCellController;
|
||||
widget.cellControllerBuilder.build() as GridSelectOptionCellController;
|
||||
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellContext)
|
||||
..add(const SelectOptionCellEvent.initial());
|
||||
super.initState();
|
||||
@ -119,7 +119,7 @@ class _MultiSelectCellState extends State<GridMultiSelectCell> {
|
||||
selectOptions: state.selectedOptions,
|
||||
cellStyle: widget.cellStyle,
|
||||
onFocus: (value) => widget.onCellEditing.value = value,
|
||||
cellContorllerBuilder: widget.cellContorllerBuilder);
|
||||
cellControllerBuilder: widget.cellControllerBuilder);
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -136,12 +136,12 @@ class _SelectOptionCell extends StatelessWidget {
|
||||
final List<SelectOptionPB> selectOptions;
|
||||
final void Function(bool) onFocus;
|
||||
final SelectOptionCellStyle? cellStyle;
|
||||
final GridCellControllerBuilder cellContorllerBuilder;
|
||||
final GridCellControllerBuilder cellControllerBuilder;
|
||||
const _SelectOptionCell({
|
||||
required this.selectOptions,
|
||||
required this.onFocus,
|
||||
required this.cellStyle,
|
||||
required this.cellContorllerBuilder,
|
||||
required this.cellControllerBuilder,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -179,7 +179,7 @@ class _SelectOptionCell extends StatelessWidget {
|
||||
onTap: () {
|
||||
onFocus(true);
|
||||
final cellContext =
|
||||
cellContorllerBuilder.build() as GridSelectOptionCellController;
|
||||
cellControllerBuilder.build() as GridSelectOptionCellController;
|
||||
SelectOptionCellEditor.show(
|
||||
context, cellContext, () => onFocus(false));
|
||||
},
|
||||
|
@ -14,10 +14,10 @@ class GridTextCellStyle extends GridCellStyle {
|
||||
}
|
||||
|
||||
class GridTextCell extends GridCellWidget {
|
||||
final GridCellControllerBuilder cellContorllerBuilder;
|
||||
final GridCellControllerBuilder cellControllerBuilder;
|
||||
late final GridTextCellStyle? cellStyle;
|
||||
GridTextCell({
|
||||
required this.cellContorllerBuilder,
|
||||
required this.cellControllerBuilder,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key) {
|
||||
@ -39,7 +39,7 @@ class _GridTextCellState extends GridFocusNodeCellState<GridTextCell> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
final cellContext = widget.cellContorllerBuilder.build();
|
||||
final cellContext = widget.cellControllerBuilder.build();
|
||||
_cellBloc = getIt<TextCellBloc>(param1: cellContext);
|
||||
_cellBloc.add(const TextCellEvent.initial());
|
||||
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||
|
@ -31,10 +31,10 @@ enum GridURLCellAccessoryType {
|
||||
}
|
||||
|
||||
class GridURLCell extends GridCellWidget {
|
||||
final GridCellControllerBuilder cellContorllerBuilder;
|
||||
final GridCellControllerBuilder cellControllerBuilder;
|
||||
late final GridURLCellStyle? cellStyle;
|
||||
GridURLCell({
|
||||
required this.cellContorllerBuilder,
|
||||
required this.cellControllerBuilder,
|
||||
GridCellStyle? style,
|
||||
Key? key,
|
||||
}) : super(key: key) {
|
||||
@ -53,14 +53,14 @@ class GridURLCell extends GridCellWidget {
|
||||
switch (ty) {
|
||||
case GridURLCellAccessoryType.edit:
|
||||
final cellContext =
|
||||
cellContorllerBuilder.build() as GridURLCellController;
|
||||
cellControllerBuilder.build() as GridURLCellController;
|
||||
return _EditURLAccessory(
|
||||
cellContext: cellContext,
|
||||
anchorContext: buildContext.anchorContext);
|
||||
|
||||
case GridURLCellAccessoryType.copyURL:
|
||||
final cellContext =
|
||||
cellContorllerBuilder.build() as GridURLCellController;
|
||||
cellControllerBuilder.build() as GridURLCellController;
|
||||
return _CopyURLAccessory(cellContext: cellContext);
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
||||
@override
|
||||
void initState() {
|
||||
final cellContext =
|
||||
widget.cellContorllerBuilder.build() as GridURLCellController;
|
||||
widget.cellControllerBuilder.build() as GridURLCellController;
|
||||
_cellBloc = URLCellBloc(cellContext: cellContext);
|
||||
_cellBloc.add(const URLCellEvent.initial());
|
||||
super.initState();
|
||||
@ -141,7 +141,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
||||
await launchUrl(uri);
|
||||
} else {
|
||||
final cellContext =
|
||||
widget.cellContorllerBuilder.build() as GridURLCellController;
|
||||
widget.cellControllerBuilder.build() as GridURLCellController;
|
||||
widget.onCellEditing.value = true;
|
||||
URLCellEditor.show(context, cellContext, () {
|
||||
widget.onCellEditing.value = false;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:app_flowy/plugins/grid/application/prelude.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/row/row_data_controller.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
@ -9,24 +10,23 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import '../../layout/sizes.dart';
|
||||
import '../cell/cell_accessory.dart';
|
||||
import '../cell/cell_cotainer.dart';
|
||||
import '../cell/cell_container.dart';
|
||||
import '../cell/prelude.dart';
|
||||
import 'row_action_sheet.dart';
|
||||
import 'row_detail.dart';
|
||||
|
||||
class GridRowWidget extends StatefulWidget {
|
||||
final GridRowInfo rowData;
|
||||
final GridRowCache rowCache;
|
||||
final GridRowDataController dataController;
|
||||
final GridCellBuilder cellBuilder;
|
||||
|
||||
GridRowWidget({
|
||||
required this.rowData,
|
||||
required this.rowCache,
|
||||
required GridFieldCache fieldCache,
|
||||
required this.dataController,
|
||||
Key? key,
|
||||
}) : cellBuilder = GridCellBuilder(
|
||||
cellCache: rowCache.cellCache,
|
||||
fieldCache: fieldCache,
|
||||
cellCache: dataController.rowCache.cellCache,
|
||||
fieldCache: dataController.fieldCache,
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
@ -41,7 +41,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
||||
void initState() {
|
||||
_rowBloc = RowBloc(
|
||||
rowInfo: widget.rowData,
|
||||
rowCache: widget.rowCache,
|
||||
dataController: widget.dataController,
|
||||
);
|
||||
_rowBloc.add(const RowEvent.initial());
|
||||
super.initState();
|
||||
@ -81,7 +81,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
||||
void _expandRow(BuildContext context) {
|
||||
final page = RowDetailPage(
|
||||
rowInfo: widget.rowData,
|
||||
rowCache: widget.rowCache,
|
||||
rowCache: widget.dataController.rowCache,
|
||||
cellBuilder: widget.cellBuilder,
|
||||
);
|
||||
page.show(context);
|
||||
|
@ -62,8 +62,10 @@ class _RowDetailPageState extends State<RowDetailPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) {
|
||||
final bloc =
|
||||
RowDetailBloc(rowInfo: widget.rowInfo, rowCache: widget.rowCache);
|
||||
final bloc = RowDetailBloc(
|
||||
rowInfo: widget.rowInfo,
|
||||
rowCache: widget.rowCache,
|
||||
);
|
||||
bloc.add(const RowDetailEvent.initial());
|
||||
return bloc;
|
||||
},
|
||||
|
@ -164,18 +164,11 @@ pub struct CreateFieldPayloadPB {
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_type: FieldType,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub create_if_not_exist: bool,
|
||||
}
|
||||
|
||||
pub struct CreateFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_id: String,
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
@ -184,10 +177,8 @@ impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
|
||||
|
||||
fn try_into(self) -> Result<CreateFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
Ok(CreateFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_id: field_id.0,
|
||||
field_type: self.field_type,
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user