|
@@ -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:flutter/services.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: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_shortcuts.dart';
|
|
|
import 'checkbox_cell.dart';
|
|
@@ -50,11 +45,30 @@ class BlankCell extends StatelessWidget {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-abstract class GridCellWidget extends StatefulWidget implements CellAccessory, CellFocustable, CellShortcuts {
|
|
|
- GridCellWidget({Key? key}) : super(key: key);
|
|
|
+abstract class CellEditable {
|
|
|
+ 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
|
|
|
+ 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> isFocus = ValueNotifier<bool>(false);
|
|
|
+ final ValueNotifier<bool> onCellEditing = ValueNotifier<bool>(false);
|
|
|
|
|
|
@override
|
|
|
List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)? get accessoryBuilder => null;
|
|
@@ -137,9 +151,9 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCell
|
|
|
}
|
|
|
|
|
|
void _listenOnFocusNodeChanged() {
|
|
|
- widget.isFocus.value = focusNode.hasFocus;
|
|
|
+ widget.onCellEditing.value = focusNode.hasFocus;
|
|
|
focusNode.setListener(() {
|
|
|
- widget.isFocus.value = focusNode.hasFocus;
|
|
|
+ widget.onCellEditing.value = focusNode.hasFocus;
|
|
|
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,
|
|
|
- ),
|
|
|
- );
|
|
|
- },
|
|
|
- );
|
|
|
- }
|
|
|
-}
|