Ver código fonte

Merge pull request #529 from AppFlowy-IO/refactor/grid_cell_focus

refactor: add GridCellState and GridFocusNodeCellState
Nathan.fooo 3 anos atrás
pai
commit
46f69ee00d

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

@@ -48,7 +48,9 @@ class BlankCell extends StatelessWidget {
   }
 }
 
-abstract class GridCellWidget implements AccessoryWidget, CellContainerFocustable {
+abstract class GridCellWidget extends StatefulWidget implements AccessoryWidget, CellContainerFocustable {
+  GridCellWidget({Key? key}) : super(key: key);
+
   @override
   final ValueNotifier<bool> isFocus = ValueNotifier<bool>(false);
 
@@ -59,6 +61,72 @@ abstract class GridCellWidget implements AccessoryWidget, CellContainerFocustabl
   final GridCellRequestBeginFocus requestBeginFocus = GridCellRequestBeginFocus();
 }
 
+abstract class GridCellState<T extends GridCellWidget> extends State<T> {
+  @override
+  void initState() {
+    widget.requestBeginFocus.setListener(() => requestBeginFocus());
+    super.initState();
+  }
+
+  @override
+  void didUpdateWidget(covariant T oldWidget) {
+    if (oldWidget != this) {
+      widget.requestBeginFocus.setListener(() => requestBeginFocus());
+    }
+    super.didUpdateWidget(oldWidget);
+  }
+
+  @override
+  void dispose() {
+    widget.requestBeginFocus.removeAllListener();
+    super.dispose();
+  }
+
+  void requestBeginFocus();
+}
+
+abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCellState<T> {
+  SingleListenrFocusNode focusNode = SingleListenrFocusNode();
+
+  @override
+  void initState() {
+    _listenOnFocusNodeChanged();
+    super.initState();
+  }
+
+  @override
+  void didUpdateWidget(covariant T oldWidget) {
+    if (oldWidget != this) {
+      _listenOnFocusNodeChanged();
+    }
+    super.didUpdateWidget(oldWidget);
+  }
+
+  @override
+  void dispose() {
+    focusNode.removeAllListener();
+    focusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  void requestBeginFocus() {
+    if (focusNode.hasFocus == false && focusNode.canRequestFocus) {
+      FocusScope.of(context).requestFocus(focusNode);
+    }
+  }
+
+  void _listenOnFocusNodeChanged() {
+    widget.isFocus.value = focusNode.hasFocus;
+    focusNode.setListener(() {
+      widget.isFocus.value = focusNode.hasFocus;
+      focusChanged();
+    });
+  }
+
+  Future<void> focusChanged() async {}
+}
+
 class GridCellRequestBeginFocus extends ChangeNotifier {
   VoidCallback? _listener;
 

+ 7 - 15
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart

@@ -6,7 +6,7 @@ import 'package:flutter/widgets.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'cell_builder.dart';
 
-class CheckboxCell extends StatefulWidget with GridCellWidget {
+class CheckboxCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
   CheckboxCell({
     required this.cellContextBuilder,
@@ -14,17 +14,17 @@ class CheckboxCell extends StatefulWidget with GridCellWidget {
   }) : super(key: key);
 
   @override
-  State<CheckboxCell> createState() => _CheckboxCellState();
+  GridCellState<CheckboxCell> createState() => _CheckboxCellState();
 }
 
-class _CheckboxCellState extends State<CheckboxCell> {
+class _CheckboxCellState extends GridCellState<CheckboxCell> {
   late CheckboxCellBloc _cellBloc;
 
   @override
   void initState() {
     final cellContext = widget.cellContextBuilder.build();
     _cellBloc = getIt<CheckboxCellBloc>(param1: cellContext)..add(const CheckboxCellEvent.initial());
-    _handleRequestFocus();
+
     super.initState();
   }
 
@@ -49,22 +49,14 @@ class _CheckboxCellState extends State<CheckboxCell> {
     );
   }
 
-  @override
-  void didUpdateWidget(covariant CheckboxCell oldWidget) {
-    _handleRequestFocus();
-    super.didUpdateWidget(oldWidget);
-  }
-
   @override
   Future<void> dispose() async {
-    widget.requestBeginFocus.removeAllListener();
     _cellBloc.close();
     super.dispose();
   }
 
-  void _handleRequestFocus() {
-    widget.requestBeginFocus.setListener(() {
-      _cellBloc.add(const CheckboxCellEvent.select());
-    });
+  @override
+  void requestBeginFocus() {
+    _cellBloc.add(const CheckboxCellEvent.select());
   }
 }

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

@@ -18,7 +18,7 @@ abstract class GridCellDelegate {
   GridCellDelegate get delegate;
 }
 
-class DateCell extends StatefulWidget with GridCellWidget {
+class DateCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
   late final DateCellStyle? cellStyle;
 

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

@@ -7,7 +7,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 
 import 'cell_builder.dart';
 
-class NumberCell extends StatefulWidget with GridCellWidget {
+class NumberCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
 
   NumberCell({
@@ -16,13 +16,12 @@ class NumberCell extends StatefulWidget with GridCellWidget {
   }) : super(key: key);
 
   @override
-  State<NumberCell> createState() => _NumberCellState();
+  GridFocusNodeCellState<NumberCell> createState() => _NumberCellState();
 }
 
-class _NumberCellState extends State<NumberCell> {
+class _NumberCellState extends GridFocusNodeCellState<NumberCell> {
   late NumberCellBloc _cellBloc;
   late TextEditingController _controller;
-  late SingleListenrFocusNode _focusNode;
   Timer? _delayOperation;
 
   @override
@@ -30,14 +29,11 @@ class _NumberCellState extends State<NumberCell> {
     final cellContext = widget.cellContextBuilder.build();
     _cellBloc = getIt<NumberCellBloc>(param1: cellContext)..add(const NumberCellEvent.initial());
     _controller = TextEditingController(text: contentFromState(_cellBloc.state));
-    _focusNode = SingleListenrFocusNode();
-    _listenOnFocusNodeChanged();
     super.initState();
   }
 
   @override
   Widget build(BuildContext context) {
-    _handleCellRequestFocus(context);
     return BlocProvider.value(
       value: _cellBloc,
       child: MultiBlocListener(
@@ -49,8 +45,8 @@ class _NumberCellState extends State<NumberCell> {
         ],
         child: TextField(
           controller: _controller,
-          focusNode: _focusNode,
-          onEditingComplete: () => _focusNode.unfocus(),
+          focusNode: focusNode,
+          onEditingComplete: () => focusNode.unfocus(),
           maxLines: null,
           style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
           decoration: const InputDecoration(
@@ -65,20 +61,12 @@ class _NumberCellState extends State<NumberCell> {
 
   @override
   Future<void> dispose() async {
-    widget.requestBeginFocus.removeAllListener();
     _delayOperation?.cancel();
     _cellBloc.close();
-    _focusNode.removeAllListener();
-    _focusNode.dispose();
     super.dispose();
   }
 
   @override
-  void didUpdateWidget(covariant NumberCell oldWidget) {
-    _listenOnFocusNodeChanged();
-    super.didUpdateWidget(oldWidget);
-  }
-
   Future<void> focusChanged() async {
     if (mounted) {
       _delayOperation?.cancel();
@@ -90,22 +78,6 @@ class _NumberCellState extends State<NumberCell> {
     }
   }
 
-  void _listenOnFocusNodeChanged() {
-    widget.isFocus.value = _focusNode.hasFocus;
-    _focusNode.setListener(() {
-      widget.isFocus.value = _focusNode.hasFocus;
-      focusChanged();
-    });
-  }
-
-  void _handleCellRequestFocus(BuildContext context) {
-    widget.requestBeginFocus.setListener(() {
-      if (_focusNode.hasFocus == false && _focusNode.canRequestFocus) {
-        FocusScope.of(context).requestFocus(_focusNode);
-      }
-    });
-  }
-
   String contentFromState(NumberCellState state) {
     return state.content.fold((l) => l, (r) => "");
   }

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

@@ -20,7 +20,7 @@ class SelectOptionCellStyle extends GridCellStyle {
   });
 }
 
-class SingleSelectCell extends StatefulWidget with GridCellWidget {
+class SingleSelectCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
   late final SelectOptionCellStyle? cellStyle;
 
@@ -74,7 +74,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
 }
 
 //----------------------------------------------------------------
-class MultiSelectCell extends StatefulWidget with GridCellWidget {
+class MultiSelectCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
   late final SelectOptionCellStyle? cellStyle;
 

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

@@ -13,7 +13,7 @@ class GridTextCellStyle extends GridCellStyle {
   });
 }
 
-class GridTextCell extends StatefulWidget with GridCellWidget {
+class GridTextCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
   late final GridTextCellStyle? cellStyle;
   GridTextCell({
@@ -29,13 +29,12 @@ class GridTextCell extends StatefulWidget with GridCellWidget {
   }
 
   @override
-  State<GridTextCell> createState() => _GridTextCellState();
+  GridFocusNodeCellState<GridTextCell> createState() => _GridTextCellState();
 }
 
-class _GridTextCellState extends State<GridTextCell> {
+class _GridTextCellState extends GridFocusNodeCellState<GridTextCell> {
   late TextCellBloc _cellBloc;
   late TextEditingController _controller;
-  late SingleListenrFocusNode _focusNode;
   Timer? _delayOperation;
 
   @override
@@ -44,10 +43,6 @@ class _GridTextCellState extends State<GridTextCell> {
     _cellBloc = getIt<TextCellBloc>(param1: cellContext);
     _cellBloc.add(const TextCellEvent.initial());
     _controller = TextEditingController(text: _cellBloc.state.content);
-    _focusNode = SingleListenrFocusNode();
-
-    _listenOnFocusNodeChanged();
-    _listenRequestFocus(context);
     super.initState();
   }
 
@@ -63,9 +58,9 @@ class _GridTextCellState extends State<GridTextCell> {
         },
         child: TextField(
           controller: _controller,
-          focusNode: _focusNode,
+          focusNode: focusNode,
           onChanged: (value) => focusChanged(),
-          onEditingComplete: () => _focusNode.unfocus(),
+          onEditingComplete: () => focusNode.unfocus(),
           maxLines: null,
           style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
           decoration: InputDecoration(
@@ -81,39 +76,12 @@ class _GridTextCellState extends State<GridTextCell> {
 
   @override
   Future<void> dispose() async {
-    widget.requestBeginFocus.removeAllListener();
     _delayOperation?.cancel();
     _cellBloc.close();
-    _focusNode.removeAllListener();
-    _focusNode.dispose();
-
     super.dispose();
   }
 
   @override
-  void didUpdateWidget(covariant GridTextCell oldWidget) {
-    if (oldWidget != widget) {
-      _listenOnFocusNodeChanged();
-    }
-    super.didUpdateWidget(oldWidget);
-  }
-
-  void _listenOnFocusNodeChanged() {
-    widget.isFocus.value = _focusNode.hasFocus;
-    _focusNode.setListener(() {
-      widget.isFocus.value = _focusNode.hasFocus;
-      focusChanged();
-    });
-  }
-
-  void _listenRequestFocus(BuildContext context) {
-    widget.requestBeginFocus.setListener(() {
-      if (_focusNode.hasFocus == false && _focusNode.canRequestFocus) {
-        FocusScope.of(context).requestFocus(_focusNode);
-      }
-    });
-  }
-
   Future<void> focusChanged() async {
     if (mounted) {
       _delayOperation?.cancel();

+ 6 - 15
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart

@@ -30,7 +30,7 @@ enum GridURLCellAccessoryType {
   copyURL,
 }
 
-class GridURLCell extends StatefulWidget with GridCellWidget {
+class GridURLCell extends GridCellWidget {
   final GridCellContextBuilder cellContextBuilder;
   late final GridURLCellStyle? cellStyle;
   GridURLCell({
@@ -46,7 +46,7 @@ class GridURLCell extends StatefulWidget with GridCellWidget {
   }
 
   @override
-  State<GridURLCell> createState() => _GridURLCellState();
+  GridCellState<GridURLCell> createState() => _GridURLCellState();
 
   GridCellAccessory accessoryFromType(GridURLCellAccessoryType ty, GridCellAccessoryBuildContext buildContext) {
     switch (ty) {
@@ -78,7 +78,7 @@ class GridURLCell extends StatefulWidget with GridCellWidget {
       };
 }
 
-class _GridURLCellState extends State<GridURLCell> {
+class _GridURLCellState extends GridCellState<GridURLCell> {
   late URLCellBloc _cellBloc;
 
   @override
@@ -86,7 +86,6 @@ class _GridURLCellState extends State<GridURLCell> {
     final cellContext = widget.cellContextBuilder.build() as GridURLCellContext;
     _cellBloc = URLCellBloc(cellContext: cellContext);
     _cellBloc.add(const URLCellEvent.initial());
-    _handleRequestFocus();
     super.initState();
   }
 
@@ -125,17 +124,10 @@ class _GridURLCellState extends State<GridURLCell> {
 
   @override
   Future<void> dispose() async {
-    widget.requestBeginFocus.removeAllListener();
     _cellBloc.close();
     super.dispose();
   }
 
-  @override
-  void didUpdateWidget(covariant GridURLCell oldWidget) {
-    _handleRequestFocus();
-    super.didUpdateWidget(oldWidget);
-  }
-
   Future<void> _openUrlOrEdit(String url) async {
     final uri = Uri.parse(url);
     if (url.isNotEmpty && await canLaunchUrl(uri)) {
@@ -146,10 +138,9 @@ class _GridURLCellState extends State<GridURLCell> {
     }
   }
 
-  void _handleRequestFocus() {
-    widget.requestBeginFocus.setListener(() {
-      _openUrlOrEdit(_cellBloc.state.url);
-    });
+  @override
+  void requestBeginFocus() {
+    _openUrlOrEdit(_cellBloc.state.url);
   }
 }