refactor: add GridCellState and GridFocusNodeCellState

This commit is contained in:
appflowy 2022-06-03 12:05:47 +08:00
parent 81efee557c
commit 4887885aae
7 changed files with 95 additions and 104 deletions

View File

@ -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 @override
final ValueNotifier<bool> isFocus = ValueNotifier<bool>(false); final ValueNotifier<bool> isFocus = ValueNotifier<bool>(false);
@ -59,6 +61,72 @@ abstract class GridCellWidget implements AccessoryWidget, CellContainerFocustabl
final GridCellRequestBeginFocus requestBeginFocus = GridCellRequestBeginFocus(); 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 { class GridCellRequestBeginFocus extends ChangeNotifier {
VoidCallback? _listener; VoidCallback? _listener;

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ class SelectOptionCellStyle extends GridCellStyle {
}); });
} }
class SingleSelectCell extends StatefulWidget with GridCellWidget { class SingleSelectCell extends GridCellWidget {
final GridCellContextBuilder cellContextBuilder; final GridCellContextBuilder cellContextBuilder;
late final SelectOptionCellStyle? cellStyle; 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; final GridCellContextBuilder cellContextBuilder;
late final SelectOptionCellStyle? cellStyle; late final SelectOptionCellStyle? cellStyle;

View File

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

View File

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