mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: click enter to exist edit state
This commit is contained in:
parent
46f69ee00d
commit
1a83cb65ed
@ -15,6 +15,7 @@ import 'layout/sizes.dart';
|
||||
import 'widgets/row/grid_row.dart';
|
||||
import 'widgets/footer/grid_footer.dart';
|
||||
import 'widgets/header/grid_header.dart';
|
||||
import 'widgets/shortcuts.dart';
|
||||
import 'widgets/toolbar/grid_toolbar.dart';
|
||||
|
||||
class GridPage extends StatefulWidget {
|
||||
@ -40,7 +41,7 @@ class _GridPageState extends State<GridPage> {
|
||||
return state.loadingState.map(
|
||||
loading: (_) => const Center(child: CircularProgressIndicator.adaptive()),
|
||||
finish: (result) => result.successOrFail.fold(
|
||||
(_) => const FlowyGrid(),
|
||||
(_) => const GridShortcuts(child: FlowyGrid()),
|
||||
(err) => FlowyErrorPage(err.toString()),
|
||||
),
|
||||
);
|
||||
|
@ -18,8 +18,8 @@ abstract class GridCellAccessory implements Widget {
|
||||
|
||||
typedef AccessoryBuilder = List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext);
|
||||
|
||||
abstract class AccessoryWidget extends Widget {
|
||||
const AccessoryWidget({Key? key}) : super(key: key);
|
||||
abstract class CellAccessory extends Widget {
|
||||
const CellAccessory({Key? key}) : super(key: key);
|
||||
|
||||
// The hover will show if the onFocus's value is true
|
||||
ValueNotifier<bool>? get isFocus;
|
||||
@ -28,7 +28,7 @@ abstract class AccessoryWidget extends Widget {
|
||||
}
|
||||
|
||||
class AccessoryHover extends StatefulWidget {
|
||||
final AccessoryWidget child;
|
||||
final CellAccessory child;
|
||||
final EdgeInsets contentPadding;
|
||||
const AccessoryHover({
|
||||
required this.child,
|
||||
|
@ -8,6 +8,7 @@ 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';
|
||||
import 'date_cell/date_cell.dart';
|
||||
import 'number_cell.dart';
|
||||
@ -48,7 +49,7 @@ class BlankCell extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class GridCellWidget extends StatefulWidget implements AccessoryWidget, CellContainerFocustable {
|
||||
abstract class GridCellWidget extends StatefulWidget implements CellAccessory, CellFocustable, CellShortcuts {
|
||||
GridCellWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -58,27 +59,30 @@ abstract class GridCellWidget extends StatefulWidget implements AccessoryWidget,
|
||||
List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)? get accessoryBuilder => null;
|
||||
|
||||
@override
|
||||
final GridCellRequestBeginFocus requestBeginFocus = GridCellRequestBeginFocus();
|
||||
final GridCellFocusListener beginFocus = GridCellFocusListener();
|
||||
|
||||
@override
|
||||
final Map<CellKeyboardKey, CellKeyboardAction> keyboardActionHandlers = {};
|
||||
}
|
||||
|
||||
abstract class GridCellState<T extends GridCellWidget> extends State<T> {
|
||||
@override
|
||||
void initState() {
|
||||
widget.requestBeginFocus.setListener(() => requestBeginFocus());
|
||||
widget.beginFocus.setListener(() => requestBeginFocus());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant T oldWidget) {
|
||||
if (oldWidget != this) {
|
||||
widget.requestBeginFocus.setListener(() => requestBeginFocus());
|
||||
widget.beginFocus.setListener(() => requestBeginFocus());
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.requestBeginFocus.removeAllListener();
|
||||
widget.beginFocus.removeAllListener();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -90,6 +94,7 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCell
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
widget.keyboardActionHandlers[CellKeyboardKey.onEnter] = () => focusNode.unfocus();
|
||||
_listenOnFocusNodeChanged();
|
||||
super.initState();
|
||||
}
|
||||
@ -104,6 +109,7 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCell
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.keyboardActionHandlers.remove(CellKeyboardKey.onEnter);
|
||||
focusNode.removeAllListener();
|
||||
focusNode.dispose();
|
||||
super.dispose();
|
||||
@ -127,7 +133,7 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCell
|
||||
Future<void> focusChanged() async {}
|
||||
}
|
||||
|
||||
class GridCellRequestBeginFocus extends ChangeNotifier {
|
||||
class GridCellFocusListener extends ChangeNotifier {
|
||||
VoidCallback? _listener;
|
||||
|
||||
void setListener(VoidCallback listener) {
|
||||
@ -194,9 +200,8 @@ class CellStateNotifier extends ChangeNotifier {
|
||||
bool get onEnter => _onEnter;
|
||||
}
|
||||
|
||||
abstract class CellContainerFocustable {
|
||||
// Listen on the requestBeginFocus if the
|
||||
GridCellRequestBeginFocus get requestBeginFocus;
|
||||
abstract class CellFocustable {
|
||||
GridCellFocusListener get beginFocus;
|
||||
}
|
||||
|
||||
class CellContainer extends StatelessWidget {
|
||||
@ -220,7 +225,7 @@ class CellContainer extends StatelessWidget {
|
||||
child: Selector<CellStateNotifier, bool>(
|
||||
selector: (context, notifier) => notifier.isFocus,
|
||||
builder: (context, isFocus, _) {
|
||||
Widget container = Center(child: child);
|
||||
Widget container = Center(child: GridCellShortcuts(child: child));
|
||||
child.isFocus.addListener(() {
|
||||
Provider.of<CellStateNotifier>(context, listen: false).isFocus = child.isFocus.value;
|
||||
});
|
||||
@ -235,7 +240,7 @@ class CellContainer extends StatelessWidget {
|
||||
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => child.requestBeginFocus.notify(),
|
||||
onTap: () => child.beginFocus.notify(),
|
||||
child: Container(
|
||||
constraints: BoxConstraints(maxWidth: width, minHeight: 46),
|
||||
decoration: _makeBoxDecoration(context, isFocus),
|
||||
|
@ -0,0 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
typedef CellKeyboardAction = VoidCallback;
|
||||
|
||||
enum CellKeyboardKey {
|
||||
onEnter,
|
||||
}
|
||||
|
||||
abstract class CellShortcuts extends Widget {
|
||||
const CellShortcuts({Key? key}) : super(key: key);
|
||||
|
||||
Map<CellKeyboardKey, CellKeyboardAction> get keyboardActionHandlers;
|
||||
}
|
||||
|
||||
class GridCellShortcuts extends StatelessWidget {
|
||||
final CellShortcuts child;
|
||||
const GridCellShortcuts({required this.child, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Shortcuts(
|
||||
shortcuts: {LogicalKeySet(LogicalKeyboardKey.enter): const GridCellEnterIdent()},
|
||||
child: Actions(
|
||||
actions: {GridCellEnterIdent: GridCellEnterAction(child: child)},
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GridCellEnterIdent extends Intent {
|
||||
const GridCellEnterIdent();
|
||||
}
|
||||
|
||||
class GridCellEnterAction extends Action<GridCellEnterIdent> {
|
||||
final CellShortcuts child;
|
||||
GridCellEnterAction({required this.child});
|
||||
|
||||
@override
|
||||
void invoke(covariant GridCellEnterIdent intent) {
|
||||
final callback = child.keyboardActionHandlers[CellKeyboardKey.onEnter];
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ class _GridTextCellState extends GridFocusNodeCellState<GridTextCell> {
|
||||
_cellBloc = getIt<TextCellBloc>(param1: cellContext);
|
||||
_cellBloc.add(const TextCellEvent.initial());
|
||||
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ class _RowDetailCell extends StatelessWidget {
|
||||
|
||||
final gesture = GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => cell.requestBeginFocus.notify(),
|
||||
onTap: () => cell.beginFocus.notify(),
|
||||
child: AccessoryHover(
|
||||
child: cell,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 12),
|
||||
|
@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class GridShortcuts extends StatelessWidget {
|
||||
final Widget child;
|
||||
const GridShortcuts({required this.child, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Shortcuts(
|
||||
shortcuts: bindKeys([]),
|
||||
child: Actions(
|
||||
dispatcher: LoggingActionDispatcher(),
|
||||
actions: const {},
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Map<ShortcutActivator, Intent> bindKeys(List<LogicalKeyboardKey> keys) {
|
||||
return {for (var key in keys) LogicalKeySet(key): KeyboardKeyIdent(key)};
|
||||
}
|
||||
|
||||
Map<Type, Action<Intent>> bindActions() {
|
||||
return {
|
||||
KeyboardKeyIdent: KeyboardBindingAction(),
|
||||
};
|
||||
}
|
||||
|
||||
class KeyboardKeyIdent extends Intent {
|
||||
final KeyboardKey key;
|
||||
|
||||
const KeyboardKeyIdent(this.key);
|
||||
}
|
||||
|
||||
class KeyboardBindingAction extends Action<KeyboardKeyIdent> {
|
||||
KeyboardBindingAction();
|
||||
|
||||
@override
|
||||
void invoke(covariant KeyboardKeyIdent intent) {
|
||||
// print(intent);
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingActionDispatcher extends ActionDispatcher {
|
||||
@override
|
||||
Object? invokeAction(
|
||||
covariant Action<Intent> action,
|
||||
covariant Intent intent, [
|
||||
BuildContext? context,
|
||||
]) {
|
||||
// print('Action invoked: $action($intent) from $context');
|
||||
super.invokeAction(action, intent, context);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user