Skip to content

Commit 243a781

Browse files
authored
chore: improve grid focus and hover event handling (#1735)
* chore: improve primary cell accessory behavior * fix: focus border disappearing * chore: port to GridCellState * chore: fix typo * chore: connect popover controller * chore: final
1 parent 347245a commit 243a781

File tree

8 files changed

+109
-122
lines changed

8 files changed

+109
-122
lines changed

frontend/app_flowy/lib/plugins/board/presentation/card/board_checklist_cell.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
22
import 'package:app_flowy/plugins/grid/application/cell/checklist_cell_bloc.dart';
3-
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart';
3+
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_progress_bar.dart';
44
import 'package:flutter/material.dart';
55
import 'package:flutter_bloc/flutter_bloc.dart';
66

@@ -29,7 +29,10 @@ class _BoardChecklistCellState extends State<BoardChecklistCell> {
2929
Widget build(BuildContext context) {
3030
return BlocProvider.value(
3131
value: _cellBloc,
32-
child: const ChecklistProgressBar(),
32+
child: BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
33+
builder: (context, state) =>
34+
ChecklistProgressBar(percent: state.percent),
35+
),
3336
);
3437
}
3538
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/cell_accessory.dart

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,14 @@ class _PrimaryCellAccessoryState extends State<PrimaryCellAccessory>
6767
with GridCellAccessoryState {
6868
@override
6969
Widget build(BuildContext context) {
70-
if (widget.isCellEditing) {
71-
return const SizedBox();
72-
} else {
73-
return Tooltip(
74-
message: LocaleKeys.tooltip_openAsPage.tr(),
75-
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
76-
child: svgWidget(
77-
"grid/expander",
78-
color: Theme.of(context).colorScheme.primary,
79-
),
80-
);
81-
}
70+
return Tooltip(
71+
message: LocaleKeys.tooltip_openAsPage.tr(),
72+
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
73+
child: svgWidget(
74+
"grid/expander",
75+
color: Theme.of(context).colorScheme.primary,
76+
),
77+
);
8278
}
8379

8480
@override

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/cell_container.dart

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,23 @@ class CellContainer extends StatelessWidget {
1212
final GridCellWidget child;
1313
final AccessoryBuilder? accessoryBuilder;
1414
final double width;
15-
final RegionStateNotifier rowStateNotifier;
15+
final bool isPrimary;
16+
final CellContainerNotifier cellContainerNotifier;
17+
1618
const CellContainer({
1719
Key? key,
1820
required this.child,
1921
required this.width,
20-
required this.rowStateNotifier,
22+
required this.isPrimary,
23+
required this.cellContainerNotifier,
2124
this.accessoryBuilder,
2225
}) : super(key: key);
2326

2427
@override
2528
Widget build(BuildContext context) {
26-
return ChangeNotifierProvider<_CellContainerNotifier>(
27-
create: (_) => _CellContainerNotifier(child),
28-
child: Selector<_CellContainerNotifier, bool>(
29+
return ChangeNotifierProvider.value(
30+
value: cellContainerNotifier,
31+
child: Selector<CellContainerNotifier, bool>(
2932
selector: (context, notifier) => notifier.isFocus,
3033
builder: (privderContext, isFocus, _) {
3134
Widget container = Center(child: GridCellShortcuts(child: child));
@@ -41,6 +44,7 @@ class CellContainer extends StatelessWidget {
4144
if (accessories.isNotEmpty) {
4245
container = _GridCellEnterRegion(
4346
accessories: accessories,
47+
isPrimary: isPrimary,
4448
child: container,
4549
);
4650
}
@@ -81,17 +85,23 @@ class CellContainer extends StatelessWidget {
8185
class _GridCellEnterRegion extends StatelessWidget {
8286
final Widget child;
8387
final List<GridCellAccessoryBuilder> accessories;
84-
const _GridCellEnterRegion(
85-
{required this.child, required this.accessories, Key? key})
86-
: super(key: key);
88+
final bool isPrimary;
89+
const _GridCellEnterRegion({
90+
required this.child,
91+
required this.accessories,
92+
required this.isPrimary,
93+
Key? key,
94+
}) : super(key: key);
8795

8896
@override
8997
Widget build(BuildContext context) {
90-
return Selector2<RegionStateNotifier, _CellContainerNotifier, bool>(
91-
selector: (context, regionNotifier, cellNotifier) => !cellNotifier.isFocus && (cellNotifier.onEnter),
92-
builder: (context, onEnter, _) {
98+
return Selector2<RegionStateNotifier, CellContainerNotifier, bool>(
99+
selector: (context, regionNotifier, cellNotifier) =>
100+
!cellNotifier.isFocus &&
101+
(cellNotifier.onEnter || regionNotifier.onEnter && isPrimary),
102+
builder: (context, showAccessory, _) {
93103
List<Widget> children = [child];
94-
if (onEnter) {
104+
if (showAccessory) {
95105
children.add(
96106
CellAccessoryContainer(accessories: accessories).positioned(
97107
right: GridSize.cellContentInsets.right,
@@ -102,10 +112,10 @@ class _GridCellEnterRegion extends StatelessWidget {
102112
return MouseRegion(
103113
cursor: SystemMouseCursors.click,
104114
onEnter: (p) =>
105-
Provider.of<_CellContainerNotifier>(context, listen: false)
115+
Provider.of<CellContainerNotifier>(context, listen: false)
106116
.onEnter = true,
107117
onExit: (p) =>
108-
Provider.of<_CellContainerNotifier>(context, listen: false)
118+
Provider.of<CellContainerNotifier>(context, listen: false)
109119
.onEnter = false,
110120
child: Stack(
111121
alignment: AlignmentDirectional.center,
@@ -118,13 +128,13 @@ class _GridCellEnterRegion extends StatelessWidget {
118128
}
119129
}
120130

121-
class _CellContainerNotifier extends ChangeNotifier {
131+
class CellContainerNotifier extends ChangeNotifier {
122132
final CellEditable cellEditable;
123133
VoidCallback? _onCellFocusListener;
124134
bool _isFocus = false;
125135
bool _onEnter = false;
126136

127-
_CellContainerNotifier(this.cellEditable) {
137+
CellContainerNotifier(this.cellEditable) {
128138
_onCellFocusListener = () => isFocus = cellEditable.onCellFocus.value;
129139
cellEditable.onCellFocus.addListener(_onCellFocusListener!);
130140
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart

Lines changed: 28 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@ import 'package:appflowy_popover/appflowy_popover.dart';
55
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
66
import 'package:flutter/material.dart';
77
import 'package:flutter_bloc/flutter_bloc.dart';
8+
89
import '../cell_builder.dart';
910
import 'checklist_cell_editor.dart';
10-
import 'checklist_prograss_bar.dart';
11+
import 'checklist_progress_bar.dart';
1112

1213
class GridChecklistCell extends GridCellWidget {
1314
final GridCellControllerBuilder cellControllerBuilder;
1415
GridChecklistCell({required this.cellControllerBuilder, Key? key})
1516
: super(key: key);
1617

1718
@override
18-
GridChecklistCellState createState() => GridChecklistCellState();
19+
GridCellState<GridChecklistCell> createState() => GridChecklistCellState();
1920
}
2021

21-
class GridChecklistCellState extends State<GridChecklistCell> {
22-
late PopoverController _popover;
22+
class GridChecklistCellState extends GridCellState<GridChecklistCell> {
2323
late ChecklistCellBloc _cellBloc;
24+
late final PopoverController _popover;
2425

2526
@override
2627
void initState() {
@@ -36,52 +37,32 @@ class GridChecklistCellState extends State<GridChecklistCell> {
3637
Widget build(BuildContext context) {
3738
return BlocProvider.value(
3839
value: _cellBloc,
39-
child: Stack(
40-
alignment: AlignmentDirectional.center,
41-
fit: StackFit.expand,
42-
children: [
43-
_wrapPopover(const ChecklistProgressBar()),
44-
InkWell(onTap: () => _popover.show()),
45-
],
46-
),
47-
);
48-
}
49-
50-
Widget _wrapPopover(Widget child) {
51-
return AppFlowyPopover(
52-
controller: _popover,
53-
constraints: BoxConstraints.loose(const Size(260, 400)),
54-
direction: PopoverDirection.bottomWithLeftAligned,
55-
triggerActions: PopoverTriggerFlags.none,
56-
popupBuilder: (BuildContext context) {
57-
WidgetsBinding.instance.addPostFrameCallback((_) {
58-
widget.onCellEditing.value = true;
59-
});
60-
return GridChecklistCellEditor(
61-
cellController: widget.cellControllerBuilder.build()
62-
as GridChecklistCellController,
63-
);
64-
},
65-
onClose: () => widget.onCellEditing.value = false,
66-
child: Padding(
67-
padding: GridSize.cellContentInsets,
68-
child: child,
40+
child: AppFlowyPopover(
41+
controller: _popover,
42+
constraints: BoxConstraints.loose(const Size(260, 400)),
43+
direction: PopoverDirection.bottomWithLeftAligned,
44+
triggerActions: PopoverTriggerFlags.none,
45+
popupBuilder: (BuildContext context) {
46+
WidgetsBinding.instance.addPostFrameCallback((_) {
47+
widget.onCellEditing.value = true;
48+
});
49+
return GridChecklistCellEditor(
50+
cellController: widget.cellControllerBuilder.build()
51+
as GridChecklistCellController,
52+
);
53+
},
54+
onClose: () => widget.onCellEditing.value = false,
55+
child: Padding(
56+
padding: GridSize.cellContentInsets,
57+
child: BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
58+
builder: (context, state) =>
59+
ChecklistProgressBar(percent: state.percent),
60+
),
61+
),
6962
),
7063
);
7164
}
72-
}
73-
74-
class ChecklistProgressBar extends StatelessWidget {
75-
const ChecklistProgressBar({Key? key}) : super(key: key);
7665

7766
@override
78-
Widget build(BuildContext context) {
79-
return BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
80-
builder: (context, state) {
81-
return ChecklistPrograssBar(
82-
percent: state.percent,
83-
);
84-
},
85-
);
86-
}
67+
void requestBeginFocus() => _popover.show();
8768
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell_editor.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
22
import 'package:app_flowy/plugins/grid/application/cell/checklist_cell_editor_bloc.dart';
33
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
4-
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart';
4+
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_progress_bar.dart';
55
import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/select_option_editor.dart';
66
import 'package:appflowy_popover/appflowy_popover.dart';
77
import 'package:flowy_infra/image.dart';
@@ -48,7 +48,7 @@ class _GridChecklistCellEditorState extends State<GridChecklistCellEditor> {
4848
child: BlocBuilder<ChecklistCellEditorBloc, ChecklistCellEditorState>(
4949
builder: (context, state) {
5050
final List<Widget> slivers = [
51-
const SliverChecklistPrograssBar(),
51+
const SliverChecklistProgressBar(),
5252
SliverToBoxAdapter(
5353
child: Padding(
5454
padding: GridSize.typeOptionContentInsets,
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import 'package:flutter/material.dart';
88
import 'package:flutter_bloc/flutter_bloc.dart';
99
import 'package:percent_indicator/percent_indicator.dart';
1010

11-
class ChecklistPrograssBar extends StatelessWidget {
11+
class ChecklistProgressBar extends StatelessWidget {
1212
final double percent;
13-
const ChecklistPrograssBar({required this.percent, Key? key})
13+
const ChecklistProgressBar({required this.percent, Key? key})
1414
: super(key: key);
1515

1616
@override
@@ -26,21 +26,21 @@ class ChecklistPrograssBar extends StatelessWidget {
2626
}
2727
}
2828

29-
class SliverChecklistPrograssBar extends StatelessWidget {
30-
const SliverChecklistPrograssBar({Key? key}) : super(key: key);
29+
class SliverChecklistProgressBar extends StatelessWidget {
30+
const SliverChecklistProgressBar({Key? key}) : super(key: key);
3131

3232
@override
3333
Widget build(BuildContext context) {
3434
return SliverPersistentHeader(
3535
pinned: true,
36-
delegate: _SliverChecklistPrograssBarDelegate(),
36+
delegate: _SliverChecklistProgressBarDelegate(),
3737
);
3838
}
3939
}
4040

41-
class _SliverChecklistPrograssBarDelegate
41+
class _SliverChecklistProgressBarDelegate
4242
extends SliverPersistentHeaderDelegate {
43-
_SliverChecklistPrograssBarDelegate();
43+
_SliverChecklistProgressBarDelegate();
4444

4545
double fixHeight = 60;
4646

@@ -71,7 +71,7 @@ class _SliverChecklistPrograssBarDelegate
7171
),
7272
Padding(
7373
padding: const EdgeInsets.only(top: 6.0),
74-
child: ChecklistPrograssBar(percent: state.percent),
74+
child: ChecklistProgressBar(percent: state.percent),
7575
),
7676
],
7777
),

0 commit comments

Comments
 (0)