32 changed files with 451 additions and 94 deletions
@ -1,2 +1,2 @@ |
|||||||
outline_name_black_list: |
outline_name_black_list: |
||||||
- 历史,日志,名称,比例,数量,金额,次数,属性,对应,分类,姓名,单位,总数,行使,子项,占比,记录,列表,目标,字段,字符串,动作,方式 |
- 历史,日志,名称,比例,数量,金额,次数,属性,对应,分类,姓名,单位,总数,行使,子项,占比,记录,列表,目标,字段,字符串,动作,方式,类型,类别 |
@ -0,0 +1,79 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
void main2() => runApp(MyApp()); |
||||||
|
|
||||||
|
class MyApp extends StatelessWidget { |
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return MaterialApp(home: DragIconDemo()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class DragIconDemo extends StatefulWidget { |
||||||
|
@override |
||||||
|
_DragIconDemoState createState() => _DragIconDemoState(); |
||||||
|
} |
||||||
|
|
||||||
|
class _DragIconDemoState extends State<DragIconDemo> { |
||||||
|
// 跟踪图标在哪个容器中(1或2) |
||||||
|
int iconContainer = 1; |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Scaffold( |
||||||
|
appBar: AppBar(title: Text('图标拖拽示例')), |
||||||
|
body: Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
||||||
|
children: [ |
||||||
|
// 第一个容器 |
||||||
|
buildContainer( |
||||||
|
containerNumber: 1, |
||||||
|
child: iconContainer == 1 ? buildDraggableIcon() : null, |
||||||
|
), |
||||||
|
|
||||||
|
// 第二个容器 |
||||||
|
buildContainer( |
||||||
|
containerNumber: 2, |
||||||
|
child: iconContainer == 2 ? buildDraggableIcon() : null, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// 构建可拖拽图标 |
||||||
|
Widget buildDraggableIcon() { |
||||||
|
return Draggable<int>( |
||||||
|
data: iconContainer, // 传递当前容器编号作为数据 |
||||||
|
feedback: const Icon(Icons.star, size: 50, color: Colors.amber), |
||||||
|
childWhenDragging: const Opacity( |
||||||
|
opacity: 0.5, |
||||||
|
child: Icon(Icons.star, size: 50, color: Colors.amber), |
||||||
|
), |
||||||
|
child: const Icon(Icons.star, size: 50, color: Colors.amber), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// 构建容器(同时也是拖放目标) |
||||||
|
Widget buildContainer({required int containerNumber, Widget? child}) { |
||||||
|
return DragTarget<int>( |
||||||
|
builder: (context, candidateData, rejectedData) { |
||||||
|
return Container( |
||||||
|
width: 150, |
||||||
|
height: 150, |
||||||
|
decoration: BoxDecoration( |
||||||
|
border: Border.all(color: Colors.blue, width: 2), |
||||||
|
borderRadius: BorderRadius.circular(10), |
||||||
|
), |
||||||
|
child: Center(child: child), |
||||||
|
); |
||||||
|
}, |
||||||
|
onWillAcceptWithDetails: (data) => true, // 接受任何拖拽数据 |
||||||
|
onAcceptWithDetails: (data) { |
||||||
|
setState(() { |
||||||
|
iconContainer = containerNumber; // 更新图标位置 |
||||||
|
}); |
||||||
|
}, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
import 'package:win_text_editor/modules/outline/models/outline_node.dart'; |
||||||
|
import 'package:win_text_editor/shared/base/base_content_controller.dart'; |
||||||
|
|
||||||
|
class CodeCreaterController extends BaseContentController { |
||||||
|
@override |
||||||
|
void onOpenFile(String filePath, {dynamic appendArg}) { |
||||||
|
// TODO: implement onOpenFile |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void onOpenFolder(String folderPath) { |
||||||
|
// TODO: implement onOpenFolder |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void onDropOutlineNode(OutlineNode node) { |
||||||
|
// TODO: implement onDropOutlineNode |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:provider/provider.dart'; |
||||||
|
import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; |
||||||
|
import 'package:win_text_editor/modules/code_creater/controllers/code_creater_controller.dart'; |
||||||
|
|
||||||
|
class CodeCreaterView extends StatefulWidget { |
||||||
|
final String tabId; |
||||||
|
const CodeCreaterView({super.key, required this.tabId}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<CodeCreaterView> createState() => _CodeCreaterViewState(); |
||||||
|
} |
||||||
|
|
||||||
|
class _CodeCreaterViewState extends State<CodeCreaterView> { |
||||||
|
late final CodeCreaterController _controller; |
||||||
|
bool _isControllerFromTabManager = false; |
||||||
|
|
||||||
|
get tabManager => Provider.of<TabItemsController>(context, listen: false); |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
|
||||||
|
final controllerFromManager = tabManager.getController(widget.tabId); |
||||||
|
if (controllerFromManager != null) { |
||||||
|
_controller = controllerFromManager; |
||||||
|
_isControllerFromTabManager = true; |
||||||
|
} else { |
||||||
|
_controller = CodeCreaterController(); |
||||||
|
_isControllerFromTabManager = false; |
||||||
|
tabManager.registerController(widget.tabId, _controller); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void dispose() { |
||||||
|
if (!_isControllerFromTabManager) { |
||||||
|
_controller.dispose(); |
||||||
|
} |
||||||
|
super.dispose(); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return const Center(child: Text('demo')); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
import 'package:path/path.dart' as path; |
||||||
|
import 'package:win_text_editor/modules/outline/models/outline_node.dart'; |
||||||
|
import 'package:win_text_editor/modules/outline/services/component_service.dart'; |
||||||
|
import 'package:win_text_editor/modules/outline/services/uft_object_service.dart'; |
||||||
|
|
||||||
|
class CodePartner { |
||||||
|
final String? name; |
||||||
|
final List<String> fields; |
||||||
|
|
||||||
|
CodePartner({required this.name, required this.fields}); |
||||||
|
|
||||||
|
factory CodePartner.fromOutlineNode(OutlineNode node) { |
||||||
|
String? name; |
||||||
|
List<String> fields = []; |
||||||
|
switch (node.value) { |
||||||
|
case "UFTTable": |
||||||
|
final List<String>? values = UftObjectService.uftObjectMap[node.title]; |
||||||
|
if (values != null && values.isNotEmpty) { |
||||||
|
name = path.basenameWithoutExtension(values[0]); |
||||||
|
fields.addAll(values.sublist(1)); |
||||||
|
} |
||||||
|
break; |
||||||
|
case "Component": |
||||||
|
name = node.name; |
||||||
|
final List<String>? values = ComponentService.componentFieldMap[node.name]; |
||||||
|
if (values != null && values.isNotEmpty) { |
||||||
|
fields.addAll(values.sublist(1)); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
return CodePartner(name: name, fields: fields); |
||||||
|
} |
||||||
|
} |
@ -1,7 +1,10 @@ |
|||||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||||
|
import 'package:win_text_editor/modules/outline/models/outline_node.dart'; |
||||||
|
|
||||||
abstract class BaseContentController with ChangeNotifier { |
abstract class BaseContentController with ChangeNotifier { |
||||||
void onOpenFolder(String folderPath); |
void onOpenFolder(String folderPath); |
||||||
|
|
||||||
void onOpenFile(String filePath, {dynamic appendArg}); |
void onOpenFile(String filePath, {dynamic appendArg}); |
||||||
|
|
||||||
|
void onDropOutlineNode(OutlineNode node); |
||||||
} |
} |
||||||
|
@ -0,0 +1,22 @@ |
|||||||
|
import 'package:mustache_template/mustache.dart'; |
||||||
|
|
||||||
|
void main() { |
||||||
|
final template = Template(''' |
||||||
|
{{#value}}Value exists: {{value}},{{/value}} |
||||||
|
others... |
||||||
|
'''); |
||||||
|
|
||||||
|
print(template.renderString({'value': '有内容'})); |
||||||
|
|
||||||
|
// ✅ 正确做法1:key 完全不存在 |
||||||
|
print(template.renderString({'value': ''})); |
||||||
|
// 输出: "No value provided" |
||||||
|
|
||||||
|
// ✅ 正确做法2:显式设置为 null(需确保非空安全环境) |
||||||
|
print(template.renderString({'value': null})); |
||||||
|
// 输出: "No value provided" |
||||||
|
|
||||||
|
// ❌ 以下会报错: |
||||||
|
// print(template.renderString({'value': ''})); // 空字符串 |
||||||
|
// print(template.renderString({'value': 'Hello'})); // 非空字符串 |
||||||
|
} |
Loading…
Reference in new issue