From 07b9464496331503909ebe6744e0d04b1c03ded6 Mon Sep 17 00:00:00 2001 From: debuggerx Date: Fri, 12 Nov 2021 18:57:34 +0800 Subject: [PATCH] feat: add gesture prop logic. --- app/lib/models/scheme.dart | 113 ++++++++++++++++++++++++++++++++++++++ app/lib/pages/content.dart | 24 ++++++-- app/lib/pages/gesture_editor.dart | 48 ++++++++++++++-- app/lib/pages/local_manager.dart | 2 + app/lib/utils/helper.dart | 26 +++++++-- app/lib/widgets/dde_button.dart | 25 +++++++-- app/resources/langs/en.json | 3 +- app/resources/langs/zh-CN.json | 3 +- 8 files changed, 222 insertions(+), 22 deletions(-) diff --git a/app/lib/models/scheme.dart b/app/lib/models/scheme.dart index 4b54d4f..b88d465 100644 --- a/app/lib/models/scheme.dart +++ b/app/lib/models/scheme.dart @@ -8,6 +8,109 @@ import 'package:uuid/uuid.dart'; typedef OnEditEnd(GestureProp prop); +class _TreeNode { + late List nodes; + + bool get fullFiled => nodes.every((element) => (element as _TreeNode).fullFiled); + + T get availableNode => nodes.firstWhere((element) => !(element as _TreeNode).fullFiled); +} + +class GestureDirectionNode extends _TreeNode { + GestureDirection direction; + bool available = true; + + GestureDirectionNode({required this.direction}); + + @override + get fullFiled => !available; + + get availableNode => null; +} + +class SchemeGestureNode extends _TreeNode { + Gesture type; + + SchemeGestureNode({required this.type}) { + switch (type) { + case Gesture.tap: + nodes = [GestureDirectionNode(direction: GestureDirection.none)]; + break; + case Gesture.swipe: + nodes = [ + GestureDirectionNode(direction: GestureDirection.up), + GestureDirectionNode(direction: GestureDirection.down), + GestureDirectionNode(direction: GestureDirection.left), + GestureDirectionNode(direction: GestureDirection.right), + ]; + break; + case Gesture.pinch: + nodes = [ + GestureDirectionNode(direction: GestureDirection.pinch_in), + GestureDirectionNode(direction: GestureDirection.pinch_out), + ]; + } + } +} + +class SchemeTreeNode extends _TreeNode { + int fingers; + + SchemeTreeNode({required this.fingers}); + + @override + List nodes = [ + SchemeGestureNode(type: Gesture.tap), + SchemeGestureNode(type: Gesture.swipe), + SchemeGestureNode(type: Gesture.pinch), + ]; +} + +class SchemeTree extends _TreeNode { + @override + List nodes = [ + SchemeTreeNode(fingers: 3), + SchemeTreeNode(fingers: 4), + SchemeTreeNode(fingers: 5), + ]; + + @override + String toString() => ''' + 3: + tap: ${nodes[0].nodes[0].nodes[0].available} + swipe: + ↑: ${nodes[0].nodes[1].nodes[0].available} + ↓: ${nodes[0].nodes[1].nodes[1].available} + ←: ${nodes[0].nodes[1].nodes[2].available} + →: ${nodes[0].nodes[1].nodes[3].available} + pinch: + in: ${nodes[0].nodes[2].nodes[0].available} + out:${nodes[0].nodes[2].nodes[1].available} + + 4: + tap: ${nodes[1].nodes[0].nodes[0].available} + swipe: + ↑: ${nodes[1].nodes[1].nodes[0].available} + ↓: ${nodes[1].nodes[1].nodes[1].available} + ←: ${nodes[1].nodes[1].nodes[2].available} + →: ${nodes[1].nodes[1].nodes[3].available} + pinch: + in: ${nodes[1].nodes[2].nodes[0].available} + out:${nodes[1].nodes[2].nodes[1].available} + + 5: + tap: ${nodes[2].nodes[0].nodes[0].available} + swipe: + ↑: ${nodes[2].nodes[1].nodes[0].available} + ↓: ${nodes[2].nodes[1].nodes[1].available} + ←: ${nodes[2].nodes[1].nodes[2].available} + →: ${nodes[2].nodes[1].nodes[3].available} + pinch: + in: ${nodes[2].nodes[2].nodes[0].available} + out:${nodes[2].nodes[2].nodes[1].available} + '''; +} + @ProviderModel(copyable: true) class Scheme { @ProviderModelProp() @@ -41,6 +144,16 @@ class Scheme { Scheme.create({this.name, this.description, this.gestures}) { this.id = Uuid().v1(); } + + SchemeTree buildSchemeTree() { + var schemeTree = SchemeTree(); + this.gestures!.forEach((gesture) { + var schemeTreeNode = schemeTree.nodes.firstWhere((ele) => ele.fingers == gesture.fingers); + var schemeGestureNode = schemeTreeNode.nodes.firstWhere((element) => element.type == gesture.gesture); + schemeGestureNode.nodes.firstWhere((element) => element.direction == gesture.direction).available = false; + }); + return schemeTree; + } } enum Gesture { diff --git a/app/lib/pages/content.dart b/app/lib/pages/content.dart index daa897f..a674c94 100644 --- a/app/lib/pages/content.dart +++ b/app/lib/pages/content.dart @@ -1,10 +1,11 @@ import 'package:dde_gesture_manager/extensions.dart'; +import 'package:dde_gesture_manager/models/content_layout.provider.dart'; +import 'package:dde_gesture_manager/models/scheme.provider.dart'; import 'package:dde_gesture_manager/pages/gesture_editor.dart'; import 'package:dde_gesture_manager/pages/local_manager.dart'; import 'package:dde_gesture_manager/pages/market.dart'; -import 'package:flutter/material.dart'; -import 'package:dde_gesture_manager/models/content_layout.provider.dart'; import 'package:dde_gesture_manager/utils/helper.dart'; +import 'package:flutter/material.dart'; class Content extends StatefulWidget { const Content({Key? key}) : super(key: key); @@ -13,6 +14,10 @@ class Content extends StatefulWidget { _ContentState createState() => _ContentState(); } +class CopiedGesturePropProvider extends GesturePropProvider { + CopiedGesturePropProvider.empty() : super.empty(); +} + class _ContentState extends State { double? preWindowWidth; @@ -21,10 +26,17 @@ class _ContentState extends State { var windowWidth = MediaQuery.of(context).size.width; var preferredPanelsStatus = H.getPreferredPanelsStatus(windowWidth); var widthChanged = preWindowWidth != null && preWindowWidth != windowWidth; - var widget = ChangeNotifierProvider( - create: (context) => ContentLayoutProvider() - ..localManagerOpened = preferredPanelsStatus.localManagerPanelOpened - ..marketOpened = preferredPanelsStatus.marketPanelOpened, + var widget = MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => ContentLayoutProvider() + ..localManagerOpened = preferredPanelsStatus.localManagerPanelOpened + ..marketOpened = preferredPanelsStatus.marketPanelOpened, + ), + ChangeNotifierProvider( + create: (context) => CopiedGesturePropProvider.empty(), + ), + ], builder: (context, child) { if (widthChanged && mounted) { Future.microtask( diff --git a/app/lib/pages/gesture_editor.dart b/app/lib/pages/gesture_editor.dart index 868d8b4..b89aefb 100644 --- a/app/lib/pages/gesture_editor.dart +++ b/app/lib/pages/gesture_editor.dart @@ -5,6 +5,7 @@ import 'package:dde_gesture_manager/models/content_layout.provider.dart'; import 'package:dde_gesture_manager/models/scheme.dart'; import 'package:dde_gesture_manager/models/scheme.provider.dart'; import 'package:dde_gesture_manager/models/settings.provider.dart'; +import 'package:dde_gesture_manager/pages/content.dart'; import 'package:dde_gesture_manager/utils/helper.dart'; import 'package:dde_gesture_manager/utils/keyboard_mapper.dart'; import 'package:dde_gesture_manager/widgets/dde_button.dart'; @@ -152,7 +153,42 @@ class GestureEditor extends StatelessWidget { ), ), ), - Container(height: 10), + Builder(builder: (context) { + var gesturePropProvider = context.watch(); + var copiedGesturePropProvider = context.watch(); + var schemeTree = schemeProvider.buildSchemeTree(); + return Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + DButton.add( + enabled: !gesturePropProvider.editMode! && !schemeTree.fullFiled, + onTap: () { + var schemeProvider = context.read(); + schemeProvider.gestures.sout(); + context.read().setProps(gestures: [ + ...?schemeProvider.gestures, + H.getNextAvailableGestureProp(schemeProvider.buildSchemeTree())!, + ]); + }, + ), + DButton.delete( + enabled: gesturePropProvider != GestureProp.empty() && !gesturePropProvider.editMode!, + ), + DButton.duplicate( + enabled: gesturePropProvider != GestureProp.empty() && !gesturePropProvider.editMode!, + ), + DButton.paste( + enabled: copiedGesturePropProvider != CopiedGesturePropProvider.empty() && + !gesturePropProvider.editMode!, + ), + ] + .map((e) => Padding( + padding: const EdgeInsets.only(top: 3.0, right: 10.0, bottom: 8.0), + child: e, + )) + .toList(), + ); + }), Container( height: 300, decoration: BoxDecoration( @@ -414,9 +450,13 @@ List _buildRowCellsNormal(BuildContext context, bool selected, Gestur }, ).toList(), ) - : Text( - gesture.command ?? '', - ), + : (gesture.type == GestureType.built_in + ? Text( + ('${LocaleKeys.built_in_commands}.${(builtInCommands.contains(gesture.command) ? gesture.command : builtInCommands.first)!}') + .tr()) + : Text( + gesture.command ?? '', + )), Text( gesture.remark ?? '', ), diff --git a/app/lib/pages/local_manager.dart b/app/lib/pages/local_manager.dart index 137ba5e..da9e169 100644 --- a/app/lib/pages/local_manager.dart +++ b/app/lib/pages/local_manager.dart @@ -2,6 +2,7 @@ import 'package:dde_gesture_manager/constants/constants.dart'; import 'package:dde_gesture_manager/extensions.dart'; import 'package:dde_gesture_manager/models/content_layout.provider.dart'; import 'package:dde_gesture_manager/models/local_schemes_provider.dart'; +import 'package:dde_gesture_manager/models/scheme.dart'; import 'package:dde_gesture_manager/models/scheme.provider.dart'; import 'package:dde_gesture_manager/models/settings.provider.dart'; import 'package:dde_gesture_manager/widgets/dde_button.dart'; @@ -111,6 +112,7 @@ class _LocalManagerState extends State { setState(() { _selectedIndex = index; }); + context.read().copyFrom(GestureProp.empty()); }, child: MouseRegion( cursor: SystemMouseCursors.click, diff --git a/app/lib/utils/helper.dart b/app/lib/utils/helper.dart index 4b891ef..d318c12 100644 --- a/app/lib/utils/helper.dart +++ b/app/lib/utils/helper.dart @@ -1,9 +1,10 @@ +import 'package:dde_gesture_manager/constants/constants.dart'; +import 'package:dde_gesture_manager/extensions.dart'; import 'package:dde_gesture_manager/models/content_layout.provider.dart'; import 'package:dde_gesture_manager/models/scheme.dart'; import 'package:flutter/cupertino.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:dde_gesture_manager/constants/constants.dart'; -import 'package:dde_gesture_manager/extensions.dart'; +import 'package:uuid/uuid.dart'; class H { H._(); @@ -85,10 +86,10 @@ class H { GestureDirection.none; static String? getGestureTypeName(GestureType? type) => const { - GestureType.built_in: 'built_in', - GestureType.shortcut: 'shortcut', - GestureType.commandline: 'commandline', - }[type]; + GestureType.built_in: 'built_in', + GestureType.shortcut: 'shortcut', + GestureType.commandline: 'commandline', + }[type]; static GestureType getGestureTypeByName(String typeName) => const { @@ -105,6 +106,19 @@ class H { var rgba = list.map((e) => int.parse(e) ~/ 257).toList(); return Color.fromARGB(rgba[3], rgba[0], rgba[1], rgba[2]); } + + static GestureProp? getNextAvailableGestureProp(SchemeTree tree) { + tree.sout(); + var gestureProp = GestureProp.empty() + ..id = Uuid().v1() + ..type = GestureType.built_in + ..command = builtInCommands.first; + if (tree.fullFiled) return null; + gestureProp.fingers = tree.availableNode.fingers; + gestureProp.gesture = tree.availableNode.availableNode.type; + gestureProp.direction = tree.availableNode.availableNode.availableNode.direction; + return gestureProp; + } } class PreferredPanelsStatus { diff --git a/app/lib/widgets/dde_button.dart b/app/lib/widgets/dde_button.dart index 77a00d6..38bcbc0 100644 --- a/app/lib/widgets/dde_button.dart +++ b/app/lib/widgets/dde_button.dart @@ -33,7 +33,7 @@ class DButton extends StatefulWidget { key: key, width: width, height: height, - onTap: onTap, + onTap: enabled ? onTap : null, child: Tooltip( child: Opacity(opacity: enabled ? 1 : 0.4, child: const Icon(Icons.add, size: 18)), message: LocaleKeys.operation_add.tr(), @@ -50,7 +50,7 @@ class DButton extends StatefulWidget { key: key, width: width, height: height, - onTap: onTap, + onTap: enabled ? onTap : null, child: Tooltip( child: Opacity(opacity: enabled ? 1 : 0.4, child: const Icon(Icons.remove, size: 18)), message: LocaleKeys.operation_delete.tr(), @@ -67,7 +67,7 @@ class DButton extends StatefulWidget { key: key, width: width, height: height, - onTap: onTap, + onTap: enabled ? onTap : null, child: Tooltip( child: Opacity(opacity: enabled ? 1 : 0.4, child: const Icon(Icons.check, size: 18)), message: LocaleKeys.operation_apply.tr(), @@ -84,12 +84,29 @@ class DButton extends StatefulWidget { key: key, width: width, height: height, - onTap: onTap, + onTap: enabled ? onTap : null, child: Tooltip( child: Opacity(opacity: enabled ? 1 : 0.4, child: const Icon(Icons.copy_rounded, size: 18)), message: LocaleKeys.operation_duplicate.tr(), )); + factory DButton.paste({ + Key? key, + required enabled, + GestureTapCallback? onTap, + height = defaultButtonHeight * .7, + width = defaultButtonHeight * .7, + }) => + DButton( + key: key, + width: width, + height: height, + onTap: enabled ? onTap : null, + child: Tooltip( + child: Opacity(opacity: enabled ? 1 : 0.4, child: const Icon(Icons.paste_rounded, size: 18)), + message: LocaleKeys.operation_paste.tr(), + )); + factory DButton.dropdown({ Key? key, width = 60.0, diff --git a/app/resources/langs/en.json b/app/resources/langs/en.json index 9790aad..efb0318 100644 --- a/app/resources/langs/en.json +++ b/app/resources/langs/en.json @@ -61,7 +61,8 @@ "add": "Add", "delete": "delete", "duplicate": "duplicate", - "apply": "apply" + "apply": "apply", + "paste": "paste" }, "str": { "null": "Null" diff --git a/app/resources/langs/zh-CN.json b/app/resources/langs/zh-CN.json index 2883e08..00e0f2d 100644 --- a/app/resources/langs/zh-CN.json +++ b/app/resources/langs/zh-CN.json @@ -61,7 +61,8 @@ "add": "新增", "delete": "删除", "duplicate": "复制", - "apply": "应用" + "apply": "应用", + "paste": "粘贴" }, "str": { "null": "无"