Kaynağa Gözat

chore: config number ui

appflowy 3 yıl önce
ebeveyn
işleme
11627269be

+ 0 - 1
frontend/app_flowy/lib/startup/deps_resolver.dart

@@ -194,7 +194,6 @@ void _resolveGridDeps(GetIt getIt) {
 
   getIt.registerFactoryParam<NumberCellBloc, CellData, void>(
     (cellData, _) => NumberCellBloc(
-      service: CellService(),
       cellData: cellData,
     ),
   );

+ 2 - 1
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart

@@ -26,7 +26,7 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
             _startListening();
           },
           select: (_Selected value) async {
-            service.updateCell(
+            _service.updateCell(
               gridId: state.cellData.gridId,
               fieldId: state.cellData.field.id,
               rowId: state.cellData.rowId,
@@ -43,6 +43,7 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
 
   @override
   Future<void> close() async {
+    await _listener.stop();
     return super.close();
   }
 

+ 59 - 7
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart

@@ -1,4 +1,6 @@
+import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart';
 import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
+import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
@@ -8,37 +10,87 @@ import 'cell_service.dart';
 part 'number_cell_bloc.freezed.dart';
 
 class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
-  final CellService service;
+  final CellService _service;
+  final CellListener _listener;
 
   NumberCellBloc({
-    required this.service,
     required CellData cellData,
-  }) : super(NumberCellState.initial()) {
+  })  : _service = CellService(),
+        _listener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
+        super(NumberCellState.initial(cellData)) {
     on<NumberCellEvent>(
       (event, emit) async {
         await event.map(
-          initial: (_InitialCell value) async {},
+          initial: (_Initial value) async {
+            _startListening();
+          },
+          didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
+            emit(state.copyWith(content: value.cell.content));
+          },
+          updateCell: (_UpdateCell value) {
+            _updateCellValue(value, emit);
+          },
         );
       },
     );
   }
 
+  void _updateCellValue(_UpdateCell value, Emitter<NumberCellState> emit) {
+    final number = num.tryParse(value.text);
+    if (number == null) {
+      emit(state.copyWith(content: ""));
+    } else {
+      _service.updateCell(
+        gridId: state.cellData.gridId,
+        fieldId: state.cellData.field.id,
+        rowId: state.cellData.rowId,
+        data: value.text,
+      );
+    }
+  }
+
   @override
   Future<void> close() async {
+    await _listener.stop();
     return super.close();
   }
+
+  void _startListening() {
+    _listener.updateCellNotifier.addPublishListener((result) {
+      result.fold(
+        (notificationData) async {
+          final result = await _service.getCell(
+            gridId: state.cellData.gridId,
+            fieldId: state.cellData.field.id,
+            rowId: state.cellData.rowId,
+          );
+          result.fold(
+            (cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)),
+            (err) => Log.error(err),
+          );
+        },
+        (err) => Log.error(err),
+      );
+    });
+    _listener.start();
+  }
 }
 
 @freezed
 class NumberCellEvent with _$NumberCellEvent {
-  const factory NumberCellEvent.initial() = _InitialCell;
+  const factory NumberCellEvent.initial() = _Initial;
+  const factory NumberCellEvent.updateCell(String text) = _UpdateCell;
+  const factory NumberCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
 }
 
 @freezed
 class NumberCellState with _$NumberCellState {
   const factory NumberCellState({
-    Cell? cell,
+    required CellData cellData,
+    required String content,
   }) = _NumberCellState;
 
-  factory NumberCellState.initial() => const NumberCellState();
+  factory NumberCellState.initial(CellData cellData) {
+    return NumberCellState(cellData: cellData, content: cellData.cell?.content ?? "");
+  }
 }

+ 42 - 2
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart

@@ -1,5 +1,8 @@
+import 'dart:async';
+
 import 'package:app_flowy/startup/startup.dart';
 import 'package:app_flowy/workspace/application/grid/prelude.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
@@ -17,20 +20,44 @@ class NumberCell extends StatefulWidget {
 
 class _NumberCellState extends State<NumberCell> {
   late NumberCellBloc _cellBloc;
+  late TextEditingController _controller;
+  late CellFocusNode _focusNode;
+  Timer? _delayOperation;
 
   @override
   void initState() {
     _cellBloc = getIt<NumberCellBloc>(param1: widget.cellData);
+    _controller = TextEditingController(text: _cellBloc.state.content);
+    _focusNode = CellFocusNode();
     super.initState();
   }
 
   @override
   Widget build(BuildContext context) {
+    _focusNode.addCallback(context, focusChanged);
+
     return BlocProvider.value(
       value: _cellBloc,
-      child: BlocBuilder<NumberCellBloc, NumberCellState>(
+      child: BlocConsumer<NumberCellBloc, NumberCellState>(
+        listener: (context, state) {
+          if (_controller.text != state.content) {
+            _controller.text = state.content;
+          }
+        },
         builder: (context, state) {
-          return Container();
+          return TextField(
+            controller: _controller,
+            focusNode: _focusNode,
+            onChanged: (value) => focusChanged(),
+            onEditingComplete: () => _focusNode.unfocus(),
+            maxLines: 1,
+            style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
+            decoration: const InputDecoration(
+              contentPadding: EdgeInsets.zero,
+              border: InputBorder.none,
+              isDense: true,
+            ),
+          );
         },
       ),
     );
@@ -38,7 +65,20 @@ class _NumberCellState extends State<NumberCell> {
 
   @override
   Future<void> dispose() async {
+    _delayOperation?.cancel();
     _cellBloc.close();
+    _focusNode.dispose();
     super.dispose();
   }
+
+  Future<void> focusChanged() async {
+    if (mounted) {
+      _delayOperation?.cancel();
+      _delayOperation = Timer(const Duration(milliseconds: 300), () {
+        if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) {
+          _cellBloc.add(NumberCellEvent.updateCell(_controller.text));
+        }
+      });
+    }
+  }
 }

+ 2 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart

@@ -63,6 +63,7 @@ class _GridTextCellState extends State<GridTextCell> {
 
   @override
   Future<void> dispose() async {
+    _delayOperation?.cancel();
     _cellBloc.close();
     _focusNode.dispose();
     super.dispose();
@@ -72,7 +73,7 @@ class _GridTextCellState extends State<GridTextCell> {
     if (mounted) {
       _delayOperation?.cancel();
       _delayOperation = Timer(const Duration(milliseconds: 300), () {
-        if (_cellBloc.isClosed == false) {
+        if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) {
           _cellBloc.add(TextCellEvent.updateText(_controller.text));
         }
       });

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

@@ -19,7 +19,7 @@ class FieldTypeList extends StatelessWidget with FlowyOverlayDelegate {
 
   @override
   Widget build(BuildContext context) {
-    final cells = FieldType.values.map((fieldType) {
+    final cells = FieldType.values.where((ty) => ty != FieldType.DateTime).map((fieldType) {
       return FieldTypeCell(
         fieldType: fieldType,
         onSelectField: (fieldType) {