Browse Source

剥离出来一个树视图

master
hejl 2 months ago
parent
commit
b9b4699036
  1. 12
      win_text_editor/lib/framework/models/file_node.dart
  2. 75
      win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart
  3. 33
      win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart
  4. 156
      win_text_editor/lib/shared/components/file_explorer.dart
  5. 214
      win_text_editor/lib/shared/components/tree_view.dart
  6. 158
      win_text_editor/pubspec.lock
  7. 1
      win_text_editor/pubspec.yaml
  8. 6
      win_text_editor/备忘.txt

12
win_text_editor/lib/framework/models/file_node.dart

@ -1,13 +1,19 @@ @@ -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<FileNode> children;
@override
bool isExpanded;
FileNode({
@ -20,7 +26,11 @@ class FileNode { @@ -20,7 +26,11 @@ class FileNode {
List<FileNode>? children,
}) : children = children ?? [];
@override
String get id => path;
//
@override
IconData get iconData {
if (isDirectory) {
return Icons.folder;

75
win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart

@ -1,36 +1,37 @@ @@ -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<TemplateNode> _treeNodes = [];
List<TemplateItem> _templateItems = [];
String? _errorMessage;
// Getters
String get filePath => _filePath;
List<TemplateNode> get treeNodes => _treeNodes;
List<TemplateItem> get templateItems => _templateItems;
String? get errorMessage => _errorMessage;
Future<void> 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 { @@ -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<void> _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<void> _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<TemplateNode> _buildTreeNodes(xml.XmlElement element) {
return [
TemplateNode(
element.name.local,
element.children
.whereType<xml.XmlElement>()
.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 { @@ -73,8 +100,10 @@ class TemplateParserController extends BaseContentController {
class TemplateNode {
final String name;
final List<TemplateNode> children;
final Map<String, String>? attributes;
final String? text;
TemplateNode(this.name, this.children);
TemplateNode(this.name, this.children, {this.attributes, this.text});
}
class TemplateItem {

33
win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart

@ -1,4 +1,3 @@ @@ -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<TemplateParserView> { @@ -51,13 +50,14 @@ class _TemplateParserViewState extends State<TemplateParserView> {
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<TemplateParserView> { @@ -69,15 +69,17 @@ class _TemplateParserViewState extends State<TemplateParserView> {
Widget _buildMainContent() {
return Consumer<TemplateParserController>(
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<TemplateParserView> { @@ -86,6 +88,10 @@ class _TemplateParserViewState extends State<TemplateParserView> {
}
Widget _buildTreeView(List<TemplateNode> 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<TemplateParserView> { @@ -96,7 +102,22 @@ class _TemplateParserViewState extends State<TemplateParserView> {
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) {

156
win_text_editor/lib/shared/components/file_explorer.dart

@ -1,11 +1,12 @@ @@ -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<FileExplorer> { @@ -28,11 +29,6 @@ class _FileExplorerState extends State<FileExplorer> {
super.dispose();
}
@override
void initState() {
super.initState();
}
Future<void> _promptForDirectory(BuildContext context) async {
final fileProvider = Provider.of<FileProvider>(context, listen: false);
final String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
@ -52,29 +48,22 @@ class _FileExplorerState extends State<FileExplorer> { @@ -52,29 +48,22 @@ class _FileExplorerState extends State<FileExplorer> {
);
}
void _handleNodeTap(BuildContext context, FileNode node) async {
final fileProvider = Provider.of<FileProvider>(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<FileNode> nodes) {
int _getMaxDepth(List<FileNode> 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<FileProvider>(context);
@ -85,41 +74,28 @@ class _FileExplorerState extends State<FileExplorer> { @@ -85,41 +74,28 @@ class _FileExplorerState extends State<FileExplorer> {
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<FileExplorer> { @@ -132,103 +108,19 @@ class _FileExplorerState extends State<FileExplorer> {
);
}
//
int _countVisibleNodes(List<FileNode> nodes) {
int count = 0;
for (final node in nodes) {
count++;
if (node.isDirectory && node.isExpanded) {
count += _countVisibleNodes(node.children);
}
Future<void> _handleNodeTap(BuildContext context, FileNode node) async {
final fileProvider = Provider.of<FileProvider>(context, listen: false);
if (node.isDirectory) {
await fileProvider.loadDirectoryContents(node);
}
return count;
}
//
FileNode _getVisibleNode(List<FileNode> 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),
],
);
}
}

214
win_text_editor/lib/shared/components/tree_view.dart

@ -0,0 +1,214 @@ @@ -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<TreeNode> 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<TreeNode> 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<TreeView> createState() => _TreeViewState();
}
class _TreeViewState extends State<TreeView> {
final Set<String> _selectedIds = {};
final Set<String> _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<TreeNode> nodes) {
int count = 0;
for (final node in nodes) {
count++;
if (node.isDirectory && node.isExpanded) {
count += _countVisibleNodes(node.children);
}
}
return count;
}
TreeNode _getVisibleNode(List<TreeNode> 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),
],
);
}
}

158
win_text_editor/pubspec.lock

@ -6,7 +6,7 @@ packages: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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"

1
win_text_editor/pubspec.yaml

@ -20,6 +20,7 @@ dependencies: @@ -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:

6
win_text_editor/备忘.txt

@ -3,4 +3,8 @@ @@ -3,4 +3,8 @@
使用国内镜像(针对中国用户)
$env:PUB_HOSTED_URL="https://pub.flutter-io.cn"
$env:FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn"
$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"
Loading…
Cancel
Save