diff --git a/app/lib/constants/constants.dart b/app/lib/constants/constants.dart index dfee4a3..b57bd45 100644 --- a/app/lib/constants/constants.dart +++ b/app/lib/constants/constants.dart @@ -22,6 +22,8 @@ const double defaultButtonHeight = 36; const List builtInCommands = [ 'ShowWorkspace', + 'Handle4Or5FingersSwipeUp', + 'Handle4Or5FingersSwipeDown', 'ToggleMaximize', 'Minimize', 'ShowWindow', diff --git a/app/lib/constants/keyboard_mapper.dart b/app/lib/constants/keyboard_mapper.dart new file mode 100644 index 0000000..859f65a --- /dev/null +++ b/app/lib/constants/keyboard_mapper.dart @@ -0,0 +1,11 @@ +import 'package:flutter/services.dart'; + +/// https://github.com/linuxdeepin/dde-daemon/blob/76be73fbf019cee73983292e1edf47611ed9a219/gesture/manager.go#L386 +final Map keyMapper = { + LogicalKeyboardKey.control: 'ctrl', + LogicalKeyboardKey.controlLeft: 'ctrl', + LogicalKeyboardKey.controlRight: 'ctrl', + LogicalKeyboardKey.shift: 'shift', + LogicalKeyboardKey.shiftLeft: 'shift', + LogicalKeyboardKey.shiftRight: 'shift', +}; diff --git a/app/lib/pages/gesture_editor.dart b/app/lib/pages/gesture_editor.dart index e5d00ff..f9cf807 100644 --- a/app/lib/pages/gesture_editor.dart +++ b/app/lib/pages/gesture_editor.dart @@ -47,8 +47,7 @@ class GestureEditor extends StatelessWidget { visible: layoutProvider.localManagerOpened == false, child: DButton( width: defaultButtonHeight, - onTap: () => - H.openPanel(context, PanelType.local_manager), + onTap: () => H.openPanel(context, PanelType.local_manager), child: Icon( CupertinoIcons.square_list, ), @@ -77,14 +76,11 @@ class GestureEditor extends StatelessWidget { Expanded( child: GestureDetector( onTap: () { - context - .read() - .setProps(editMode: false); + context.read().setProps(editMode: false); }, child: Container( decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(defaultBorderRadius), + borderRadius: BorderRadius.circular(defaultBorderRadius), border: Border.all( width: .2, color: context.t.dividerColor, @@ -92,19 +88,16 @@ class GestureEditor extends StatelessWidget { ), width: double.infinity, clipBehavior: Clip.antiAlias, - child: LayoutBuilder(builder: - (BuildContext context, BoxConstraints constraints) { + child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { return AdaptiveScrollbar( controller: verticalCtrl, underColor: Colors.transparent, sliderDecoration: BoxDecoration( - borderRadius: - BorderRadius.circular(_scrollBarWidth / 2), + borderRadius: BorderRadius.circular(_scrollBarWidth / 2), color: Colors.grey.withOpacity(.4), ), sliderActiveDecoration: BoxDecoration( - borderRadius: - BorderRadius.circular(_scrollBarWidth / 2), + borderRadius: BorderRadius.circular(_scrollBarWidth / 2), color: Colors.grey.withOpacity(.6), ), position: ScrollbarPosition.right, @@ -114,13 +107,11 @@ class GestureEditor extends StatelessWidget { width: _scrollBarWidth, underColor: Colors.transparent, sliderDecoration: BoxDecoration( - borderRadius: - BorderRadius.circular(_scrollBarWidth / 2), + borderRadius: BorderRadius.circular(_scrollBarWidth / 2), color: Colors.grey.withOpacity(.4), ), sliderActiveDecoration: BoxDecoration( - borderRadius: - BorderRadius.circular(_scrollBarWidth / 2), + borderRadius: BorderRadius.circular(_scrollBarWidth / 2), color: Colors.grey.withOpacity(.6), ), controller: horizontalCtrl, @@ -129,58 +120,28 @@ class GestureEditor extends StatelessWidget { scrollDirection: Axis.horizontal, controller: horizontalCtrl, child: ConstrainedBox( - constraints: BoxConstraints( - minWidth: constraints.maxWidth), + constraints: BoxConstraints(minWidth: constraints.maxWidth), child: DDataTable( showBottomBorder: true, headingRowHeight: _headingRowHeight, showCheckboxColumn: true, - headerBackgroundColor: - context.t.dialogBackgroundColor, + headerBackgroundColor: context.t.dialogBackgroundColor, verticalScrollController: verticalCtrl, - dataRowColor: - MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.hovered)) - return context.t.dialogBackgroundColor; + dataRowColor: MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered)) return context.t.dialogBackgroundColor; if (states.contains(MaterialState.selected)) - return context - .read() - .currentActiveColor; + return context.read().currentActiveColor; return null; }), columns: [ - DDataColumn( - label: Text(LocaleKeys - .gesture_editor_fingers - .tr()), - center: true), - DDataColumn( - label: Text(LocaleKeys - .gesture_editor_gesture - .tr()), - center: true), - DDataColumn( - label: Text(LocaleKeys - .gesture_editor_direction - .tr()), - center: true), - DDataColumn( - label: Text(LocaleKeys - .gesture_editor_type - .tr()), - center: true), - DDataColumn( - label: Text(LocaleKeys - .gesture_editor_command - .tr())), - DDataColumn( - label: Text(LocaleKeys - .gesture_editor_remark - .tr())), + DDataColumn(label: Text(LocaleKeys.gesture_editor_fingers.tr()), center: true), + DDataColumn(label: Text(LocaleKeys.gesture_editor_gesture.tr()), center: true), + DDataColumn(label: Text(LocaleKeys.gesture_editor_direction.tr()), center: true), + DDataColumn(label: Text(LocaleKeys.gesture_editor_type.tr()), center: true), + DDataColumn(label: Text(LocaleKeys.gesture_editor_command.tr())), + DDataColumn(label: Text(LocaleKeys.gesture_editor_remark.tr())), ], - rows: _buildDataRows( - schemeProvider.gestures, context), + rows: _buildDataRows(schemeProvider.gestures, context), ), ), ), @@ -210,12 +171,9 @@ class GestureEditor extends StatelessWidget { } } -List _buildDataRows( - List? gestures, BuildContext context) => - (gestures ?? []).map((gesture) { +List _buildDataRows(List? gestures, BuildContext context) => (gestures ?? []).map((gesture) { var gesturePropProvider = context.watch(); - bool editing = gesturePropProvider == gesture && - gesturePropProvider.editMode == true; + bool editing = gesturePropProvider == gesture && gesturePropProvider.editMode == true; bool selected = gesturePropProvider == gesture && !editing; return DDataRow( onSelectChanged: (selected) { @@ -243,15 +201,11 @@ List _buildDataRows( } }, selected: selected, - cells: editing - ? _buildRowCellsEditing(context, gesture) - : _buildRowCellsNormal(context, selected, gesture), + cells: editing ? _buildRowCellsEditing(context, gesture) : _buildRowCellsNormal(context, selected, gesture), ); }).toList(); -List _buildRowCellsEditing( - BuildContext context, GestureProp gesture) => - [ +List _buildRowCellsEditing(BuildContext context, GestureProp gesture) => [ DButton.dropdown( enabled: true, child: DropdownButton( @@ -339,6 +293,7 @@ List _buildRowCellsEditing( value: context.watch().type, onChanged: (value) => context.read().setProps( type: value, + command: '', editMode: true, ), isExpanded: true, @@ -356,7 +311,6 @@ List _buildRowCellsEditing( ].map((e) => DDataCell(e)).toList(); Widget _buildCommandCellsEditing(BuildContext context) { - 'build cmd cell'.sout(); var gesture = context.read(); switch (gesture.type) { case GestureType.commandline: @@ -385,9 +339,7 @@ Widget _buildCommandCellsEditing(BuildContext context) { ), ) .toList(), - value: builtInCommands.contains(gesture.command) - ? gesture.command - : builtInCommands.first, + value: builtInCommands.contains(gesture.command) ? gesture.command : builtInCommands.first, onChanged: (value) => context.read().setProps( command: value, editMode: true, @@ -397,7 +349,7 @@ Widget _buildCommandCellsEditing(BuildContext context) { ); case GestureType.shortcut: return TableCellShortcutListener( - width: 150.0, + width: 250.0, initShortcut: gesture.command ?? '', onComplete: (value) => context.read().setProps( command: value, @@ -409,9 +361,7 @@ Widget _buildCommandCellsEditing(BuildContext context) { } } -List _buildRowCellsNormal( - BuildContext context, bool selected, GestureProp gesture) => - [ +List _buildRowCellsNormal(BuildContext context, bool selected, GestureProp gesture) => [ Center( child: Text( '${gesture.fingers}', @@ -430,9 +380,40 @@ List _buildRowCellsNormal( child: Text( '${LocaleKeys.gesture_editor_types}.${H.getGestureTypeName(gesture.type)}', ).tr()), - Text( - gesture.command ?? '', - ), + gesture.type == GestureType.shortcut + ? Row( + mainAxisAlignment: MainAxisAlignment.start, + children: (gesture.command ?? '') + .split('+') + .map( + (e) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 2.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(defaultBorderRadius / 2), + color: context.t.dialogBackgroundColor, + border: Border.all( + width: 1, + color: Color(0xff565656), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 5.0), + child: Text( + e.notNull ? e : LocaleKeys.str_null.tr(), + style: TextStyle( + color: context.watch().currentActiveColor, + ), + ), + ), + ), + ), + ) + .toList(), + ) + : Text( + gesture.command ?? '', + ), Text( gesture.remark ?? '', ), diff --git a/app/lib/widgets/dde_button.dart b/app/lib/widgets/dde_button.dart index ce54464..77a00d6 100644 --- a/app/lib/widgets/dde_button.dart +++ b/app/lib/widgets/dde_button.dart @@ -126,8 +126,9 @@ class _DButtonState extends State { begin: Alignment.topCenter, end: Alignment.bottomCenter, ), - borderColor: - _hovering ? widget.activeBorderColor ?? context.watch().activeColor : Color(0xff565656), + borderColor: _hovering + ? (widget.activeBorderColor ?? context.watch().currentActiveColor) + : Color(0xff565656), borderWidth: 2, borderRadius: BorderRadius.circular(defaultBorderRadius), child: MouseRegion( diff --git a/app/lib/widgets/table_cell_shortcut_listener.dart b/app/lib/widgets/table_cell_shortcut_listener.dart index fc8a963..b1f8282 100644 --- a/app/lib/widgets/table_cell_shortcut_listener.dart +++ b/app/lib/widgets/table_cell_shortcut_listener.dart @@ -1,7 +1,9 @@ import 'package:dde_gesture_manager/constants/constants.dart'; +import 'package:dde_gesture_manager/constants/keyboard_mapper.dart'; import 'package:dde_gesture_manager/models/settings.provider.dart'; import 'package:flutter/material.dart'; import 'package:dde_gesture_manager/extensions.dart'; +import 'package:flutter/services.dart'; class TableCellShortcutListener extends StatefulWidget { final double width; @@ -16,28 +18,62 @@ class TableCellShortcutListener extends StatefulWidget { }) : super(key: key); @override - _TableCellShortcutListenerState createState() => - _TableCellShortcutListenerState(); + _TableCellShortcutListenerState createState() => _TableCellShortcutListenerState(); } class _TableCellShortcutListenerState extends State { List _shortcut = []; + bool inputMode = false; + FocusNode _focusNode = FocusNode(); + + _handleFocusChange() { + if (!_focusNode.hasFocus) { + widget.onComplete(_shortcut.join('+')); + } + } + + _tryToAddKey(LogicalKeyboardKey key) { + if (key.keyLabel.length == 1) key.keyLabel.sout(); + late String _key; + if (keyMapper.containsKey(key)) + _key = keyMapper[key]!; + else if (key.keyLabel.length == 1) _key = key.keyLabel.toLowerCase(); + + if (!_shortcut.contains(_key)) { + setState(() { + _shortcut.add(_key); + }); + } + } @override void initState() { _shortcut = widget.initShortcut.split('+'); + _focusNode.addListener(_handleFocusChange); super.initState(); } @override + void dispose() { + _focusNode.removeListener(_handleFocusChange); + super.dispose(); + } + + @override Widget build(BuildContext context) { return RawKeyboardListener( - focusNode: FocusNode(), + focusNode: _focusNode, onKey: (evt) { - evt.sout(); + RawKeyboard.instance.keysPressed.forEach(_tryToAddKey); + RawKeyboard.instance.keysPressed.sout(); }, child: GestureDetector( - onTap: () {}, + onTap: () { + setState(() { + _shortcut = []; + inputMode = true; + }); + }, child: Focus( autofocus: true, onKeyEvent: (_, __) => KeyEventResult.skipRemainingHandlers, @@ -50,8 +86,7 @@ class _TableCellShortcutListenerState extends State { border: Border.all( width: 2, color: Focus.of(context).hasFocus - ? context.watch().activeColor ?? - Color(0xff565656) + ? context.watch().activeColor ?? Color(0xff565656) : Color(0xff565656)), ), child: Align( @@ -66,27 +101,16 @@ class _TableCellShortcutListenerState extends State { padding: const EdgeInsets.symmetric(horizontal: 2.0), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular( - defaultBorderRadius / 2), + borderRadius: BorderRadius.circular(defaultBorderRadius / 2), color: context.t.dialogBackgroundColor, - border: Border.all( - width: 1, - color: Focus.of(context).hasFocus - ? context - .watch() - .activeColor ?? - Color(0xff565656) - : Color(0xff565656)), + border: Border.all(width: 1, color: Color(0xff565656)), ), child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 5.0), + padding: const EdgeInsets.symmetric(horizontal: 5.0), child: Text( - e, + e.notNull ? e : LocaleKeys.str_null.tr(), style: TextStyle( - color: context - .watch() - .activeColor, + color: context.watch().activeColor, ), ), ), diff --git a/app/resources/langs/en.json b/app/resources/langs/en.json index 7c1a22a..1e35fb9 100644 --- a/app/resources/langs/en.json +++ b/app/resources/langs/en.json @@ -62,5 +62,8 @@ "delete": "delete", "duplicate": "duplicate", "apply": "apply" + }, + "str": { + "null": "Null" } } \ No newline at end of file diff --git a/app/resources/langs/zh-CN.json b/app/resources/langs/zh-CN.json index 12c8ed0..e11ad41 100644 --- a/app/resources/langs/zh-CN.json +++ b/app/resources/langs/zh-CN.json @@ -62,5 +62,8 @@ "delete": "删除", "duplicate": "复制", "apply": "应用" + }, + "str": { + "null": "无" } } \ No newline at end of file