mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: hide accessory when cell is editing
This commit is contained in:
parent
fbf7c9c9b8
commit
f61bebe869
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flowy_infra/theme.dart';
|
import 'package:flowy_infra/theme.dart';
|
||||||
@ -8,12 +9,45 @@ import 'package:styled_widget/styled_widget.dart';
|
|||||||
|
|
||||||
class GridCellAccessoryBuildContext {
|
class GridCellAccessoryBuildContext {
|
||||||
final BuildContext anchorContext;
|
final BuildContext anchorContext;
|
||||||
|
final bool isCellEditing;
|
||||||
|
|
||||||
GridCellAccessoryBuildContext({required this.anchorContext});
|
GridCellAccessoryBuildContext({
|
||||||
|
required this.anchorContext,
|
||||||
|
required this.isCellEditing,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class GridCellAccessory implements Widget {
|
abstract class GridCellAccessory implements Widget {
|
||||||
void onTap();
|
void onTap();
|
||||||
|
|
||||||
|
// The accessory will be hidden if enable() return false;
|
||||||
|
bool enable() => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrimaryCellAccessory extends StatelessWidget with GridCellAccessory {
|
||||||
|
final VoidCallback onTapCallback;
|
||||||
|
final bool isCellEditing;
|
||||||
|
const PrimaryCellAccessory({
|
||||||
|
required this.onTapCallback,
|
||||||
|
required this.isCellEditing,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (isCellEditing) {
|
||||||
|
return const SizedBox();
|
||||||
|
} else {
|
||||||
|
final theme = context.watch<AppTheme>();
|
||||||
|
return svgWidget("grid/expander", color: theme.main1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTap() => onTapCallback();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool enable() => !isCellEditing;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef AccessoryBuilder = List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext);
|
typedef AccessoryBuilder = List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext);
|
||||||
@ -21,8 +55,8 @@ typedef AccessoryBuilder = List<GridCellAccessory> Function(GridCellAccessoryBui
|
|||||||
abstract class CellAccessory extends Widget {
|
abstract class CellAccessory extends Widget {
|
||||||
const CellAccessory({Key? key}) : super(key: key);
|
const CellAccessory({Key? key}) : super(key: key);
|
||||||
|
|
||||||
// The hover will show if the onFocus's value is true
|
// The hover will show if the isHover's value is true
|
||||||
ValueNotifier<bool>? get isFocus;
|
ValueNotifier<bool>? get onAccessoryHover;
|
||||||
|
|
||||||
AccessoryBuilder? get accessoryBuilder;
|
AccessoryBuilder? get accessoryBuilder;
|
||||||
}
|
}
|
||||||
@ -47,8 +81,8 @@ class _AccessoryHoverState extends State<AccessoryHover> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_hoverState = AccessoryHoverState();
|
_hoverState = AccessoryHoverState();
|
||||||
_listenerFn = () => _hoverState.isFocus = widget.child.isFocus?.value ?? false;
|
_listenerFn = () => _hoverState.onHover = widget.child.onAccessoryHover?.value ?? false;
|
||||||
widget.child.isFocus?.addListener(_listenerFn!);
|
widget.child.onAccessoryHover?.addListener(_listenerFn!);
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
@ -58,7 +92,7 @@ class _AccessoryHoverState extends State<AccessoryHover> {
|
|||||||
_hoverState.dispose();
|
_hoverState.dispose();
|
||||||
|
|
||||||
if (_listenerFn != null) {
|
if (_listenerFn != null) {
|
||||||
widget.child.isFocus?.removeListener(_listenerFn!);
|
widget.child.onAccessoryHover?.removeListener(_listenerFn!);
|
||||||
_listenerFn = null;
|
_listenerFn = null;
|
||||||
}
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@ -73,11 +107,14 @@ class _AccessoryHoverState extends State<AccessoryHover> {
|
|||||||
|
|
||||||
final accessoryBuilder = widget.child.accessoryBuilder;
|
final accessoryBuilder = widget.child.accessoryBuilder;
|
||||||
if (accessoryBuilder != null) {
|
if (accessoryBuilder != null) {
|
||||||
final accessories = accessoryBuilder((GridCellAccessoryBuildContext(anchorContext: context)));
|
final accessories = accessoryBuilder((GridCellAccessoryBuildContext(
|
||||||
|
anchorContext: context,
|
||||||
|
isCellEditing: false,
|
||||||
|
)));
|
||||||
children.add(
|
children.add(
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 6),
|
padding: const EdgeInsets.only(right: 6),
|
||||||
child: AccessoryContainer(accessories: accessories),
|
child: CellAccessoryContainer(accessories: accessories),
|
||||||
).positioned(right: 0),
|
).positioned(right: 0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -101,7 +138,6 @@ class _AccessoryHoverState extends State<AccessoryHover> {
|
|||||||
|
|
||||||
class AccessoryHoverState extends ChangeNotifier {
|
class AccessoryHoverState extends ChangeNotifier {
|
||||||
bool _onHover = false;
|
bool _onHover = false;
|
||||||
bool _isFocus = false;
|
|
||||||
|
|
||||||
set onHover(bool value) {
|
set onHover(bool value) {
|
||||||
if (_onHover != value) {
|
if (_onHover != value) {
|
||||||
@ -111,15 +147,6 @@ class AccessoryHoverState extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool get onHover => _onHover;
|
bool get onHover => _onHover;
|
||||||
|
|
||||||
set isFocus(bool value) {
|
|
||||||
if (_isFocus != value) {
|
|
||||||
_isFocus = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get isFocus => _isFocus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Background extends StatelessWidget {
|
class _Background extends StatelessWidget {
|
||||||
@ -130,7 +157,7 @@ class _Background extends StatelessWidget {
|
|||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
return Consumer<AccessoryHoverState>(
|
return Consumer<AccessoryHoverState>(
|
||||||
builder: (context, state, child) {
|
builder: (context, state, child) {
|
||||||
if (state.onHover || state.isFocus) {
|
if (state.onHover) {
|
||||||
return FlowyHoverContainer(
|
return FlowyHoverContainer(
|
||||||
style: HoverStyle(borderRadius: Corners.s6Border, hoverColor: theme.shader6),
|
style: HoverStyle(borderRadius: Corners.s6Border, hoverColor: theme.shader6),
|
||||||
);
|
);
|
||||||
@ -142,14 +169,14 @@ class _Background extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessoryContainer extends StatelessWidget {
|
class CellAccessoryContainer extends StatelessWidget {
|
||||||
final List<GridCellAccessory> accessories;
|
final List<GridCellAccessory> accessories;
|
||||||
const AccessoryContainer({required this.accessories, Key? key}) : super(key: key);
|
const CellAccessoryContainer({required this.accessories, Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
final children = accessories.map((accessory) {
|
final children = accessories.where((accessory) => accessory.enable()).map((accessory) {
|
||||||
final hover = FlowyHover(
|
final hover = FlowyHover(
|
||||||
style: HoverStyle(hoverColor: theme.bg3, backgroundColor: theme.surface),
|
style: HoverStyle(hoverColor: theme.bg3, backgroundColor: theme.surface),
|
||||||
builder: (_, onHover) => Container(
|
builder: (_, onHover) => Container(
|
||||||
|
@ -2,12 +2,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_serv
|
|||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType;
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart';
|
|
||||||
import 'package:flowy_infra/theme.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
import 'cell_accessory.dart';
|
import 'cell_accessory.dart';
|
||||||
import 'cell_shortcuts.dart';
|
import 'cell_shortcuts.dart';
|
||||||
import 'checkbox_cell.dart';
|
import 'checkbox_cell.dart';
|
||||||
@ -50,11 +45,30 @@ class BlankCell extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class GridCellWidget extends StatefulWidget implements CellAccessory, CellFocustable, CellShortcuts {
|
abstract class CellEditable {
|
||||||
GridCellWidget({Key? key}) : super(key: key);
|
GridCellFocusListener get beginFocus;
|
||||||
|
|
||||||
|
ValueNotifier<bool> get onCellFocus;
|
||||||
|
|
||||||
|
ValueNotifier<bool> get onCellEditing;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GridCellWidget extends StatefulWidget implements CellAccessory, CellEditable, CellShortcuts {
|
||||||
|
GridCellWidget({Key? key}) : super(key: key) {
|
||||||
|
onCellEditing.addListener(() {
|
||||||
|
onCellFocus.value = onCellEditing.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final ValueNotifier<bool> isFocus = ValueNotifier<bool>(false);
|
final ValueNotifier<bool> onCellFocus = ValueNotifier<bool>(false);
|
||||||
|
|
||||||
|
// When the cell is focused, we assume that the accessory alse be hovered.
|
||||||
|
@override
|
||||||
|
ValueNotifier<bool> get onAccessoryHover => onCellFocus;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final ValueNotifier<bool> onCellEditing = ValueNotifier<bool>(false);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)? get accessoryBuilder => null;
|
List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)? get accessoryBuilder => null;
|
||||||
@ -137,9 +151,9 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCell
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _listenOnFocusNodeChanged() {
|
void _listenOnFocusNodeChanged() {
|
||||||
widget.isFocus.value = focusNode.hasFocus;
|
widget.onCellEditing.value = focusNode.hasFocus;
|
||||||
focusNode.setListener(() {
|
focusNode.setListener(() {
|
||||||
widget.isFocus.value = focusNode.hasFocus;
|
widget.onCellEditing.value = focusNode.hasFocus;
|
||||||
focusChanged();
|
focusChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -190,121 +204,3 @@ class SingleListenrFocusNode extends FocusNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CellStateNotifier extends ChangeNotifier {
|
|
||||||
bool _isFocus = false;
|
|
||||||
bool _onEnter = false;
|
|
||||||
|
|
||||||
set isFocus(bool value) {
|
|
||||||
if (_isFocus != value) {
|
|
||||||
_isFocus = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set onEnter(bool value) {
|
|
||||||
if (_onEnter != value) {
|
|
||||||
_onEnter = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get isFocus => _isFocus;
|
|
||||||
|
|
||||||
bool get onEnter => _onEnter;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class CellFocustable {
|
|
||||||
GridCellFocusListener get beginFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CellContainer extends StatelessWidget {
|
|
||||||
final GridCellWidget child;
|
|
||||||
final AccessoryBuilder? accessoryBuilder;
|
|
||||||
final double width;
|
|
||||||
final RegionStateNotifier rowStateNotifier;
|
|
||||||
const CellContainer({
|
|
||||||
Key? key,
|
|
||||||
required this.child,
|
|
||||||
required this.width,
|
|
||||||
required this.rowStateNotifier,
|
|
||||||
this.accessoryBuilder,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ChangeNotifierProxyProvider<RegionStateNotifier, CellStateNotifier>(
|
|
||||||
create: (_) => CellStateNotifier(),
|
|
||||||
update: (_, row, cell) => cell!..onEnter = row.onEnter,
|
|
||||||
child: Selector<CellStateNotifier, bool>(
|
|
||||||
selector: (context, notifier) => notifier.isFocus,
|
|
||||||
builder: (context, isFocus, _) {
|
|
||||||
Widget container = Center(child: GridCellShortcuts(child: child));
|
|
||||||
child.isFocus.addListener(() {
|
|
||||||
Provider.of<CellStateNotifier>(context, listen: false).isFocus = child.isFocus.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (accessoryBuilder != null) {
|
|
||||||
final buildContext = GridCellAccessoryBuildContext(anchorContext: context);
|
|
||||||
final accessories = accessoryBuilder!(buildContext);
|
|
||||||
if (accessories.isNotEmpty) {
|
|
||||||
container = CellEnterRegion(child: container, accessories: accessories);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
behavior: HitTestBehavior.translucent,
|
|
||||||
onTap: () => child.beginFocus.notify(),
|
|
||||||
child: Container(
|
|
||||||
constraints: BoxConstraints(maxWidth: width, minHeight: 46),
|
|
||||||
decoration: _makeBoxDecoration(context, isFocus),
|
|
||||||
padding: GridSize.cellContentInsets,
|
|
||||||
child: container,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxDecoration _makeBoxDecoration(BuildContext context, bool isFocus) {
|
|
||||||
final theme = context.watch<AppTheme>();
|
|
||||||
if (isFocus) {
|
|
||||||
final borderSide = BorderSide(color: theme.main1, width: 1.0);
|
|
||||||
return BoxDecoration(border: Border.fromBorderSide(borderSide));
|
|
||||||
} else {
|
|
||||||
final borderSide = BorderSide(color: theme.shader5, width: 1.0);
|
|
||||||
return BoxDecoration(border: Border(right: borderSide, bottom: borderSide));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CellEnterRegion extends StatelessWidget {
|
|
||||||
final Widget child;
|
|
||||||
final List<GridCellAccessory> accessories;
|
|
||||||
const CellEnterRegion({required this.child, required this.accessories, Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Selector<CellStateNotifier, bool>(
|
|
||||||
selector: (context, notifier) => notifier.onEnter,
|
|
||||||
builder: (context, onEnter, _) {
|
|
||||||
List<Widget> children = [child];
|
|
||||||
if (onEnter) {
|
|
||||||
children.add(AccessoryContainer(accessories: accessories).positioned(right: 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.click,
|
|
||||||
onEnter: (p) => Provider.of<CellStateNotifier>(context, listen: false).onEnter = true,
|
|
||||||
onExit: (p) => Provider.of<CellStateNotifier>(context, listen: false).onEnter = false,
|
|
||||||
child: Stack(
|
|
||||||
alignment: AlignmentDirectional.center,
|
|
||||||
fit: StackFit.expand,
|
|
||||||
children: children,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart';
|
||||||
|
import 'package:flowy_infra/theme.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
|
import 'cell_accessory.dart';
|
||||||
|
import 'cell_builder.dart';
|
||||||
|
import 'cell_shortcuts.dart';
|
||||||
|
|
||||||
|
class CellContainer extends StatelessWidget {
|
||||||
|
final GridCellWidget child;
|
||||||
|
final AccessoryBuilder? accessoryBuilder;
|
||||||
|
final double width;
|
||||||
|
final RegionStateNotifier rowStateNotifier;
|
||||||
|
const CellContainer({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
required this.width,
|
||||||
|
required this.rowStateNotifier,
|
||||||
|
this.accessoryBuilder,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ChangeNotifierProxyProvider<RegionStateNotifier, CellContainerNotifier>(
|
||||||
|
create: (_) => CellContainerNotifier(child),
|
||||||
|
update: (_, rowStateNotifier, cellStateNotifier) => cellStateNotifier!..onEnter = rowStateNotifier.onEnter,
|
||||||
|
child: Selector<CellContainerNotifier, bool>(
|
||||||
|
selector: (context, notifier) => notifier.isFocus,
|
||||||
|
builder: (context, isFocus, _) {
|
||||||
|
Widget container = Center(child: GridCellShortcuts(child: child));
|
||||||
|
|
||||||
|
if (accessoryBuilder != null) {
|
||||||
|
final accessories = accessoryBuilder!(GridCellAccessoryBuildContext(
|
||||||
|
anchorContext: context,
|
||||||
|
isCellEditing: isFocus,
|
||||||
|
));
|
||||||
|
|
||||||
|
if (accessories.isNotEmpty) {
|
||||||
|
container = CellEnterRegion(child: container, accessories: accessories);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onTap: () => child.beginFocus.notify(),
|
||||||
|
child: Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: width, minHeight: 46),
|
||||||
|
decoration: _makeBoxDecoration(context, isFocus),
|
||||||
|
padding: GridSize.cellContentInsets,
|
||||||
|
child: container,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxDecoration _makeBoxDecoration(BuildContext context, bool isFocus) {
|
||||||
|
final theme = context.watch<AppTheme>();
|
||||||
|
if (isFocus) {
|
||||||
|
final borderSide = BorderSide(color: theme.main1, width: 1.0);
|
||||||
|
return BoxDecoration(border: Border.fromBorderSide(borderSide));
|
||||||
|
} else {
|
||||||
|
final borderSide = BorderSide(color: theme.shader5, width: 1.0);
|
||||||
|
return BoxDecoration(border: Border(right: borderSide, bottom: borderSide));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CellEnterRegion extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
final List<GridCellAccessory> accessories;
|
||||||
|
const CellEnterRegion({required this.child, required this.accessories, Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Selector<CellContainerNotifier, bool>(
|
||||||
|
selector: (context, notifier) => notifier.onEnter,
|
||||||
|
builder: (context, onEnter, _) {
|
||||||
|
List<Widget> children = [child];
|
||||||
|
if (onEnter) {
|
||||||
|
children.add(CellAccessoryContainer(accessories: accessories).positioned(right: 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
onEnter: (p) => Provider.of<CellContainerNotifier>(context, listen: false).onEnter = true,
|
||||||
|
onExit: (p) => Provider.of<CellContainerNotifier>(context, listen: false).onEnter = false,
|
||||||
|
child: Stack(
|
||||||
|
alignment: AlignmentDirectional.center,
|
||||||
|
fit: StackFit.expand,
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CellContainerNotifier extends ChangeNotifier {
|
||||||
|
final CellEditable cellEditable;
|
||||||
|
bool mouted = false;
|
||||||
|
VoidCallback? _onCellFocusListener;
|
||||||
|
bool _isFocus = false;
|
||||||
|
bool _onEnter = false;
|
||||||
|
|
||||||
|
CellContainerNotifier(this.cellEditable) {
|
||||||
|
_onCellFocusListener = () => isFocus = cellEditable.onCellFocus.value;
|
||||||
|
cellEditable.onCellFocus.addListener(_onCellFocusListener!);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
if (_onCellFocusListener != null) {
|
||||||
|
cellEditable.onCellFocus.removeListener(_onCellFocusListener!);
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
set isFocus(bool value) {
|
||||||
|
if (_isFocus != value) {
|
||||||
|
_isFocus = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set onEnter(bool value) {
|
||||||
|
if (_onEnter != value) {
|
||||||
|
_onEnter = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isFocus => _isFocus;
|
||||||
|
|
||||||
|
bool get onEnter => _onEnter;
|
||||||
|
}
|
@ -76,8 +76,8 @@ class _DateCellState extends GridCellState<DateCell> {
|
|||||||
|
|
||||||
void _showCalendar(BuildContext context) {
|
void _showCalendar(BuildContext context) {
|
||||||
final bloc = context.read<DateCellBloc>();
|
final bloc = context.read<DateCellBloc>();
|
||||||
widget.isFocus.value = true;
|
widget.onCellEditing.value = true;
|
||||||
final calendar = DateCellEditor(onDismissed: () => widget.isFocus.value = false);
|
final calendar = DateCellEditor(onDismissed: () => widget.onCellEditing.value = false);
|
||||||
calendar.show(
|
calendar.show(
|
||||||
context,
|
context,
|
||||||
cellContext: bloc.cellContext.clone(),
|
cellContext: bloc.cellContext.clone(),
|
||||||
|
@ -59,7 +59,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
|||||||
return _SelectOptionCell(
|
return _SelectOptionCell(
|
||||||
selectOptions: state.selectedOptions,
|
selectOptions: state.selectedOptions,
|
||||||
cellStyle: widget.cellStyle,
|
cellStyle: widget.cellStyle,
|
||||||
onFocus: (value) => widget.isFocus.value = value,
|
onFocus: (value) => widget.onCellEditing.value = value,
|
||||||
cellContextBuilder: widget.cellContextBuilder);
|
cellContextBuilder: widget.cellContextBuilder);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -113,7 +113,7 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
|
|||||||
return _SelectOptionCell(
|
return _SelectOptionCell(
|
||||||
selectOptions: state.selectedOptions,
|
selectOptions: state.selectedOptions,
|
||||||
cellStyle: widget.cellStyle,
|
cellStyle: widget.cellStyle,
|
||||||
onFocus: (value) => widget.isFocus.value = value,
|
onFocus: (value) => widget.onCellEditing.value = value,
|
||||||
cellContextBuilder: widget.cellContextBuilder);
|
cellContextBuilder: widget.cellContextBuilder);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -112,7 +112,6 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
child: Align(alignment: Alignment.centerLeft, child: richText),
|
child: Align(alignment: Alignment.centerLeft, child: richText),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
widget.isFocus.value = true;
|
|
||||||
final url = context.read<URLCellBloc>().state.url;
|
final url = context.read<URLCellBloc>().state.url;
|
||||||
await _openUrlOrEdit(url);
|
await _openUrlOrEdit(url);
|
||||||
},
|
},
|
||||||
@ -131,12 +130,12 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
|||||||
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)) {
|
||||||
widget.isFocus.value = false;
|
|
||||||
await launchUrl(uri);
|
await launchUrl(uri);
|
||||||
} else {
|
} else {
|
||||||
final cellContext = widget.cellContextBuilder.build() as GridURLCellContext;
|
final cellContext = widget.cellContextBuilder.build() as GridURLCellContext;
|
||||||
|
widget.onCellEditing.value = true;
|
||||||
URLCellEditor.show(context, cellContext, () {
|
URLCellEditor.show(context, cellContext, () {
|
||||||
widget.isFocus.value = false;
|
widget.onCellEditing.value = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_accessory.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_accessory.dart';
|
||||||
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_cotainer.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra/theme.dart';
|
import 'package:flowy_infra/theme.dart';
|
||||||
@ -172,16 +173,15 @@ class _RowCells extends StatelessWidget {
|
|||||||
return gridCellMap.values.map(
|
return gridCellMap.values.map(
|
||||||
(gridCell) {
|
(gridCell) {
|
||||||
final GridCellWidget child = buildGridCellWidget(gridCell, cellCache);
|
final GridCellWidget child = buildGridCellWidget(gridCell, cellCache);
|
||||||
List<GridCellAccessory> accessories = [];
|
|
||||||
if (gridCell.field.isPrimary) {
|
|
||||||
accessories.add(_PrimaryCellAccessory(onTapCallback: onExpand));
|
|
||||||
}
|
|
||||||
|
|
||||||
accessoryBuilder(buildContext) {
|
accessoryBuilder(GridCellAccessoryBuildContext buildContext) {
|
||||||
final builder = child.accessoryBuilder;
|
final builder = child.accessoryBuilder;
|
||||||
List<GridCellAccessory> accessories = [];
|
List<GridCellAccessory> accessories = [];
|
||||||
if (gridCell.field.isPrimary) {
|
if (gridCell.field.isPrimary) {
|
||||||
accessories.add(_PrimaryCellAccessory(onTapCallback: onExpand));
|
accessories.add(PrimaryCellAccessory(
|
||||||
|
onTapCallback: onExpand,
|
||||||
|
isCellEditing: buildContext.isCellEditing,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builder != null) {
|
if (builder != null) {
|
||||||
@ -214,22 +214,6 @@ class RegionStateNotifier extends ChangeNotifier {
|
|||||||
bool get onEnter => _onEnter;
|
bool get onEnter => _onEnter;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PrimaryCellAccessory extends StatelessWidget with GridCellAccessory {
|
|
||||||
final VoidCallback onTapCallback;
|
|
||||||
const _PrimaryCellAccessory({required this.onTapCallback, Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = context.watch<AppTheme>();
|
|
||||||
return svgWidget("grid/expander", color: theme.main1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onTap() {
|
|
||||||
onTapCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RowEnterRegion extends StatefulWidget {
|
class _RowEnterRegion extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const _RowEnterRegion({required this.child, Key? key}) : super(key: key);
|
const _RowEnterRegion({required this.child, Key? key}) : super(key: key);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user