From b9b46990369da830208b2deca32b7950484a030f Mon Sep 17 00:00:00 2001 From: hejl Date: Tue, 20 May 2025 09:35:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=89=A5=E7=A6=BB=E5=87=BA=E6=9D=A5=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=A0=91=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/framework/models/file_node.dart | 12 +- .../template_parser_controller.dart | 75 ++++-- .../widgets/template_parser_view.dart | 33 ++- .../lib/shared/components/file_explorer.dart | 156 ++----------- .../lib/shared/components/tree_view.dart | 214 ++++++++++++++++++ win_text_editor/pubspec.lock | 158 ++++++++----- win_text_editor/pubspec.yaml | 1 + win_text_editor/备忘.txt | 6 +- 8 files changed, 441 insertions(+), 214 deletions(-) create mode 100644 win_text_editor/lib/shared/components/tree_view.dart diff --git a/win_text_editor/lib/framework/models/file_node.dart b/win_text_editor/lib/framework/models/file_node.dart index c38032e..960b174 100644 --- a/win_text_editor/lib/framework/models/file_node.dart +++ b/win_text_editor/lib/framework/models/file_node.dart @@ -1,13 +1,19 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:win_text_editor/shared/components/tree_view.dart'; -class FileNode { +class FileNode implements TreeNode { + @override final String name; final String path; + @override final bool isDirectory; final bool isRoot; + @override final int depth; + @override List children; + @override bool isExpanded; FileNode({ @@ -20,7 +26,11 @@ class FileNode { List? children, }) : children = children ?? []; + @override + String get id => path; + // 获取文件图标数据 + @override IconData get iconData { if (isDirectory) { return Icons.folder; diff --git a/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart b/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart index 08caec5..2559a16 100644 --- a/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart +++ b/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart @@ -1,36 +1,37 @@ -// template_parser_controller.dart - import 'package:file_picker/file_picker.dart'; import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/shared/base/base_content_controller.dart'; +import 'package:xml/xml.dart' as xml; +import 'dart:io'; class TemplateParserController extends BaseContentController { String _filePath = ''; List _treeNodes = []; List _templateItems = []; + String? _errorMessage; // Getters String get filePath => _filePath; List get treeNodes => _treeNodes; List get templateItems => _templateItems; + String? get errorMessage => _errorMessage; Future pickFile() async { final result = await FilePicker.platform.pickFiles(); if (result != null) { _filePath = result.files.single.path!; - _loadTemplateData(); // Simulate loading data + await _loadTemplateData(); notifyListeners(); } } void setFilePath(String path) { _filePath = path; - _loadTemplateData(); // Simulate loading data + _loadTemplateData(); notifyListeners(); } void selectTreeNode(TemplateNode node) { - // Simulate loading items when a tree node is selected _templateItems = List.generate( 10, (index) => TemplateItem(id: index + 1, content: 'Content for ${node.name} item ${index + 1}'), @@ -38,24 +39,50 @@ class TemplateParserController extends BaseContentController { notifyListeners(); } - void _loadTemplateData() { - // Simulate loading tree data - _treeNodes = [ - TemplateNode('Section 1', [ - TemplateNode('Subsection 1.1', []), - TemplateNode('Subsection 1.2', []), - ]), - TemplateNode('Section 2', [ - TemplateNode('Subsection 2.1', []), - TemplateNode('Subsection 2.2', []), - ]), - ]; + Future _loadTemplateData() async { + _errorMessage = null; + _treeNodes = []; + _templateItems = []; - // Simulate loading initial items - _templateItems = List.generate( - 15, - (index) => TemplateItem(id: index + 1, content: 'Initial template content ${index + 1}'), - ); + if (_filePath.isEmpty) return; + + try { + final file = File(_filePath); + final content = await file.readAsString(); + await _parseXmlContent(content); + } catch (e) { + _errorMessage = '格式错误: 不是有效的XML文档'; + Logger().error('Failed to parse XML: $e'); + } + + notifyListeners(); + } + + Future _parseXmlContent(String xmlContent) async { + try { + final document = xml.XmlDocument.parse(xmlContent); + _treeNodes = _buildTreeNodes(document.rootElement); + } on xml.XmlParserException catch (e) { + throw Exception('XML解析错误: ${e.message}'); + } + } + + List _buildTreeNodes(xml.XmlElement element) { + return [ + TemplateNode( + element.name.local, + element.children + .whereType() + .map((e) => _buildTreeNodes(e)) + .expand((nodes) => nodes) + .toList(), + attributes: element.attributes.fold( + {}, + (map, attr) => map!..[attr.name.local] = attr.value, + ), + text: element.text, + ), + ]; } @override @@ -73,8 +100,10 @@ class TemplateParserController extends BaseContentController { class TemplateNode { final String name; final List children; + final Map? attributes; + final String? text; - TemplateNode(this.name, this.children); + TemplateNode(this.name, this.children, {this.attributes, this.text}); } class TemplateItem { diff --git a/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart b/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart index e1b0aaf..82cb65c 100644 --- a/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart +++ b/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart @@ -1,4 +1,3 @@ -// template_parser_view.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; @@ -51,13 +50,14 @@ class _TemplateParserViewState extends State { builder: (context, controller, _) { return TextField( decoration: InputDecoration( - labelText: 'Template File', - hintText: 'Select a template file', + labelText: 'XML File', + hintText: 'Select an XML file', suffixIcon: IconButton( icon: const Icon(Icons.folder_open), onPressed: controller.pickFile, ), border: const OutlineInputBorder(), + errorText: controller.errorMessage, ), controller: TextEditingController(text: controller.filePath), readOnly: true, @@ -69,15 +69,17 @@ class _TemplateParserViewState extends State { Widget _buildMainContent() { return Consumer( builder: (context, controller, _) { + if (controller.errorMessage != null) { + return Center(child: Text(controller.errorMessage!)); + } + return Row( children: [ - // Tree view (30% width) SizedBox( width: MediaQuery.of(context).size.width * 0.3, child: Card(child: _buildTreeView(controller.treeNodes)), ), const SizedBox(width: 8), - // Grid view (70% width) Expanded(child: Card(child: _buildGridView(controller.templateItems))), ], ); @@ -86,6 +88,10 @@ class _TemplateParserViewState extends State { } Widget _buildTreeView(List nodes) { + if (nodes.isEmpty) { + return const Center(child: Text('No XML data available')); + } + return ListView.builder( itemCount: nodes.length, itemBuilder: (context, index) { @@ -96,7 +102,22 @@ class _TemplateParserViewState extends State { Widget _buildTreeNode(TemplateNode node) { return ExpansionTile( - title: Text(node.name), + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(node.name), + if (node.attributes != null && node.attributes!.isNotEmpty) + Text( + node.attributes!.entries.map((e) => '${e.key}="${e.value}"').join(' '), + style: const TextStyle(fontSize: 12, color: Colors.grey), + ), + if (node.text != null && node.text!.trim().isNotEmpty) + Text( + 'Text: ${node.text!.trim()}', + style: const TextStyle(fontSize: 12, color: Colors.blue), + ), + ], + ), children: node.children.map((child) => _buildTreeNode(child)).toList(), onExpansionChanged: (expanded) { if (expanded) { diff --git a/win_text_editor/lib/shared/components/file_explorer.dart b/win_text_editor/lib/shared/components/file_explorer.dart index dba25cc..7bf7b53 100644 --- a/win_text_editor/lib/shared/components/file_explorer.dart +++ b/win_text_editor/lib/shared/components/file_explorer.dart @@ -1,11 +1,12 @@ +import 'dart:math'; + import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../framework/models/file_node.dart'; import '../../framework/controllers/file_provider.dart'; - -import 'dart:math'; +import 'tree_view.dart'; class FileExplorer extends StatefulWidget { final Function(String)? onFileDoubleTap; @@ -28,11 +29,6 @@ class _FileExplorerState extends State { super.dispose(); } - @override - void initState() { - super.initState(); - } - Future _promptForDirectory(BuildContext context) async { final fileProvider = Provider.of(context, listen: false); final String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); @@ -52,29 +48,22 @@ class _FileExplorerState extends State { ); } - void _handleNodeTap(BuildContext context, FileNode node) async { - final fileProvider = Provider.of(context, listen: false); - if (node.isDirectory) { - await fileProvider.loadDirectoryContents(node); - } + // 动态计算总宽度(根据层级深度调整) + double calculateTotalWidth(BuildContext context, FileProvider fileProvider) { + final maxDepth = _getMaxDepth(fileProvider.fileNodes); + return maxDepth * 200 + MediaQuery.of(context).size.width * 0.5; } - int getMaxDepth(List nodes) { + int _getMaxDepth(List nodes) { int maxDepth = 0; for (final node in nodes) { if (node.isDirectory && node.isExpanded) { - maxDepth = max(maxDepth, getMaxDepth(node.children) + 1); + maxDepth = max(maxDepth, _getMaxDepth(node.children) + 1); } } return maxDepth; } - // 动态计算总宽度(示例:根据层级深度调整) - double calculateTotalWidth(BuildContext context, FileProvider fileProvider) { - final maxDepth = getMaxDepth(fileProvider.fileNodes); - return maxDepth * 200 + MediaQuery.of(context).size.width * 0.5; - } - @override Widget build(BuildContext context) { final fileProvider = Provider.of(context); @@ -85,41 +74,28 @@ class _FileExplorerState extends State { children: [ Expanded( child: ClipRect( - // 添加ClipRect防止视觉效果溢出 child: fileProvider.isLoading ? const Center(child: CircularProgressIndicator()) : fileProvider.fileNodes.isEmpty ? Center(child: _buildEmptyPrompt(context)) : Scrollbar( - // 外层:垂直滚动条 controller: _verticalScrollController, thumbVisibility: true, child: SingleChildScrollView( - // 中层:水平滚动 scrollDirection: Axis.horizontal, controller: _horizontalScrollController, child: Scrollbar( - // 内层:水平滚动条(横向) controller: _horizontalScrollController, thumbVisibility: true, scrollbarOrientation: ScrollbarOrientation.bottom, child: SizedBox( width: calculateTotalWidth(context, fileProvider), - child: ListView.builder( - // 内层:垂直列表 - controller: _verticalScrollController, - itemCount: _countVisibleNodes(fileProvider.fileNodes), - itemBuilder: (context, index) { - final node = _getVisibleNode(fileProvider.fileNodes, index); - return _FileNodeWidget( - key: ValueKey(node.path), - node: node, - onTap: () => _handleNodeTap(context, node), - onFileDoubleTap: widget.onFileDoubleTap, - onFolderDoubleTap: widget.onFolderDoubleTap, - ); - }, + child: TreeView( + nodes: fileProvider.fileNodes, + config: const TreeViewConfig(showIcons: true, lazyLoad: true), + onNodeTap: (node) => _handleNodeTap(context, node as FileNode), + onNodeDoubleTap: (node) => _handleNodeDoubleTap(node as FileNode), ), ), ), @@ -132,103 +108,19 @@ class _FileExplorerState extends State { ); } - // 辅助方法:计算所有可见节点数量 - int _countVisibleNodes(List nodes) { - int count = 0; - for (final node in nodes) { - count++; - if (node.isDirectory && node.isExpanded) { - count += _countVisibleNodes(node.children); - } + Future _handleNodeTap(BuildContext context, FileNode node) async { + final fileProvider = Provider.of(context, listen: false); + if (node.isDirectory) { + await fileProvider.loadDirectoryContents(node); } - return count; } - // 辅助方法:根据索引获取可见节点 - FileNode _getVisibleNode(List nodes, int index) { - int current = 0; - for (final node in nodes) { - if (current == index) return node; - current++; - if (node.isDirectory && node.isExpanded) { - final childCount = _countVisibleNodes(node.children); - if (index - current < childCount) { - return _getVisibleNode(node.children, index - current); - } - current += childCount; - } + void _handleNodeDoubleTap(TreeNode node) { + final fileNode = node as FileNode; + if (fileNode.isDirectory && widget.onFolderDoubleTap != null) { + widget.onFolderDoubleTap!(fileNode.path); + } else if (!fileNode.isDirectory && widget.onFileDoubleTap != null) { + widget.onFileDoubleTap!(fileNode.path); } - throw Exception('Index out of bounds: $index (max: ${current - 1})'); - } -} - -class _FileNodeWidget extends StatelessWidget { - final FileNode node; - final VoidCallback onTap; - final Function(String)? onFileDoubleTap; - final Function(String)? onFolderDoubleTap; - - const _FileNodeWidget({ - Key? key, - required this.node, - required this.onTap, - required this.onFileDoubleTap, - required this.onFolderDoubleTap, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - onDoubleTap: () { - if (node.isDirectory && onFolderDoubleTap != null) { - onFolderDoubleTap!(node.path); - } else if (!node.isDirectory && onFileDoubleTap != null) { - onFileDoubleTap!(node.path); - } - }, - splashColor: Colors.transparent, - highlightColor: Colors.grey.withOpacity(0.1), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 0), - child: ListTile( - dense: true, - visualDensity: const VisualDensity(vertical: -4), - contentPadding: const EdgeInsets.symmetric(horizontal: 2), - minVerticalPadding: 0, - leading: _buildLeadingWidget(context), - title: Text(node.name, style: Theme.of(context).textTheme.bodyMedium), - ), - ), - ); - } - - Widget _buildLeadingWidget(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - // Indentation lines - ...List.generate(node.depth, (index) { - return Padding( - padding: const EdgeInsets.only(left: 6, right: 6.0), - child: Container(width: 1.0, height: 32.0, color: Colors.grey[500]), - ); - }), - node.isDirectory - ? Icon( - node.isExpanded ? Icons.expand_more : Icons.chevron_right, - color: Colors.cyan[200], - size: 20, // 缩小图标尺寸 - ) - : const Icon(null, size: 2), - node.isDirectory - ? Icon( - node.isExpanded ? Icons.folder_open : Icons.folder, - color: Colors.cyan[500], - size: 18, - ) - : Icon(node.iconData, color: Colors.amber[700], size: 20), - ], - ); } } diff --git a/win_text_editor/lib/shared/components/tree_view.dart b/win_text_editor/lib/shared/components/tree_view.dart new file mode 100644 index 0000000..0f53565 --- /dev/null +++ b/win_text_editor/lib/shared/components/tree_view.dart @@ -0,0 +1,214 @@ +import 'package:flutter/material.dart'; + +/// 树节点数据接口 +abstract class TreeNode { + String get id; + String get name; + bool get isExpanded; + bool get isDirectory; + List get children; + int get depth; + IconData? get iconData; +} + +/// 树视图配置 +class TreeViewConfig { + final bool lazyLoad; // 是否延时加载 + final bool singleSelect; // 是否单一选择 + final bool showCheckboxes; // 是否显示复选框 + final bool showIcons; // 是否显示图标 + final Color? selectedColor; // 选中项背景色 + final double indentWidth; // 缩进宽度 + + const TreeViewConfig({ + this.lazyLoad = false, + this.singleSelect = false, + this.showCheckboxes = false, + this.showIcons = true, + this.selectedColor, + this.indentWidth = 24.0, + }); +} + +/// 通用树视图组件 +class TreeView extends StatefulWidget { + final List nodes; + final TreeViewConfig config; + final Function(TreeNode)? onNodeTap; + final Function(TreeNode)? onNodeDoubleTap; + final Function(TreeNode, bool?)? onNodeCheckChanged; + + const TreeView({ + super.key, + required this.nodes, + this.config = const TreeViewConfig(), + this.onNodeTap, + this.onNodeDoubleTap, + this.onNodeCheckChanged, + }); + + @override + State createState() => _TreeViewState(); +} + +class _TreeViewState extends State { + final Set _selectedIds = {}; + final Set _checkedIds = {}; + + @override + Widget build(BuildContext context) { + return ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: _countVisibleNodes(widget.nodes), + itemBuilder: (context, index) { + final node = _getVisibleNode(widget.nodes, index); + return _TreeNodeWidget( + node: node, + config: widget.config, + isSelected: _selectedIds.contains(node.id), + isChecked: _checkedIds.contains(node.id), + onTap: () => _handleNodeTap(node), + onDoubleTap: () => widget.onNodeDoubleTap?.call(node), + onCheckChanged: (value) => _handleNodeCheckChanged(node, value), + ); + }, + ); + } + + void _handleNodeTap(TreeNode node) { + if (widget.config.singleSelect) { + setState(() { + _selectedIds.clear(); + _selectedIds.add(node.id); + }); + } + + widget.onNodeTap?.call(node); + } + + void _handleNodeCheckChanged(TreeNode node, bool? value) { + setState(() { + if (value == true) { + _checkedIds.add(node.id); + } else { + _checkedIds.remove(node.id); + } + }); + + widget.onNodeCheckChanged?.call(node, value); + } + + int _countVisibleNodes(List nodes) { + int count = 0; + for (final node in nodes) { + count++; + if (node.isDirectory && node.isExpanded) { + count += _countVisibleNodes(node.children); + } + } + return count; + } + + TreeNode _getVisibleNode(List nodes, int index) { + int current = 0; + for (final node in nodes) { + if (current == index) return node; + current++; + if (node.isDirectory && node.isExpanded) { + final childCount = _countVisibleNodes(node.children); + if (index - current < childCount) { + return _getVisibleNode(node.children, index - current); + } + current += childCount; + } + } + throw Exception('Index out of bounds: $index'); + } +} + +class _TreeNodeWidget extends StatelessWidget { + final TreeNode node; + final TreeViewConfig config; + final bool isSelected; + final bool isChecked; + final VoidCallback onTap; + final VoidCallback onDoubleTap; + final Function(bool?)? onCheckChanged; + + const _TreeNodeWidget({ + required this.node, + required this.config, + required this.isSelected, + required this.isChecked, + required this.onTap, + required this.onDoubleTap, + this.onCheckChanged, + }); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + onDoubleTap: onDoubleTap, + splashColor: Colors.transparent, + highlightColor: Colors.grey.withOpacity(0.1), + child: Container( + color: + isSelected + ? (config.selectedColor ?? Theme.of(context).primaryColor.withOpacity(0.1)) + : Colors.transparent, + padding: const EdgeInsets.symmetric(vertical: 0), + child: ListTile( + dense: true, + visualDensity: const VisualDensity(vertical: -4), + contentPadding: const EdgeInsets.symmetric(horizontal: 2), + minVerticalPadding: 0, + leading: _buildLeadingWidget(context), + title: Text(node.name, style: Theme.of(context).textTheme.bodyMedium), + trailing: + config.showCheckboxes + ? Checkbox( + value: isChecked, + onChanged: onCheckChanged, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ) + : null, + ), + ), + ); + } + + Widget _buildLeadingWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 缩进线 + ...List.generate(node.depth, (index) { + return Padding( + padding: EdgeInsets.only(left: 6, right: config.indentWidth - 6), + child: Container(width: 1.0, height: 32.0, color: Colors.grey[500]), + ); + }), + + // 展开/折叠图标 + if (node.isDirectory) + Icon( + node.isExpanded ? Icons.expand_more : Icons.chevron_right, + color: Colors.cyan[200], + size: 20, + ), + + // 节点图标 + if (config.showIcons) + node.isDirectory + ? Icon( + node.isExpanded ? Icons.folder_open : Icons.folder, + color: Colors.cyan[500], + size: 18, + ) + : Icon(node.iconData ?? Icons.insert_drive_file, color: Colors.amber[700], size: 20), + ], + ); + } +} diff --git a/win_text_editor/pubspec.lock b/win_text_editor/pubspec.lock index c508250..6718fb9 100644 --- a/win_text_editor/pubspec.lock +++ b/win_text_editor/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: async sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.12.0" bitsdojo_window: @@ -14,7 +14,7 @@ packages: description: name: bitsdojo_window sha256: "88ef7765dafe52d97d7a3684960fb5d003e3151e662c18645c1641c22b873195" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.6" bitsdojo_window_linux: @@ -22,7 +22,7 @@ packages: description: name: bitsdojo_window_linux sha256: "9519c0614f98be733e0b1b7cb15b827007886f6fe36a4fb62cf3d35b9dd578ab" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.4" bitsdojo_window_macos: @@ -30,7 +30,7 @@ packages: description: name: bitsdojo_window_macos sha256: f7c5be82e74568c68c5b8449e2c5d8fd12ec195ecd70745a7b9c0f802bb0268f - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.4" bitsdojo_window_platform_interface: @@ -38,7 +38,7 @@ packages: description: name: bitsdojo_window_platform_interface sha256: "65daa015a0c6dba749bdd35a0f092e7a8ba8b0766aa0480eb3ef808086f6e27c" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.2" bitsdojo_window_windows: @@ -46,7 +46,7 @@ packages: description: name: bitsdojo_window_windows sha256: fa982cf61ede53f483e50b257344a1c250af231a3cdc93a7064dd6dc0d720b68 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.6" boolean_selector: @@ -54,7 +54,7 @@ packages: description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.2" characters: @@ -62,7 +62,7 @@ packages: description: name: characters sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.0" clock: @@ -70,7 +70,7 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.2" collection: @@ -78,7 +78,7 @@ packages: description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.19.1" cross_file: @@ -86,7 +86,7 @@ packages: description: name: cross_file sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.3.4+2" expandable: @@ -94,7 +94,7 @@ packages: description: name: expandable sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.0.1" fake_async: @@ -102,7 +102,7 @@ packages: description: name: fake_async sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.3.2" ffi: @@ -110,7 +110,7 @@ packages: description: name: ffi sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.4" file_picker: @@ -118,7 +118,7 @@ packages: description: name: file_picker sha256: "77f8e81d22d2a07d0dee2c62e1dda71dc1da73bf43bb2d45af09727406167964" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "10.1.9" flutter: @@ -126,12 +126,20 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_js: + dependency: "direct main" + description: + name: flutter_js + sha256: "0d22d73a474b5b80c3ab5508e7c3eab6fb20beea9dec45bbd21088cfd27a5e61" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "0.8.3" flutter_lints: dependency: "direct dev" description: name: flutter_lints sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.3" flutter_plugin_android_lifecycle: @@ -139,7 +147,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.28" flutter_syntax_view: @@ -147,7 +155,7 @@ packages: description: name: flutter_syntax_view sha256: c5017bbedfdcf538daba765e16541fcb26434071655ca00cea7cbc205a70246a - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.1.7" flutter_test: @@ -160,12 +168,28 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: transitive + description: + name: http + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.4.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "4.1.2" leak_tracker: dependency: transitive description: name: leak_tracker sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "10.0.8" leak_tracker_flutter_testing: @@ -173,7 +197,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.9" leak_tracker_testing: @@ -181,7 +205,7 @@ packages: description: name: leak_tracker_testing sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.1" lints: @@ -189,7 +213,7 @@ packages: description: name: lints sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.1" matcher: @@ -197,7 +221,7 @@ packages: description: name: matcher sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.12.17" material_color_utilities: @@ -205,7 +229,7 @@ packages: description: name: material_color_utilities sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.11.1" meta: @@ -213,7 +237,7 @@ packages: description: name: meta sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.16.0" nested: @@ -221,7 +245,7 @@ packages: description: name: nested sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.0" path: @@ -229,7 +253,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.9.1" path_provider: @@ -237,7 +261,7 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.5" path_provider_android: @@ -245,7 +269,7 @@ packages: description: name: path_provider_android sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.17" path_provider_foundation: @@ -253,7 +277,7 @@ packages: description: name: path_provider_foundation sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.1" path_provider_linux: @@ -261,7 +285,7 @@ packages: description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -269,7 +293,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.2" path_provider_windows: @@ -277,15 +301,23 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "6.1.0" platform: dependency: transitive description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.1.6" plugin_platform_interface: @@ -293,7 +325,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.8" provider: @@ -301,7 +333,7 @@ packages: description: name: provider sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.1.5" screen_retriever: @@ -309,7 +341,7 @@ packages: description: name: screen_retriever sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.9" sky_engine: @@ -322,7 +354,7 @@ packages: description: name: source_span sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.10.1" stack_trace: @@ -330,7 +362,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.12.1" stream_channel: @@ -338,7 +370,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.4" string_scanner: @@ -346,15 +378,23 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "0.3.1" syncfusion_flutter_core: dependency: transitive description: name: syncfusion_flutter_core sha256: "9f0a4593f7642b2f106e329734d0e5fc746baf8d0a59495eec586cd0d9ba7d02" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "22.2.12" syncfusion_flutter_datagrid: @@ -362,7 +402,7 @@ packages: description: name: syncfusion_flutter_datagrid sha256: ae93228333ebed39bc59c90bc40cfd3d5a0361591a330fe551b355d3a49a265c - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "22.2.12" term_glyph: @@ -370,7 +410,7 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.2.2" test_api: @@ -378,15 +418,23 @@ packages: description: name: test_api sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.7.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.4" vm_service: @@ -394,7 +442,7 @@ packages: description: name: vm_service sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "14.3.1" web: @@ -402,7 +450,7 @@ packages: description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.1" win32: @@ -410,7 +458,7 @@ packages: description: name: win32 sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.13.0" window_manager: @@ -418,7 +466,7 @@ packages: description: name: window_manager sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.3.9" xdg_directories: @@ -426,9 +474,17 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.0" + xml: + dependency: "direct main" + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "6.5.0" sdks: dart: ">=3.7.0 <4.0.0" flutter: ">=3.27.0" diff --git a/win_text_editor/pubspec.yaml b/win_text_editor/pubspec.yaml index 93e68a1..d069363 100644 --- a/win_text_editor/pubspec.yaml +++ b/win_text_editor/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: path: ^1.8.0 syncfusion_flutter_datagrid: ^22.1.40 flutter_js: ^0.8.3 + xml: ^6.5.0 dev_dependencies: flutter_test: diff --git a/win_text_editor/备忘.txt b/win_text_editor/备忘.txt index 7fcc5fe..dece232 100644 --- a/win_text_editor/备忘.txt +++ b/win_text_editor/备忘.txt @@ -3,4 +3,8 @@ 使用国内镜像(针对中国用户) $env:PUB_HOSTED_URL="https://pub.flutter-io.cn" -$env:FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn" \ No newline at end of file +$env:FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn" + +其他备用镜像 +$env:PUB_HOSTED_URL="https://mirrors.tuna.tsinghua.edu.cn/dart-pub" +$env:PUB_HOSTED_URL="https://pub.dartlang.org" \ No newline at end of file