appflowy 3 rokov pred
rodič
commit
fe8811392b
24 zmenil súbory, kde vykonal 635 pridanie a 100 odobranie
  1. 40 0
      frontend/app_flowy/lib/startup/home_deps_resolver.dart
  2. 1 0
      frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_service.dart
  3. 46 0
      frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart
  4. 46 0
      frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart
  5. 46 0
      frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart
  6. 46 0
      frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart
  7. 48 0
      frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart
  8. 0 1
      frontend/app_flowy/lib/workspace/application/grid/column_bloc.dart
  9. 6 0
      frontend/app_flowy/lib/workspace/application/grid/prelude.dart
  10. 1 1
      frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart
  11. 1 0
      frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart
  12. 1 0
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart
  13. 30 12
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/cell_builder.dart
  14. 47 0
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/checkbox_cell.dart
  15. 47 0
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/date_cell.dart
  16. 0 80
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_cell.dart
  17. 3 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart
  18. 47 0
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/number_cell.dart
  19. 75 0
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/selection_cell.dart
  20. 70 0
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/text_cell.dart
  21. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart
  22. 14 1
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  23. 5 1
      frontend/rust-lib/flowy-grid/src/event_map.rs
  24. 14 0
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

+ 40 - 0
frontend/app_flowy/lib/startup/home_deps_resolver.dart

@@ -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
     getIt.registerLazySingleton<TrashService>(() => TrashService());
     getIt.registerLazySingleton<TrashListener>(() => TrashListener());

+ 1 - 0
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_service.dart

@@ -0,0 +1 @@
+class CellService {}

+ 46 - 0
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart

@@ -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);
+}

+ 46 - 0
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart

@@ -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);
+}

+ 46 - 0
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart

@@ -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);
+}

+ 46 - 0
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart

@@ -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);
+}

+ 48 - 0
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart

@@ -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);
+}

+ 0 - 1
frontend/app_flowy/lib/workspace/application/grid/column_bloc.dart

@@ -1,7 +1,6 @@
 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 'package:dartz/dartz.dart';
 import 'dart:async';
 import 'column_service.dart';
 import 'data.dart';

+ 6 - 0
frontend/app_flowy/lib/workspace/application/grid/prelude.dart

@@ -5,3 +5,9 @@ export 'grid_service.dart';
 export 'data.dart';
 export 'column_service.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';

+ 1 - 1
frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart

@@ -34,7 +34,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
 
 @freezed
 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.activeRow() = _ActiveRow;
   const factory RowEvent.disactiveRow() = _DisactiveRow;

+ 1 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart

@@ -141,6 +141,7 @@ class _DocumentLeftBarItemState extends State<DocumentLeftBarItem> {
   @override
   void dispose() {
     _controller.dispose();
+    _focusNode.removeListener(_handleFocusChanged);
     _focusNode.dispose();
     super.dispose();
   }

+ 1 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart

@@ -10,6 +10,7 @@ class GridSize {
   static double get trailHeaderPadding => 140 * scale;
   static double get headerContentPadding => 8 * scale;
   static double get cellContentPadding => 8 * scale;
+
   //
   static EdgeInsets get headerContentInsets => EdgeInsets.symmetric(
         horizontal: GridSize.headerContentPadding,

+ 30 - 12
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/cell_builder.dart

@@ -1,17 +1,35 @@
 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';
+import 'date_cell.dart';
+import 'number_cell.dart';
+import 'selection_cell.dart';
+import 'text_cell.dart';
 
-class GridCellBuilder {
-  static GridCellWidget buildCell(Field? field, Cell? cell) {
-    if (field == null || cell == null) {
-      return GridTextCell("123123123");
-    }
+Widget buildGridCell(Field field, Cell? cell) {
+  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:
+      return GridTextCell(field: field, cell: cell);
+    case FieldType.SingleSelect:
+      return SingleSelectCell(field: field, cell: cell);
+    default:
+      return const BlankCell();
+  }
+}
+
+class BlankCell extends StatelessWidget {
+  const BlankCell({Key? key}) : super(key: key);
 
-    switch (field.fieldType) {
-      case FieldType.RichText:
-        return GridTextCell(cell.content);
-      default:
-        return const BlankCell();
-    }
+  @override
+  Widget build(BuildContext context) {
+    return Container();
   }
 }

+ 47 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/checkbox_cell.dart

@@ -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();
+  }
+}

+ 47 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/date_cell.dart

@@ -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();
+  }
+}

+ 0 - 80
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_cell.dart

@@ -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();
-  }
-}

+ 3 - 3
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart

@@ -22,7 +22,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
 
   @override
   void initState() {
-    _rowBloc = getIt<RowBloc>(param1: widget.data);
+    _rowBloc = getIt<RowBloc>(param1: widget.data)..add(const RowEvent.initial());
     super.initState();
   }
 
@@ -54,7 +54,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
 
   @override
   Future<void> dispose() async {
-    _rowBloc.close();
+    await _rowBloc.close();
     super.dispose();
   }
 
@@ -69,7 +69,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
               final cellData = state.data.cellMap[field.id];
               return CellContainer(
                 width: field.width.toDouble(),
-                child: GridCellBuilder.buildCell(field, cellData),
+                child: buildGridCell(field, cellData),
               );
             },
           ).toList(),

+ 47 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/number_cell.dart

@@ -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();
+  }
+}

+ 75 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/selection_cell.dart

@@ -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();
+  }
+}

+ 70 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/text_cell.dart

@@ -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));
+  }
+}

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart

@@ -43,7 +43,7 @@ class GridHeader extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return BlocProvider(
-      create: (context) => getIt<ColumnBloc>(param1: fields),
+      create: (context) => getIt<ColumnBloc>(param1: fields)..add(const ColumnEvent.initial()),
       child: BlocBuilder<ColumnBloc, ColumnState>(
         builder: (context, state) {
           final headers = state.fields

+ 14 - 1
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -1,6 +1,8 @@
 use crate::manager::GridManager;
 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 std::sync::Arc;
 
@@ -47,3 +49,14 @@ pub(crate) async fn create_row_handler(
     let _ = editor.create_empty_row().await?;
     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(())
+}

+ 5 - 1
frontend/rust-lib/flowy-grid/src/event_map.rs

@@ -11,7 +11,8 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         .event(GridEvent::GetGridData, get_grid_data_handler)
         .event(GridEvent::GetRows, get_rows_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
 }
@@ -30,4 +31,7 @@ pub enum GridEvent {
 
     #[event(input = "GridId")]
     CreateRow = 3,
+
+    #[event(input = "Cell")]
+    UpdateCell = 4,
 }

+ 14 - 0
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -15,6 +15,7 @@ use lib_infra::future::FutureResult;
 use lib_infra::uuid;
 use lib_ot::core::PlainTextAttributes;
 
+use dashmap::mapref::one::Ref;
 use rayon::iter::{IntoParallelIterator, ParallelIterator};
 use std::collections::HashMap;
 use std::sync::Arc;
@@ -28,6 +29,7 @@ pub struct ClientGridEditor {
     kv_persistence: Arc<GridKVPersistence>,
 
     field_map: DashMap<String, Field>,
+    cell_map: DashMap<String, RawCell>,
 }
 
 impl ClientGridEditor {
@@ -44,6 +46,7 @@ impl ClientGridEditor {
         let rev_manager = Arc::new(rev_manager);
         let field_map = load_all_fields(&grid_pad, &kv_persistence).await?;
         let grid_pad = Arc::new(RwLock::new(grid_pad));
+        let cell_map = DashMap::new();
 
         Ok(Arc::new(Self {
             grid_id: grid_id.to_owned(),
@@ -52,17 +55,20 @@ impl ClientGridEditor {
             rev_manager,
             kv_persistence,
             field_map,
+            cell_map,
         }))
     }
 
     pub async fn create_empty_row(&self) -> FlowyResult<()> {
         let row = RawRow::new(&uuid(), &self.grid_id, vec![]);
+        self.cell_map.insert(row.id.clone(), row.clone());
         self.create_row(row).await?;
         Ok(())
     }
 
     async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
         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)?;
         Ok(())
     }
@@ -73,6 +79,13 @@ impl ClientGridEditor {
         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<()> {
         let _ = self.modify(|grid| Ok(grid.create_field(&field)?)).await?;
         let _ = self.kv_persistence.set(field)?;
@@ -99,6 +112,7 @@ impl ClientGridEditor {
                 tracing::error!("Can't find the field with {}", field_id);
                 return None;
             }
+            self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone());
 
             let field = some_field.unwrap();
             match stringify_deserialize(raw_cell.data, field.value()) {