mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: config cells
This commit is contained in:
parent
321682717c
commit
fe8811392b
@ -110,6 +110,46 @@ class HomeDepsResolver {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<TextCellBloc, Field, Cell?>(
|
||||||
|
(field, cell) => TextCellBloc(
|
||||||
|
field: field,
|
||||||
|
cell: cell,
|
||||||
|
service: CellService(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<SelectionCellBloc, Field, Cell?>(
|
||||||
|
(field, cell) => SelectionCellBloc(
|
||||||
|
field: field,
|
||||||
|
cell: cell,
|
||||||
|
service: CellService(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<NumberCellBloc, Field, Cell?>(
|
||||||
|
(field, cell) => NumberCellBloc(
|
||||||
|
field: field,
|
||||||
|
cell: cell,
|
||||||
|
service: CellService(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<DateCellBloc, Field, Cell?>(
|
||||||
|
(field, cell) => DateCellBloc(
|
||||||
|
field: field,
|
||||||
|
cell: cell,
|
||||||
|
service: CellService(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<CheckboxCellBloc, Field, Cell?>(
|
||||||
|
(field, cell) => CheckboxCellBloc(
|
||||||
|
field: field,
|
||||||
|
cell: cell,
|
||||||
|
service: CellService(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// trash
|
// trash
|
||||||
getIt.registerLazySingleton<TrashService>(() => TrashService());
|
getIt.registerLazySingleton<TrashService>(() => TrashService());
|
||||||
getIt.registerLazySingleton<TrashListener>(() => TrashListener());
|
getIt.registerLazySingleton<TrashListener>(() => TrashListener());
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
class CellService {}
|
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'cell_service.dart';
|
||||||
|
|
||||||
|
part 'checkbox_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
final CellService service;
|
||||||
|
|
||||||
|
CheckboxCellBloc({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
required this.service,
|
||||||
|
}) : super(CheckboxCellState.initial(cell)) {
|
||||||
|
on<CheckboxCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class CheckboxCellEvent with _$CheckboxCellEvent {
|
||||||
|
const factory CheckboxCellEvent.initial() = _InitialCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class CheckboxCellState with _$CheckboxCellState {
|
||||||
|
const factory CheckboxCellState({
|
||||||
|
required Cell? cell,
|
||||||
|
}) = _CheckboxCellState;
|
||||||
|
|
||||||
|
factory CheckboxCellState.initial(Cell? cell) => CheckboxCellState(cell: cell);
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'cell_service.dart';
|
||||||
|
|
||||||
|
part 'date_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
final CellService service;
|
||||||
|
|
||||||
|
DateCellBloc({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
required this.service,
|
||||||
|
}) : super(DateCellState.initial(cell)) {
|
||||||
|
on<DateCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class DateCellEvent with _$DateCellEvent {
|
||||||
|
const factory DateCellEvent.initial() = _InitialCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class DateCellState with _$DateCellState {
|
||||||
|
const factory DateCellState({
|
||||||
|
required Cell? cell,
|
||||||
|
}) = _DateCellState;
|
||||||
|
|
||||||
|
factory DateCellState.initial(Cell? cell) => DateCellState(cell: cell);
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'cell_service.dart';
|
||||||
|
|
||||||
|
part 'number_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
final CellService service;
|
||||||
|
|
||||||
|
NumberCellBloc({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
required this.service,
|
||||||
|
}) : super(NumberCellState.initial(cell)) {
|
||||||
|
on<NumberCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class NumberCellEvent with _$NumberCellEvent {
|
||||||
|
const factory NumberCellEvent.initial() = _InitialCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class NumberCellState with _$NumberCellState {
|
||||||
|
const factory NumberCellState({
|
||||||
|
required Cell? cell,
|
||||||
|
}) = _NumberCellState;
|
||||||
|
|
||||||
|
factory NumberCellState.initial(Cell? cell) => NumberCellState(cell: cell);
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'cell_service.dart';
|
||||||
|
|
||||||
|
part 'selection_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
final CellService service;
|
||||||
|
|
||||||
|
SelectionCellBloc({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
required this.service,
|
||||||
|
}) : super(SelectionCellState.initial(cell)) {
|
||||||
|
on<SelectionCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class SelectionCellEvent with _$SelectionCellEvent {
|
||||||
|
const factory SelectionCellEvent.initial() = _InitialCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class SelectionCellState with _$SelectionCellState {
|
||||||
|
const factory SelectionCellState({
|
||||||
|
required Cell? cell,
|
||||||
|
}) = _SelectionCellState;
|
||||||
|
|
||||||
|
factory SelectionCellState.initial(Cell? cell) => SelectionCellState(cell: cell);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'cell_service.dart';
|
||||||
|
|
||||||
|
part 'text_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
final CellService service;
|
||||||
|
|
||||||
|
TextCellBloc({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
required this.service,
|
||||||
|
}) : super(TextCellState.initial(cell?.content ?? "")) {
|
||||||
|
on<TextCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {},
|
||||||
|
updateText: (_UpdateText value) {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class TextCellEvent with _$TextCellEvent {
|
||||||
|
const factory TextCellEvent.initial() = _InitialCell;
|
||||||
|
const factory TextCellEvent.updateText(String text) = _UpdateText;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class TextCellState with _$TextCellState {
|
||||||
|
const factory TextCellState({
|
||||||
|
required String content,
|
||||||
|
}) = _TextCellState;
|
||||||
|
|
||||||
|
factory TextCellState.initial(String content) => TextCellState(content: content);
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'column_service.dart';
|
import 'column_service.dart';
|
||||||
import 'data.dart';
|
import 'data.dart';
|
||||||
|
@ -5,3 +5,9 @@ export 'grid_service.dart';
|
|||||||
export 'data.dart';
|
export 'data.dart';
|
||||||
export 'column_service.dart';
|
export 'column_service.dart';
|
||||||
export 'column_bloc.dart';
|
export 'column_bloc.dart';
|
||||||
|
export 'cell_bloc/text_cell_bloc.dart';
|
||||||
|
export 'cell_bloc/number_cell_bloc.dart';
|
||||||
|
export 'cell_bloc/selection_cell_bloc.dart';
|
||||||
|
export 'cell_bloc/date_cell_bloc.dart';
|
||||||
|
export 'cell_bloc/checkbox_cell_bloc.dart';
|
||||||
|
export 'cell_bloc/cell_service.dart';
|
||||||
|
@ -34,7 +34,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
|||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
abstract class RowEvent with _$RowEvent {
|
abstract class RowEvent with _$RowEvent {
|
||||||
const factory RowEvent.initial(GridRowData data) = _InitialRow;
|
const factory RowEvent.initial() = _InitialRow;
|
||||||
const factory RowEvent.createRow() = _CreateRow;
|
const factory RowEvent.createRow() = _CreateRow;
|
||||||
const factory RowEvent.activeRow() = _ActiveRow;
|
const factory RowEvent.activeRow() = _ActiveRow;
|
||||||
const factory RowEvent.disactiveRow() = _DisactiveRow;
|
const factory RowEvent.disactiveRow() = _DisactiveRow;
|
||||||
|
@ -141,6 +141,7 @@ class _DocumentLeftBarItemState extends State<DocumentLeftBarItem> {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
|
_focusNode.removeListener(_handleFocusChanged);
|
||||||
_focusNode.dispose();
|
_focusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ class GridSize {
|
|||||||
static double get trailHeaderPadding => 140 * scale;
|
static double get trailHeaderPadding => 140 * scale;
|
||||||
static double get headerContentPadding => 8 * scale;
|
static double get headerContentPadding => 8 * scale;
|
||||||
static double get cellContentPadding => 8 * scale;
|
static double get cellContentPadding => 8 * scale;
|
||||||
|
|
||||||
//
|
//
|
||||||
static EdgeInsets get headerContentInsets => EdgeInsets.symmetric(
|
static EdgeInsets get headerContentInsets => EdgeInsets.symmetric(
|
||||||
horizontal: GridSize.headerContentPadding,
|
horizontal: GridSize.headerContentPadding,
|
||||||
|
@ -1,17 +1,35 @@
|
|||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
import 'grid_cell.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'checkbox_cell.dart';
|
||||||
class GridCellBuilder {
|
import 'date_cell.dart';
|
||||||
static GridCellWidget buildCell(Field? field, Cell? cell) {
|
import 'number_cell.dart';
|
||||||
if (field == null || cell == null) {
|
import 'selection_cell.dart';
|
||||||
return GridTextCell("123123123");
|
import 'text_cell.dart';
|
||||||
}
|
|
||||||
|
|
||||||
|
Widget buildGridCell(Field field, Cell? cell) {
|
||||||
switch (field.fieldType) {
|
switch (field.fieldType) {
|
||||||
|
case FieldType.Checkbox:
|
||||||
|
return CheckboxCell(field: field, cell: cell);
|
||||||
|
case FieldType.DateTime:
|
||||||
|
return DateCell(field: field, cell: cell);
|
||||||
|
case FieldType.MultiSelect:
|
||||||
|
return MultiSelectCell(field: field, cell: cell);
|
||||||
|
case FieldType.Number:
|
||||||
|
return NumberCell(field: field, cell: cell);
|
||||||
case FieldType.RichText:
|
case FieldType.RichText:
|
||||||
return GridTextCell(cell.content);
|
return GridTextCell(field: field, cell: cell);
|
||||||
|
case FieldType.SingleSelect:
|
||||||
|
return SingleSelectCell(field: field, cell: cell);
|
||||||
default:
|
default:
|
||||||
return const BlankCell();
|
return const BlankCell();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BlankCell extends StatelessWidget {
|
||||||
|
const BlankCell({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
class CheckboxCell extends StatefulWidget {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
|
||||||
|
const CheckboxCell({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CheckboxCell> createState() => _CheckboxCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CheckboxCellState extends State<CheckboxCell> {
|
||||||
|
late CheckboxCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<CheckboxCellBloc>(param1: widget.field, param2: widget.cell);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: _cellBloc,
|
||||||
|
child: BlocBuilder<CheckboxCellBloc, CheckboxCellState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/cell_bloc/date_cell_bloc.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
class DateCell extends StatefulWidget {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
|
||||||
|
const DateCell({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DateCell> createState() => _DateCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DateCellState extends State<DateCell> {
|
||||||
|
late DateCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<DateCellBloc>(param1: widget.field, param2: widget.cell);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: _cellBloc,
|
||||||
|
child: BlocBuilder<DateCellBloc, DateCellState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -1,80 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
/// The interface of base cell.
|
|
||||||
abstract class GridCellWidget extends StatelessWidget {
|
|
||||||
final canSelect = true;
|
|
||||||
|
|
||||||
const GridCellWidget({Key? key}) : super(key: key);
|
|
||||||
}
|
|
||||||
|
|
||||||
class GridTextCell extends GridCellWidget {
|
|
||||||
late final TextEditingController _controller;
|
|
||||||
|
|
||||||
GridTextCell(String content, {Key? key}) : super(key: key) {
|
|
||||||
_controller = TextEditingController(text: content);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return TextField(
|
|
||||||
controller: _controller,
|
|
||||||
onChanged: (value) {},
|
|
||||||
maxLines: 1,
|
|
||||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
border: InputBorder.none,
|
|
||||||
isDense: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DateCell extends GridCellWidget {
|
|
||||||
final String content;
|
|
||||||
const DateCell(this.content, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Text(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumberCell extends GridCellWidget {
|
|
||||||
final String content;
|
|
||||||
const NumberCell(this.content, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Text(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SingleSelectCell extends GridCellWidget {
|
|
||||||
final String content;
|
|
||||||
const SingleSelectCell(this.content, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Text(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MultiSelectCell extends GridCellWidget {
|
|
||||||
final String content;
|
|
||||||
const MultiSelectCell(this.content, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Text(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BlankCell extends GridCellWidget {
|
|
||||||
const BlankCell({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,7 +22,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_rowBloc = getIt<RowBloc>(param1: widget.data);
|
_rowBloc = getIt<RowBloc>(param1: widget.data)..add(const RowEvent.initial());
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
_rowBloc.close();
|
await _rowBloc.close();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
|||||||
final cellData = state.data.cellMap[field.id];
|
final cellData = state.data.cellMap[field.id];
|
||||||
return CellContainer(
|
return CellContainer(
|
||||||
width: field.width.toDouble(),
|
width: field.width.toDouble(),
|
||||||
child: GridCellBuilder.buildCell(field, cellData),
|
child: buildGridCell(field, cellData),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).toList(),
|
).toList(),
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/cell_bloc/number_cell_bloc.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
class NumberCell extends StatefulWidget {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
|
||||||
|
const NumberCell({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NumberCell> createState() => _NumberCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NumberCellState extends State<NumberCell> {
|
||||||
|
late NumberCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<NumberCellBloc>(param1: widget.field, param2: widget.cell);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: _cellBloc,
|
||||||
|
child: BlocBuilder<NumberCellBloc, NumberCellState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SingleSelectCell extends StatefulWidget {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
|
||||||
|
const SingleSelectCell({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SingleSelectCell> createState() => _SingleSelectCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||||
|
late SelectionCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<SelectionCellBloc>(param1: widget.field, param2: widget.cell);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
class MultiSelectCell extends StatefulWidget {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
|
||||||
|
const MultiSelectCell({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MultiSelectCell> createState() => _MultiSelectCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MultiSelectCellState extends State<MultiSelectCell> {
|
||||||
|
late SelectionCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<SelectionCellBloc>(param1: widget.field, param2: widget.cell);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/cell_bloc/text_cell_bloc.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
/// The interface of base cell.
|
||||||
|
|
||||||
|
class GridTextCell extends StatefulWidget {
|
||||||
|
final Field field;
|
||||||
|
final Cell? cell;
|
||||||
|
|
||||||
|
const GridTextCell({
|
||||||
|
required this.field,
|
||||||
|
required this.cell,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GridTextCell> createState() => _GridTextCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GridTextCellState extends State<GridTextCell> {
|
||||||
|
late TextEditingController _controller;
|
||||||
|
final _focusNode = FocusNode();
|
||||||
|
late TextCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<TextCellBloc>(param1: widget.field, param2: widget.cell);
|
||||||
|
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||||
|
_focusNode.addListener(_focusChanged);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: _cellBloc,
|
||||||
|
child: BlocBuilder<TextCellBloc, TextCellState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return TextField(
|
||||||
|
controller: _controller,
|
||||||
|
focusNode: _focusNode,
|
||||||
|
onChanged: (value) {},
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _cellBloc.close();
|
||||||
|
_focusNode.removeListener(_focusChanged);
|
||||||
|
_focusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _focusChanged() {
|
||||||
|
_cellBloc.add(TextCellEvent.updateText(_controller.text));
|
||||||
|
}
|
||||||
|
}
|
@ -43,7 +43,7 @@ class GridHeader extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => getIt<ColumnBloc>(param1: fields),
|
create: (context) => getIt<ColumnBloc>(param1: fields)..add(const ColumnEvent.initial()),
|
||||||
child: BlocBuilder<ColumnBloc, ColumnState>(
|
child: BlocBuilder<ColumnBloc, ColumnState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final headers = state.fields
|
final headers = state.fields
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::manager::GridManager;
|
use crate::manager::GridManager;
|
||||||
use flowy_error::FlowyError;
|
use flowy_error::FlowyError;
|
||||||
use flowy_grid_data_model::entities::{Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedRow};
|
use flowy_grid_data_model::entities::{
|
||||||
|
Cell, Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedRow,
|
||||||
|
};
|
||||||
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -47,3 +49,14 @@ pub(crate) async fn create_row_handler(
|
|||||||
let _ = editor.create_empty_row().await?;
|
let _ = editor.create_empty_row().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||||
|
pub(crate) async fn update_cell_handler(
|
||||||
|
data: Data<Cell>,
|
||||||
|
manager: AppData<Arc<GridManager>>,
|
||||||
|
) -> Result<(), FlowyError> {
|
||||||
|
let cell: Cell = data.into_inner();
|
||||||
|
let editor = manager.get_grid_editor(id.as_ref())?;
|
||||||
|
let _ = editor.create_empty_row().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -11,7 +11,8 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
|
|||||||
.event(GridEvent::GetGridData, get_grid_data_handler)
|
.event(GridEvent::GetGridData, get_grid_data_handler)
|
||||||
.event(GridEvent::GetRows, get_rows_handler)
|
.event(GridEvent::GetRows, get_rows_handler)
|
||||||
.event(GridEvent::GetFields, get_fields_handler)
|
.event(GridEvent::GetFields, get_fields_handler)
|
||||||
.event(GridEvent::CreateRow, create_row_handler);
|
.event(GridEvent::CreateRow, create_row_handler)
|
||||||
|
.event(GridEvent::UpdateCell, update_cell_handler);
|
||||||
|
|
||||||
module
|
module
|
||||||
}
|
}
|
||||||
@ -30,4 +31,7 @@ pub enum GridEvent {
|
|||||||
|
|
||||||
#[event(input = "GridId")]
|
#[event(input = "GridId")]
|
||||||
CreateRow = 3,
|
CreateRow = 3,
|
||||||
|
|
||||||
|
#[event(input = "Cell")]
|
||||||
|
UpdateCell = 4,
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use lib_infra::future::FutureResult;
|
|||||||
use lib_infra::uuid;
|
use lib_infra::uuid;
|
||||||
use lib_ot::core::PlainTextAttributes;
|
use lib_ot::core::PlainTextAttributes;
|
||||||
|
|
||||||
|
use dashmap::mapref::one::Ref;
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -28,6 +29,7 @@ pub struct ClientGridEditor {
|
|||||||
kv_persistence: Arc<GridKVPersistence>,
|
kv_persistence: Arc<GridKVPersistence>,
|
||||||
|
|
||||||
field_map: DashMap<String, Field>,
|
field_map: DashMap<String, Field>,
|
||||||
|
cell_map: DashMap<String, RawCell>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientGridEditor {
|
impl ClientGridEditor {
|
||||||
@ -44,6 +46,7 @@ impl ClientGridEditor {
|
|||||||
let rev_manager = Arc::new(rev_manager);
|
let rev_manager = Arc::new(rev_manager);
|
||||||
let field_map = load_all_fields(&grid_pad, &kv_persistence).await?;
|
let field_map = load_all_fields(&grid_pad, &kv_persistence).await?;
|
||||||
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
||||||
|
let cell_map = DashMap::new();
|
||||||
|
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
grid_id: grid_id.to_owned(),
|
grid_id: grid_id.to_owned(),
|
||||||
@ -52,17 +55,20 @@ impl ClientGridEditor {
|
|||||||
rev_manager,
|
rev_manager,
|
||||||
kv_persistence,
|
kv_persistence,
|
||||||
field_map,
|
field_map,
|
||||||
|
cell_map,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_empty_row(&self) -> FlowyResult<()> {
|
pub async fn create_empty_row(&self) -> FlowyResult<()> {
|
||||||
let row = RawRow::new(&uuid(), &self.grid_id, vec![]);
|
let row = RawRow::new(&uuid(), &self.grid_id, vec![]);
|
||||||
|
self.cell_map.insert(row.id.clone(), row.clone());
|
||||||
self.create_row(row).await?;
|
self.create_row(row).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
|
async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
|
||||||
let _ = self.modify(|grid| Ok(grid.create_row(&row)?)).await?;
|
let _ = self.modify(|grid| Ok(grid.create_row(&row)?)).await?;
|
||||||
|
self.cell_map.insert(row.id.clone(), row.clone());
|
||||||
let _ = self.kv_persistence.set(row)?;
|
let _ = self.kv_persistence.set(row)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -73,6 +79,13 @@ impl ClientGridEditor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub async fn update_row(&self, cell: Cell) -> FlowyResult<()> {
|
||||||
|
// match self.cell_map.get(&cell.id) {
|
||||||
|
// None => Err(FlowyError::internal().context(format!("Can't find cell with id: {}", cell.id))),
|
||||||
|
// Some(raw_cell) => {}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub async fn create_field(&mut self, field: Field) -> FlowyResult<()> {
|
pub async fn create_field(&mut self, field: Field) -> FlowyResult<()> {
|
||||||
let _ = self.modify(|grid| Ok(grid.create_field(&field)?)).await?;
|
let _ = self.modify(|grid| Ok(grid.create_field(&field)?)).await?;
|
||||||
let _ = self.kv_persistence.set(field)?;
|
let _ = self.kv_persistence.set(field)?;
|
||||||
@ -99,6 +112,7 @@ impl ClientGridEditor {
|
|||||||
tracing::error!("Can't find the field with {}", field_id);
|
tracing::error!("Can't find the field with {}", field_id);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone());
|
||||||
|
|
||||||
let field = some_field.unwrap();
|
let field = some_field.unwrap();
|
||||||
match stringify_deserialize(raw_cell.data, field.value()) {
|
match stringify_deserialize(raw_cell.data, field.value()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user